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