Use start/stop callbacks if provided
[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 static void append_entry(DBusMessageIter *dict,
99                                 const char *key, int type, void *val)
100 {
101         DBusMessageIter entry, value;
102         const char *signature;
103
104         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
105                                                                 NULL, &entry);
106
107         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
108
109         switch (type) {
110         case DBUS_TYPE_STRING:
111                 signature = DBUS_TYPE_STRING_AS_STRING;
112                 break;
113         case DBUS_TYPE_UINT16:
114                 signature = DBUS_TYPE_UINT16_AS_STRING;
115                 break;
116         default:
117                 signature = DBUS_TYPE_VARIANT_AS_STRING;
118                 break;
119         }
120
121         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
122                                                         signature, &value);
123         dbus_message_iter_append_basic(&value, type, val);
124         dbus_message_iter_close_container(&entry, &value);
125
126         dbus_message_iter_close_container(dict, &entry);
127 }
128
129 static gboolean scan_timeout(gpointer user_data)
130 {
131         struct connman_iface *iface = user_data;
132
133         switch (iface->state) {
134         case CONNMAN_IFACE_STATE_SCANNING:
135         case CONNMAN_IFACE_STATE_READY:
136                 if (iface->driver->scan)
137                         iface->driver->scan(iface);
138                 return TRUE;
139         default:
140                 break;
141         }
142
143         return FALSE;
144 }
145
146 static void state_changed(struct connman_iface *iface)
147 {
148         const char *str = __connman_iface_state2string(iface->state);
149         enum connman_iface_state state = iface->state;
150
151         DBG("iface %p state %s", iface, str);
152
153         g_dbus_emit_signal(connection, iface->path,
154                                 CONNMAN_IFACE_INTERFACE, "StateChanged",
155                                 DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
156
157         switch (iface->state) {
158         case CONNMAN_IFACE_STATE_OFF:
159                 __connman_dhcp_release(iface);
160                 break;
161
162         case CONNMAN_IFACE_STATE_ENABLED:
163                 __connman_dhcp_release(iface);
164                 connman_iface_clear_ipv4(iface);
165                 if (iface->driver->disconnect)
166                         iface->driver->disconnect(iface);
167                 if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING)
168                         state = CONNMAN_IFACE_STATE_SCANNING;
169                 break;
170
171         case CONNMAN_IFACE_STATE_SCANNING:
172                 if (iface->driver->scan)
173                         iface->driver->scan(iface);
174                 g_timeout_add(8000, scan_timeout, iface);
175                 break;
176
177         case CONNMAN_IFACE_STATE_CARRIER:
178                 if (iface->policy == CONNMAN_IFACE_POLICY_AUTO)
179                         state = CONNMAN_IFACE_STATE_CONFIGURE;
180                 break;
181
182         case CONNMAN_IFACE_STATE_CONFIGURE:
183                 __connman_dhcp_request(iface);
184                 break;
185
186         case CONNMAN_IFACE_STATE_SHUTDOWN:
187                 __connman_dhcp_release(iface);
188                 if (iface->driver->disconnect)
189                         iface->driver->disconnect(iface);
190                 if (iface->policy != CONNMAN_IFACE_POLICY_AUTO)
191                         state = CONNMAN_IFACE_STATE_OFF;
192                 break;
193
194         case CONNMAN_IFACE_STATE_READY:
195                 if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING)
196                         g_timeout_add(20000, scan_timeout, iface);
197                 break;
198
199         default:
200                 break;
201         }
202
203         if (iface->state != state) {
204                 iface->state = state;
205                 state_changed(iface);
206         }
207 }
208
209 static void switch_policy(struct connman_iface *iface)
210 {
211         DBG("iface %p", iface);
212
213         switch (iface->policy) {
214         case CONNMAN_IFACE_POLICY_OFF:
215                 iface->state = CONNMAN_IFACE_STATE_SHUTDOWN;
216                 state_changed(iface);
217                 connman_iface_clear_ipv4(iface);
218                 if (iface->driver->stop)
219                         iface->driver->stop(iface);
220                 else
221                         __connman_iface_down(iface);
222                 break;
223
224         case CONNMAN_IFACE_POLICY_IGNORE:
225                 break;
226
227         case CONNMAN_IFACE_POLICY_AUTO:
228                 if (iface->driver->start)
229                         iface->driver->start(iface);
230                 else
231                         __connman_iface_up(iface);
232                 state_changed(iface);
233                 break;
234
235         default:
236                 break;
237         }
238 }
239
240 void connman_iface_indicate_enabled(struct connman_iface *iface)
241 {
242         DBG("iface %p state %d", iface, iface->state);
243
244         switch (iface->state) {
245         case CONNMAN_IFACE_STATE_OFF:
246         case CONNMAN_IFACE_STATE_CARRIER:
247                 iface->state = CONNMAN_IFACE_STATE_ENABLED;
248                 state_changed(iface);
249                 break;
250         default:
251                 break;
252         }
253 }
254
255 void connman_iface_indicate_disabled(struct connman_iface *iface)
256 {
257         DBG("iface %p state %d", iface, iface->state);
258
259         if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) {
260                 iface->state = CONNMAN_IFACE_STATE_ENABLED;
261                 if (iface->driver->start)
262                         iface->driver->start(iface);
263                 else
264                         __connman_iface_up(iface);
265         } else
266                 iface->state = CONNMAN_IFACE_STATE_SHUTDOWN;
267
268         state_changed(iface);
269 }
270
271 void connman_iface_indicate_connected(struct connman_iface *iface)
272 {
273         DBG("iface %p state %d", iface, iface->state);
274
275         switch (iface->state) {
276         case CONNMAN_IFACE_STATE_CONNECT:
277                 iface->state = CONNMAN_IFACE_STATE_CONNECTED;
278                 state_changed(iface);
279                 break;
280         default:
281                 break;
282         }
283 }
284
285 void connman_iface_indicate_carrier_on(struct connman_iface *iface)
286 {
287         DBG("iface %p state %d", iface, iface->state);
288
289         switch (iface->state) {
290         case CONNMAN_IFACE_STATE_ENABLED:
291         case CONNMAN_IFACE_STATE_CONNECT:
292         case CONNMAN_IFACE_STATE_CONNECTED:
293                 iface->state = CONNMAN_IFACE_STATE_CARRIER;
294                 state_changed(iface);
295                 break;
296         default:
297                 break;
298         }
299 }
300
301 void connman_iface_indicate_carrier_off(struct connman_iface *iface)
302 {
303         DBG("iface %p state %d", iface, iface->state);
304
305         switch (iface->state) {
306         case CONNMAN_IFACE_STATE_CARRIER:
307         case CONNMAN_IFACE_STATE_CONFIGURE:
308         case CONNMAN_IFACE_STATE_READY:
309 #if 0
310                 if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING) {
311                         if (iface->driver->disconnect)
312                                 iface->driver->disconnect(iface);
313                         iface->state = CONNMAN_IFACE_STATE_SCANNING;
314                 } else
315 #endif
316                         iface->state = CONNMAN_IFACE_STATE_ENABLED;
317                 state_changed(iface);
318                 break;
319         default:
320                 break;
321         }
322 }
323
324 void connman_iface_indicate_configured(struct connman_iface *iface)
325 {
326         DBG("iface %p state %d", iface, iface->state);
327
328         switch (iface->state) {
329         case CONNMAN_IFACE_STATE_CONFIGURE:
330                 iface->state = CONNMAN_IFACE_STATE_READY;
331                 state_changed(iface);
332                 break;
333         default:
334                 break;
335         }
336 }
337
338 static void append_station(DBusMessage *reply, const char *name,
339                                                 int signal, int security)
340 {
341         DBusMessageIter array, dict;
342         const char *wpa = "WPA";
343
344         dbus_message_iter_init_append(reply, &array);
345
346         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
347                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
348                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
349                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
350
351         append_entry(&dict, "ESSID", DBUS_TYPE_STRING, &name);
352         append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
353
354         if (security > 0)
355                 append_entry(&dict, "Security", DBUS_TYPE_STRING, &wpa);
356
357         dbus_message_iter_close_container(&array, &dict);
358 }
359
360 void connman_iface_indicate_station(struct connman_iface *iface,
361                                 const char *name, int strength, int security)
362 {
363         DBusMessage *signal;
364
365         DBG("iface %p security %d name %s", iface, security, name);
366
367         if (name == NULL || strlen(name) == 0)
368                 return;
369
370         signal = dbus_message_new_signal(iface->path,
371                                 CONNMAN_IFACE_INTERFACE, "NetworkFound");
372         if (signal == NULL)
373                 return;
374
375         append_station(signal, name, strength, security);
376
377         dbus_connection_send(connection, signal, NULL);
378         dbus_message_unref(signal);
379
380         if (g_str_equal(name, iface->network.essid) == TRUE &&
381                         iface->state == CONNMAN_IFACE_STATE_SCANNING) {
382                 if (iface->driver->set_network)
383                         iface->driver->set_network(iface, name);
384                 if (iface->driver->set_passphrase)
385                         iface->driver->set_passphrase(iface,
386                                                 iface->network.psk);
387
388                 if (iface->driver->connect) {
389                         iface->driver->connect(iface, NULL);
390                         iface->state = CONNMAN_IFACE_STATE_CONNECT;
391                         state_changed(iface);
392                 }
393         }
394 }
395
396 int connman_iface_get_ipv4(struct connman_iface *iface,
397                                                 struct connman_ipv4 *ipv4)
398 {
399 #if 0
400         struct {
401                 struct nlmsghdr hdr;
402                 struct rtgenmsg msg;
403         } req;
404
405         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
406                 return -1;
407
408         DBG("iface %p ipv4 %p", iface, ipv4);
409
410         memset(&req, 0, sizeof(req));
411         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
412         req.hdr.nlmsg_type = RTM_GETADDR;
413         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
414         req.hdr.nlmsg_pid = 0;
415         req.hdr.nlmsg_seq = 4711;
416         req.msg.rtgen_family = AF_INET;
417
418         __connman_rtnl_send(&req, sizeof(req));
419 #endif
420
421         return 0;
422 }
423
424 int connman_iface_set_ipv4(struct connman_iface *iface,
425                                                 struct connman_ipv4 *ipv4)
426 {
427         struct ifreq ifr;
428         struct rtentry rt;
429         struct sockaddr_in *addr;
430         char cmd[128];
431         int sk, err;
432
433         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
434                 return -1;
435
436         DBG("iface %p ipv4 %p", iface, ipv4);
437
438         sk = socket(PF_INET, SOCK_DGRAM, 0);
439         if (sk < 0)
440                 return -1;
441
442         memset(&ifr, 0, sizeof(ifr));
443         ifr.ifr_ifindex = iface->index;
444
445         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
446                 close(sk);
447                 return -1;
448         }
449
450         DBG("ifname %s", ifr.ifr_name);
451
452         addr = (struct sockaddr_in *) &ifr.ifr_addr;
453         addr->sin_family = AF_INET;
454         addr->sin_addr = ipv4->address;
455
456         err = ioctl(sk, SIOCSIFADDR, &ifr);
457
458         if (err < 0)
459                 DBG("address setting failed (%s)", strerror(errno));
460
461         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
462         addr->sin_family = AF_INET;
463         addr->sin_addr = ipv4->netmask;
464
465         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
466
467         if (err < 0)
468                 DBG("netmask setting failed (%s)", strerror(errno));
469
470         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
471         addr->sin_family = AF_INET;
472         addr->sin_addr = ipv4->broadcast;
473
474         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
475
476         if (err < 0)
477                 DBG("broadcast setting failed (%s)", strerror(errno));
478
479         memset(&rt, 0, sizeof(rt));
480         rt.rt_flags = RTF_UP | RTF_GATEWAY;
481
482         addr = (struct sockaddr_in *) &rt.rt_dst;
483         addr->sin_family = AF_INET;
484         addr->sin_addr.s_addr = INADDR_ANY;
485
486         addr = (struct sockaddr_in *) &rt.rt_gateway;
487         addr->sin_family = AF_INET;
488         addr->sin_addr = ipv4->gateway;
489
490         addr = (struct sockaddr_in *) &rt.rt_genmask;
491         addr->sin_family = AF_INET;
492         addr->sin_addr.s_addr = INADDR_ANY;
493
494         err = ioctl(sk, SIOCADDRT, &rt);
495
496         close(sk);
497
498         if (err < 0) {
499                 DBG("default route failed (%s)", strerror(errno));
500                 return -1;
501         }
502
503         sprintf(cmd, "echo \"nameserver %s\" | resolvconf -a %s",
504                                 inet_ntoa(ipv4->nameserver), ifr.ifr_name);
505
506         DBG("%s", cmd);
507
508         err = system(cmd);
509
510         return 0;
511 }
512
513 int connman_iface_clear_ipv4(struct connman_iface *iface)
514 {
515         struct ifreq ifr;
516         struct sockaddr_in *addr;
517         char cmd[128];
518         int sk, err;
519
520         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
521                 return -1;
522
523         DBG("iface %p", iface);
524
525         sk = socket(PF_INET, SOCK_DGRAM, 0);
526         if (sk < 0)
527                 return -1;
528
529         memset(&ifr, 0, sizeof(ifr));
530         ifr.ifr_ifindex = iface->index;
531
532         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
533                 close(sk);
534                 return -1;
535         }
536
537         DBG("ifname %s", ifr.ifr_name);
538
539         addr = (struct sockaddr_in *) &ifr.ifr_addr;
540         addr->sin_family = AF_INET;
541         addr->sin_addr.s_addr = INADDR_ANY;
542
543         //err = ioctl(sk, SIOCDIFADDR, &ifr);
544         err = ioctl(sk, SIOCSIFADDR, &ifr);
545
546         close(sk);
547
548         if (err < 0 && errno != EADDRNOTAVAIL) {
549                 DBG("address removal failed (%s)", strerror(errno));
550                 return -1;
551         }
552
553         sprintf(cmd, "resolvconf -d %s", ifr.ifr_name);
554
555         DBG("%s", cmd);
556
557         err = system(cmd);
558
559         return 0;
560 }
561
562 static DBusMessage *scan_iface(DBusConnection *conn,
563                                         DBusMessage *msg, void *data)
564 {
565         struct connman_iface *iface = data;
566         struct connman_iface_driver *driver = iface->driver;
567         DBusMessage *reply;
568
569         DBG("conn %p", conn);
570
571         reply = dbus_message_new_method_return(msg);
572         if (reply == NULL)
573                 return NULL;
574
575         if (driver->scan) {
576                 //driver->scan(iface);
577         }
578
579         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
580
581         return reply;
582 }
583
584 static DBusMessage *get_properties(DBusConnection *conn,
585                                         DBusMessage *msg, void *data)
586 {
587         struct connman_iface *iface = data;
588         DBusMessage *reply;
589         DBusMessageIter array, dict;
590         const char *str;
591
592         DBG("conn %p", conn);
593
594         reply = dbus_message_new_method_return(msg);
595         if (reply == NULL)
596                 return NULL;
597
598         dbus_message_iter_init_append(reply, &array);
599
600         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
601                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
602                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
603                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
604
605         str = __connman_iface_type2string(iface->type);
606         append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
607
608         str = __connman_iface_state2string(iface->state);
609         append_entry(&dict, "State", DBUS_TYPE_STRING, &str);
610
611         if (iface->type == CONNMAN_IFACE_TYPE_80211) {
612                 dbus_uint16_t signal = 75;
613                 append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
614         }
615
616         str = __connman_iface_policy2string(iface->policy);
617         append_entry(&dict, "Policy", DBUS_TYPE_STRING, &str);
618
619         if (iface->device.driver != NULL)
620                 append_entry(&dict, "Driver",
621                                 DBUS_TYPE_STRING, &iface->device.driver);
622
623         if (iface->device.vendor != NULL)
624                 append_entry(&dict, "Vendor",
625                                 DBUS_TYPE_STRING, &iface->device.vendor);
626
627         if (iface->device.product != NULL)
628                 append_entry(&dict, "Product",
629                                 DBUS_TYPE_STRING, &iface->device.product);
630
631         dbus_message_iter_close_container(&array, &dict);
632
633         return reply;
634 }
635
636 static DBusMessage *get_state(DBusConnection *conn,
637                                         DBusMessage *msg, void *data)
638 {
639         struct connman_iface *iface = data;
640         DBusMessage *reply;
641         const char *state;
642
643         DBG("conn %p", conn);
644
645         reply = dbus_message_new_method_return(msg);
646         if (reply == NULL)
647                 return NULL;
648
649         state = __connman_iface_state2string(iface->state);
650
651         dbus_message_append_args(reply, DBUS_TYPE_STRING, &state,
652                                                         DBUS_TYPE_INVALID);
653
654         return reply;
655 }
656
657 static DBusMessage *get_signal(DBusConnection *conn,
658                                         DBusMessage *msg, void *data)
659 {
660         struct connman_iface *iface = data;
661         DBusMessage *reply;
662         dbus_uint16_t signal;
663
664         DBG("conn %p", conn);
665
666         reply = dbus_message_new_method_return(msg);
667         if (reply == NULL)
668                 return NULL;
669
670         if (iface->type == CONNMAN_IFACE_TYPE_80211)
671                 signal = 75;
672         else
673                 signal = 0;
674
675         dbus_message_append_args(reply, DBUS_TYPE_UINT16, &signal,
676                                                         DBUS_TYPE_INVALID);
677
678         return reply;
679 }
680
681 static DBusMessage *get_policy(DBusConnection *conn,
682                                         DBusMessage *msg, void *data)
683 {
684         struct connman_iface *iface = data;
685         DBusMessage *reply;
686         const char *policy;
687
688         DBG("conn %p", conn);
689
690         reply = dbus_message_new_method_return(msg);
691         if (reply == NULL)
692                 return NULL;
693
694         policy = __connman_iface_policy2string(iface->policy);
695
696         dbus_message_append_args(reply, DBUS_TYPE_STRING, &policy,
697                                                         DBUS_TYPE_INVALID);
698
699         return reply;
700 }
701
702 static DBusMessage *set_policy(DBusConnection *conn,
703                                         DBusMessage *msg, void *data)
704 {
705         struct connman_iface *iface = data;
706         DBusMessage *reply;
707         enum connman_iface_policy new_policy;
708         const char *policy;
709
710         DBG("conn %p", conn);
711
712         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &policy,
713                                                         DBUS_TYPE_INVALID);
714
715         new_policy = __connman_iface_string2policy(policy);
716
717         reply = dbus_message_new_method_return(msg);
718         if (reply == NULL)
719                 return NULL;
720
721         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
722
723         if (iface->policy != new_policy) {
724                 iface->policy = new_policy;
725                 __connman_iface_store(iface);
726
727                 switch_policy(iface);
728                 policy = __connman_iface_policy2string(new_policy);
729
730                 g_dbus_emit_signal(conn, iface->path, CONNMAN_IFACE_INTERFACE,
731                                 "PolicyChanged", DBUS_TYPE_STRING, &policy,
732                                                         DBUS_TYPE_INVALID);
733         }
734
735         return reply;
736 }
737
738 static void append_network(DBusMessage *reply,
739                                 struct connman_iface *iface, gboolean secrets)
740 {
741         DBusMessageIter array, dict;
742
743         dbus_message_iter_init_append(reply, &array);
744
745         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
746                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
747                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
748                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
749
750         switch (iface->type) {
751         case CONNMAN_IFACE_TYPE_80211:
752                 if (iface->network.essid != NULL)
753                         append_entry(&dict, "ESSID",
754                                 DBUS_TYPE_STRING, &iface->network.essid);
755                 if (secrets == TRUE && iface->network.psk != NULL)
756                         append_entry(&dict, "PSK",
757                                 DBUS_TYPE_STRING, &iface->network.psk);
758                 break;
759         default:
760                 break;
761         }
762
763         dbus_message_iter_close_container(&array, &dict);
764 }
765
766 static DBusMessage *get_network(DBusConnection *conn,
767                                         DBusMessage *msg, void *data)
768 {
769         struct connman_iface *iface = data;
770         DBusMessage *reply;
771
772         DBG("conn %p", conn);
773
774         reply = dbus_message_new_method_return(msg);
775         if (reply == NULL)
776                 return NULL;
777
778         append_network(reply, iface, TRUE);
779
780         return reply;
781 }
782
783 static DBusMessage *set_network(DBusConnection *conn,
784                                         DBusMessage *msg, void *data)
785 {
786         struct connman_iface *iface = data;
787         DBusMessage *reply, *signal;
788         DBusMessageIter array, dict;
789         gboolean changed = FALSE;
790
791         DBG("conn %p", conn);
792
793         dbus_message_iter_init(msg, &array);
794
795         dbus_message_iter_recurse(&array, &dict);
796
797         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
798                 DBusMessageIter entry, value;
799                 const char *key, *val;
800
801                 dbus_message_iter_recurse(&dict, &entry);
802                 dbus_message_iter_get_basic(&entry, &key);
803
804                 dbus_message_iter_next(&entry);
805
806                 dbus_message_iter_recurse(&entry, &value);
807
808                 //type = dbus_message_iter_get_arg_type(&value);
809                 dbus_message_iter_get_basic(&value, &val);
810
811                 if (g_strcasecmp(key, "ESSID") == 0) {
812                         g_free(iface->network.essid);
813                         iface->network.essid = g_strdup(val);
814                         if (iface->driver->set_network)
815                                 iface->driver->set_network(iface, val);
816                         changed = TRUE;
817                 }
818
819                 if (g_strcasecmp(key, "PSK") == 0) {
820                         g_free(iface->network.psk);
821                         iface->network.psk = g_strdup(val);
822                         if (iface->driver->set_passphrase)
823                                 iface->driver->set_passphrase(iface, val);
824                         changed = TRUE;
825                 }
826
827                 dbus_message_iter_next(&dict);
828         }
829
830         reply = dbus_message_new_method_return(msg);
831         if (reply == NULL)
832                 return NULL;
833
834         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
835
836         if (changed == TRUE) {
837                 __connman_iface_store(iface);
838
839                 signal = dbus_message_new_signal(iface->path,
840                                 CONNMAN_IFACE_INTERFACE, "NetworkChanged");
841                 if (signal != NULL) {
842                         append_network(signal, iface, FALSE);
843                         dbus_connection_send(conn, signal, NULL);
844                         dbus_message_unref(signal);
845                 }
846         }
847
848         return reply;
849 }
850
851 static DBusMessage *select_network(DBusConnection *conn,
852                                         DBusMessage *msg, void *data)
853 {
854         struct connman_iface *iface = data;
855         DBusMessage *reply;
856         const char *network;
857
858         DBG("conn %p", conn);
859
860         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &network,
861                                                         DBUS_TYPE_INVALID);
862
863         g_free(iface->network.essid);
864         iface->network.essid = g_strdup(network);
865
866         if (iface->driver->set_network)
867                 iface->driver->set_network(iface, network);
868
869         reply = dbus_message_new_method_return(msg);
870         if (reply == NULL)
871                 return NULL;
872
873         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
874
875         return reply;
876 }
877
878 static void append_ipv4(DBusMessage *reply, struct connman_iface *iface)
879 {
880         DBusMessageIter array, dict;
881         const char *str;
882
883         dbus_message_iter_init_append(reply, &array);
884
885         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
886                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
887                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
888                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
889
890         str = __connman_ipv4_method2string(iface->ipv4.method);
891         append_entry(&dict, "Method", DBUS_TYPE_STRING, &str);
892
893         if (iface->ipv4.address.s_addr != INADDR_ANY) {
894                 str = inet_ntoa(iface->ipv4.address);
895                 append_entry(&dict, "Address", DBUS_TYPE_STRING, &str);
896         }
897
898         if (iface->ipv4.netmask.s_addr != INADDR_ANY) {
899                 str = inet_ntoa(iface->ipv4.netmask);
900                 append_entry(&dict, "Netmask", DBUS_TYPE_STRING, &str);
901         }
902
903         if (iface->ipv4.gateway.s_addr != INADDR_ANY) {
904                 str = inet_ntoa(iface->ipv4.gateway);
905                 append_entry(&dict, "Gateway", DBUS_TYPE_STRING, &str);
906         }
907
908         dbus_message_iter_close_container(&array, &dict);
909 }
910
911 static DBusMessage *get_ipv4(DBusConnection *conn,
912                                         DBusMessage *msg, void *data)
913 {
914         struct connman_iface *iface = data;
915         DBusMessage *reply;
916
917         DBG("conn %p", conn);
918
919         reply = dbus_message_new_method_return(msg);
920         if (reply == NULL)
921                 return NULL;
922
923         append_ipv4(reply, iface);
924
925         return reply;
926 }
927
928 static DBusMessage *set_ipv4(DBusConnection *conn,
929                                         DBusMessage *msg, void *data)
930 {
931         struct connman_iface *iface = data;
932         DBusMessage *reply, *signal;
933         DBusMessageIter array, dict;
934         gboolean changed = FALSE;
935
936         DBG("conn %p", conn);
937
938         dbus_message_iter_init(msg, &array);
939
940         dbus_message_iter_recurse(&array, &dict);
941
942         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
943                 DBusMessageIter entry, value;
944                 const char *key, *val;
945                 enum connman_ipv4_method method;
946                 in_addr_t addr;
947
948                 dbus_message_iter_recurse(&dict, &entry);
949                 dbus_message_iter_get_basic(&entry, &key);
950
951                 dbus_message_iter_next(&entry);
952
953                 dbus_message_iter_recurse(&entry, &value);
954
955                 //type = dbus_message_iter_get_arg_type(&value);
956                 dbus_message_iter_get_basic(&value, &val);
957
958                 if (g_strcasecmp(key, "Method") == 0) {
959                         method = __connman_ipv4_string2method(val);
960                         if (iface->ipv4.method != method) {
961                                 iface->ipv4.method = method;
962                                 changed = TRUE;
963                         }
964                 }
965
966                 if (g_strcasecmp(key, "Address") == 0) {
967                         addr = inet_addr(val);
968                         if (iface->ipv4.address.s_addr != addr) {
969                                 iface->ipv4.address.s_addr = addr;
970                                 changed = TRUE;
971                         }
972                 }
973
974                 if (g_strcasecmp(key, "Netmask") == 0) {
975                         addr = inet_addr(val);
976                         if (iface->ipv4.netmask.s_addr != addr) {
977                                 iface->ipv4.netmask.s_addr = addr;
978                                 changed = TRUE;
979                         }
980                 }
981
982                 if (g_strcasecmp(key, "Gateway") == 0) {
983                         addr = inet_addr(val);
984                         if (iface->ipv4.gateway.s_addr != addr) {
985                                 iface->ipv4.gateway.s_addr = addr;
986                                 changed = TRUE;
987                         }
988                 }
989
990                 dbus_message_iter_next(&dict);
991         }
992
993         reply = dbus_message_new_method_return(msg);
994         if (reply == NULL)
995                 return NULL;
996
997         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
998
999         if (changed == TRUE) {
1000                 __connman_iface_store(iface);
1001
1002                 signal = dbus_message_new_signal(iface->path,
1003                                 CONNMAN_IFACE_INTERFACE, "IPv4Changed");
1004                 if (signal != NULL) {
1005                         append_ipv4(signal, iface);
1006                         dbus_connection_send(conn, signal, NULL);
1007                         dbus_message_unref(signal);
1008                 }
1009         }
1010
1011         return reply;
1012 }
1013
1014 static GDBusMethodTable iface_methods[] = {
1015         { "Scan",          "",      "",      scan_iface     },
1016         { "GetProperties", "",      "a{sv}", get_properties },
1017         { "GetState",      "",      "s",     get_state      },
1018         { "GetSignal",     "",      "q",     get_signal     },
1019         { "GetPolicy",     "",      "s",     get_policy     },
1020         { "SetPolicy",     "s",     "",      set_policy     },
1021         { "GetNetwork",    "",      "a{sv}", get_network    },
1022         { "SetNetwork",    "a{sv}", "",      set_network    },
1023         { "SelectNetwork", "s",     "",      select_network },
1024         { "GetIPv4",       "",      "a{sv}", get_ipv4       },
1025         { "SetIPv4",       "a{sv}", "",      set_ipv4       },
1026         { },
1027 };
1028
1029 static GDBusSignalTable iface_signals[] = {
1030         { "StateChanged",   "s"     },
1031         { "SignalChanged",  "q"     },
1032         { "PolicyChanged",  "s"     },
1033         { "NetworkFound",   "a{sv}" },
1034         { "NetworkChanged", "a{sv}" },
1035         { "IPv4Changed",    "a{sv}" },
1036         { },
1037 };
1038
1039 static void device_free(void *data)
1040 {
1041         struct connman_iface *iface = data;
1042
1043         DBG("iface %p", iface);
1044
1045         connman_iface_clear_ipv4(iface);
1046
1047         if (iface->driver && iface->driver->remove)
1048                 iface->driver->remove(iface);
1049
1050         g_free(iface->path);
1051         g_free(iface->udi);
1052         g_free(iface->sysfs);
1053         g_free(iface->identifier);
1054         g_free(iface->network.essid);
1055         g_free(iface->device.driver);
1056         g_free(iface->device.vendor);
1057         g_free(iface->device.product);
1058         g_free(iface);
1059 }
1060
1061 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
1062 {
1063         char *parent, *subsys, *value;
1064
1065         parent = libhal_device_get_property_string(ctx, iface->udi,
1066                                                 "info.parent", NULL);
1067
1068         subsys = libhal_device_get_property_string(ctx, iface->udi,
1069                                                 "linux.subsystem", NULL);
1070
1071         value = libhal_device_get_property_string(ctx, iface->udi,
1072                                                 "info.linux.driver", NULL);
1073         if (value == NULL) {
1074                 value = libhal_device_get_property_string(ctx, parent,
1075                                                 "info.linux.driver", NULL);
1076                 if (value != NULL)
1077                         iface->device.driver = g_strdup(value);
1078         }
1079
1080         if (strcmp(subsys, "net") == 0) {
1081                 value = libhal_device_get_property_string(ctx, parent,
1082                                                         "info.vendor", NULL);
1083                 if (value != NULL)
1084                         iface->device.vendor = g_strdup(value);
1085
1086                 value = libhal_device_get_property_string(ctx, parent,
1087                                                         "info.product", NULL);
1088                 if (value != NULL)
1089                         iface->device.product = g_strdup(value);
1090         }
1091 }
1092
1093 static int probe_device(LibHalContext *ctx,
1094                         struct connman_iface_driver *driver, const char *udi)
1095 {
1096         DBusConnection *conn;
1097         struct connman_iface *iface;
1098         char *temp, *sysfs;
1099         int err;
1100
1101         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
1102
1103         if (!driver->probe)
1104                 return -1;
1105
1106         iface = g_try_new0(struct connman_iface, 1);
1107         if (iface == NULL)
1108                 return -1;
1109
1110         temp = g_path_get_basename(udi);
1111         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
1112         g_free(temp);
1113
1114         iface->udi = g_strdup(udi);
1115
1116         DBG("iface %p path %s", iface, iface->path);
1117
1118         sysfs = libhal_device_get_property_string(ctx, udi,
1119                                                 "linux.sysfs_path", NULL);
1120         if (sysfs != NULL)
1121                 iface->sysfs = g_strdup(sysfs);
1122
1123         detect_device_info(ctx, iface);
1124
1125         iface->index = -1;
1126
1127         if (g_str_has_prefix(driver->capability, "net") == TRUE)
1128                 iface->index = libhal_device_get_property_int(ctx, udi,
1129                                                 "net.linux.ifindex", NULL);
1130
1131         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
1132         iface->flags = 0;
1133         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
1134         iface->policy = CONNMAN_IFACE_POLICY_UNKNOWN;
1135
1136         err = driver->probe(iface);
1137         if (err < 0) {
1138                 device_free(iface);
1139                 return -1;
1140         }
1141
1142         __connman_iface_create_identifier(iface);
1143
1144         __connman_iface_init_via_inet(iface);
1145
1146         iface->driver = driver;
1147
1148         __connman_iface_load(iface);
1149
1150         DBG("iface %p network %s secret %s", iface,
1151                                 iface->network.essid, iface->network.psk);
1152
1153         conn = libhal_ctx_get_dbus_connection(ctx);
1154
1155         g_dbus_register_object(conn, iface->path, iface, device_free);
1156
1157         interfaces = g_slist_append(interfaces, iface);
1158
1159         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
1160                 connman_iface_get_ipv4(iface, &iface->ipv4);
1161
1162                 DBG("address %s", inet_ntoa(iface->ipv4.address));
1163         }
1164
1165         g_dbus_register_interface(conn, iface->path,
1166                                         CONNMAN_IFACE_INTERFACE,
1167                                         iface_methods, iface_signals, NULL);
1168
1169         DBG("iface %p identifier %s", iface, iface->identifier);
1170
1171         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1172                                         CONNMAN_MANAGER_INTERFACE,
1173                                         "InterfaceAdded",
1174                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1175                                         DBUS_TYPE_INVALID);
1176
1177         switch_policy(iface);
1178
1179         return 0;
1180 }
1181
1182 static void device_added(LibHalContext *ctx, const char *udi)
1183 {
1184         GSList *list;
1185
1186         DBG("ctx %p udi %s", ctx, udi);
1187
1188         for (list = drivers; list; list = list->next) {
1189                 struct connman_iface_driver *driver = list->data;
1190
1191                 if (driver->capability == NULL)
1192                         continue;
1193
1194                 if (libhal_device_query_capability(ctx, udi,
1195                                         driver->capability, NULL) == TRUE) {
1196                         if (probe_device(ctx, driver, udi) == 0)
1197                                 break;
1198                 }
1199         }
1200 }
1201
1202 static void device_removed(LibHalContext *ctx, const char *udi)
1203 {
1204         DBusConnection *conn;
1205         GSList *list;
1206
1207         DBG("ctx %p udi %s", ctx, udi);
1208
1209         conn = libhal_ctx_get_dbus_connection(ctx);
1210
1211         for (list = interfaces; list; list = list->next) {
1212                 struct connman_iface *iface = list->data;
1213
1214                 if (strcmp(udi, iface->udi) == 0) {
1215                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1216                                         CONNMAN_MANAGER_INTERFACE,
1217                                         "InterfaceRemoved",
1218                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1219                                         DBUS_TYPE_INVALID);
1220                         interfaces = g_slist_remove(interfaces, iface);
1221                         g_dbus_unregister_interface(conn, iface->path,
1222                                                 CONNMAN_IFACE_INTERFACE);
1223                         g_dbus_unregister_object(conn, iface->path);
1224                         break;
1225                 }
1226         }
1227 }
1228
1229 static void probe_driver(LibHalContext *ctx,
1230                                 struct connman_iface_driver *driver)
1231 {
1232         char **list;
1233         int num;
1234
1235         DBG("ctx %p driver %p", ctx, driver);
1236
1237         list = libhal_find_device_by_capability(ctx,
1238                                         driver->capability, &num, NULL);
1239         if (list) {
1240                 char **tmp = list;
1241
1242                 while (*tmp) {
1243                         probe_device(ctx, driver, *tmp);
1244                         tmp++;
1245                 }
1246
1247                 libhal_free_string_array(list);
1248         }
1249 }
1250
1251 static void find_devices(LibHalContext *ctx)
1252 {
1253         GSList *list;
1254
1255         DBG("ctx %p", ctx);
1256
1257         for (list = drivers; list; list = list->next) {
1258                 struct connman_iface_driver *driver = list->data;
1259
1260                 DBG("driver %p", driver);
1261
1262                 if (driver->capability == NULL)
1263                         continue;
1264
1265                 probe_driver(ctx, driver);
1266         }
1267 }
1268
1269 static LibHalContext *hal_ctx = NULL;
1270
1271 static void hal_init(void *data)
1272 {
1273         DBusConnection *conn = data;
1274
1275         DBG("conn %p", conn);
1276
1277         if (hal_ctx != NULL)
1278                 return;
1279
1280         hal_ctx = libhal_ctx_new();
1281         if (hal_ctx == NULL)
1282                 return;
1283
1284         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
1285                 libhal_ctx_free(hal_ctx);
1286                 return;
1287         }
1288
1289         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
1290                 libhal_ctx_free(hal_ctx);
1291                 return ;
1292         }
1293
1294         libhal_ctx_set_device_added(hal_ctx, device_added);
1295         libhal_ctx_set_device_removed(hal_ctx, device_removed);
1296
1297         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
1298         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
1299
1300         find_devices(hal_ctx);
1301 }
1302
1303 static void hal_cleanup(void *data)
1304 {
1305         DBusConnection *conn = data;
1306         GSList *list;
1307
1308         DBG("conn %p", conn);
1309
1310         if (hal_ctx == NULL)
1311                 return;
1312
1313         for (list = interfaces; list; list = list->next) {
1314                 struct connman_iface *iface = list->data;
1315
1316                 DBG("path %s", iface->path);
1317
1318                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1319                                         CONNMAN_MANAGER_INTERFACE,
1320                                         "InterfaceRemoved",
1321                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1322                                         DBUS_TYPE_INVALID);
1323
1324                 g_dbus_unregister_interface(conn, iface->path,
1325                                                 CONNMAN_IFACE_INTERFACE);
1326
1327                 g_dbus_unregister_object(conn, iface->path);
1328         }
1329
1330         g_slist_free(interfaces);
1331
1332         interfaces = NULL;
1333
1334         libhal_ctx_shutdown(hal_ctx, NULL);
1335
1336         libhal_ctx_free(hal_ctx);
1337
1338         hal_ctx = NULL;
1339 }
1340
1341 static guint hal_watch = 0;
1342
1343 int __connman_iface_init(DBusConnection *conn)
1344 {
1345         DBG("conn %p", conn);
1346
1347         connection = dbus_connection_ref(conn);
1348         if (connection == NULL)
1349                 return -1;
1350
1351         hal_init(connection);
1352
1353         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
1354                                 hal_init, hal_cleanup, connection, NULL);
1355
1356         return 0;
1357 }
1358
1359 void __connman_iface_cleanup(void)
1360 {
1361         DBG("conn %p", connection);
1362
1363         g_dbus_remove_watch(connection, hal_watch);
1364
1365         hal_cleanup(connection);
1366
1367         dbus_connection_unref(connection);
1368 }