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