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