Update state machine handling for wireless networks
[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_iface_stop(iface);
161                 break;
162
163         case CONNMAN_IFACE_STATE_ENABLED:
164                 __connman_iface_start(iface);
165                 if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING)
166                         state = CONNMAN_IFACE_STATE_SCANNING;
167                 break;
168
169         case CONNMAN_IFACE_STATE_SCANNING:
170                 if (iface->driver->scan)
171                         iface->driver->scan(iface);
172                 g_timeout_add(8000, scan_timeout, iface);
173                 break;
174
175         case CONNMAN_IFACE_STATE_CARRIER:
176                 if (iface->policy == CONNMAN_IFACE_POLICY_AUTO)
177                         state = CONNMAN_IFACE_STATE_CONFIGURE;
178                 break;
179
180         case CONNMAN_IFACE_STATE_CONFIGURE:
181                 __connman_dhcp_request(iface);
182                 break;
183
184         case CONNMAN_IFACE_STATE_SHUTDOWN:
185                 __connman_iface_stop(iface);
186                 if (iface->policy != CONNMAN_IFACE_POLICY_AUTO)
187                         state = CONNMAN_IFACE_STATE_OFF;
188                 break;
189
190         case CONNMAN_IFACE_STATE_READY:
191                 break;
192
193         default:
194                 break;
195         }
196
197         if (iface->state != state) {
198                 iface->state = state;
199                 state_changed(iface);
200         }
201 }
202
203 static void switch_policy(struct connman_iface *iface)
204 {
205         DBG("iface %p policy %d", iface, iface->policy);
206
207         switch (iface->policy) {
208         case CONNMAN_IFACE_POLICY_OFF:
209                 __connman_iface_stop(iface);
210                 break;
211
212         case CONNMAN_IFACE_POLICY_IGNORE:
213                 break;
214
215         case CONNMAN_IFACE_POLICY_AUTO:
216         case CONNMAN_IFACE_POLICY_ASK:
217                 __connman_iface_start(iface);
218                 break;
219
220         default:
221                 break;
222         }
223 }
224
225 void connman_iface_indicate_ifup(struct connman_iface *iface)
226 {
227         DBG("iface %p state %d", iface, iface->state);
228
229         switch (iface->state) {
230         case CONNMAN_IFACE_STATE_OFF:
231                 iface->state = CONNMAN_IFACE_STATE_ENABLED;
232                 state_changed(iface);
233                 break;
234         default:
235                 break;
236         }
237 }
238
239 void connman_iface_indicate_ifdown(struct connman_iface *iface)
240 {
241         DBG("iface %p state %d", iface, iface->state);
242
243         if (iface->policy == CONNMAN_IFACE_POLICY_AUTO)
244                 iface->state = CONNMAN_IFACE_STATE_ENABLED;
245         else
246                 iface->state = CONNMAN_IFACE_STATE_SHUTDOWN;
247
248         state_changed(iface);
249 }
250
251 void connman_iface_indicate_connected(struct connman_iface *iface)
252 {
253         DBG("iface %p state %d", iface, iface->state);
254
255         switch (iface->state) {
256         case CONNMAN_IFACE_STATE_CONNECT:
257                 iface->state = CONNMAN_IFACE_STATE_CONNECTED;
258                 state_changed(iface);
259                 break;
260         default:
261                 break;
262         }
263 }
264
265 void connman_iface_indicate_carrier_on(struct connman_iface *iface)
266 {
267         DBG("iface %p state %d", iface, iface->state);
268
269         switch (iface->state) {
270         case CONNMAN_IFACE_STATE_ENABLED:
271         case CONNMAN_IFACE_STATE_CONNECT:
272         case CONNMAN_IFACE_STATE_CONNECTED:
273                 iface->state = CONNMAN_IFACE_STATE_CARRIER;
274                 state_changed(iface);
275                 break;
276         default:
277                 break;
278         }
279 }
280
281 void connman_iface_indicate_carrier_off(struct connman_iface *iface)
282 {
283         DBG("iface %p state %d", iface, iface->state);
284
285         switch (iface->state) {
286         case CONNMAN_IFACE_STATE_CARRIER:
287         case CONNMAN_IFACE_STATE_CONFIGURE:
288         case CONNMAN_IFACE_STATE_READY:
289                 __connman_iface_disconnect(iface);
290                 if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING)
291                         iface->state = CONNMAN_IFACE_STATE_SCANNING;
292                 else
293                         iface->state = CONNMAN_IFACE_STATE_ENABLED;
294                 state_changed(iface);
295                 break;
296         default:
297                 break;
298         }
299 }
300
301 void connman_iface_indicate_configured(struct connman_iface *iface)
302 {
303         DBG("iface %p state %d", iface, iface->state);
304
305         switch (iface->state) {
306         case CONNMAN_IFACE_STATE_CONFIGURE:
307                 iface->state = CONNMAN_IFACE_STATE_READY;
308                 state_changed(iface);
309                 break;
310         default:
311                 break;
312         }
313 }
314
315 static void append_station(DBusMessage *reply, const char *name,
316                                                 int signal, int security)
317 {
318         DBusMessageIter array, dict;
319         const char *wpa = "WPA";
320
321         dbus_message_iter_init_append(reply, &array);
322
323         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
324                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
325                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
326                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
327
328         append_entry(&dict, "ESSID", DBUS_TYPE_STRING, &name);
329         append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
330
331         if (security > 0)
332                 append_entry(&dict, "Security", DBUS_TYPE_STRING, &wpa);
333
334         dbus_message_iter_close_container(&array, &dict);
335 }
336
337 void connman_iface_indicate_station(struct connman_iface *iface,
338                                 const char *name, int strength, int security)
339 {
340         DBusMessage *signal;
341         char *ssid, *passphrase;
342         int len;
343
344         DBG("iface %p security %d name %s", iface, security, name);
345
346         if (name == NULL || strlen(name) == 0)
347                 return;
348
349         signal = dbus_message_new_signal(iface->path,
350                                 CONNMAN_IFACE_INTERFACE, "NetworkFound");
351         if (signal == NULL)
352                 return;
353
354         append_station(signal, name, strength, security);
355
356         dbus_connection_send(connection, signal, NULL);
357         dbus_message_unref(signal);
358
359         switch (iface->state) {
360         case CONNMAN_IFACE_STATE_CONNECT:
361         case CONNMAN_IFACE_STATE_CONNECTED:
362         case CONNMAN_IFACE_STATE_CARRIER:
363         case CONNMAN_IFACE_STATE_CONFIGURE:
364         case CONNMAN_IFACE_STATE_READY:
365                 return;
366         default:
367                 break;
368         }
369
370         len = strlen(name);
371         ssid = strdup(name);
372         if (ssid == NULL)
373                 return;
374
375         /* The D-Link access points return a 0x05 at the end of the SSID */
376         if (ssid[len - 1] == '\05')
377                 ssid[len - 1] = '\0';
378
379         passphrase = __connman_iface_find_passphrase(iface, ssid);
380         if (passphrase != NULL) {
381                 DBG("network %s passphrase %s", ssid, passphrase);
382
383                 g_free(iface->network.identifier);
384                 iface->network.identifier = g_strdup(ssid);
385                 g_free(iface->network.passphrase);
386                 iface->network.passphrase = passphrase;
387
388                 __connman_iface_connect(iface, &iface->network);
389
390                 iface->state = CONNMAN_IFACE_STATE_CONNECT;
391                 state_changed(iface);
392         }
393
394         free(ssid);
395 }
396
397 int connman_iface_get_ipv4(struct connman_iface *iface,
398                                                 struct connman_ipv4 *ipv4)
399 {
400 #if 0
401         struct {
402                 struct nlmsghdr hdr;
403                 struct rtgenmsg msg;
404         } req;
405
406         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
407                 return -1;
408
409         DBG("iface %p ipv4 %p", iface, ipv4);
410
411         memset(&req, 0, sizeof(req));
412         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
413         req.hdr.nlmsg_type = RTM_GETADDR;
414         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
415         req.hdr.nlmsg_pid = 0;
416         req.hdr.nlmsg_seq = 4711;
417         req.msg.rtgen_family = AF_INET;
418
419         __connman_rtnl_send(&req, sizeof(req));
420 #endif
421
422         return 0;
423 }
424
425 int connman_iface_set_ipv4(struct connman_iface *iface,
426                                                 struct connman_ipv4 *ipv4)
427 {
428         struct ifreq ifr;
429         struct rtentry rt;
430         struct sockaddr_in *addr;
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         __connman_resolver_append(iface, inet_ntoa(ipv4->nameserver));
504
505         return 0;
506 }
507
508 int connman_iface_clear_ipv4(struct connman_iface *iface)
509 {
510         struct ifreq ifr;
511         struct sockaddr_in *addr;
512         int sk, err;
513
514         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
515                 return -1;
516
517         DBG("iface %p", iface);
518
519         sk = socket(PF_INET, SOCK_DGRAM, 0);
520         if (sk < 0)
521                 return -1;
522
523         memset(&ifr, 0, sizeof(ifr));
524         ifr.ifr_ifindex = iface->index;
525
526         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
527                 close(sk);
528                 return -1;
529         }
530
531         DBG("ifname %s", ifr.ifr_name);
532
533         addr = (struct sockaddr_in *) &ifr.ifr_addr;
534         addr->sin_family = AF_INET;
535         addr->sin_addr.s_addr = INADDR_ANY;
536
537         //err = ioctl(sk, SIOCDIFADDR, &ifr);
538         err = ioctl(sk, SIOCSIFADDR, &ifr);
539
540         close(sk);
541
542         if (err < 0 && errno != EADDRNOTAVAIL) {
543                 DBG("address removal failed (%s)", strerror(errno));
544                 return -1;
545         }
546
547         __connman_resolver_remove(iface);
548
549         return 0;
550 }
551
552 static DBusMessage *scan_iface(DBusConnection *conn,
553                                         DBusMessage *msg, void *data)
554 {
555         struct connman_iface *iface = data;
556         struct connman_iface_driver *driver = iface->driver;
557         DBusMessage *reply;
558
559         DBG("conn %p", conn);
560
561         reply = dbus_message_new_method_return(msg);
562         if (reply == NULL)
563                 return NULL;
564
565         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
566
567         switch (iface->state) {
568         case CONNMAN_IFACE_STATE_CONNECT:
569         case CONNMAN_IFACE_STATE_CONFIGURE:
570                         return reply;
571         default:
572                 break;
573         }
574
575         if (driver->scan)
576                 driver->scan(iface);
577
578         return reply;
579 }
580
581 static DBusMessage *get_properties(DBusConnection *conn,
582                                         DBusMessage *msg, void *data)
583 {
584         struct connman_iface *iface = data;
585         DBusMessage *reply;
586         DBusMessageIter array, dict;
587         const char *str;
588
589         DBG("conn %p", conn);
590
591         reply = dbus_message_new_method_return(msg);
592         if (reply == NULL)
593                 return NULL;
594
595         dbus_message_iter_init_append(reply, &array);
596
597         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
598                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
599                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
600                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
601
602         str = __connman_iface_type2string(iface->type);
603         append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
604
605         str = __connman_iface_state2string(iface->state);
606         append_entry(&dict, "State", DBUS_TYPE_STRING, &str);
607
608         if (iface->type == CONNMAN_IFACE_TYPE_80211) {
609                 dbus_uint16_t signal = 75;
610                 append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
611         }
612
613         str = __connman_iface_policy2string(iface->policy);
614         append_entry(&dict, "Policy", DBUS_TYPE_STRING, &str);
615
616         if (iface->device.driver != NULL)
617                 append_entry(&dict, "Driver",
618                                 DBUS_TYPE_STRING, &iface->device.driver);
619
620         if (iface->device.vendor != NULL)
621                 append_entry(&dict, "Vendor",
622                                 DBUS_TYPE_STRING, &iface->device.vendor);
623
624         if (iface->device.product != NULL)
625                 append_entry(&dict, "Product",
626                                 DBUS_TYPE_STRING, &iface->device.product);
627
628         dbus_message_iter_close_container(&array, &dict);
629
630         return reply;
631 }
632
633 static DBusMessage *get_state(DBusConnection *conn,
634                                         DBusMessage *msg, void *data)
635 {
636         struct connman_iface *iface = data;
637         DBusMessage *reply;
638         const char *state;
639
640         DBG("conn %p", conn);
641
642         reply = dbus_message_new_method_return(msg);
643         if (reply == NULL)
644                 return NULL;
645
646         state = __connman_iface_state2string(iface->state);
647
648         dbus_message_append_args(reply, DBUS_TYPE_STRING, &state,
649                                                         DBUS_TYPE_INVALID);
650
651         return reply;
652 }
653
654 static DBusMessage *get_signal(DBusConnection *conn,
655                                         DBusMessage *msg, void *data)
656 {
657         struct connman_iface *iface = data;
658         DBusMessage *reply;
659         dbus_uint16_t signal;
660
661         DBG("conn %p", conn);
662
663         reply = dbus_message_new_method_return(msg);
664         if (reply == NULL)
665                 return NULL;
666
667         if (iface->type == CONNMAN_IFACE_TYPE_80211)
668                 signal = 75;
669         else
670                 signal = 0;
671
672         dbus_message_append_args(reply, DBUS_TYPE_UINT16, &signal,
673                                                         DBUS_TYPE_INVALID);
674
675         return reply;
676 }
677
678 static DBusMessage *get_policy(DBusConnection *conn,
679                                         DBusMessage *msg, void *data)
680 {
681         struct connman_iface *iface = data;
682         DBusMessage *reply;
683         const char *policy;
684
685         DBG("conn %p", conn);
686
687         reply = dbus_message_new_method_return(msg);
688         if (reply == NULL)
689                 return NULL;
690
691         policy = __connman_iface_policy2string(iface->policy);
692
693         dbus_message_append_args(reply, DBUS_TYPE_STRING, &policy,
694                                                         DBUS_TYPE_INVALID);
695
696         return reply;
697 }
698
699 static DBusMessage *set_policy(DBusConnection *conn,
700                                         DBusMessage *msg, void *data)
701 {
702         struct connman_iface *iface = data;
703         DBusMessage *reply;
704         enum connman_iface_policy new_policy;
705         const char *policy;
706
707         DBG("conn %p", conn);
708
709         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &policy,
710                                                         DBUS_TYPE_INVALID);
711
712         new_policy = __connman_iface_string2policy(policy);
713
714         reply = dbus_message_new_method_return(msg);
715         if (reply == NULL)
716                 return NULL;
717
718         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
719
720         if (iface->policy != new_policy) {
721                 iface->policy = new_policy;
722                 __connman_iface_store(iface);
723
724                 switch_policy(iface);
725                 policy = __connman_iface_policy2string(new_policy);
726
727                 g_dbus_emit_signal(conn, iface->path, CONNMAN_IFACE_INTERFACE,
728                                 "PolicyChanged", DBUS_TYPE_STRING, &policy,
729                                                         DBUS_TYPE_INVALID);
730         }
731
732         return reply;
733 }
734
735 static void append_network(DBusMessage *reply,
736                                 struct connman_iface *iface, gboolean secrets)
737 {
738         DBusMessageIter array, dict;
739
740         dbus_message_iter_init_append(reply, &array);
741
742         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
743                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
744                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
745                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
746
747         switch (iface->type) {
748         case CONNMAN_IFACE_TYPE_80211:
749                 if (iface->network.identifier != NULL)
750                         append_entry(&dict, "ESSID",
751                                 DBUS_TYPE_STRING, &iface->network.identifier);
752                 if (secrets == TRUE && iface->network.passphrase != NULL)
753                         append_entry(&dict, "PSK",
754                                 DBUS_TYPE_STRING, &iface->network.passphrase);
755                 break;
756         default:
757                 break;
758         }
759
760         dbus_message_iter_close_container(&array, &dict);
761 }
762
763 static DBusMessage *get_network(DBusConnection *conn,
764                                         DBusMessage *msg, void *data)
765 {
766         struct connman_iface *iface = data;
767         DBusMessage *reply;
768
769         DBG("conn %p", conn);
770
771         reply = dbus_message_new_method_return(msg);
772         if (reply == NULL)
773                 return NULL;
774
775         append_network(reply, iface, TRUE);
776
777         return reply;
778 }
779
780 static DBusMessage *set_network(DBusConnection *conn,
781                                         DBusMessage *msg, void *data)
782 {
783         struct connman_iface *iface = data;
784         DBusMessage *reply, *signal;
785         DBusMessageIter array, dict;
786         gboolean changed = FALSE;
787
788         DBG("conn %p", conn);
789
790         dbus_message_iter_init(msg, &array);
791
792         dbus_message_iter_recurse(&array, &dict);
793
794         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
795                 DBusMessageIter entry, value;
796                 const char *key, *val;
797
798                 dbus_message_iter_recurse(&dict, &entry);
799                 dbus_message_iter_get_basic(&entry, &key);
800
801                 dbus_message_iter_next(&entry);
802
803                 dbus_message_iter_recurse(&entry, &value);
804
805                 //type = dbus_message_iter_get_arg_type(&value);
806                 dbus_message_iter_get_basic(&value, &val);
807
808                 if (g_strcasecmp(key, "ESSID") == 0) {
809                         g_free(iface->network.identifier);
810                         iface->network.identifier = g_strdup(val);
811                         changed = TRUE;
812                 }
813
814                 if (g_strcasecmp(key, "PSK") == 0) {
815                         g_free(iface->network.passphrase);
816                         iface->network.passphrase = g_strdup(val);
817                         changed = TRUE;
818                 }
819
820                 dbus_message_iter_next(&dict);
821         }
822
823         reply = dbus_message_new_method_return(msg);
824         if (reply == NULL)
825                 return NULL;
826
827         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
828
829         if (changed == TRUE) {
830                 __connman_iface_store(iface);
831
832                 signal = dbus_message_new_signal(iface->path,
833                                 CONNMAN_IFACE_INTERFACE, "NetworkChanged");
834                 if (signal != NULL) {
835                         append_network(signal, iface, FALSE);
836                         dbus_connection_send(conn, signal, NULL);
837                         dbus_message_unref(signal);
838                 }
839
840                 __connman_iface_connect(iface, &iface->network);
841         }
842
843         return reply;
844 }
845
846 static DBusMessage *select_network(DBusConnection *conn,
847                                         DBusMessage *msg, void *data)
848 {
849         struct connman_iface *iface = data;
850         DBusMessage *reply;
851         const char *network;
852
853         DBG("conn %p", conn);
854
855         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &network,
856                                                         DBUS_TYPE_INVALID);
857
858         g_free(iface->network.identifier);
859         iface->network.identifier = g_strdup(network);
860
861         __connman_iface_connect(iface, &iface->network);
862
863         reply = dbus_message_new_method_return(msg);
864         if (reply == NULL)
865                 return NULL;
866
867         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
868
869         return reply;
870 }
871
872 static void append_ipv4(DBusMessage *reply, struct connman_iface *iface)
873 {
874         DBusMessageIter array, dict;
875         const char *str;
876
877         dbus_message_iter_init_append(reply, &array);
878
879         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
880                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
881                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
882                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
883
884         str = __connman_ipv4_method2string(CONNMAN_IPV4_METHOD_DHCP);
885         append_entry(&dict, "Method", DBUS_TYPE_STRING, &str);
886
887         if (iface->ipv4.address.s_addr != INADDR_ANY) {
888                 str = inet_ntoa(iface->ipv4.address);
889                 append_entry(&dict, "Address", DBUS_TYPE_STRING, &str);
890         }
891
892         if (iface->ipv4.netmask.s_addr != INADDR_ANY) {
893                 str = inet_ntoa(iface->ipv4.netmask);
894                 append_entry(&dict, "Netmask", DBUS_TYPE_STRING, &str);
895         }
896
897         if (iface->ipv4.gateway.s_addr != INADDR_ANY) {
898                 str = inet_ntoa(iface->ipv4.gateway);
899                 append_entry(&dict, "Gateway", DBUS_TYPE_STRING, &str);
900         }
901
902         dbus_message_iter_close_container(&array, &dict);
903 }
904
905 static DBusMessage *get_ipv4(DBusConnection *conn,
906                                         DBusMessage *msg, void *data)
907 {
908         struct connman_iface *iface = data;
909         DBusMessage *reply;
910
911         DBG("conn %p", conn);
912
913         switch (iface->policy) {
914         case CONNMAN_IFACE_POLICY_OFF:
915         case CONNMAN_IFACE_POLICY_IGNORE:
916                 return dbus_message_new_error(msg, CONNMAN_ERROR_INTERFACE
917                                                 ".NotAvailable", "");
918         default:
919                 break;
920         }
921
922         reply = dbus_message_new_method_return(msg);
923         if (reply == NULL)
924                 return NULL;
925
926         append_ipv4(reply, iface);
927
928         return reply;
929 }
930
931 static DBusMessage *set_ipv4(DBusConnection *conn,
932                                         DBusMessage *msg, void *data)
933 {
934         struct connman_iface *iface = data;
935         DBusMessage *reply, *signal;
936         DBusMessageIter array, dict;
937         gboolean changed = FALSE;
938
939         DBG("conn %p", conn);
940
941         return dbus_message_new_error(msg, CONNMAN_ERROR_INTERFACE
942                                                 ".NotImplemented", "");
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         iface->policy = CONNMAN_IFACE_POLICY_AUTO;
1166
1167         __connman_iface_load(iface);
1168
1169         DBG("iface %p network %s secret %s", iface,
1170                                         iface->network.identifier,
1171                                         iface->network.passphrase);
1172
1173         conn = libhal_ctx_get_dbus_connection(ctx);
1174
1175         g_dbus_register_object(conn, iface->path, iface, device_free);
1176
1177         interfaces = g_slist_append(interfaces, iface);
1178
1179         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
1180                 connman_iface_get_ipv4(iface, &iface->ipv4);
1181
1182                 DBG("address %s", inet_ntoa(iface->ipv4.address));
1183         }
1184
1185         g_dbus_register_interface(conn, iface->path,
1186                                         CONNMAN_IFACE_INTERFACE,
1187                                         iface_methods, iface_signals, NULL);
1188
1189         DBG("iface %p identifier %s", iface, iface->identifier);
1190
1191         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1192                                         CONNMAN_MANAGER_INTERFACE,
1193                                         "InterfaceAdded",
1194                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1195                                         DBUS_TYPE_INVALID);
1196
1197         switch_policy(iface);
1198
1199         state_changed(iface);
1200
1201         return 0;
1202 }
1203
1204 static void device_added(LibHalContext *ctx, const char *udi)
1205 {
1206         GSList *list;
1207
1208         DBG("ctx %p udi %s", ctx, udi);
1209
1210         for (list = drivers; list; list = list->next) {
1211                 struct connman_iface_driver *driver = list->data;
1212
1213                 if (driver->capability == NULL)
1214                         continue;
1215
1216                 if (libhal_device_query_capability(ctx, udi,
1217                                         driver->capability, NULL) == TRUE) {
1218                         if (probe_device(ctx, driver, udi) == 0)
1219                                 break;
1220                 }
1221         }
1222 }
1223
1224 static void device_removed(LibHalContext *ctx, const char *udi)
1225 {
1226         DBusConnection *conn;
1227         GSList *list;
1228
1229         DBG("ctx %p udi %s", ctx, udi);
1230
1231         conn = libhal_ctx_get_dbus_connection(ctx);
1232
1233         for (list = interfaces; list; list = list->next) {
1234                 struct connman_iface *iface = list->data;
1235
1236                 if (strcmp(udi, iface->udi) == 0) {
1237                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1238                                         CONNMAN_MANAGER_INTERFACE,
1239                                         "InterfaceRemoved",
1240                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1241                                         DBUS_TYPE_INVALID);
1242                         interfaces = g_slist_remove(interfaces, iface);
1243                         g_dbus_unregister_interface(conn, iface->path,
1244                                                 CONNMAN_IFACE_INTERFACE);
1245                         g_dbus_unregister_object(conn, iface->path);
1246                         break;
1247                 }
1248         }
1249 }
1250
1251 static void probe_driver(LibHalContext *ctx,
1252                                 struct connman_iface_driver *driver)
1253 {
1254         char **list;
1255         int num;
1256
1257         DBG("ctx %p driver %p", ctx, driver);
1258
1259         list = libhal_find_device_by_capability(ctx,
1260                                         driver->capability, &num, NULL);
1261         if (list) {
1262                 char **tmp = list;
1263
1264                 while (*tmp) {
1265                         probe_device(ctx, driver, *tmp);
1266                         tmp++;
1267                 }
1268
1269                 libhal_free_string_array(list);
1270         }
1271 }
1272
1273 static void find_devices(LibHalContext *ctx)
1274 {
1275         GSList *list;
1276
1277         DBG("ctx %p", ctx);
1278
1279         for (list = drivers; list; list = list->next) {
1280                 struct connman_iface_driver *driver = list->data;
1281
1282                 DBG("driver %p", driver);
1283
1284                 if (driver->capability == NULL)
1285                         continue;
1286
1287                 probe_driver(ctx, driver);
1288         }
1289 }
1290
1291 static LibHalContext *hal_ctx = NULL;
1292
1293 static void hal_init(void *data)
1294 {
1295         DBusConnection *conn = data;
1296
1297         DBG("conn %p", conn);
1298
1299         if (hal_ctx != NULL)
1300                 return;
1301
1302         hal_ctx = libhal_ctx_new();
1303         if (hal_ctx == NULL)
1304                 return;
1305
1306         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
1307                 libhal_ctx_free(hal_ctx);
1308                 return;
1309         }
1310
1311         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
1312                 libhal_ctx_free(hal_ctx);
1313                 return ;
1314         }
1315
1316         libhal_ctx_set_device_added(hal_ctx, device_added);
1317         libhal_ctx_set_device_removed(hal_ctx, device_removed);
1318
1319         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
1320         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
1321
1322         find_devices(hal_ctx);
1323 }
1324
1325 static void hal_cleanup(void *data)
1326 {
1327         DBusConnection *conn = data;
1328         GSList *list;
1329
1330         DBG("conn %p", conn);
1331
1332         if (hal_ctx == NULL)
1333                 return;
1334
1335         for (list = interfaces; list; list = list->next) {
1336                 struct connman_iface *iface = list->data;
1337
1338                 DBG("path %s", iface->path);
1339
1340                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1341                                         CONNMAN_MANAGER_INTERFACE,
1342                                         "InterfaceRemoved",
1343                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1344                                         DBUS_TYPE_INVALID);
1345
1346                 g_dbus_unregister_interface(conn, iface->path,
1347                                                 CONNMAN_IFACE_INTERFACE);
1348
1349                 g_dbus_unregister_object(conn, iface->path);
1350         }
1351
1352         g_slist_free(interfaces);
1353
1354         interfaces = NULL;
1355
1356         libhal_ctx_shutdown(hal_ctx, NULL);
1357
1358         libhal_ctx_free(hal_ctx);
1359
1360         hal_ctx = NULL;
1361 }
1362
1363 static guint hal_watch = 0;
1364
1365 int __connman_iface_init(DBusConnection *conn, const char *interface)
1366 {
1367         DBG("conn %p", conn);
1368
1369         connection = dbus_connection_ref(conn);
1370         if (connection == NULL)
1371                 return -1;
1372
1373         if (interface != NULL)
1374                 ifname_filter = g_strdup(interface);
1375
1376         hal_init(connection);
1377
1378         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
1379                                 hal_init, hal_cleanup, connection, NULL);
1380
1381         return 0;
1382 }
1383
1384 void __connman_iface_cleanup(void)
1385 {
1386         DBG("conn %p", connection);
1387
1388         g_dbus_remove_watch(connection, hal_watch);
1389
1390         hal_cleanup(connection);
1391
1392         g_free(ifname_filter);
1393
1394         dbus_connection_unref(connection);
1395 }