Implemented rest of status plugin, only external networking script is still missing
[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 static gint mtetherd_device_list_find_index(gpointer *array, const gchar *udi) {
154         guint i;
155         for (i = 0; i < MAX_DEVICES; i++) {
156                 MTetherDDevice *device = MTETHERD_DEVICE(array[i]);
157                 if (device && device->priv) {
158                         if (g_strcmp0(device->priv->udi, udi) == 0) {
159                                 return i;
160                         }
161                 }
162         }
163         return -1;
164 }
165
166 gpointer mtetherd_device_list_new() {
167         return g_malloc0(sizeof(gpointer) * MAX_DEVICES);
168 }
169
170 void mtetherd_device_list_free(gpointer list) {
171         if (list) {
172                 gpointer *array = (gpointer *) list;
173                 
174                 guint i;
175                 for (i = 0; i < MAX_DEVICES; i++) {
176                         if (array[i]) {
177                                 g_object_unref(G_OBJECT(array[i]));
178                         }
179                 }
180                 g_free(array);
181         }
182 }
183
184 MTetherDDevice *mtetherd_device_list_find(gpointer list, const gchar *udi) {
185         if (list) {
186                 gpointer *array = (gpointer *) list;
187         
188                 gint index = mtetherd_device_list_find_index(array, udi);
189                 if (index >= 0) {
190                         return array[index];
191                 }
192         }
193         return NULL;
194 }
195
196 gboolean mtetherd_device_list_add(gpointer list, MTetherDDevice *device) {
197         if (list) {
198                 gpointer *array = (gpointer *) list;
199                 
200                 guint i;
201                 for (i = 0; i < MAX_DEVICES; i++) {
202                         if (!array[i]) {
203                                 array[i] = (gpointer) device;
204                                 return TRUE;
205                         }
206                 }
207         }
208         return FALSE;
209 }
210
211 gboolean mtetherd_device_list_remove(gpointer list, const gchar *udi) {
212         if (list) {
213                 gpointer *array = (gpointer *) list;
214                 
215                 gint index = mtetherd_device_list_find_index(array, udi);
216                 if (index >= 0) {
217                         g_object_unref(G_OBJECT(array[index]));
218                         array[index] = NULL;
219                         return TRUE;
220                 }
221         }
222         return FALSE;
223 }
224
225 gboolean mtetherd_device_ok(const gchar *interface) {
226         if (strncmp("usb", interface, sizeof("usb")) == 0) {
227                 return TRUE;
228         }
229         if (strncmp("bnep", interface, sizeof("bnep")) == 0) {
230                 return TRUE;
231         }
232         return FALSE;
233 }
234