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