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