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