Added empty network setup scripts
[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
25 #define MTETHERD_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_MTETHERD_DEVICE, MTetherDDevicePrivate))
26
27 G_DEFINE_TYPE(MTetherDDevice, mtetherd_device, G_TYPE_OBJECT);
28
29 static const guint MAX_DEVICES = 64;
30 // Host order 192.168.255.0
31 static const in_addr_t HOST_BASE_ADDRESS = 0xc0a8ff00;
32 // Host order 255.255.255.252
33 static const in_addr_t HOST_NETMASK = 0xfffffffc;
34 // Host order 0.0.0.2
35 static const in_addr_t HOST_ROUTER = 0x00000002;
36 // Host order 0.0.0.1
37 static const in_addr_t HOST_DHCP = 0x00000001;
38
39 struct _MTetherDDevicePrivate {
40         gchar *interface;
41         gchar *udi;
42         // Network order
43         in_addr_t addr;
44         in_addr_t netmask;
45         in_addr_t dhcp_start;
46         in_addr_t dhcp_end;
47 };
48
49 static void mtetherd_device_finalize(GObject *object) {
50         MTetherDDevice *self = MTETHERD_DEVICE(object);
51
52         if (self && self->priv) {
53                 g_free(self->priv->interface);
54                 g_free(self->priv->udi);
55         }
56 }
57
58 static void mtetherd_device_class_init(MTetherDDeviceClass *klass) {
59         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
60
61         gobject_class->finalize = mtetherd_device_finalize;
62         g_type_class_add_private(klass, sizeof(MTetherDDevicePrivate));
63 }
64
65 static void mtetherd_device_init(MTetherDDevice *self) {
66         self->priv = MTETHERD_DEVICE_GET_PRIVATE(self);
67         
68         if (self->priv) {
69                 self->priv->interface = NULL;
70                 self->priv->udi = NULL;
71                 self->priv->addr = 0;
72                 self->priv->netmask = 0;
73                 self->priv->dhcp_start = 0;
74                 self->priv->dhcp_end = 0;
75         }
76 }
77
78 static void mtetherd_device_set_interface(MTetherDDevice *self, const gchar *interface) {
79         if (self && self->priv) {
80                 if (self->priv->interface) {
81                         g_free(self->priv->interface);
82                 }
83                 if (interface) {
84                         size_t len = strlen(interface);
85                         self->priv->interface = g_malloc(len + 1);
86                         size_t i, j;
87                         for (i = 0, j = 0; i < len; i++) {
88                                 if (g_ascii_isalnum(interface[i])) {
89                                         self->priv->interface[j] = interface[i];
90                                         j++;
91                                 }
92                         }
93                         self->priv->interface[j] = '\0';
94                 }
95         }
96 }
97
98 static void mtetherd_device_set_udi(MTetherDDevice *self, const gchar *udi) {
99         if (self && self->priv) {
100                 if (self->priv->udi) {
101                         g_free(self->priv->udi);
102                 }
103                 if (udi) {
104                         size_t len = strlen(udi);
105                         self->priv->udi = g_malloc(len + 1);
106                         size_t i, j;
107                         for (i = 0, j = 0; i < len; i++) {
108                                 if (g_ascii_isalnum(udi[i]) || g_ascii_ispunct(udi[i])) {
109                                         self->priv->udi[j] = udi[i];
110                                         j++;
111                                 }
112                         }
113                         self->priv->udi[j] = '\0';
114                 }
115         }
116 }
117
118 void mtetherd_device_set_index(MTetherDDevice *self, guint index) {
119         if (self && self->priv) {
120                 // Maximum is 63, we need four addresses per subnet
121                 if (index < 64) {
122                         in_addr_t subnet = HOST_BASE_ADDRESS | (index << 2);
123                         in_addr_t addr = subnet | HOST_ROUTER;
124                         in_addr_t start = subnet | HOST_DHCP;
125                         self->priv->addr = htonl(addr);
126                         self->priv->netmask = htonl(HOST_NETMASK);
127                         self->priv->dhcp_start = htonl(start);
128                         self->priv->dhcp_end = htonl(addr);
129                 } else {
130                         g_warning("Invalid subnet index: %u (0..%u expected)", index, MAX_DEVICES - 1);
131                 }
132         }
133 }
134
135 MTetherDDevice *mtetherd_device_new(const gchar *interface, const gchar *udi) {
136         MTetherDDevice *self = MTETHERD_DEVICE(g_object_new(TYPE_MTETHERD_DEVICE, NULL));
137
138         if (self && self->priv) {
139                 mtetherd_device_set_interface(self, interface);
140                 mtetherd_device_set_udi(self, udi);
141         }
142         
143         return self;
144 }
145
146 const gchar *mtetherd_device_get_interface(MTetherDDevice *self) {
147         if (self && self->priv) {
148                 return self->priv->interface;
149         }
150         return NULL;
151 }
152
153 gchar *mtetherd_device_get_addr(MTetherDDevice *self) {
154         if (self && self->priv) {
155                 guchar a = self->priv->addr & 0xff;
156                 guchar b = (self->priv->addr >> 8) & 0xff;
157                 guchar c = (self->priv->addr >> 16) & 0xff;
158                 guchar d = (self->priv->addr >> 24) & 0xff;
159                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
160         }
161         return NULL;
162 }
163
164 gchar *mtetherd_device_get_netmask(MTetherDDevice *self) {
165         if (self && self->priv) {
166                 guchar a = self->priv->netmask & 0xff;
167                 guchar b = (self->priv->netmask >> 8) & 0xff;
168                 guchar c = (self->priv->netmask >> 16) & 0xff;
169                 guchar d = (self->priv->netmask >> 24) & 0xff;
170                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
171         }
172         return NULL;
173 }
174
175 gchar *mtetherd_device_get_dhcp_start(MTetherDDevice *self) {
176         if (self && self->priv) {
177                 guchar a = self->priv->dhcp_start & 0xff;
178                 guchar b = (self->priv->dhcp_start >> 8) & 0xff;
179                 guchar c = (self->priv->dhcp_start >> 16) & 0xff;
180                 guchar d = (self->priv->dhcp_start >> 24) & 0xff;
181                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
182         }
183         return NULL;
184 }
185
186 gchar *mtetherd_device_get_dhcp_end(MTetherDDevice *self) {
187         if (self && self->priv) {
188                 guchar a = self->priv->dhcp_end & 0xff;
189                 guchar b = (self->priv->dhcp_end >> 8) & 0xff;
190                 guchar c = (self->priv->dhcp_end >> 16) & 0xff;
191                 guchar d = (self->priv->dhcp_end >> 24) & 0xff;
192                 return g_strdup_printf("%u.%u.%u.%u", a, b, c, d);
193         }
194         return NULL;
195 }
196
197 static gint mtetherd_device_list_find_index(gpointer *array, const gchar *udi) {
198         guint i;
199         for (i = 0; i < MAX_DEVICES; i++) {
200                 MTetherDDevice *device = MTETHERD_DEVICE(array[i]);
201                 if (device && device->priv) {
202                         if (g_strcmp0(device->priv->udi, udi) == 0) {
203                                 return i;
204                         }
205                 }
206         }
207         return -1;
208 }
209
210 gpointer mtetherd_device_list_new() {
211         return g_malloc0(sizeof(gpointer) * MAX_DEVICES);
212 }
213
214 void mtetherd_device_list_free(gpointer list) {
215         if (list) {
216                 gpointer *array = (gpointer *) list;
217                 
218                 guint i;
219                 for (i = 0; i < MAX_DEVICES; i++) {
220                         if (array[i]) {
221                                 g_object_unref(G_OBJECT(array[i]));
222                         }
223                 }
224                 g_free(array);
225         }
226 }
227
228 MTetherDDevice *mtetherd_device_list_find(gpointer list, const gchar *udi) {
229         if (list) {
230                 gpointer *array = (gpointer *) list;
231         
232                 gint index = mtetherd_device_list_find_index(array, udi);
233                 if (index >= 0) {
234                         return array[index];
235                 }
236         }
237         return NULL;
238 }
239
240 gboolean mtetherd_device_list_add(gpointer list, MTetherDDevice *device) {
241         if (list) {
242                 gpointer *array = (gpointer *) list;
243                 
244                 guint i;
245                 for (i = 0; i < MAX_DEVICES; i++) {
246                         if (!array[i]) {
247                                 array[i] = (gpointer) device;
248                                 return TRUE;
249                         }
250                 }
251         }
252         return FALSE;
253 }
254
255 gboolean mtetherd_device_list_remove(gpointer list, const gchar *udi) {
256         if (list) {
257                 gpointer *array = (gpointer *) list;
258                 
259                 gint index = mtetherd_device_list_find_index(array, udi);
260                 if (index >= 0) {
261                         g_object_unref(G_OBJECT(array[index]));
262                         array[index] = NULL;
263                         return TRUE;
264                 }
265         }
266         return FALSE;
267 }
268
269 gboolean mtetherd_device_ok(const gchar *interface) {
270         if (strncmp("usb", interface, sizeof("usb")) == 0) {
271                 return TRUE;
272         }
273         if (strncmp("bnep", interface, sizeof("bnep")) == 0) {
274                 return TRUE;
275         }
276         return FALSE;
277 }
278