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