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