a1e136df1c0aa47a91352517a7931e9ea5d75f44
[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                 __connman_iface_store_current_network(iface);
310                 break;
311         default:
312                 break;
313         }
314 }
315
316 static void append_station(DBusMessage *reply, const char *name,
317                                                 int signal, int security)
318 {
319         DBusMessageIter array, dict;
320         const char *wpa = "WPA";
321
322         dbus_message_iter_init_append(reply, &array);
323
324         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
325                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
326                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
327                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
328
329         append_entry(&dict, "ESSID", DBUS_TYPE_STRING, &name);
330         append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
331
332         if (security > 0)
333                 append_entry(&dict, "Security", DBUS_TYPE_STRING, &wpa);
334
335         dbus_message_iter_close_container(&array, &dict);
336 }
337
338 void connman_iface_indicate_station(struct connman_iface *iface,
339                                 const char *name, int strength, int security)
340 {
341         DBusMessage *signal;
342         char *ssid, *passphrase;
343         int len;
344
345         DBG("iface %p security %d name %s", iface, security, name);
346
347         if (name == NULL || strlen(name) == 0)
348                 return;
349
350         signal = dbus_message_new_signal(iface->path,
351                                 CONNMAN_IFACE_INTERFACE, "NetworkFound");
352         if (signal == NULL)
353                 return;
354
355         append_station(signal, name, strength, security);
356
357         dbus_connection_send(connection, signal, NULL);
358         dbus_message_unref(signal);
359
360         switch (iface->state) {
361         case CONNMAN_IFACE_STATE_CONNECT:
362         case CONNMAN_IFACE_STATE_CONNECTED:
363         case CONNMAN_IFACE_STATE_CARRIER:
364         case CONNMAN_IFACE_STATE_CONFIGURE:
365         case CONNMAN_IFACE_STATE_READY:
366                 return;
367         default:
368                 break;
369         }
370
371         len = strlen(name);
372         ssid = strdup(name);
373         if (ssid == NULL)
374                 return;
375
376         /* The D-Link access points return a 0x05 at the end of the SSID */
377         if (ssid[len - 1] == '\05')
378                 ssid[len - 1] = '\0';
379
380         passphrase = __connman_iface_find_passphrase(iface, ssid);
381         if (passphrase != NULL) {
382                 DBG("network %s passphrase %s", ssid, passphrase);
383
384                 g_free(iface->network.identifier);
385                 iface->network.identifier = g_strdup(ssid);
386                 g_free(iface->network.passphrase);
387                 iface->network.passphrase = passphrase;
388
389                 __connman_iface_connect(iface, &iface->network);
390
391                 iface->state = CONNMAN_IFACE_STATE_CONNECT;
392                 state_changed(iface);
393         }
394
395         free(ssid);
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         int sk, err;
433
434         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
435                 return -1;
436
437         DBG("iface %p ipv4 %p", iface, ipv4);
438
439         sk = socket(PF_INET, SOCK_DGRAM, 0);
440         if (sk < 0)
441                 return -1;
442
443         memset(&ifr, 0, sizeof(ifr));
444         ifr.ifr_ifindex = iface->index;
445
446         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
447                 close(sk);
448                 return -1;
449         }
450
451         DBG("ifname %s", ifr.ifr_name);
452
453         addr = (struct sockaddr_in *) &ifr.ifr_addr;
454         addr->sin_family = AF_INET;
455         addr->sin_addr = ipv4->address;
456
457         err = ioctl(sk, SIOCSIFADDR, &ifr);
458
459         if (err < 0)
460                 DBG("address setting failed (%s)", strerror(errno));
461
462         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
463         addr->sin_family = AF_INET;
464         addr->sin_addr = ipv4->netmask;
465
466         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
467
468         if (err < 0)
469                 DBG("netmask setting failed (%s)", strerror(errno));
470
471         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
472         addr->sin_family = AF_INET;
473         addr->sin_addr = ipv4->broadcast;
474
475         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
476
477         if (err < 0)
478                 DBG("broadcast setting failed (%s)", strerror(errno));
479
480         memset(&rt, 0, sizeof(rt));
481         rt.rt_flags = RTF_UP | RTF_GATEWAY;
482
483         addr = (struct sockaddr_in *) &rt.rt_dst;
484         addr->sin_family = AF_INET;
485         addr->sin_addr.s_addr = INADDR_ANY;
486
487         addr = (struct sockaddr_in *) &rt.rt_gateway;
488         addr->sin_family = AF_INET;
489         addr->sin_addr = ipv4->gateway;
490
491         addr = (struct sockaddr_in *) &rt.rt_genmask;
492         addr->sin_family = AF_INET;
493         addr->sin_addr.s_addr = INADDR_ANY;
494
495         err = ioctl(sk, SIOCADDRT, &rt);
496
497         close(sk);
498
499         if (err < 0) {
500                 DBG("default route failed (%s)", strerror(errno));
501                 return -1;
502         }
503
504         __connman_resolver_append(iface, inet_ntoa(ipv4->nameserver));
505
506         return 0;
507 }
508
509 int connman_iface_clear_ipv4(struct connman_iface *iface)
510 {
511         struct ifreq ifr;
512         struct sockaddr_in *addr;
513         int sk, err;
514
515         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
516                 return -1;
517
518         DBG("iface %p", iface);
519
520         sk = socket(PF_INET, SOCK_DGRAM, 0);
521         if (sk < 0)
522                 return -1;
523
524         memset(&ifr, 0, sizeof(ifr));
525         ifr.ifr_ifindex = iface->index;
526
527         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
528                 close(sk);
529                 return -1;
530         }
531
532         DBG("ifname %s", ifr.ifr_name);
533
534         addr = (struct sockaddr_in *) &ifr.ifr_addr;
535         addr->sin_family = AF_INET;
536         addr->sin_addr.s_addr = INADDR_ANY;
537
538         //err = ioctl(sk, SIOCDIFADDR, &ifr);
539         err = ioctl(sk, SIOCSIFADDR, &ifr);
540
541         close(sk);
542
543         if (err < 0 && errno != EADDRNOTAVAIL) {
544                 DBG("address removal failed (%s)", strerror(errno));
545                 return -1;
546         }
547
548         __connman_resolver_remove(iface);
549
550         return 0;
551 }
552
553 static DBusMessage *scan_iface(DBusConnection *conn,
554                                         DBusMessage *msg, void *data)
555 {
556         struct connman_iface *iface = data;
557         struct connman_iface_driver *driver = iface->driver;
558         DBusMessage *reply;
559
560         DBG("conn %p", conn);
561
562         reply = dbus_message_new_method_return(msg);
563         if (reply == NULL)
564                 return NULL;
565
566         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
567
568         switch (iface->state) {
569         case CONNMAN_IFACE_STATE_CONNECT:
570         case CONNMAN_IFACE_STATE_CONFIGURE:
571                         return reply;
572         default:
573                 break;
574         }
575
576         if (driver->scan)
577                 driver->scan(iface);
578
579         return reply;
580 }
581
582 static DBusMessage *get_properties(DBusConnection *conn,
583                                         DBusMessage *msg, void *data)
584 {
585         struct connman_iface *iface = data;
586         DBusMessage *reply;
587         DBusMessageIter array, dict;
588         const char *str;
589
590         DBG("conn %p", conn);
591
592         reply = dbus_message_new_method_return(msg);
593         if (reply == NULL)
594                 return NULL;
595
596         dbus_message_iter_init_append(reply, &array);
597
598         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
599                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
600                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
601                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
602
603         str = __connman_iface_type2string(iface->type);
604         append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
605
606         str = __connman_iface_state2string(iface->state);
607         append_entry(&dict, "State", DBUS_TYPE_STRING, &str);
608
609         if (iface->type == CONNMAN_IFACE_TYPE_80211) {
610                 dbus_uint16_t signal = 75;
611                 append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
612         }
613
614         str = __connman_iface_policy2string(iface->policy);
615         append_entry(&dict, "Policy", DBUS_TYPE_STRING, &str);
616
617         if (iface->device.driver != NULL)
618                 append_entry(&dict, "Driver",
619                                 DBUS_TYPE_STRING, &iface->device.driver);
620
621         if (iface->device.vendor != NULL)
622                 append_entry(&dict, "Vendor",
623                                 DBUS_TYPE_STRING, &iface->device.vendor);
624
625         if (iface->device.product != NULL)
626                 append_entry(&dict, "Product",
627                                 DBUS_TYPE_STRING, &iface->device.product);
628
629         dbus_message_iter_close_container(&array, &dict);
630
631         return reply;
632 }
633
634 static DBusMessage *get_state(DBusConnection *conn,
635                                         DBusMessage *msg, void *data)
636 {
637         struct connman_iface *iface = data;
638         DBusMessage *reply;
639         const char *state;
640
641         DBG("conn %p", conn);
642
643         reply = dbus_message_new_method_return(msg);
644         if (reply == NULL)
645                 return NULL;
646
647         state = __connman_iface_state2string(iface->state);
648
649         dbus_message_append_args(reply, DBUS_TYPE_STRING, &state,
650                                                         DBUS_TYPE_INVALID);
651
652         return reply;
653 }
654
655 static DBusMessage *get_signal(DBusConnection *conn,
656                                         DBusMessage *msg, void *data)
657 {
658         struct connman_iface *iface = data;
659         DBusMessage *reply;
660         dbus_uint16_t signal;
661
662         DBG("conn %p", conn);
663
664         reply = dbus_message_new_method_return(msg);
665         if (reply == NULL)
666                 return NULL;
667
668         if (iface->type == CONNMAN_IFACE_TYPE_80211)
669                 signal = 75;
670         else
671                 signal = 0;
672
673         dbus_message_append_args(reply, DBUS_TYPE_UINT16, &signal,
674                                                         DBUS_TYPE_INVALID);
675
676         return reply;
677 }
678
679 static DBusMessage *get_policy(DBusConnection *conn,
680                                         DBusMessage *msg, void *data)
681 {
682         struct connman_iface *iface = data;
683         DBusMessage *reply;
684         const char *policy;
685
686         DBG("conn %p", conn);
687
688         reply = dbus_message_new_method_return(msg);
689         if (reply == NULL)
690                 return NULL;
691
692         policy = __connman_iface_policy2string(iface->policy);
693
694         dbus_message_append_args(reply, DBUS_TYPE_STRING, &policy,
695                                                         DBUS_TYPE_INVALID);
696
697         return reply;
698 }
699
700 static DBusMessage *set_policy(DBusConnection *conn,
701                                         DBusMessage *msg, void *data)
702 {
703         struct connman_iface *iface = data;
704         DBusMessage *reply;
705         enum connman_iface_policy new_policy;
706         const char *policy;
707
708         DBG("conn %p", conn);
709
710         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &policy,
711                                                         DBUS_TYPE_INVALID);
712
713         new_policy = __connman_iface_string2policy(policy);
714
715         reply = dbus_message_new_method_return(msg);
716         if (reply == NULL)
717                 return NULL;
718
719         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
720
721         if (iface->policy != new_policy) {
722                 iface->policy = new_policy;
723                 __connman_iface_store(iface);
724
725                 switch_policy(iface);
726                 policy = __connman_iface_policy2string(new_policy);
727
728                 g_dbus_emit_signal(conn, iface->path, CONNMAN_IFACE_INTERFACE,
729                                 "PolicyChanged", DBUS_TYPE_STRING, &policy,
730                                                         DBUS_TYPE_INVALID);
731         }
732
733         return reply;
734 }
735
736 static void append_network(DBusMessage *reply,
737                                 struct connman_iface *iface, gboolean secrets)
738 {
739         DBusMessageIter array, dict;
740
741         dbus_message_iter_init_append(reply, &array);
742
743         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
744                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
745                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
746                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
747
748         switch (iface->type) {
749         case CONNMAN_IFACE_TYPE_80211:
750                 if (iface->network.identifier != NULL)
751                         append_entry(&dict, "ESSID",
752                                 DBUS_TYPE_STRING, &iface->network.identifier);
753                 if (secrets == TRUE && iface->network.passphrase != NULL)
754                         append_entry(&dict, "PSK",
755                                 DBUS_TYPE_STRING, &iface->network.passphrase);
756                 break;
757         default:
758                 break;
759         }
760
761         dbus_message_iter_close_container(&array, &dict);
762 }
763
764 static DBusMessage *get_network(DBusConnection *conn,
765                                         DBusMessage *msg, void *data)
766 {
767         struct connman_iface *iface = data;
768         DBusMessage *reply;
769
770         DBG("conn %p", conn);
771
772         reply = dbus_message_new_method_return(msg);
773         if (reply == NULL)
774                 return NULL;
775
776         append_network(reply, iface, TRUE);
777
778         return reply;
779 }
780
781 static DBusMessage *set_network(DBusConnection *conn,
782                                         DBusMessage *msg, void *data)
783 {
784         struct connman_iface *iface = data;
785         DBusMessage *reply, *signal;
786         DBusMessageIter array, dict;
787         gboolean changed = FALSE;
788
789         DBG("conn %p", conn);
790
791         dbus_message_iter_init(msg, &array);
792
793         dbus_message_iter_recurse(&array, &dict);
794
795         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
796                 DBusMessageIter entry, value;
797                 const char *key, *val;
798
799                 dbus_message_iter_recurse(&dict, &entry);
800                 dbus_message_iter_get_basic(&entry, &key);
801
802                 dbus_message_iter_next(&entry);
803
804                 dbus_message_iter_recurse(&entry, &value);
805
806                 //type = dbus_message_iter_get_arg_type(&value);
807                 dbus_message_iter_get_basic(&value, &val);
808
809                 if (g_strcasecmp(key, "ESSID") == 0) {
810                         g_free(iface->network.identifier);
811                         iface->network.identifier = g_strdup(val);
812                         changed = TRUE;
813                 }
814
815                 if (g_strcasecmp(key, "PSK") == 0) {
816                         g_free(iface->network.passphrase);
817                         iface->network.passphrase = g_strdup(val);
818                         changed = TRUE;
819                 }
820
821                 dbus_message_iter_next(&dict);
822         }
823
824         reply = dbus_message_new_method_return(msg);
825         if (reply == NULL)
826                 return NULL;
827
828         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
829
830         if (changed == TRUE) {
831                 __connman_iface_store(iface);
832
833                 signal = dbus_message_new_signal(iface->path,
834                                 CONNMAN_IFACE_INTERFACE, "NetworkChanged");
835                 if (signal != NULL) {
836                         append_network(signal, iface, FALSE);
837                         dbus_connection_send(conn, signal, NULL);
838                         dbus_message_unref(signal);
839                 }
840
841                 __connman_iface_connect(iface, &iface->network);
842         }
843
844         return reply;
845 }
846
847 static DBusMessage *select_network(DBusConnection *conn,
848                                         DBusMessage *msg, void *data)
849 {
850         struct connman_iface *iface = data;
851         DBusMessage *reply;
852         const char *network;
853
854         DBG("conn %p", conn);
855
856         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &network,
857                                                         DBUS_TYPE_INVALID);
858
859         g_free(iface->network.identifier);
860         iface->network.identifier = g_strdup(network);
861
862         __connman_iface_connect(iface, &iface->network);
863
864         reply = dbus_message_new_method_return(msg);
865         if (reply == NULL)
866                 return NULL;
867
868         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
869
870         return reply;
871 }
872
873 static void append_ipv4(DBusMessage *reply, struct connman_iface *iface)
874 {
875         DBusMessageIter array, dict;
876         const char *str;
877
878         dbus_message_iter_init_append(reply, &array);
879
880         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
881                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
882                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
883                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
884
885         str = __connman_ipv4_method2string(CONNMAN_IPV4_METHOD_DHCP);
886         append_entry(&dict, "Method", DBUS_TYPE_STRING, &str);
887
888         if (iface->ipv4.address.s_addr != INADDR_ANY) {
889                 str = inet_ntoa(iface->ipv4.address);
890                 append_entry(&dict, "Address", DBUS_TYPE_STRING, &str);
891         }
892
893         if (iface->ipv4.netmask.s_addr != INADDR_ANY) {
894                 str = inet_ntoa(iface->ipv4.netmask);
895                 append_entry(&dict, "Netmask", DBUS_TYPE_STRING, &str);
896         }
897
898         if (iface->ipv4.gateway.s_addr != INADDR_ANY) {
899                 str = inet_ntoa(iface->ipv4.gateway);
900                 append_entry(&dict, "Gateway", DBUS_TYPE_STRING, &str);
901         }
902
903         dbus_message_iter_close_container(&array, &dict);
904 }
905
906 static DBusMessage *get_ipv4(DBusConnection *conn,
907                                         DBusMessage *msg, void *data)
908 {
909         struct connman_iface *iface = data;
910         DBusMessage *reply;
911
912         DBG("conn %p", conn);
913
914         switch (iface->policy) {
915         case CONNMAN_IFACE_POLICY_OFF:
916         case CONNMAN_IFACE_POLICY_IGNORE:
917                 return dbus_message_new_error(msg, CONNMAN_ERROR_INTERFACE
918                                                 ".NotAvailable", "");
919         default:
920                 break;
921         }
922
923         reply = dbus_message_new_method_return(msg);
924         if (reply == NULL)
925                 return NULL;
926
927         append_ipv4(reply, iface);
928
929         return reply;
930 }
931
932 static DBusMessage *set_ipv4(DBusConnection *conn,
933                                         DBusMessage *msg, void *data)
934 {
935         struct connman_iface *iface = data;
936         DBusMessage *reply, *signal;
937         DBusMessageIter array, dict;
938         gboolean changed = FALSE;
939
940         DBG("conn %p", conn);
941
942         return dbus_message_new_error(msg, CONNMAN_ERROR_INTERFACE
943                                                 ".NotImplemented", "");
944
945         dbus_message_iter_init(msg, &array);
946
947         dbus_message_iter_recurse(&array, &dict);
948
949         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
950                 DBusMessageIter entry, value;
951                 const char *key, *val;
952                 enum connman_ipv4_method method;
953                 in_addr_t addr;
954
955                 dbus_message_iter_recurse(&dict, &entry);
956                 dbus_message_iter_get_basic(&entry, &key);
957
958                 dbus_message_iter_next(&entry);
959
960                 dbus_message_iter_recurse(&entry, &value);
961
962                 //type = dbus_message_iter_get_arg_type(&value);
963                 dbus_message_iter_get_basic(&value, &val);
964
965                 if (g_strcasecmp(key, "Method") == 0) {
966                         method = __connman_ipv4_string2method(val);
967                         if (iface->ipv4.method != method) {
968                                 iface->ipv4.method = method;
969                                 changed = TRUE;
970                         }
971                 }
972
973                 if (g_strcasecmp(key, "Address") == 0) {
974                         addr = inet_addr(val);
975                         if (iface->ipv4.address.s_addr != addr) {
976                                 iface->ipv4.address.s_addr = addr;
977                                 changed = TRUE;
978                         }
979                 }
980
981                 if (g_strcasecmp(key, "Netmask") == 0) {
982                         addr = inet_addr(val);
983                         if (iface->ipv4.netmask.s_addr != addr) {
984                                 iface->ipv4.netmask.s_addr = addr;
985                                 changed = TRUE;
986                         }
987                 }
988
989                 if (g_strcasecmp(key, "Gateway") == 0) {
990                         addr = inet_addr(val);
991                         if (iface->ipv4.gateway.s_addr != addr) {
992                                 iface->ipv4.gateway.s_addr = addr;
993                                 changed = TRUE;
994                         }
995                 }
996
997                 dbus_message_iter_next(&dict);
998         }
999
1000         reply = dbus_message_new_method_return(msg);
1001         if (reply == NULL)
1002                 return NULL;
1003
1004         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
1005
1006         if (changed == TRUE) {
1007                 __connman_iface_store(iface);
1008
1009                 signal = dbus_message_new_signal(iface->path,
1010                                 CONNMAN_IFACE_INTERFACE, "IPv4Changed");
1011                 if (signal != NULL) {
1012                         append_ipv4(signal, iface);
1013                         dbus_connection_send(conn, signal, NULL);
1014                         dbus_message_unref(signal);
1015                 }
1016         }
1017
1018         return reply;
1019 }
1020
1021 static GDBusMethodTable iface_methods[] = {
1022         { "Scan",          "",      "",      scan_iface     },
1023         { "GetProperties", "",      "a{sv}", get_properties },
1024         { "GetState",      "",      "s",     get_state      },
1025         { "GetSignal",     "",      "q",     get_signal     },
1026         { "GetPolicy",     "",      "s",     get_policy     },
1027         { "SetPolicy",     "s",     "",      set_policy     },
1028         { "GetNetwork",    "",      "a{sv}", get_network    },
1029         { "SetNetwork",    "a{sv}", "",      set_network    },
1030         { "SelectNetwork", "s",     "",      select_network },
1031         { "GetIPv4",       "",      "a{sv}", get_ipv4       },
1032         { "SetIPv4",       "a{sv}", "",      set_ipv4       },
1033         { },
1034 };
1035
1036 static GDBusSignalTable iface_signals[] = {
1037         { "StateChanged",   "s"     },
1038         { "SignalChanged",  "q"     },
1039         { "PolicyChanged",  "s"     },
1040         { "NetworkFound",   "a{sv}" },
1041         { "NetworkChanged", "a{sv}" },
1042         { "IPv4Changed",    "a{sv}" },
1043         { },
1044 };
1045
1046 static void device_free(void *data)
1047 {
1048         struct connman_iface *iface = data;
1049
1050         DBG("iface %p", iface);
1051
1052         connman_iface_clear_ipv4(iface);
1053
1054         if (iface->driver && iface->driver->remove)
1055                 iface->driver->remove(iface);
1056
1057         g_free(iface->path);
1058         g_free(iface->udi);
1059         g_free(iface->sysfs);
1060         g_free(iface->identifier);
1061         g_free(iface->network.identifier);
1062         g_free(iface->network.passphrase);
1063         g_free(iface->device.driver);
1064         g_free(iface->device.vendor);
1065         g_free(iface->device.product);
1066         g_free(iface);
1067 }
1068
1069 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
1070 {
1071         char *parent, *subsys, *value;
1072
1073         parent = libhal_device_get_property_string(ctx, iface->udi,
1074                                                 "info.parent", NULL);
1075
1076         subsys = libhal_device_get_property_string(ctx, iface->udi,
1077                                                 "linux.subsystem", NULL);
1078
1079         value = libhal_device_get_property_string(ctx, iface->udi,
1080                                                 "info.linux.driver", NULL);
1081         if (value == NULL) {
1082                 value = libhal_device_get_property_string(ctx, parent,
1083                                                 "info.linux.driver", NULL);
1084                 if (value != NULL)
1085                         iface->device.driver = g_strdup(value);
1086         }
1087
1088         if (strcmp(subsys, "net") == 0) {
1089                 value = libhal_device_get_property_string(ctx, parent,
1090                                                         "info.vendor", NULL);
1091                 if (value != NULL)
1092                         iface->device.vendor = g_strdup(value);
1093
1094                 value = libhal_device_get_property_string(ctx, parent,
1095                                                         "info.product", NULL);
1096                 if (value != NULL)
1097                         iface->device.product = g_strdup(value);
1098         }
1099 }
1100
1101 static int probe_device(LibHalContext *ctx,
1102                         struct connman_iface_driver *driver, const char *udi)
1103 {
1104         DBusConnection *conn;
1105         struct connman_iface *iface;
1106         char *temp, *sysfs, *ifname;
1107         int err;
1108
1109         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
1110
1111         if (!driver->probe)
1112                 return -1;
1113
1114         iface = g_try_new0(struct connman_iface, 1);
1115         if (iface == NULL)
1116                 return -1;
1117
1118         temp = g_path_get_basename(udi);
1119         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
1120         g_free(temp);
1121
1122         iface->udi = g_strdup(udi);
1123
1124         DBG("iface %p path %s", iface, iface->path);
1125
1126         sysfs = libhal_device_get_property_string(ctx, udi,
1127                                                 "linux.sysfs_path", NULL);
1128         if (sysfs != NULL)
1129                 iface->sysfs = g_strdup(sysfs);
1130
1131         detect_device_info(ctx, iface);
1132
1133         iface->index = -1;
1134
1135         if (g_str_has_prefix(driver->capability, "net") == TRUE) {
1136                 iface->index = libhal_device_get_property_int(ctx, udi,
1137                                                 "net.linux.ifindex", NULL);
1138
1139                 ifname = libhal_device_get_property_string(ctx, udi,
1140                                                 "net.interface", NULL);
1141                 if (ifname != NULL && ifname_filter != NULL &&
1142                                                 *ifname_filter != '\0' &&
1143                                 g_str_equal(ifname, ifname_filter) == FALSE) {
1144                         device_free(iface);
1145                         return -1;
1146                 }
1147         }
1148
1149         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
1150         iface->flags = 0;
1151         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
1152         iface->policy = CONNMAN_IFACE_POLICY_UNKNOWN;
1153
1154         err = driver->probe(iface);
1155         if (err < 0) {
1156                 device_free(iface);
1157                 return -1;
1158         }
1159
1160         __connman_iface_create_identifier(iface);
1161
1162         __connman_iface_init_via_inet(iface);
1163
1164         iface->driver = driver;
1165
1166         iface->policy = CONNMAN_IFACE_POLICY_AUTO;
1167
1168         __connman_iface_load(iface);
1169
1170         DBG("iface %p network %s secret %s", iface,
1171                                         iface->network.identifier,
1172                                         iface->network.passphrase);
1173
1174         conn = libhal_ctx_get_dbus_connection(ctx);
1175
1176         g_dbus_register_object(conn, iface->path, iface, device_free);
1177
1178         interfaces = g_slist_append(interfaces, iface);
1179
1180         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
1181                 connman_iface_get_ipv4(iface, &iface->ipv4);
1182
1183                 DBG("address %s", inet_ntoa(iface->ipv4.address));
1184         }
1185
1186         g_dbus_register_interface(conn, iface->path,
1187                                         CONNMAN_IFACE_INTERFACE,
1188                                         iface_methods, iface_signals, NULL);
1189
1190         DBG("iface %p identifier %s", iface, iface->identifier);
1191
1192         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1193                                         CONNMAN_MANAGER_INTERFACE,
1194                                         "InterfaceAdded",
1195                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1196                                         DBUS_TYPE_INVALID);
1197
1198         switch_policy(iface);
1199
1200         state_changed(iface);
1201
1202         return 0;
1203 }
1204
1205 static void device_added(LibHalContext *ctx, const char *udi)
1206 {
1207         GSList *list;
1208
1209         DBG("ctx %p udi %s", ctx, udi);
1210
1211         for (list = drivers; list; list = list->next) {
1212                 struct connman_iface_driver *driver = list->data;
1213
1214                 if (driver->capability == NULL)
1215                         continue;
1216
1217                 if (libhal_device_query_capability(ctx, udi,
1218                                         driver->capability, NULL) == TRUE) {
1219                         if (probe_device(ctx, driver, udi) == 0)
1220                                 break;
1221                 }
1222         }
1223 }
1224
1225 static void device_removed(LibHalContext *ctx, const char *udi)
1226 {
1227         DBusConnection *conn;
1228         GSList *list;
1229
1230         DBG("ctx %p udi %s", ctx, udi);
1231
1232         conn = libhal_ctx_get_dbus_connection(ctx);
1233
1234         for (list = interfaces; list; list = list->next) {
1235                 struct connman_iface *iface = list->data;
1236
1237                 if (strcmp(udi, iface->udi) == 0) {
1238                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1239                                         CONNMAN_MANAGER_INTERFACE,
1240                                         "InterfaceRemoved",
1241                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1242                                         DBUS_TYPE_INVALID);
1243                         interfaces = g_slist_remove(interfaces, iface);
1244                         g_dbus_unregister_interface(conn, iface->path,
1245                                                 CONNMAN_IFACE_INTERFACE);
1246                         g_dbus_unregister_object(conn, iface->path);
1247                         break;
1248                 }
1249         }
1250 }
1251
1252 static void probe_driver(LibHalContext *ctx,
1253                                 struct connman_iface_driver *driver)
1254 {
1255         char **list;
1256         int num;
1257
1258         DBG("ctx %p driver %p", ctx, driver);
1259
1260         list = libhal_find_device_by_capability(ctx,
1261                                         driver->capability, &num, NULL);
1262         if (list) {
1263                 char **tmp = list;
1264
1265                 while (*tmp) {
1266                         probe_device(ctx, driver, *tmp);
1267                         tmp++;
1268                 }
1269
1270                 libhal_free_string_array(list);
1271         }
1272 }
1273
1274 static void find_devices(LibHalContext *ctx)
1275 {
1276         GSList *list;
1277
1278         DBG("ctx %p", ctx);
1279
1280         for (list = drivers; list; list = list->next) {
1281                 struct connman_iface_driver *driver = list->data;
1282
1283                 DBG("driver %p", driver);
1284
1285                 if (driver->capability == NULL)
1286                         continue;
1287
1288                 probe_driver(ctx, driver);
1289         }
1290 }
1291
1292 static LibHalContext *hal_ctx = NULL;
1293
1294 static void hal_init(void *data)
1295 {
1296         DBusConnection *conn = data;
1297
1298         DBG("conn %p", conn);
1299
1300         if (hal_ctx != NULL)
1301                 return;
1302
1303         hal_ctx = libhal_ctx_new();
1304         if (hal_ctx == NULL)
1305                 return;
1306
1307         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
1308                 libhal_ctx_free(hal_ctx);
1309                 return;
1310         }
1311
1312         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
1313                 libhal_ctx_free(hal_ctx);
1314                 return ;
1315         }
1316
1317         libhal_ctx_set_device_added(hal_ctx, device_added);
1318         libhal_ctx_set_device_removed(hal_ctx, device_removed);
1319
1320         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
1321         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
1322
1323         find_devices(hal_ctx);
1324 }
1325
1326 static void hal_cleanup(void *data)
1327 {
1328         DBusConnection *conn = data;
1329         GSList *list;
1330
1331         DBG("conn %p", conn);
1332
1333         if (hal_ctx == NULL)
1334                 return;
1335
1336         for (list = interfaces; list; list = list->next) {
1337                 struct connman_iface *iface = list->data;
1338
1339                 DBG("path %s", iface->path);
1340
1341                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1342                                         CONNMAN_MANAGER_INTERFACE,
1343                                         "InterfaceRemoved",
1344                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1345                                         DBUS_TYPE_INVALID);
1346
1347                 g_dbus_unregister_interface(conn, iface->path,
1348                                                 CONNMAN_IFACE_INTERFACE);
1349
1350                 g_dbus_unregister_object(conn, iface->path);
1351         }
1352
1353         g_slist_free(interfaces);
1354
1355         interfaces = NULL;
1356
1357         libhal_ctx_shutdown(hal_ctx, NULL);
1358
1359         libhal_ctx_free(hal_ctx);
1360
1361         hal_ctx = NULL;
1362 }
1363
1364 static guint hal_watch = 0;
1365
1366 int __connman_iface_init(DBusConnection *conn, const char *interface)
1367 {
1368         DBG("conn %p", conn);
1369
1370         connection = dbus_connection_ref(conn);
1371         if (connection == NULL)
1372                 return -1;
1373
1374         if (interface != NULL)
1375                 ifname_filter = g_strdup(interface);
1376
1377         hal_init(connection);
1378
1379         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
1380                                 hal_init, hal_cleanup, connection, NULL);
1381
1382         return 0;
1383 }
1384
1385 void __connman_iface_cleanup(void)
1386 {
1387         DBG("conn %p", connection);
1388
1389         g_dbus_remove_watch(connection, hal_watch);
1390
1391         hal_cleanup(connection);
1392
1393         g_free(ifname_filter);
1394
1395         dbus_connection_unref(connection);
1396 }