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