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