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