Updated documentation for 0.2 release
[mtetherd] / net.c
1 /*
2   mtetherd
3   (c) 2010 Gregor Riepl <onitake@gmail.com>
4   
5   Tethering utility for Maemo
6   
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11   
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16   
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <string.h>
22 #include <netinet/in.h>
23 #include "net.h"
24 #include "plugin.h"
25
26 #define MTETHERD_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_MTETHERD_DEVICE, MTetherDDevicePrivate))
27
28 G_DEFINE_TYPE(MTetherDDevice, mtetherd_device, G_TYPE_OBJECT);
29
30 static const guint MAX_DEVICES = 64;
31 // Host order 192.168.255.0
32 static const in_addr_t HOST_BASE_ADDRESS = 0xc0a8ff00;
33 // Host order 255.255.255.252
34 static const in_addr_t HOST_NETMASK = 0xfffffffc;
35 // Host order 0.0.0.1
36 static const in_addr_t HOST_ROUTER = 0x00000001;
37 // Host order 0.0.0.1
38 static const in_addr_t HOST_DHCP = 0x00000002;
39
40 struct _MTetherDDevicePrivate {
41         gchar *interface;
42         gchar *udi;
43         // Network order
44         in_addr_t addr;
45         in_addr_t netmask;
46         in_addr_t dhcp_start;
47         in_addr_t dhcp_end;
48 };
49
50 static void mtetherd_device_finalize(GObject *object) {
51         MTetherDDevice *self = MTETHERD_DEVICE(object);
52
53         if (self && self->priv) {
54                 g_free(self->priv->interface);
55                 g_free(self->priv->udi);
56         }
57 }
58
59 static void mtetherd_device_class_init(MTetherDDeviceClass *klass) {
60         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
61
62         gobject_class->finalize = mtetherd_device_finalize;
63         g_type_class_add_private(klass, sizeof(MTetherDDevicePrivate));
64 }
65
66 static void mtetherd_device_init(MTetherDDevice *self) {
67         self->priv = MTETHERD_DEVICE_GET_PRIVATE(self);
68         
69         if (self->priv) {
70                 self->priv->interface = NULL;
71                 self->priv->udi = NULL;
72                 self->priv->addr = 0;
73                 self->priv->netmask = 0;
74                 self->priv->dhcp_start = 0;
75                 self->priv->dhcp_end = 0;
76         }
77 }
78
79 static void mtetherd_device_set_interface(MTetherDDevice *self, const gchar *interface) {
80         if (self && self->priv) {
81                 if (self->priv->interface) {
82                         g_free(self->priv->interface);
83                 }
84                 if (interface) {
85                         size_t len = strlen(interface);
86                         self->priv->interface = g_malloc(len + 1);
87                         size_t i, j;
88                         for (i = 0, j = 0; i < len; i++) {
89                                 if (g_ascii_isalnum(interface[i])) {
90                                         self->priv->interface[j] = interface[i];
91                                         j++;
92                                 }
93                         }
94                         self->priv->interface[j] = '\0';
95                 }
96         }
97 }
98
99 static void mtetherd_device_set_udi(MTetherDDevice *self, const gchar *udi) {
100         if (self && self->priv) {
101                 if (self->priv->udi) {
102                         g_free(self->priv->udi);
103                 }
104                 if (udi) {
105                         size_t len = strlen(udi);
106                         self->priv->udi = g_malloc(len + 1);
107                         size_t i, j;
108                         for (i = 0, j = 0; i < len; i++) {
109                                 if (g_ascii_isalnum(udi[i]) || g_ascii_ispunct(udi[i])) {
110                                         self->priv->udi[j] = udi[i];
111                                         j++;
112                                 }
113                         }
114                         self->priv->udi[j] = '\0';
115                 }
116         }
117 }
118
119 void mtetherd_device_set_index(MTetherDDevice *self, guint index) {
120         if (self && self->priv) {
121                 // Maximum is 63, we need four addresses per subnet
122                 if (index < 64) {
123                         in_addr_t subnet = HOST_BASE_ADDRESS | (index << 2);
124                         in_addr_t addr = subnet | HOST_ROUTER;
125                         in_addr_t end = subnet | HOST_DHCP;
126                         self->priv->addr = htonl(addr);
127                         self->priv->netmask = htonl(HOST_NETMASK);
128                         self->priv->dhcp_start = htonl(addr);
129                         self->priv->dhcp_end = htonl(end);
130                 } else {
131                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Invalid subnet index: %u (0..%u expected)", index, MAX_DEVICES - 1);
132                 }
133         }
134 }
135
136 MTetherDDevice *mtetherd_device_new(const gchar *interface, const gchar *udi) {
137         MTetherDDevice *self = MTETHERD_DEVICE(g_object_new(TYPE_MTETHERD_DEVICE, NULL));
138
139         if (self && self->priv) {
140                 mtetherd_device_set_interface(self, interface);
141                 mtetherd_device_set_udi(self, udi);
142         }
143         
144         return self;
145 }
146
147 const gchar *mtetherd_device_get_interface(MTetherDDevice *self) {
148         if (self && self->priv) {
149                 return self->priv->interface;
150         }
151         return NULL;
152 }
153
154 gchar *mtetherd_device_get_addr(MTetherDDevice *self) {
155         if (self && self->priv) {
156                 guchar a = self->priv->addr & 0xff;
157                 guchar b = (self->priv->addr >> 8) & 0xff;
158                 guchar c = (self->priv->addr >> 16) & 0xff;
159                 guchar d = (self->priv->addr >> 24) & 0xff;
160                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
161         }
162         return NULL;
163 }
164
165 gchar *mtetherd_device_get_netmask(MTetherDDevice *self) {
166         if (self && self->priv) {
167                 guchar a = self->priv->netmask & 0xff;
168                 guchar b = (self->priv->netmask >> 8) & 0xff;
169                 guchar c = (self->priv->netmask >> 16) & 0xff;
170                 guchar d = (self->priv->netmask >> 24) & 0xff;
171                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
172         }
173         return NULL;
174 }
175
176 gchar *mtetherd_device_get_dhcp_start(MTetherDDevice *self) {
177         if (self && self->priv) {
178                 guchar a = self->priv->dhcp_start & 0xff;
179                 guchar b = (self->priv->dhcp_start >> 8) & 0xff;
180                 guchar c = (self->priv->dhcp_start >> 16) & 0xff;
181                 guchar d = (self->priv->dhcp_start >> 24) & 0xff;
182                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
183         }
184         return NULL;
185 }
186
187 gchar *mtetherd_device_get_dhcp_end(MTetherDDevice *self) {
188         if (self && self->priv) {
189                 guchar a = self->priv->dhcp_end & 0xff;
190                 guchar b = (self->priv->dhcp_end >> 8) & 0xff;
191                 guchar c = (self->priv->dhcp_end >> 16) & 0xff;
192                 guchar d = (self->priv->dhcp_end >> 24) & 0xff;
193                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
194         }
195         return NULL;
196 }
197
198 static gint mtetherd_device_list_find_index(gpointer *array, const gchar *udi) {
199         guint i;
200         for (i = 0; i < MAX_DEVICES; i++) {
201                 MTetherDDevice *device = MTETHERD_DEVICE(array[i]);
202                 if (device && device->priv) {
203                         if (g_strcmp0(device->priv->udi, udi) == 0) {
204                                 return i;
205                         }
206                 }
207         }
208         return -1;
209 }
210
211 gpointer mtetherd_device_list_new() {
212         return g_malloc0(sizeof(gpointer) * MAX_DEVICES);
213 }
214
215 void mtetherd_device_list_free(gpointer list) {
216         if (list) {
217                 gpointer *array = (gpointer *) list;
218                 
219                 guint i;
220                 for (i = 0; i < MAX_DEVICES; i++) {
221                         if (array[i]) {
222                                 g_object_unref(G_OBJECT(array[i]));
223                         }
224                 }
225                 g_free(array);
226         }
227 }
228
229 MTetherDDevice *mtetherd_device_list_find(gpointer list, const gchar *udi) {
230         if (list) {
231                 gpointer *array = (gpointer *) list;
232         
233                 gint index = mtetherd_device_list_find_index(array, udi);
234                 if (index >= 0) {
235                         return array[index];
236                 }
237         }
238         return NULL;
239 }
240
241 gboolean mtetherd_device_list_add(gpointer list, MTetherDDevice *device) {
242         if (list) {
243                 gpointer *array = (gpointer *) list;
244                 
245                 guint i;
246                 for (i = 0; i < MAX_DEVICES; i++) {
247                         if (!array[i]) {
248                                 array[i] = (gpointer) device;
249                                 mtetherd_device_set_index(device, i);
250                                 return TRUE;
251                         }
252                 }
253         }
254         return FALSE;
255 }
256
257 gboolean mtetherd_device_list_remove(gpointer list, const gchar *udi) {
258         if (list) {
259                 gpointer *array = (gpointer *) list;
260                 
261                 gint index = mtetherd_device_list_find_index(array, udi);
262                 if (index >= 0) {
263                         g_object_unref(G_OBJECT(array[index]));
264                         array[index] = NULL;
265                         return TRUE;
266                 }
267         }
268         return FALSE;
269 }
270
271 gboolean mtetherd_device_ok(const gchar *interface) {
272         if (g_str_has_prefix(interface, "usb")) {
273                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s has prefix %s", interface, "usb");
274                 return TRUE;
275         }
276         if (g_str_has_prefix(interface, "bnep")) {
277                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s has prefix %s", interface, "bnep");
278                 return TRUE;
279         }
280         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s has unknown prefix :(", interface);
281         return FALSE;
282 }
283