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