Remove interface property callbacks
[connman] / src / iface.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007  Intel Corporation. All rights reserved.
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 version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <net/if.h>
36 #include <net/route.h>
37
38 #include <linux/netlink.h>
39 #include <linux/rtnetlink.h>
40
41 #include <glib.h>
42 #include <gdbus.h>
43
44 #include <hal/libhal.h>
45
46 #include "connman.h"
47
48 static GSList *drivers = NULL;
49
50 int connman_iface_register(struct connman_iface_driver *driver)
51 {
52         DBG("driver %p", driver);
53
54         drivers = g_slist_append(drivers, driver);
55
56         return 0;
57 }
58
59 void connman_iface_unregister(struct connman_iface_driver *driver)
60 {
61         DBG("driver %p", driver);
62
63         drivers = g_slist_remove(drivers, driver);
64 }
65
66 static GSList *interfaces = NULL;
67
68 struct connman_iface *__connman_iface_find(int index)
69 {
70         GSList *list;
71
72         for (list = interfaces; list; list = list->next) {
73                 struct connman_iface *iface = list->data;
74
75                 if (iface->index == index)
76                         return iface;
77         }
78
79         return NULL;
80 }
81
82 void __connman_iface_list(DBusMessageIter *iter)
83 {
84         GSList *list;
85
86         DBG("");
87
88         for (list = interfaces; list; list = list->next) {
89                 struct connman_iface *iface = list->data;
90
91                 dbus_message_iter_append_basic(iter,
92                                 DBUS_TYPE_OBJECT_PATH, &iface->path);
93         }
94 }
95
96 int connman_iface_update(struct connman_iface *iface,
97                                         enum connman_iface_state state)
98 {
99         switch (state) {
100         case CONNMAN_IFACE_STATE_ACTIVE:
101                 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
102                         if (iface->driver->connect)
103                                 iface->driver->connect(iface, NULL);
104                 }
105                 break;
106
107         case CONNMAN_IFACE_STATE_CONNECTED:
108                 __connman_dhcp_request(iface);
109                 break;
110
111         default:
112                 break;
113         }
114
115         iface->state = state;
116
117         return 0;
118 }
119
120 void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier)
121 {
122         DBG("iface %p carrier %d", iface, carrier);
123 }
124
125 int connman_iface_get_ipv4(struct connman_iface *iface,
126                                                 struct connman_ipv4 *ipv4)
127 {
128         struct {
129                 struct nlmsghdr hdr;
130                 struct rtgenmsg msg;
131         } req;
132
133         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
134                 return -1;
135
136         DBG("iface %p ipv4 %p", iface, ipv4);
137
138         memset(&req, 0, sizeof(req));
139         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
140         req.hdr.nlmsg_type = RTM_GETADDR;
141         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
142         req.hdr.nlmsg_pid = 0;
143         req.hdr.nlmsg_seq = 4711;
144         req.msg.rtgen_family = AF_INET;
145
146         __connman_rtnl_send(&req, sizeof(req));
147
148         return 0;
149 }
150
151 int connman_iface_set_ipv4(struct connman_iface *iface,
152                                                 struct connman_ipv4 *ipv4)
153 {
154         struct ifreq ifr;
155         struct rtentry rt;
156         struct sockaddr_in *addr;
157         char cmd[128];
158         int sk, err;
159
160         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
161                 return -1;
162
163         DBG("iface %p ipv4 %p", iface, ipv4);
164
165         sk = socket(PF_INET, SOCK_DGRAM, 0);
166         if (sk < 0)
167                 return -1;
168
169         memset(&ifr, 0, sizeof(ifr));
170         ifr.ifr_ifindex = iface->index;
171
172         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
173                 close(sk);
174                 return -1;
175         }
176
177         DBG("ifname %s", ifr.ifr_name);
178
179         addr = (struct sockaddr_in *) &ifr.ifr_addr;
180         addr->sin_family = AF_INET;
181         addr->sin_addr = ipv4->address;
182
183         err = ioctl(sk, SIOCSIFADDR, &ifr);
184
185         if (err < 0)
186                 DBG("address setting failed (%s)", strerror(errno));
187
188         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
189         addr->sin_family = AF_INET;
190         addr->sin_addr = ipv4->netmask;
191
192         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
193
194         if (err < 0)
195                 DBG("netmask setting failed (%s)", strerror(errno));
196
197         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
198         addr->sin_family = AF_INET;
199         addr->sin_addr = ipv4->broadcast;
200
201         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
202
203         if (err < 0)
204                 DBG("broadcast setting failed (%s)", strerror(errno));
205
206         memset(&rt, 0, sizeof(rt));
207         rt.rt_flags = RTF_UP | RTF_GATEWAY;
208
209         addr = (struct sockaddr_in *) &rt.rt_dst;
210         addr->sin_family = AF_INET;
211         addr->sin_addr.s_addr = INADDR_ANY;
212
213         addr = (struct sockaddr_in *) &rt.rt_gateway;
214         addr->sin_family = AF_INET;
215         addr->sin_addr = ipv4->gateway;
216
217         addr = (struct sockaddr_in *) &rt.rt_genmask;
218         addr->sin_family = AF_INET;
219         addr->sin_addr.s_addr = INADDR_ANY;
220
221         err = ioctl(sk, SIOCADDRT, &rt);
222
223         close(sk);
224
225         if (err < 0) {
226                 DBG("default route failed (%s)", strerror(errno));
227                 return -1;
228         }
229
230         sprintf(cmd, "echo \"nameserver %s\" | resolvconf -a %s",
231                                 inet_ntoa(ipv4->nameserver), ifr.ifr_name);
232
233         DBG("%s", cmd);
234
235         system(cmd);
236
237         return 0;
238 }
239
240 int connman_iface_clear_ipv4(struct connman_iface *iface)
241 {
242         struct ifreq ifr;
243         struct sockaddr_in *addr;
244         char cmd[128];
245         int sk, err;
246
247         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
248                 return -1;
249
250         DBG("iface %p", iface);
251
252         sk = socket(PF_INET, SOCK_DGRAM, 0);
253         if (sk < 0)
254                 return -1;
255
256         memset(&ifr, 0, sizeof(ifr));
257         ifr.ifr_ifindex = iface->index;
258
259         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
260                 close(sk);
261                 return -1;
262         }
263
264         DBG("ifname %s", ifr.ifr_name);
265
266         addr = (struct sockaddr_in *) &ifr.ifr_addr;
267         addr->sin_family = AF_INET;
268         addr->sin_addr.s_addr = INADDR_ANY;
269
270         //err = ioctl(sk, SIOCDIFADDR, &ifr);
271         err = ioctl(sk, SIOCSIFADDR, &ifr);
272
273         close(sk);
274
275         if (err < 0 && errno != EADDRNOTAVAIL) {
276                 DBG("address removal failed (%s)", strerror(errno));
277                 return -1;
278         }
279
280         sprintf(cmd, "resolvconf -d %s", ifr.ifr_name);
281
282         DBG("%s", cmd);
283
284         system(cmd);
285
286         return 0;
287 }
288
289 static DBusMessage *enable_iface(DBusConnection *conn,
290                                         DBusMessage *msg, void *data)
291 {
292         struct connman_iface *iface = data;
293         struct connman_iface_driver *driver = iface->driver;
294         DBusMessage *reply;
295
296         DBG("conn %p", conn);
297
298         reply = dbus_message_new_method_return(msg);
299         if (reply == NULL)
300                 return NULL;
301
302         if (driver->activate)
303                 driver->activate(iface);
304
305         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
306
307         return reply;
308 }
309
310 static DBusMessage *scan_iface(DBusConnection *conn,
311                                         DBusMessage *msg, void *data)
312 {
313         struct connman_iface *iface = data;
314         struct connman_iface_driver *driver = iface->driver;
315         DBusMessage *reply;
316
317         DBG("conn %p", conn);
318
319         reply = dbus_message_new_method_return(msg);
320         if (reply == NULL)
321                 return NULL;
322
323         if (driver->scan)
324                 driver->scan(iface);
325
326         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
327
328         return reply;
329 }
330
331 static DBusMessage *set_network(DBusConnection *conn,
332                                         DBusMessage *msg, void *data)
333 {
334         struct connman_iface *iface = data;
335         struct connman_iface_driver *driver = iface->driver;
336         DBusMessage *reply;
337         const char *network;
338
339         DBG("conn %p", conn);
340
341         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &network,
342                                                         DBUS_TYPE_INVALID);
343
344         reply = dbus_message_new_method_return(msg);
345         if (reply == NULL)
346                 return NULL;
347
348         if (driver->set_network)
349                 driver->set_network(iface, network);
350
351         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
352
353         return reply;
354 }
355
356 static DBusMessage *set_passphrase(DBusConnection *conn,
357                                         DBusMessage *msg, void *data)
358 {
359         struct connman_iface *iface = data;
360         struct connman_iface_driver *driver = iface->driver;
361         DBusMessage *reply;
362         const char *passphrase;
363
364         DBG("conn %p", conn);
365
366         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &passphrase,
367                                                         DBUS_TYPE_INVALID);
368
369         reply = dbus_message_new_method_return(msg);
370         if (reply == NULL)
371                 return NULL;
372
373         if (driver->set_passphrase)
374                 driver->set_passphrase(iface, passphrase);
375
376         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
377
378         return reply;
379 }
380
381 static GDBusMethodTable iface_methods[] = {
382         { "Enable",        "",  "", enable_iface   },
383         { "Scan",          "",  "", scan_iface     },
384         { "SetNetwork",    "s", "", set_network    },
385         { "SetPassphrase", "s", "", set_passphrase },
386         { },
387 };
388
389 static void device_free(void *data)
390 {
391         struct connman_iface *iface = data;
392
393         DBG("iface %p", iface);
394
395         connman_iface_clear_ipv4(iface);
396
397         if (iface->driver && iface->driver->remove)
398                 iface->driver->remove(iface);
399
400         g_free(iface->path);
401         g_free(iface->udi);
402         g_free(iface->sysfs);
403         g_free(iface->device.driver);
404         g_free(iface->device.vendor);
405         g_free(iface->device.product);
406         g_free(iface);
407 }
408
409 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
410 {
411         char *parent, *subsys, *value;
412
413         parent = libhal_device_get_property_string(ctx, iface->udi,
414                                                 "info.parent", NULL);
415
416         subsys = libhal_device_get_property_string(ctx, iface->udi,
417                                                 "linux.subsystem", NULL);
418
419         value = libhal_device_get_property_string(ctx, iface->udi,
420                                                 "info.linux.driver", NULL);
421         if (value == NULL) {
422                 value = libhal_device_get_property_string(ctx, parent,
423                                                 "info.linux.driver", NULL);
424                 if (value != NULL)
425                         iface->device.driver = g_strdup(value);
426         }
427
428         if (strcmp(subsys, "net") == 0) {
429                 value = libhal_device_get_property_string(ctx, parent,
430                                                         "info.vendor", NULL);
431                 if (value != NULL)
432                         iface->device.vendor = g_strdup(value);
433
434                 value = libhal_device_get_property_string(ctx, parent,
435                                                         "info.product", NULL);
436                 if (value != NULL)
437                         iface->device.product = g_strdup(value);
438         }
439 }
440
441 static int probe_device(LibHalContext *ctx,
442                         struct connman_iface_driver *driver, const char *udi)
443 {
444         DBusConnection *conn;
445         struct connman_iface *iface;
446         char *temp, *sysfs;
447         int err;
448
449         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
450
451         if (!driver->probe)
452                 return -1;
453
454         iface = g_try_new0(struct connman_iface, 1);
455         if (iface == NULL)
456                 return -1;
457
458         temp = g_path_get_basename(udi);
459         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
460         g_free(temp);
461
462         iface->udi = g_strdup(udi);
463
464         DBG("path %s", iface->path);
465
466         sysfs = libhal_device_get_property_string(ctx, udi,
467                                                 "linux.sysfs_path", NULL);
468         if (sysfs != NULL)
469                 iface->sysfs = g_strdup(sysfs);
470
471         detect_device_info(ctx, iface);
472
473         iface->index = -1;
474
475         if (g_str_has_prefix(driver->capability, "net") == TRUE)
476                 iface->index = libhal_device_get_property_int(ctx, udi,
477                                                 "net.linux.ifindex", NULL);
478
479         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
480         iface->flags = 0;
481         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
482
483         DBG("iface %p", iface);
484
485         err = driver->probe(iface);
486         if (err < 0) {
487                 device_free(iface);
488                 return -1;
489         }
490
491         iface->driver = driver;
492
493         conn = libhal_ctx_get_dbus_connection(ctx);
494
495         g_dbus_register_object(conn, iface->path, iface, device_free);
496
497         interfaces = g_slist_append(interfaces, iface);
498
499         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
500                 if (driver->get_ipv4)
501                         driver->get_ipv4(iface, &iface->ipv4);
502                 else
503                         connman_iface_get_ipv4(iface, &iface->ipv4);
504
505                 DBG("address %s", inet_ntoa(iface->ipv4.address));
506         }
507
508         g_dbus_register_interface(conn, iface->path,
509                                         CONNMAN_IFACE_INTERFACE,
510                                         iface_methods, NULL, NULL);
511
512         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
513                                         CONNMAN_MANAGER_INTERFACE,
514                                         "InterfaceAdded",
515                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
516                                         DBUS_TYPE_INVALID);
517
518         return 0;
519 }
520
521 static void device_added(LibHalContext *ctx, const char *udi)
522 {
523         GSList *list;
524
525         DBG("ctx %p udi %s", ctx, udi);
526
527         for (list = drivers; list; list = list->next) {
528                 struct connman_iface_driver *driver = list->data;
529
530                 if (driver->capability == NULL)
531                         continue;
532
533                 if (libhal_device_query_capability(ctx, udi,
534                                         driver->capability, NULL) == TRUE) {
535                         if (probe_device(ctx, driver, udi) == 0)
536                                 break;
537                 }
538         }
539 }
540
541 static void device_removed(LibHalContext *ctx, const char *udi)
542 {
543         DBusConnection *conn;
544         GSList *list;
545
546         DBG("ctx %p udi %s", ctx, udi);
547
548         conn = libhal_ctx_get_dbus_connection(ctx);
549
550         for (list = interfaces; list; list = list->next) {
551                 struct connman_iface *iface = list->data;
552
553                 if (strcmp(udi, iface->udi) == 0) {
554                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
555                                         CONNMAN_MANAGER_INTERFACE,
556                                         "InterfaceRemoved",
557                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
558                                         DBUS_TYPE_INVALID);
559                         interfaces = g_slist_remove(interfaces, iface);
560                         g_dbus_unregister_interface(conn, iface->path,
561                                                 CONNMAN_IFACE_INTERFACE);
562                         g_dbus_unregister_object(conn, iface->path);
563                         break;
564                 }
565         }
566 }
567
568 static void probe_driver(LibHalContext *ctx,
569                                 struct connman_iface_driver *driver)
570 {
571         char **list;
572         int num;
573
574         DBG("ctx %p driver %p", ctx, driver);
575
576         list = libhal_find_device_by_capability(ctx,
577                                         driver->capability, &num, NULL);
578         if (list) {
579                 char **tmp = list;
580
581                 while (*tmp) {
582                         probe_device(ctx, driver, *tmp);
583                         tmp++;
584                 }
585
586                 libhal_free_string_array(list);
587         }
588 }
589
590 static void find_devices(LibHalContext *ctx)
591 {
592         GSList *list;
593
594         DBG("ctx %p", ctx);
595
596         for (list = drivers; list; list = list->next) {
597                 struct connman_iface_driver *driver = list->data;
598
599                 DBG("driver %p", driver);
600
601                 if (driver->capability == NULL)
602                         continue;
603
604                 probe_driver(ctx, driver);
605         }
606 }
607
608 static LibHalContext *hal_ctx = NULL;
609
610 static void hal_init(void *data)
611 {
612         DBusConnection *conn = data;
613
614         DBG("conn %p", conn);
615
616         if (hal_ctx != NULL)
617                 return;
618
619         hal_ctx = libhal_ctx_new();
620         if (hal_ctx == NULL)
621                 return;
622
623         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
624                 libhal_ctx_free(hal_ctx);
625                 return;
626         }
627
628         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
629                 libhal_ctx_free(hal_ctx);
630                 return ;
631         }
632
633         libhal_ctx_set_device_added(hal_ctx, device_added);
634         libhal_ctx_set_device_removed(hal_ctx, device_removed);
635
636         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
637         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
638
639         find_devices(hal_ctx);
640 }
641
642 static void hal_cleanup(void *data)
643 {
644         DBusConnection *conn = data;
645         GSList *list;
646
647         DBG("conn %p", conn);
648
649         if (hal_ctx == NULL)
650                 return;
651
652         for (list = interfaces; list; list = list->next) {
653                 struct connman_iface *iface = list->data;
654
655                 DBG("path %s", iface->path);
656
657                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
658                                         CONNMAN_MANAGER_INTERFACE,
659                                         "InterfaceRemoved",
660                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
661                                         DBUS_TYPE_INVALID);
662
663                 g_dbus_unregister_interface(conn, iface->path,
664                                                 CONNMAN_IFACE_INTERFACE);
665
666                 g_dbus_unregister_object(conn, iface->path);
667         }
668
669         g_slist_free(interfaces);
670
671         interfaces = NULL;
672
673         libhal_ctx_shutdown(hal_ctx, NULL);
674
675         libhal_ctx_free(hal_ctx);
676
677         hal_ctx = NULL;
678 }
679
680 static DBusConnection *connection = NULL;
681 static guint hal_watch = 0;
682
683 int __connman_iface_init(DBusConnection *conn)
684 {
685         DBG("conn %p", conn);
686
687         connection = dbus_connection_ref(conn);
688         if (connection == NULL)
689                 return -1;
690
691         hal_init(connection);
692
693         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
694                                 hal_init, hal_cleanup, connection, NULL);
695
696         return 0;
697 }
698
699 void __connman_iface_cleanup(void)
700 {
701         DBG("conn %p", connection);
702
703         g_dbus_remove_watch(connection, hal_watch);
704
705         hal_cleanup(connection);
706
707         dbus_connection_unref(connection);
708 }