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