Add generic handling for hardware addresses and setup
[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 int connman_iface_update(struct connman_iface *iface,
99                                         enum connman_iface_state state)
100 {
101         const char *str = NULL;
102
103         switch (state) {
104         case CONNMAN_IFACE_STATE_ENABLED:
105                 str = "enabled";
106                 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
107                         if (iface->driver->connect)
108                                 iface->driver->connect(iface, NULL);
109                 }
110                 break;
111
112         case CONNMAN_IFACE_STATE_CARRIER:
113                 str = "carrier";
114                 __connman_dhcp_request(iface);
115                 break;
116
117         case CONNMAN_IFACE_STATE_READY:
118                 str = "ready";
119                 break;
120
121         case CONNMAN_IFACE_STATE_SHUTDOWN:
122                 break;
123
124         default:
125                 break;
126         }
127
128         iface->state = state;
129
130         if (str != NULL) {
131                 g_dbus_emit_signal(connection, iface->path,
132                                 CONNMAN_IFACE_INTERFACE, "StateChanged",
133                                 DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
134         }
135
136         return 0;
137 }
138
139 void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier)
140 {
141         DBG("iface %p carrier %d", iface, carrier);
142 }
143
144 int connman_iface_get_ipv4(struct connman_iface *iface,
145                                                 struct connman_ipv4 *ipv4)
146 {
147         struct {
148                 struct nlmsghdr hdr;
149                 struct rtgenmsg msg;
150         } req;
151
152         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
153                 return -1;
154
155         DBG("iface %p ipv4 %p", iface, ipv4);
156
157         memset(&req, 0, sizeof(req));
158         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
159         req.hdr.nlmsg_type = RTM_GETADDR;
160         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
161         req.hdr.nlmsg_pid = 0;
162         req.hdr.nlmsg_seq = 4711;
163         req.msg.rtgen_family = AF_INET;
164
165         __connman_rtnl_send(&req, sizeof(req));
166
167         return 0;
168 }
169
170 int connman_iface_set_ipv4(struct connman_iface *iface,
171                                                 struct connman_ipv4 *ipv4)
172 {
173         struct ifreq ifr;
174         struct rtentry rt;
175         struct sockaddr_in *addr;
176         char cmd[128];
177         int sk, err;
178
179         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
180                 return -1;
181
182         DBG("iface %p ipv4 %p", iface, ipv4);
183
184         sk = socket(PF_INET, SOCK_DGRAM, 0);
185         if (sk < 0)
186                 return -1;
187
188         memset(&ifr, 0, sizeof(ifr));
189         ifr.ifr_ifindex = iface->index;
190
191         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
192                 close(sk);
193                 return -1;
194         }
195
196         DBG("ifname %s", ifr.ifr_name);
197
198         addr = (struct sockaddr_in *) &ifr.ifr_addr;
199         addr->sin_family = AF_INET;
200         addr->sin_addr = ipv4->address;
201
202         err = ioctl(sk, SIOCSIFADDR, &ifr);
203
204         if (err < 0)
205                 DBG("address setting failed (%s)", strerror(errno));
206
207         addr = (struct sockaddr_in *) &ifr.ifr_netmask;
208         addr->sin_family = AF_INET;
209         addr->sin_addr = ipv4->netmask;
210
211         err = ioctl(sk, SIOCSIFNETMASK, &ifr);
212
213         if (err < 0)
214                 DBG("netmask setting failed (%s)", strerror(errno));
215
216         addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
217         addr->sin_family = AF_INET;
218         addr->sin_addr = ipv4->broadcast;
219
220         err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
221
222         if (err < 0)
223                 DBG("broadcast setting failed (%s)", strerror(errno));
224
225         memset(&rt, 0, sizeof(rt));
226         rt.rt_flags = RTF_UP | RTF_GATEWAY;
227
228         addr = (struct sockaddr_in *) &rt.rt_dst;
229         addr->sin_family = AF_INET;
230         addr->sin_addr.s_addr = INADDR_ANY;
231
232         addr = (struct sockaddr_in *) &rt.rt_gateway;
233         addr->sin_family = AF_INET;
234         addr->sin_addr = ipv4->gateway;
235
236         addr = (struct sockaddr_in *) &rt.rt_genmask;
237         addr->sin_family = AF_INET;
238         addr->sin_addr.s_addr = INADDR_ANY;
239
240         err = ioctl(sk, SIOCADDRT, &rt);
241
242         close(sk);
243
244         if (err < 0) {
245                 DBG("default route failed (%s)", strerror(errno));
246                 return -1;
247         }
248
249         sprintf(cmd, "echo \"nameserver %s\" | resolvconf -a %s",
250                                 inet_ntoa(ipv4->nameserver), ifr.ifr_name);
251
252         DBG("%s", cmd);
253
254         system(cmd);
255
256         return 0;
257 }
258
259 int connman_iface_clear_ipv4(struct connman_iface *iface)
260 {
261         struct ifreq ifr;
262         struct sockaddr_in *addr;
263         char cmd[128];
264         int sk, err;
265
266         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
267                 return -1;
268
269         DBG("iface %p", iface);
270
271         sk = socket(PF_INET, SOCK_DGRAM, 0);
272         if (sk < 0)
273                 return -1;
274
275         memset(&ifr, 0, sizeof(ifr));
276         ifr.ifr_ifindex = iface->index;
277
278         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
279                 close(sk);
280                 return -1;
281         }
282
283         DBG("ifname %s", ifr.ifr_name);
284
285         addr = (struct sockaddr_in *) &ifr.ifr_addr;
286         addr->sin_family = AF_INET;
287         addr->sin_addr.s_addr = INADDR_ANY;
288
289         //err = ioctl(sk, SIOCDIFADDR, &ifr);
290         err = ioctl(sk, SIOCSIFADDR, &ifr);
291
292         close(sk);
293
294         if (err < 0 && errno != EADDRNOTAVAIL) {
295                 DBG("address removal failed (%s)", strerror(errno));
296                 return -1;
297         }
298
299         sprintf(cmd, "resolvconf -d %s", ifr.ifr_name);
300
301         DBG("%s", cmd);
302
303         system(cmd);
304
305         return 0;
306 }
307
308 static DBusMessage *scan_iface(DBusConnection *conn,
309                                         DBusMessage *msg, void *data)
310 {
311         struct connman_iface *iface = data;
312         struct connman_iface_driver *driver = iface->driver;
313         DBusMessage *reply;
314
315         DBG("conn %p", conn);
316
317         reply = dbus_message_new_method_return(msg);
318         if (reply == NULL)
319                 return NULL;
320
321         if (driver->scan)
322                 driver->scan(iface);
323
324         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
325
326         return reply;
327 }
328
329 static void append_entry(DBusMessageIter *dict,
330                                 const char *key, int type, void *val)
331 {
332         DBusMessageIter entry, value;
333         const char *signature;
334
335         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
336                                                                 NULL, &entry);
337
338         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
339
340         switch (type) {
341         case DBUS_TYPE_STRING:
342                 signature = DBUS_TYPE_STRING_AS_STRING;
343                 break;
344         case DBUS_TYPE_UINT16:
345                 signature = DBUS_TYPE_UINT16_AS_STRING;
346                 break;
347         default:
348                 signature = DBUS_TYPE_VARIANT_AS_STRING;
349                 break;
350         }
351
352         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
353                                                         signature, &value);
354         dbus_message_iter_append_basic(&value, type, val);
355         dbus_message_iter_close_container(&entry, &value);
356
357         dbus_message_iter_close_container(dict, &entry);
358 }
359
360 static DBusMessage *get_properties(DBusConnection *conn,
361                                         DBusMessage *msg, void *data)
362 {
363         struct connman_iface *iface = data;
364         DBusMessage *reply;
365         DBusMessageIter array, dict;
366         const char *str;
367
368         DBG("conn %p", conn);
369
370         reply = dbus_message_new_method_return(msg);
371         if (reply == NULL)
372                 return NULL;
373
374         dbus_message_iter_init_append(reply, &array);
375
376         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
377                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
378                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
379                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
380
381         str = __connman_iface_type2string(iface->type);
382         append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
383
384         str = __connman_iface_state2string(iface->state);
385         append_entry(&dict, "State", DBUS_TYPE_STRING, &str);
386
387         if (iface->type == CONNMAN_IFACE_TYPE_80211) {
388                 dbus_uint16_t signal = 75;
389                 append_entry(&dict, "Signal", DBUS_TYPE_UINT16, &signal);
390         }
391
392         str = __connman_iface_policy2string(iface->policy);
393         append_entry(&dict, "Policy", DBUS_TYPE_STRING, &str);
394
395         if (iface->device.driver != NULL)
396                 append_entry(&dict, "Driver",
397                                 DBUS_TYPE_STRING, &iface->device.driver);
398
399         if (iface->device.vendor != NULL)
400                 append_entry(&dict, "Vendor",
401                                 DBUS_TYPE_STRING, &iface->device.vendor);
402
403         if (iface->device.product != NULL)
404                 append_entry(&dict, "Product",
405                                 DBUS_TYPE_STRING, &iface->device.product);
406
407         dbus_message_iter_close_container(&array, &dict);
408
409         return reply;
410 }
411
412 static DBusMessage *get_state(DBusConnection *conn,
413                                         DBusMessage *msg, void *data)
414 {
415         struct connman_iface *iface = data;
416         DBusMessage *reply;
417         const char *state;
418
419         DBG("conn %p", conn);
420
421         reply = dbus_message_new_method_return(msg);
422         if (reply == NULL)
423                 return NULL;
424
425         state = __connman_iface_state2string(iface->state);
426
427         dbus_message_append_args(reply, DBUS_TYPE_STRING, &state,
428                                                         DBUS_TYPE_INVALID);
429
430         return reply;
431 }
432
433 static DBusMessage *get_signal(DBusConnection *conn,
434                                         DBusMessage *msg, void *data)
435 {
436         struct connman_iface *iface = data;
437         DBusMessage *reply;
438         dbus_uint16_t signal;
439
440         DBG("conn %p", conn);
441
442         reply = dbus_message_new_method_return(msg);
443         if (reply == NULL)
444                 return NULL;
445
446         if (iface->type == CONNMAN_IFACE_TYPE_80211)
447                 signal = 75;
448         else
449                 signal = 0;
450
451         dbus_message_append_args(reply, DBUS_TYPE_UINT16, &signal,
452                                                         DBUS_TYPE_INVALID);
453
454         return reply;
455 }
456
457 static DBusMessage *get_policy(DBusConnection *conn,
458                                         DBusMessage *msg, void *data)
459 {
460         struct connman_iface *iface = data;
461         DBusMessage *reply;
462         const char *policy;
463
464         DBG("conn %p", conn);
465
466         reply = dbus_message_new_method_return(msg);
467         if (reply == NULL)
468                 return NULL;
469
470         policy = __connman_iface_policy2string(iface->policy);
471
472         dbus_message_append_args(reply, DBUS_TYPE_STRING, &policy,
473                                                         DBUS_TYPE_INVALID);
474
475         return reply;
476 }
477
478 static DBusMessage *set_policy(DBusConnection *conn,
479                                         DBusMessage *msg, void *data)
480 {
481         struct connman_iface *iface = data;
482         DBusMessage *reply;
483         enum connman_iface_policy new_policy;
484         const char *path, *policy;
485
486         DBG("conn %p", conn);
487
488         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &policy,
489                                                         DBUS_TYPE_INVALID);
490
491         new_policy = __connman_iface_string2policy(policy);
492
493         reply = dbus_message_new_method_return(msg);
494         if (reply == NULL)
495                 return NULL;
496
497         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
498
499         if (iface->policy != new_policy) {
500                 path = dbus_message_get_path(msg);
501
502                 iface->policy = new_policy;
503
504                 if (new_policy == CONNMAN_IFACE_POLICY_AUTO) {
505                         if (iface->driver->activate)
506                                 iface->driver->activate(iface);
507                 } else {
508                         if (iface->driver->shutdown)
509                                 iface->driver->shutdown(iface);
510                 }
511
512                 g_dbus_emit_signal(conn, path, CONNMAN_IFACE_INTERFACE,
513                                 "PolicyChanged", DBUS_TYPE_STRING, &policy,
514                                                         DBUS_TYPE_INVALID);
515         }
516
517         return reply;
518 }
519
520 static void append_ipv4(DBusMessage *reply, struct connman_iface *iface)
521 {
522         DBusMessageIter array, dict;
523         const char *str;
524
525         dbus_message_iter_init_append(reply, &array);
526
527         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
528                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
529                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
530                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
531
532         str = __connman_ipv4_method2string(iface->ipv4.method);
533         append_entry(&dict, "Method", DBUS_TYPE_STRING, &str);
534
535         if (iface->ipv4.address.s_addr != INADDR_ANY) {
536                 str = inet_ntoa(iface->ipv4.address);
537                 append_entry(&dict, "Address", DBUS_TYPE_STRING, &str);
538         }
539
540         if (iface->ipv4.netmask.s_addr != INADDR_ANY) {
541                 str = inet_ntoa(iface->ipv4.netmask);
542                 append_entry(&dict, "Netmask", DBUS_TYPE_STRING, &str);
543         }
544
545         if (iface->ipv4.gateway.s_addr != INADDR_ANY) {
546                 str = inet_ntoa(iface->ipv4.gateway);
547                 append_entry(&dict, "Gateway", DBUS_TYPE_STRING, &str);
548         }
549
550         dbus_message_iter_close_container(&array, &dict);
551 }
552
553 static DBusMessage *get_ipv4(DBusConnection *conn,
554                                         DBusMessage *msg, void *data)
555 {
556         struct connman_iface *iface = data;
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         append_ipv4(reply, iface);
566
567         return reply;
568 }
569
570 static DBusMessage *set_ipv4(DBusConnection *conn,
571                                         DBusMessage *msg, void *data)
572 {
573         struct connman_iface *iface = data;
574         DBusMessage *reply, *signal;
575         DBusMessageIter array, dict;
576         const char *path;
577         gboolean changed = FALSE;
578
579         DBG("conn %p", conn);
580
581         dbus_message_iter_init(msg, &array);
582
583         dbus_message_iter_recurse(&array, &dict);
584
585         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
586                 DBusMessageIter entry, value;
587                 const char *key, *val;
588                 enum connman_ipv4_method method;
589                 in_addr_t addr;
590
591                 dbus_message_iter_recurse(&dict, &entry);
592                 dbus_message_iter_get_basic(&entry, &key);
593
594                 dbus_message_iter_next(&entry);
595
596                 dbus_message_iter_recurse(&entry, &value);
597
598                 //type = dbus_message_iter_get_arg_type(&value);
599                 dbus_message_iter_get_basic(&value, &val);
600
601                 if (g_strcasecmp(key, "Method") == 0) {
602                         method = __connman_ipv4_string2method(val);
603                         if (iface->ipv4.method != method) {
604                                 iface->ipv4.method = method;
605                                 changed = TRUE;
606                         }
607                 }
608
609                 if (g_strcasecmp(key, "Address") == 0) {
610                         addr = inet_addr(val);
611                         if (iface->ipv4.address.s_addr != addr) {
612                                 iface->ipv4.address.s_addr = addr;
613                                 changed = TRUE;
614                         }
615                 }
616
617                 if (g_strcasecmp(key, "Netmask") == 0) {
618                         addr = inet_addr(val);
619                         if (iface->ipv4.netmask.s_addr != addr) {
620                                 iface->ipv4.netmask.s_addr = addr;
621                                 changed = TRUE;
622                         }
623                 }
624
625                 if (g_strcasecmp(key, "Gateway") == 0) {
626                         addr = inet_addr(val);
627                         if (iface->ipv4.gateway.s_addr != addr) {
628                                 iface->ipv4.gateway.s_addr = addr;
629                                 changed = TRUE;
630                         }
631                 }
632
633                 dbus_message_iter_next(&dict);
634         }
635
636         reply = dbus_message_new_method_return(msg);
637         if (reply == NULL)
638                 return NULL;
639
640         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
641
642         path = dbus_message_get_path(msg);
643
644         if (changed == TRUE) {
645                 signal = dbus_message_new_signal(path,
646                                 CONNMAN_IFACE_INTERFACE, "IPv4Changed");
647                 if (signal != NULL) {
648                         append_ipv4(signal, iface);
649                         dbus_connection_send(conn, signal, NULL);
650                         dbus_message_unref(signal);
651                 }
652         }
653
654         return reply;
655 }
656
657 static DBusMessage *set_network(DBusConnection *conn,
658                                         DBusMessage *msg, void *data)
659 {
660         struct connman_iface *iface = data;
661         DBusMessage *reply;
662         DBusMessageIter array, dict;
663
664         DBG("conn %p", conn);
665
666         dbus_message_iter_init(msg, &array);
667
668         dbus_message_iter_recurse(&array, &dict);
669
670         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
671                 DBusMessageIter entry, value;
672                 const char *key, *val;
673
674                 dbus_message_iter_recurse(&dict, &entry);
675                 dbus_message_iter_get_basic(&entry, &key);
676
677                 dbus_message_iter_next(&entry);
678
679                 dbus_message_iter_recurse(&entry, &value);
680
681                 //type = dbus_message_iter_get_arg_type(&value);
682                 dbus_message_iter_get_basic(&value, &val);
683
684                 if (g_strcasecmp(key, "ESSID") == 0) {
685                         if (iface->driver->set_network)
686                                 iface->driver->set_network(iface, val);
687                 }
688
689                 if (g_strcasecmp(key, "PSK") == 0) {
690                         if (iface->driver->set_network)
691                                 iface->driver->set_passphrase(iface, val);
692                 }
693
694                 dbus_message_iter_next(&dict);
695         }
696
697         reply = dbus_message_new_method_return(msg);
698         if (reply == NULL)
699                 return NULL;
700
701         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
702
703         return reply;
704 }
705
706 static GDBusMethodTable iface_methods[] = {
707         { "Scan",          "",      "",      scan_iface     },
708         { "GetProperties", "",      "a{sv}", get_properties },
709         { "GetState",      "",      "s",     get_state      },
710         { "GetSignal",     "",      "q",     get_signal     },
711         { "GetPolicy",     "",      "s",     get_policy     },
712         { "SetPolicy",     "s",     "",      set_policy     },
713         { "GetIPv4",       "",      "a{sv}", get_ipv4       },
714         { "SetIPv4",       "a{sv}", "",      set_ipv4       },
715         { "SetNetwork",    "a{sv}", "",      set_network    },
716         { },
717 };
718
719 static GDBusSignalTable iface_signals[] = {
720         { "StateChanged",   "s"     },
721         { "SignalChanged",  "q"     },
722         { "PolicyChanged",  "s"     },
723         { "IPv4Changed",    "a{sv}" },
724         { "NetworkChanged", "a{sv}" },
725         { },
726 };
727
728 static void device_free(void *data)
729 {
730         struct connman_iface *iface = data;
731
732         DBG("iface %p", iface);
733
734         connman_iface_clear_ipv4(iface);
735
736         if (iface->driver && iface->driver->remove)
737                 iface->driver->remove(iface);
738
739         g_free(iface->path);
740         g_free(iface->udi);
741         g_free(iface->sysfs);
742         g_free(iface->identifier);
743         g_free(iface->device.driver);
744         g_free(iface->device.vendor);
745         g_free(iface->device.product);
746         g_free(iface);
747 }
748
749 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
750 {
751         char *parent, *subsys, *value;
752
753         parent = libhal_device_get_property_string(ctx, iface->udi,
754                                                 "info.parent", NULL);
755
756         subsys = libhal_device_get_property_string(ctx, iface->udi,
757                                                 "linux.subsystem", NULL);
758
759         value = libhal_device_get_property_string(ctx, iface->udi,
760                                                 "info.linux.driver", NULL);
761         if (value == NULL) {
762                 value = libhal_device_get_property_string(ctx, parent,
763                                                 "info.linux.driver", NULL);
764                 if (value != NULL)
765                         iface->device.driver = g_strdup(value);
766         }
767
768         if (strcmp(subsys, "net") == 0) {
769                 value = libhal_device_get_property_string(ctx, parent,
770                                                         "info.vendor", NULL);
771                 if (value != NULL)
772                         iface->device.vendor = g_strdup(value);
773
774                 value = libhal_device_get_property_string(ctx, parent,
775                                                         "info.product", NULL);
776                 if (value != NULL)
777                         iface->device.product = g_strdup(value);
778         }
779 }
780
781 static int probe_device(LibHalContext *ctx,
782                         struct connman_iface_driver *driver, const char *udi)
783 {
784         DBusConnection *conn;
785         struct connman_iface *iface;
786         char *temp, *sysfs;
787         int err;
788
789         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
790
791         if (!driver->probe)
792                 return -1;
793
794         iface = g_try_new0(struct connman_iface, 1);
795         if (iface == NULL)
796                 return -1;
797
798         temp = g_path_get_basename(udi);
799         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
800         g_free(temp);
801
802         iface->udi = g_strdup(udi);
803
804         DBG("iface %p path %s", iface, iface->path);
805
806         sysfs = libhal_device_get_property_string(ctx, udi,
807                                                 "linux.sysfs_path", NULL);
808         if (sysfs != NULL)
809                 iface->sysfs = g_strdup(sysfs);
810
811         detect_device_info(ctx, iface);
812
813         iface->index = -1;
814
815         if (g_str_has_prefix(driver->capability, "net") == TRUE)
816                 iface->index = libhal_device_get_property_int(ctx, udi,
817                                                 "net.linux.ifindex", NULL);
818
819         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
820         iface->flags = 0;
821         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
822         iface->policy = CONNMAN_IFACE_POLICY_UNKNOWN;
823
824         err = driver->probe(iface);
825         if (err < 0) {
826                 device_free(iface);
827                 return -1;
828         }
829
830         __connman_iface_create_identifier(iface);
831
832         __connman_iface_init_via_inet(iface);
833
834         iface->driver = driver;
835
836         conn = libhal_ctx_get_dbus_connection(ctx);
837
838         g_dbus_register_object(conn, iface->path, iface, device_free);
839
840         interfaces = g_slist_append(interfaces, iface);
841
842         if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
843                 if (driver->get_ipv4)
844                         driver->get_ipv4(iface, &iface->ipv4);
845                 else
846                         connman_iface_get_ipv4(iface, &iface->ipv4);
847
848                 DBG("address %s", inet_ntoa(iface->ipv4.address));
849         }
850
851         g_dbus_register_interface(conn, iface->path,
852                                         CONNMAN_IFACE_INTERFACE,
853                                         iface_methods, iface_signals, NULL);
854
855         DBG("iface %p identifier %s", iface, iface->identifier);
856
857         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
858                                         CONNMAN_MANAGER_INTERFACE,
859                                         "InterfaceAdded",
860                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
861                                         DBUS_TYPE_INVALID);
862
863         if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) {
864                 if (driver->activate)
865                         driver->activate(iface);
866         }
867
868         return 0;
869 }
870
871 static void device_added(LibHalContext *ctx, const char *udi)
872 {
873         GSList *list;
874
875         DBG("ctx %p udi %s", ctx, udi);
876
877         for (list = drivers; list; list = list->next) {
878                 struct connman_iface_driver *driver = list->data;
879
880                 if (driver->capability == NULL)
881                         continue;
882
883                 if (libhal_device_query_capability(ctx, udi,
884                                         driver->capability, NULL) == TRUE) {
885                         if (probe_device(ctx, driver, udi) == 0)
886                                 break;
887                 }
888         }
889 }
890
891 static void device_removed(LibHalContext *ctx, const char *udi)
892 {
893         DBusConnection *conn;
894         GSList *list;
895
896         DBG("ctx %p udi %s", ctx, udi);
897
898         conn = libhal_ctx_get_dbus_connection(ctx);
899
900         for (list = interfaces; list; list = list->next) {
901                 struct connman_iface *iface = list->data;
902
903                 if (strcmp(udi, iface->udi) == 0) {
904                         g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
905                                         CONNMAN_MANAGER_INTERFACE,
906                                         "InterfaceRemoved",
907                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
908                                         DBUS_TYPE_INVALID);
909                         interfaces = g_slist_remove(interfaces, iface);
910                         g_dbus_unregister_interface(conn, iface->path,
911                                                 CONNMAN_IFACE_INTERFACE);
912                         g_dbus_unregister_object(conn, iface->path);
913                         break;
914                 }
915         }
916 }
917
918 static void probe_driver(LibHalContext *ctx,
919                                 struct connman_iface_driver *driver)
920 {
921         char **list;
922         int num;
923
924         DBG("ctx %p driver %p", ctx, driver);
925
926         list = libhal_find_device_by_capability(ctx,
927                                         driver->capability, &num, NULL);
928         if (list) {
929                 char **tmp = list;
930
931                 while (*tmp) {
932                         probe_device(ctx, driver, *tmp);
933                         tmp++;
934                 }
935
936                 libhal_free_string_array(list);
937         }
938 }
939
940 static void find_devices(LibHalContext *ctx)
941 {
942         GSList *list;
943
944         DBG("ctx %p", ctx);
945
946         for (list = drivers; list; list = list->next) {
947                 struct connman_iface_driver *driver = list->data;
948
949                 DBG("driver %p", driver);
950
951                 if (driver->capability == NULL)
952                         continue;
953
954                 probe_driver(ctx, driver);
955         }
956 }
957
958 static LibHalContext *hal_ctx = NULL;
959
960 static void hal_init(void *data)
961 {
962         DBusConnection *conn = data;
963
964         DBG("conn %p", conn);
965
966         if (hal_ctx != NULL)
967                 return;
968
969         hal_ctx = libhal_ctx_new();
970         if (hal_ctx == NULL)
971                 return;
972
973         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
974                 libhal_ctx_free(hal_ctx);
975                 return;
976         }
977
978         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
979                 libhal_ctx_free(hal_ctx);
980                 return ;
981         }
982
983         libhal_ctx_set_device_added(hal_ctx, device_added);
984         libhal_ctx_set_device_removed(hal_ctx, device_removed);
985
986         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
987         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
988
989         find_devices(hal_ctx);
990 }
991
992 static void hal_cleanup(void *data)
993 {
994         DBusConnection *conn = data;
995         GSList *list;
996
997         DBG("conn %p", conn);
998
999         if (hal_ctx == NULL)
1000                 return;
1001
1002         for (list = interfaces; list; list = list->next) {
1003                 struct connman_iface *iface = list->data;
1004
1005                 DBG("path %s", iface->path);
1006
1007                 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
1008                                         CONNMAN_MANAGER_INTERFACE,
1009                                         "InterfaceRemoved",
1010                                         DBUS_TYPE_OBJECT_PATH, &iface->path,
1011                                         DBUS_TYPE_INVALID);
1012
1013                 g_dbus_unregister_interface(conn, iface->path,
1014                                                 CONNMAN_IFACE_INTERFACE);
1015
1016                 g_dbus_unregister_object(conn, iface->path);
1017         }
1018
1019         g_slist_free(interfaces);
1020
1021         interfaces = NULL;
1022
1023         libhal_ctx_shutdown(hal_ctx, NULL);
1024
1025         libhal_ctx_free(hal_ctx);
1026
1027         hal_ctx = NULL;
1028 }
1029
1030 static guint hal_watch = 0;
1031
1032 int __connman_iface_init(DBusConnection *conn)
1033 {
1034         DBG("conn %p", conn);
1035
1036         connection = dbus_connection_ref(conn);
1037         if (connection == NULL)
1038                 return -1;
1039
1040         hal_init(connection);
1041
1042         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
1043                                 hal_init, hal_cleanup, connection, NULL);
1044
1045         return 0;
1046 }
1047
1048 void __connman_iface_cleanup(void)
1049 {
1050         DBG("conn %p", connection);
1051
1052         g_dbus_remove_watch(connection, hal_watch);
1053
1054         hal_cleanup(connection);
1055
1056         dbus_connection_unref(connection);
1057 }