df020a3a8f71f72512b1c14e2f178e4aad955384
[framework/connectivity/connman.git] / 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 DBusConnection *connection = NULL;
49
50 static GSList *drivers = NULL;
51
52 int connman_iface_register(struct connman_iface_driver *driver)
53 {
54         DBG("driver %p", driver);
55
56         drivers = g_slist_append(drivers, driver);
57
58         return 0;
59 }
60
61 void connman_iface_unregister(struct connman_iface_driver *driver)
62 {
63         DBG("driver %p", driver);
64
65         drivers = g_slist_remove(drivers, driver);
66 }
67
68 static GSList *interfaces = NULL;
69
70 struct connman_iface *__connman_iface_find(int index)
71 {
72         GSList *list;
73
74         for (list = interfaces; list; list = list->next) {
75                 struct connman_iface *iface = list->data;
76
77                 if (iface->index == index)
78                         return iface;
79         }
80
81         return NULL;
82 }
83
84 void __connman_iface_list(DBusMessageIter *iter)
85 {
86         GSList *list;
87
88         DBG("");
89
90         for (list = interfaces; list; list = list->next) {
91                 struct connman_iface *iface = list->data;
92
93                 dbus_message_iter_append_basic(iter,
94                                 DBUS_TYPE_OBJECT_PATH, &iface->path);
95         }
96 }
97
98 int connman_iface_update(struct connman_iface *iface,
99                                         enum connman_iface_state state)
100 {
101         const char *str = NULL;
102
103         switch (state) {
104         case CONNMAN_IFACE_STATE_ENABLED:
105                 str = "enabled";
106                 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
107                         if (iface->driver->connect)
108                                 iface->driver->connect(iface, NULL);
109                 }
110                 break;
111
112         case CONNMAN_IFACE_STATE_CARRIER:
113                 str = "carrier";
114                 __connman_dhcp_request(iface);
115                 break;
116
117         case CONNMAN_IFACE_STATE_READY:
118                 str = "ready";
119                 break;
120
121         case CONNMAN_IFACE_STATE_SHUTDOWN:
122                 break;
123
124         default:
125                 break;
126         }
127
128         iface->state = state;
129
130         if (str != NULL) {
131                 g_dbus_emit_signal(connection, iface->path,
132                                 CONNMAN_IFACE_INTERFACE, "StateChanged",
133                                 DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
134         }
135
136         return 0;
137 }
138
139 void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier)
140 {
141         DBG("iface %p carrier %d", iface, carrier);
142 }
143
144 int connman_iface_get_ipv4(struct connman_iface *iface,
145                                                 struct connman_ipv4 *ipv4)
146 {
147         struct {
148                 struct nlmsghdr hdr;
149                 struct rtgenmsg msg;
150         } req;
151
152         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
153                 return -1;
154
155         DBG("iface %p ipv4 %p", iface, ipv4);
156
157         memset(&req, 0, sizeof(req));
158         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
159         req.hdr.nlmsg_type = RTM_GETADDR;
160         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
161         req.hdr.nlmsg_pid = 0;
162         req.hdr.nlmsg_seq = 4711;
163         req.msg.rtgen_family = AF_INET;
164
165         __connman_rtnl_send(&req, sizeof(req));
166
167         return 0;
168 }
169
170 int connman_iface_set_ipv4(struct connman_iface *iface,
171                                                 struct connman_ipv4 *ipv4)
172 {
173         struct ifreq ifr;
174         struct rtentry rt;
175         struct sockaddr_in *addr;
176         char cmd[128];
177         int sk, err;
178
179         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
180                 return -1;
181
182         DBG("iface %p ipv4 %p", iface, ipv4);
183
184         sk = socket(PF_INET, SOCK_DGRAM, 0);
185         if (sk < 0)
186                 return -1;
187
188         memset(&ifr, 0, sizeof(ifr));
189         ifr.ifr_ifindex = iface->index;
190
191         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
192                 close(sk);
193                 return -1;
194         }
195
196         DBG("ifname %s", ifr.ifr_name);
197
198         addr = (struct sockaddr_in *) &ifr.ifr_addr;
199         addr->sin_family = AF_INET;
200         addr->sin_addr = ipv4->address;
201
202         err = ioctl(sk, SIOCSIFADDR, &ifr);
203
204         if (err < 0)
205                 DBG("address setting failed (%s)", strerror(errno));
206
207         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
208         addr->sin_family = AF_INET;
209         addr->sin_addr = ipv4->netmask;
210
211         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
212
213         if (err < 0)
214                 DBG("netmask setting failed (%s)", strerror(errno));
215
216         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
217         addr->sin_family = AF_INET;
218         addr->sin_addr = ipv4->broadcast;
219
220         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
221
222         if (err < 0)
223                 DBG("broadcast setting failed (%s)", strerror(errno));
224
225         memset(&rt, 0, sizeof(rt));
226         rt.rt_flags = RTF_UP | RTF_GATEWAY;
227
228         addr = (struct sockaddr_in *) &rt.rt_dst;
229         addr->sin_family = AF_INET;
230         addr->sin_addr.s_addr = INADDR_ANY;
231
232         addr = (struct sockaddr_in *) &rt.rt_gateway;
233         addr->sin_family = AF_INET;
234         addr->sin_addr = ipv4->gateway;
235
236         addr = (struct sockaddr_in *) &rt.rt_genmask;
237         addr->sin_family = AF_INET;
238         addr->sin_addr.s_addr = INADDR_ANY;
239
240         err = ioctl(sk, SIOCADDRT, &rt);
241
242         close(sk);
243
244         if (err < 0) {
245                 DBG("default route failed (%s)", strerror(errno));
246                 return -1;
247         }
248
249         sprintf(cmd, "echo \"nameserver %s\" | resolvconf -a %s",
250                                 inet_ntoa(ipv4->nameserver), ifr.ifr_name);
251
252         DBG("%s", cmd);
253
254         system(cmd);
255
256         return 0;
257 }
258
259 int connman_iface_clear_ipv4(struct connman_iface *iface)
260 {
261         struct ifreq ifr;
262         struct sockaddr_in *addr;
263         char cmd[128];
264         int sk, err;
265
266         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
267                 return -1;
268
269         DBG("iface %p", iface);
270
271         sk = socket(PF_INET, SOCK_DGRAM, 0);
272         if (sk < 0)
273                 return -1;
274
275         memset(&ifr, 0, sizeof(ifr));
276         ifr.ifr_ifindex = iface->index;
277
278         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
279                 close(sk);
280                 return -1;
281         }
282
283         DBG("ifname %s", ifr.ifr_name);
284
285         addr = (struct sockaddr_in *) &ifr.ifr_addr;
286         addr->sin_family = AF_INET;
287         addr->sin_addr.s_addr = INADDR_ANY;
288
289         //err = ioctl(sk, SIOCDIFADDR, &ifr);
290         err = ioctl(sk, SIOCSIFADDR, &ifr);
291
292         close(sk);
293
294         if (err < 0 && errno != EADDRNOTAVAIL) {
295                 DBG("address removal failed (%s)", strerror(errno));
296                 return -1;
297         }
298
299         sprintf(cmd, "resolvconf -d %s", ifr.ifr_name);
300
301         DBG("%s", cmd);
302
303         system(cmd);
304
305         return 0;
306 }
307
308 static DBusMessage *scan_iface(DBusConnection *conn,
309                                         DBusMessage *msg, void *data)
310 {
311         struct connman_iface *iface = data;
312         struct connman_iface_driver *driver = iface->driver;
313         DBusMessage *reply;
314
315         DBG("conn %p", conn);
316
317         reply = dbus_message_new_method_return(msg);
318         if (reply == NULL)
319                 return NULL;
320
321         if (driver->scan)
322                 driver->scan(iface);
323
324         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
325
326         return reply;
327 }
328
329 static void append_entry(DBusMessageIter *dict,
330                                 const char *key, int type, void *val)
331 {
332         DBusMessageIter entry, value;
333         const char *signature;
334
335         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
336                                                                 NULL, &entry);
337
338         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
339
340         switch (type) {
341         case DBUS_TYPE_STRING:
342                 signature = DBUS_TYPE_STRING_AS_STRING;
343                 break;
344         case DBUS_TYPE_UINT16:
345                 signature = DBUS_TYPE_UINT16_AS_STRING;
346                 break;
347         default:
348                 signature = DBUS_TYPE_VARIANT_AS_STRING;
349                 break;
350         }
351
352         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
353                                                         signature, &value);
354         dbus_message_iter_append_basic(&value, type, val);
355         dbus_message_iter_close_container(&entry, &value);
356
357         dbus_message_iter_close_container(dict, &entry);
358 }
359
360 static DBusMessage *get_properties(DBusConnection *conn,
361                                         DBusMessage *msg, void *data)
362 {
363         struct connman_iface *iface = data;
364         DBusMessage *reply;
365         DBusMessageIter array, dict;
366         const char *str;
367
368         DBG("conn %p", conn);
369
370         reply = dbus_message_new_method_return(msg);
371         if (reply == NULL)
372                 return NULL;
373
374         dbus_message_iter_init_append(reply, &array);
375
376         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
377                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
378                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
379                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
380
381         str = __connman_iface_type2string(iface->type);
382         append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
383
384         str = __connman_iface_state2string(iface->state);
385         append_entry(&dict, "State", DBUS_TYPE_STRING, &str);
386
387         if (iface->type == CONNMAN_IFACE_TYPE_80211) {
388                 dbus_uint16_t signal = 75;
389                 append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
390         }
391
392         str = __connman_iface_policy2string(iface->policy);
393         append_entry(&dict, "Policy", DBUS_TYPE_STRING, &str);
394
395         if (iface->device.driver != NULL)
396                 append_entry(&dict, "Driver",
397                                 DBUS_TYPE_STRING, &iface->device.driver);
398
399         if (iface->device.vendor != NULL)
400                 append_entry(&dict, "Vendor",
401                                 DBUS_TYPE_STRING, &iface->device.vendor);
402
403         if (iface->device.product != NULL)
404                 append_entry(&dict, "Product",
405                                 DBUS_TYPE_STRING, &iface->device.product);
406
407         dbus_message_iter_close_container(&array, &dict);
408
409         return reply;
410 }
411
412 static DBusMessage *get_state(DBusConnection *conn,
413                                         DBusMessage *msg, void *data)
414 {
415         struct connman_iface *iface = data;
416         DBusMessage *reply;
417         const char *state;
418
419         DBG("conn %p", conn);
420
421         reply = dbus_message_new_method_return(msg);
422         if (reply == NULL)
423                 return NULL;
424
425         state = __connman_iface_state2string(iface->state);
426
427         dbus_message_append_args(reply, DBUS_TYPE_STRING, &state,
428                                                         DBUS_TYPE_INVALID);
429
430         return reply;
431 }
432
433 static DBusMessage *get_signal(DBusConnection *conn,
434                                         DBusMessage *msg, void *data)
435 {
436         struct connman_iface *iface = data;
437         DBusMessage *reply;
438         dbus_uint16_t signal;
439
440         DBG("conn %p", conn);
441
442         reply = dbus_message_new_method_return(msg);
443         if (reply == NULL)
444                 return NULL;
445
446         if (iface->type == CONNMAN_IFACE_TYPE_80211)
447                 signal = 75;
448         else
449                 signal = 0;
450
451         dbus_message_append_args(reply, DBUS_TYPE_UINT16, &signal,
452                                                         DBUS_TYPE_INVALID);
453
454         return reply;
455 }
456
457 static DBusMessage *get_policy(DBusConnection *conn,
458                                         DBusMessage *msg, void *data)
459 {
460         struct connman_iface *iface = data;
461         DBusMessage *reply;
462         const char *policy;
463
464         DBG("conn %p", conn);
465
466         reply = dbus_message_new_method_return(msg);
467         if (reply == NULL)
468                 return NULL;
469
470         policy = __connman_iface_policy2string(iface->policy);
471
472         dbus_message_append_args(reply, DBUS_TYPE_STRING, &policy,
473                                                         DBUS_TYPE_INVALID);
474
475         return reply;
476 }
477
478 static DBusMessage *set_policy(DBusConnection *conn,
479                                         DBusMessage *msg, void *data)
480 {
481         struct connman_iface *iface = data;
482         DBusMessage *reply;
483         enum connman_iface_policy new_policy;
484         const char *path, *policy;
485
486         DBG("conn %p", conn);
487
488         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &policy,
489                                                         DBUS_TYPE_INVALID);
490
491         new_policy = __connman_iface_string2policy(policy);
492
493         reply = dbus_message_new_method_return(msg);
494         if (reply == NULL)
495                 return NULL;
496
497         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
498
499         if (iface->policy != new_policy) {
500                 path = dbus_message_get_path(msg);
501
502                 iface->policy = new_policy;
503                 __connman_iface_store(iface);
504
505                 if (new_policy == CONNMAN_IFACE_POLICY_AUTO) {
506                         if (iface->driver->activate)
507                                 iface->driver->activate(iface);
508                 } else {
509                         if (iface->driver->shutdown)
510                                 iface->driver->shutdown(iface);
511                 }
512
513                 g_dbus_emit_signal(conn, path, CONNMAN_IFACE_INTERFACE,
514                                 "PolicyChanged", DBUS_TYPE_STRING, &policy,
515                                                         DBUS_TYPE_INVALID);
516         }
517
518         return reply;
519 }
520
521 static void append_ipv4(DBusMessage *reply, struct connman_iface *iface)
522 {
523         DBusMessageIter array, dict;
524         const char *str;
525
526         dbus_message_iter_init_append(reply, &array);
527
528         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
529                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
530                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
531                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
532
533         str = __connman_ipv4_method2string(iface->ipv4.method);
534         append_entry(&dict, "Method", DBUS_TYPE_STRING, &str);
535
536         if (iface->ipv4.address.s_addr != INADDR_ANY) {
537                 str = inet_ntoa(iface->ipv4.address);
538                 append_entry(&dict, "Address", DBUS_TYPE_STRING, &str);
539         }
540
541         if (iface->ipv4.netmask.s_addr != INADDR_ANY) {
542                 str = inet_ntoa(iface->ipv4.netmask);
543                 append_entry(&dict, "Netmask", DBUS_TYPE_STRING, &str);
544         }
545
546         if (iface->ipv4.gateway.s_addr != INADDR_ANY) {
547                 str = inet_ntoa(iface->ipv4.gateway);
548                 append_entry(&dict, "Gateway", DBUS_TYPE_STRING, &str);
549         }
550
551         dbus_message_iter_close_container(&array, &dict);
552 }
553
554 static DBusMessage *get_ipv4(DBusConnection *conn,
555                                         DBusMessage *msg, void *data)
556 {
557         struct connman_iface *iface = data;
558         DBusMessage *reply;
559
560         DBG("conn %p", conn);
561
562         reply = dbus_message_new_method_return(msg);
563         if (reply == NULL)
564                 return NULL;
565
566         append_ipv4(reply, iface);
567
568         return reply;
569 }
570
571 static DBusMessage *set_ipv4(DBusConnection *conn,
572                                         DBusMessage *msg, void *data)
573 {
574         struct connman_iface *iface = data;
575         DBusMessage *reply, *signal;
576         DBusMessageIter array, dict;
577         const char *path;
578         gboolean changed = FALSE;
579
580         DBG("conn %p", conn);
581
582         dbus_message_iter_init(msg, &array);
583
584         dbus_message_iter_recurse(&array, &dict);
585
586         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
587                 DBusMessageIter entry, value;
588                 const char *key, *val;
589                 enum connman_ipv4_method method;
590                 in_addr_t addr;
591
592                 dbus_message_iter_recurse(&dict, &entry);
593                 dbus_message_iter_get_basic(&entry, &key);
594
595                 dbus_message_iter_next(&entry);
596
597                 dbus_message_iter_recurse(&entry, &value);
598
599                 //type = dbus_message_iter_get_arg_type(&value);
600                 dbus_message_iter_get_basic(&value, &val);
601
602                 if (g_strcasecmp(key, "Method") == 0) {
603                         method = __connman_ipv4_string2method(val);
604                         if (iface->ipv4.method != method) {
605                                 iface->ipv4.method = method;
606                                 changed = TRUE;
607                         }
608                 }
609
610                 if (g_strcasecmp(key, "Address") == 0) {
611                         addr = inet_addr(val);
612                         if (iface->ipv4.address.s_addr != addr) {
613                                 iface->ipv4.address.s_addr = addr;
614                                 changed = TRUE;
615                         }
616                 }
617
618                 if (g_strcasecmp(key, "Netmask") == 0) {
619                         addr = inet_addr(val);
620                         if (iface->ipv4.netmask.s_addr != addr) {
621                                 iface->ipv4.netmask.s_addr = addr;
622                                 changed = TRUE;
623                         }
624                 }
625
626                 if (g_strcasecmp(key, "Gateway") == 0) {
627                         addr = inet_addr(val);
628                         if (iface->ipv4.gateway.s_addr != addr) {
629                                 iface->ipv4.gateway.s_addr = addr;
630                                 changed = TRUE;
631                         }
632                 }
633
634                 dbus_message_iter_next(&dict);
635         }
636
637         reply = dbus_message_new_method_return(msg);
638         if (reply == NULL)
639                 return NULL;
640
641         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
642
643         path = dbus_message_get_path(msg);
644
645         if (changed == TRUE) {
646                 __connman_iface_store(iface);
647
648                 signal = dbus_message_new_signal(path,
649                                 CONNMAN_IFACE_INTERFACE, "IPv4Changed");
650                 if (signal != NULL) {
651                         append_ipv4(signal, iface);
652                         dbus_connection_send(conn, signal, NULL);
653                         dbus_message_unref(signal);
654                 }
655         }
656
657         return reply;
658 }
659
660 static DBusMessage *set_network(DBusConnection *conn,
661                                         DBusMessage *msg, void *data)
662 {
663         struct connman_iface *iface = data;
664         DBusMessage *reply;
665         DBusMessageIter array, dict;
666
667         DBG("conn %p", conn);
668
669         dbus_message_iter_init(msg, &array);
670
671         dbus_message_iter_recurse(&array, &dict);
672
673         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
674                 DBusMessageIter entry, value;
675                 const char *key, *val;
676
677                 dbus_message_iter_recurse(&dict, &entry);
678                 dbus_message_iter_get_basic(&entry, &key);
679
680                 dbus_message_iter_next(&entry);
681
682                 dbus_message_iter_recurse(&entry, &value);
683
684                 //type = dbus_message_iter_get_arg_type(&value);
685                 dbus_message_iter_get_basic(&value, &val);
686
687                 if (g_strcasecmp(key, "ESSID") == 0) {
688                         if (iface->driver->set_network)
689                                 iface->driver->set_network(iface, val);
690                 }
691
692                 if (g_strcasecmp(key, "PSK") == 0) {
693                         if (iface->driver->set_network)
694                                 iface->driver->set_passphrase(iface, val);
695                 }
696
697                 dbus_message_iter_next(&dict);
698         }
699
700         reply = dbus_message_new_method_return(msg);
701         if (reply == NULL)
702                 return NULL;
703
704         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
705
706         return reply;
707 }
708
709 static GDBusMethodTable iface_methods[] = {
710         { "Scan",          "",      "",      scan_iface     },
711         { "GetProperties", "",      "a{sv}", get_properties },
712         { "GetState",      "",      "s",     get_state      },
713         { "GetSignal",     "",      "q",     get_signal     },
714         { "GetPolicy",     "",      "s",     get_policy     },
715         { "SetPolicy",     "s",     "",      set_policy     },
716         { "GetIPv4",       "",      "a{sv}", get_ipv4       },
717         { "SetIPv4",       "a{sv}", "",      set_ipv4       },
718         { "SetNetwork",    "a{sv}", "",      set_network    },
719         { },
720 };
721
722 static GDBusSignalTable iface_signals[] = {
723         { "StateChanged",   "s"     },
724         { "SignalChanged",  "q"     },
725         { "PolicyChanged",  "s"     },
726         { "IPv4Changed",    "a{sv}" },
727         { "NetworkChanged", "a{sv}" },
728         { },
729 };
730
731 static void device_free(void *data)
732 {
733         struct connman_iface *iface = data;
734
735         DBG("iface %p", iface);
736
737         connman_iface_clear_ipv4(iface);
738
739         if (iface->driver && iface->driver->remove)
740                 iface->driver->remove(iface);
741
742         g_free(iface->path);
743         g_free(iface->udi);
744         g_free(iface->sysfs);
745         g_free(iface->identifier);
746         g_free(iface->device.driver);
747         g_free(iface->device.vendor);
748         g_free(iface->device.product);
749         g_free(iface);
750 }
751
752 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
753 {
754         char *parent, *subsys, *value;
755
756         parent = libhal_device_get_property_string(ctx, iface->udi,
757                                                 "info.parent", NULL);
758
759         subsys = libhal_device_get_property_string(ctx, iface->udi,
760                                                 "linux.subsystem", NULL);
761
762         value = libhal_device_get_property_string(ctx, iface->udi,
763                                                 "info.linux.driver", NULL);
764         if (value == NULL) {
765                 value = libhal_device_get_property_string(ctx, parent,
766                                                 "info.linux.driver", NULL);
767                 if (value != NULL)
768                         iface->device.driver = g_strdup(value);
769         }
770
771         if (strcmp(subsys, "net") == 0) {
772                 value = libhal_device_get_property_string(ctx, parent,
773                                                         "info.vendor", NULL);
774                 if (value != NULL)
775                         iface->device.vendor = g_strdup(value);
776
777                 value = libhal_device_get_property_string(ctx, parent,
778                                                         "info.product", NULL);
779                 if (value != NULL)
780                         iface->device.product = g_strdup(value);
781         }
782 }
783
784 static int probe_device(LibHalContext *ctx,
785                         struct connman_iface_driver *driver, const char *udi)
786 {
787         DBusConnection *conn;
788         struct connman_iface *iface;
789         char *temp, *sysfs;
790         int err;
791
792         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
793
794         if (!driver->probe)
795                 return -1;
796
797         iface = g_try_new0(struct connman_iface, 1);
798         if (iface == NULL)
799                 return -1;
800
801         temp = g_path_get_basename(udi);
802         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
803         g_free(temp);
804
805         iface->udi = g_strdup(udi);
806
807         DBG("iface %p path %s", iface, iface->path);
808
809         sysfs = libhal_device_get_property_string(ctx, udi,
810                                                 "linux.sysfs_path", NULL);
811         if (sysfs != NULL)
812                 iface->sysfs = g_strdup(sysfs);
813
814         detect_device_info(ctx, iface);
815
816         iface->index = -1;
817
818         if (g_str_has_prefix(driver->capability, "net") == TRUE)
819                 iface->index = libhal_device_get_property_int(ctx, udi,
820                                                 "net.linux.ifindex", NULL);
821
822         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
823         iface->flags = 0;
824         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
825         iface->policy = CONNMAN_IFACE_POLICY_UNKNOWN;
826
827         err = driver->probe(iface);
828         if (err < 0) {
829                 device_free(iface);
830                 return -1;
831         }
832
833         __connman_iface_create_identifier(iface);
834
835         __connman_iface_init_via_inet(iface);
836
837         __connman_iface_load(iface);
838
839         iface->driver = driver;
840
841         conn = libhal_ctx_get_dbus_connection(ctx);
842
843         g_dbus_register_object(conn, iface->path, iface, device_free);
844
845         interfaces = g_slist_append(interfaces, iface);
846
847         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
848                 if (driver->get_ipv4)
849                         driver->get_ipv4(iface, &iface->ipv4);
850                 else
851                         connman_iface_get_ipv4(iface, &iface->ipv4);
852
853                 DBG("address %s", inet_ntoa(iface->ipv4.address));
854         }
855
856         g_dbus_register_interface(conn, iface->path,
857                                         CONNMAN_IFACE_INTERFACE,
858                                         iface_methods, iface_signals, NULL);
859
860         DBG("iface %p identifier %s", iface, iface->identifier);
861
862         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
863                                         CONNMAN_MANAGER_INTERFACE,
864                                         "InterfaceAdded",
865                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
866                                         DBUS_TYPE_INVALID);
867
868         if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) {
869                 if (driver->activate)
870                         driver->activate(iface);
871         }
872
873         return 0;
874 }
875
876 static void device_added(LibHalContext *ctx, const char *udi)
877 {
878         GSList *list;
879
880         DBG("ctx %p udi %s", ctx, udi);
881
882         for (list = drivers; list; list = list->next) {
883                 struct connman_iface_driver *driver = list->data;
884
885                 if (driver->capability == NULL)
886                         continue;
887
888                 if (libhal_device_query_capability(ctx, udi,
889                                         driver->capability, NULL) == TRUE) {
890                         if (probe_device(ctx, driver, udi) == 0)
891                                 break;
892                 }
893         }
894 }
895
896 static void device_removed(LibHalContext *ctx, const char *udi)
897 {
898         DBusConnection *conn;
899         GSList *list;
900
901         DBG("ctx %p udi %s", ctx, udi);
902
903         conn = libhal_ctx_get_dbus_connection(ctx);
904
905         for (list = interfaces; list; list = list->next) {
906                 struct connman_iface *iface = list->data;
907
908                 if (strcmp(udi, iface->udi) == 0) {
909                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
910                                         CONNMAN_MANAGER_INTERFACE,
911                                         "InterfaceRemoved",
912                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
913                                         DBUS_TYPE_INVALID);
914                         interfaces = g_slist_remove(interfaces, iface);
915                         g_dbus_unregister_interface(conn, iface->path,
916                                                 CONNMAN_IFACE_INTERFACE);
917                         g_dbus_unregister_object(conn, iface->path);
918                         break;
919                 }
920         }
921 }
922
923 static void probe_driver(LibHalContext *ctx,
924                                 struct connman_iface_driver *driver)
925 {
926         char **list;
927         int num;
928
929         DBG("ctx %p driver %p", ctx, driver);
930
931         list = libhal_find_device_by_capability(ctx,
932                                         driver->capability, &num, NULL);
933         if (list) {
934                 char **tmp = list;
935
936                 while (*tmp) {
937                         probe_device(ctx, driver, *tmp);
938                         tmp++;
939                 }
940
941                 libhal_free_string_array(list);
942         }
943 }
944
945 static void find_devices(LibHalContext *ctx)
946 {
947         GSList *list;
948
949         DBG("ctx %p", ctx);
950
951         for (list = drivers; list; list = list->next) {
952                 struct connman_iface_driver *driver = list->data;
953
954                 DBG("driver %p", driver);
955
956                 if (driver->capability == NULL)
957                         continue;
958
959                 probe_driver(ctx, driver);
960         }
961 }
962
963 static LibHalContext *hal_ctx = NULL;
964
965 static void hal_init(void *data)
966 {
967         DBusConnection *conn = data;
968
969         DBG("conn %p", conn);
970
971         if (hal_ctx != NULL)
972                 return;
973
974         hal_ctx = libhal_ctx_new();
975         if (hal_ctx == NULL)
976                 return;
977
978         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
979                 libhal_ctx_free(hal_ctx);
980                 return;
981         }
982
983         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
984                 libhal_ctx_free(hal_ctx);
985                 return ;
986         }
987
988         libhal_ctx_set_device_added(hal_ctx, device_added);
989         libhal_ctx_set_device_removed(hal_ctx, device_removed);
990
991         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
992         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
993
994         find_devices(hal_ctx);
995 }
996
997 static void hal_cleanup(void *data)
998 {
999         DBusConnection *conn = data;
1000         GSList *list;
1001
1002         DBG("conn %p", conn);
1003
1004         if (hal_ctx == NULL)
1005                 return;
1006
1007         for (list = interfaces; list; list = list->next) {
1008                 struct connman_iface *iface = list->data;
1009
1010                 DBG("path %s", iface->path);
1011
1012                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1013                                         CONNMAN_MANAGER_INTERFACE,
1014                                         "InterfaceRemoved",
1015                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1016                                         DBUS_TYPE_INVALID);
1017
1018                 g_dbus_unregister_interface(conn, iface->path,
1019                                                 CONNMAN_IFACE_INTERFACE);
1020
1021                 g_dbus_unregister_object(conn, iface->path);
1022         }
1023
1024         g_slist_free(interfaces);
1025
1026         interfaces = NULL;
1027
1028         libhal_ctx_shutdown(hal_ctx, NULL);
1029
1030         libhal_ctx_free(hal_ctx);
1031
1032         hal_ctx = NULL;
1033 }
1034
1035 static guint hal_watch = 0;
1036
1037 int __connman_iface_init(DBusConnection *conn)
1038 {
1039         DBG("conn %p", conn);
1040
1041         connection = dbus_connection_ref(conn);
1042         if (connection == NULL)
1043                 return -1;
1044
1045         hal_init(connection);
1046
1047         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
1048                                 hal_init, hal_cleanup, connection, NULL);
1049
1050         return 0;
1051 }
1052
1053 void __connman_iface_cleanup(void)
1054 {
1055         DBG("conn %p", connection);
1056
1057         g_dbus_remove_watch(connection, hal_watch);
1058
1059         hal_cleanup(connection);
1060
1061         dbus_connection_unref(connection);
1062 }