3 (c) 2010 Gregor Riepl <onitake@gmail.com>
5 Tethering utility for Maemo
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.
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.
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/>.
22 #include <netinet/in.h>
26 #define MTETHERD_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_MTETHERD_DEVICE, MTetherDDevicePrivate))
28 G_DEFINE_TYPE(MTetherDDevice, mtetherd_device, G_TYPE_OBJECT);
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;
36 static const in_addr_t HOST_ROUTER = 0x00000002;
38 static const in_addr_t HOST_DHCP = 0x00000001;
40 struct _MTetherDDevicePrivate {
50 static void mtetherd_device_finalize(GObject *object) {
51 MTetherDDevice *self = MTETHERD_DEVICE(object);
53 if (self && self->priv) {
54 g_free(self->priv->interface);
55 g_free(self->priv->udi);
59 static void mtetherd_device_class_init(MTetherDDeviceClass *klass) {
60 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
62 gobject_class->finalize = mtetherd_device_finalize;
63 g_type_class_add_private(klass, sizeof(MTetherDDevicePrivate));
66 static void mtetherd_device_init(MTetherDDevice *self) {
67 self->priv = MTETHERD_DEVICE_GET_PRIVATE(self);
70 self->priv->interface = NULL;
71 self->priv->udi = NULL;
73 self->priv->netmask = 0;
74 self->priv->dhcp_start = 0;
75 self->priv->dhcp_end = 0;
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);
85 size_t len = strlen(interface);
86 self->priv->interface = g_malloc(len + 1);
88 for (i = 0, j = 0; i < len; i++) {
89 if (g_ascii_isalnum(interface[i])) {
90 self->priv->interface[j] = interface[i];
94 self->priv->interface[j] = '\0';
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);
105 size_t len = strlen(udi);
106 self->priv->udi = g_malloc(len + 1);
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];
114 self->priv->udi[j] = '\0';
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
123 in_addr_t subnet = HOST_BASE_ADDRESS | (index << 2);
124 in_addr_t addr = subnet | HOST_ROUTER;
125 in_addr_t start = subnet | HOST_DHCP;
126 self->priv->addr = htonl(addr);
127 self->priv->netmask = htonl(HOST_NETMASK);
128 self->priv->dhcp_start = htonl(start);
129 self->priv->dhcp_end = htonl(addr);
131 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Invalid subnet index: %u (0..%u expected)", index, MAX_DEVICES - 1);
136 MTetherDDevice *mtetherd_device_new(const gchar *interface, const gchar *udi) {
137 MTetherDDevice *self = MTETHERD_DEVICE(g_object_new(TYPE_MTETHERD_DEVICE, NULL));
139 if (self && self->priv) {
140 mtetherd_device_set_interface(self, interface);
141 mtetherd_device_set_udi(self, udi);
147 const gchar *mtetherd_device_get_interface(MTetherDDevice *self) {
148 if (self && self->priv) {
149 return self->priv->interface;
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);
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);
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);
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);
198 static gint mtetherd_device_list_find_index(gpointer *array, const gchar *udi) {
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) {
211 gpointer mtetherd_device_list_new() {
212 return g_malloc0(sizeof(gpointer) * MAX_DEVICES);
215 void mtetherd_device_list_free(gpointer list) {
217 gpointer *array = (gpointer *) list;
220 for (i = 0; i < MAX_DEVICES; i++) {
222 g_object_unref(G_OBJECT(array[i]));
229 MTetherDDevice *mtetherd_device_list_find(gpointer list, const gchar *udi) {
231 gpointer *array = (gpointer *) list;
233 gint index = mtetherd_device_list_find_index(array, udi);
241 gboolean mtetherd_device_list_add(gpointer list, MTetherDDevice *device) {
243 gpointer *array = (gpointer *) list;
246 for (i = 0; i < MAX_DEVICES; i++) {
248 array[i] = (gpointer) device;
256 gboolean mtetherd_device_list_remove(gpointer list, const gchar *udi) {
258 gpointer *array = (gpointer *) list;
260 gint index = mtetherd_device_list_find_index(array, udi);
262 g_object_unref(G_OBJECT(array[index]));
270 gboolean mtetherd_device_ok(const gchar *interface) {
271 if (strncmp("usb", interface, sizeof("usb")) == 0) {
274 if (strncmp("bnep", interface, sizeof("bnep")) == 0) {