5 * Copyright (C) 2007 Intel Corporation. All rights reserved.
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.
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.
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
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
36 #include <net/route.h>
38 #include <linux/netlink.h>
39 #include <linux/rtnetlink.h>
44 #include <hal/libhal.h>
48 static GSList *drivers = NULL;
50 int connman_iface_register(struct connman_iface_driver *driver)
52 DBG("driver %p", driver);
54 drivers = g_slist_append(drivers, driver);
59 void connman_iface_unregister(struct connman_iface_driver *driver)
61 DBG("driver %p", driver);
63 drivers = g_slist_remove(drivers, driver);
66 static GSList *interfaces = NULL;
68 struct connman_iface *__connman_iface_find(int index)
72 for (list = interfaces; list; list = list->next) {
73 struct connman_iface *iface = list->data;
75 if (iface->index == index)
82 void __connman_iface_list(DBusMessageIter *iter)
88 for (list = interfaces; list; list = list->next) {
89 struct connman_iface *iface = list->data;
91 dbus_message_iter_append_basic(iter,
92 DBUS_TYPE_OBJECT_PATH, &iface->path);
96 int connman_iface_update(struct connman_iface *iface,
97 enum connman_iface_state state)
100 case CONNMAN_IFACE_STATE_ACTIVE:
101 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
102 if (iface->driver->connect)
103 iface->driver->connect(iface, NULL);
107 case CONNMAN_IFACE_STATE_CONNECTED:
108 __connman_dhcp_request(iface);
115 iface->state = state;
120 void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier)
122 DBG("iface %p carrier %d", iface, carrier);
125 int connman_iface_get_ipv4(struct connman_iface *iface,
126 struct connman_ipv4 *ipv4)
133 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
136 DBG("iface %p ipv4 %p", iface, ipv4);
138 memset(&req, 0, sizeof(req));
139 req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
140 req.hdr.nlmsg_type = RTM_GETADDR;
141 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
142 req.hdr.nlmsg_pid = 0;
143 req.hdr.nlmsg_seq = 4711;
144 req.msg.rtgen_family = AF_INET;
146 __connman_rtnl_send(&req, sizeof(req));
151 int connman_iface_set_ipv4(struct connman_iface *iface,
152 struct connman_ipv4 *ipv4)
156 struct sockaddr_in *addr;
160 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
163 DBG("iface %p ipv4 %p", iface, ipv4);
165 sk = socket(PF_INET, SOCK_DGRAM, 0);
169 memset(&ifr, 0, sizeof(ifr));
170 ifr.ifr_ifindex = iface->index;
172 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
177 DBG("ifname %s", ifr.ifr_name);
179 addr = (struct sockaddr_in *) &ifr.ifr_addr;
180 addr->sin_family = AF_INET;
181 addr->sin_addr = ipv4->address;
183 err = ioctl(sk, SIOCSIFADDR, &ifr);
186 DBG("address setting failed (%s)", strerror(errno));
188 addr = (struct sockaddr_in *) &ifr.ifr_netmask;
189 addr->sin_family = AF_INET;
190 addr->sin_addr = ipv4->netmask;
192 err = ioctl(sk, SIOCSIFNETMASK, &ifr);
195 DBG("netmask setting failed (%s)", strerror(errno));
197 addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
198 addr->sin_family = AF_INET;
199 addr->sin_addr = ipv4->broadcast;
201 err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
204 DBG("broadcast setting failed (%s)", strerror(errno));
206 memset(&rt, 0, sizeof(rt));
207 rt.rt_flags = RTF_UP | RTF_GATEWAY;
209 addr = (struct sockaddr_in *) &rt.rt_dst;
210 addr->sin_family = AF_INET;
211 addr->sin_addr.s_addr = INADDR_ANY;
213 addr = (struct sockaddr_in *) &rt.rt_gateway;
214 addr->sin_family = AF_INET;
215 addr->sin_addr = ipv4->gateway;
217 addr = (struct sockaddr_in *) &rt.rt_genmask;
218 addr->sin_family = AF_INET;
219 addr->sin_addr.s_addr = INADDR_ANY;
221 err = ioctl(sk, SIOCADDRT, &rt);
226 DBG("default route failed (%s)", strerror(errno));
230 sprintf(cmd, "echo \"nameserver %s\" | resolvconf -a %s",
231 inet_ntoa(ipv4->nameserver), ifr.ifr_name);
240 int connman_iface_clear_ipv4(struct connman_iface *iface)
243 struct sockaddr_in *addr;
247 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
250 DBG("iface %p", iface);
252 sk = socket(PF_INET, SOCK_DGRAM, 0);
256 memset(&ifr, 0, sizeof(ifr));
257 ifr.ifr_ifindex = iface->index;
259 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
264 DBG("ifname %s", ifr.ifr_name);
266 addr = (struct sockaddr_in *) &ifr.ifr_addr;
267 addr->sin_family = AF_INET;
268 addr->sin_addr.s_addr = INADDR_ANY;
270 //err = ioctl(sk, SIOCDIFADDR, &ifr);
271 err = ioctl(sk, SIOCSIFADDR, &ifr);
275 if (err < 0 && errno != EADDRNOTAVAIL) {
276 DBG("address removal failed (%s)", strerror(errno));
280 sprintf(cmd, "resolvconf -d %s", ifr.ifr_name);
289 static DBusMessage *enable_iface(DBusConnection *conn,
290 DBusMessage *msg, void *data)
292 struct connman_iface *iface = data;
293 struct connman_iface_driver *driver = iface->driver;
296 DBG("conn %p", conn);
298 reply = dbus_message_new_method_return(msg);
302 if (driver->activate)
303 driver->activate(iface);
305 dbus_message_append_args(reply, DBUS_TYPE_INVALID);
310 static DBusMessage *scan_iface(DBusConnection *conn,
311 DBusMessage *msg, void *data)
313 struct connman_iface *iface = data;
314 struct connman_iface_driver *driver = iface->driver;
317 DBG("conn %p", conn);
319 reply = dbus_message_new_method_return(msg);
326 dbus_message_append_args(reply, DBUS_TYPE_INVALID);
331 static DBusMessage *set_network(DBusConnection *conn,
332 DBusMessage *msg, void *data)
334 struct connman_iface *iface = data;
335 struct connman_iface_driver *driver = iface->driver;
339 DBG("conn %p", conn);
341 dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &network,
344 reply = dbus_message_new_method_return(msg);
348 if (driver->set_network)
349 driver->set_network(iface, network);
351 dbus_message_append_args(reply, DBUS_TYPE_INVALID);
356 static DBusMessage *set_passphrase(DBusConnection *conn,
357 DBusMessage *msg, void *data)
359 struct connman_iface *iface = data;
360 struct connman_iface_driver *driver = iface->driver;
362 const char *passphrase;
364 DBG("conn %p", conn);
366 dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &passphrase,
369 reply = dbus_message_new_method_return(msg);
373 if (driver->set_passphrase)
374 driver->set_passphrase(iface, passphrase);
376 dbus_message_append_args(reply, DBUS_TYPE_INVALID);
381 static GDBusMethodTable iface_methods[] = {
382 { "Enable", "", "", enable_iface },
383 { "Scan", "", "", scan_iface },
384 { "SetNetwork", "s", "", set_network },
385 { "SetPassphrase", "s", "", set_passphrase },
389 static dbus_bool_t get_type(DBusConnection *conn,
390 DBusMessageIter *iter, void *data)
392 struct connman_iface *iface = data;
395 DBG("iface %p", iface);
397 switch (iface->type) {
398 case CONNMAN_IFACE_TYPE_80203:
401 case CONNMAN_IFACE_TYPE_80211:
404 case CONNMAN_IFACE_TYPE_WIMAX:
407 case CONNMAN_IFACE_TYPE_BLUETOOTH:
415 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
420 static dbus_bool_t get_address(DBusConnection *conn,
421 DBusMessageIter *iter, void *data)
423 struct connman_iface *iface = data;
426 DBG("iface %p", iface);
428 if (!iface->driver->get_address)
431 address = iface->driver->get_address(iface);
435 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &address);
440 static dbus_bool_t get_driver(DBusConnection *conn,
441 DBusMessageIter *iter, void *data)
443 struct connman_iface *iface = data;
445 DBG("iface %p", iface);
447 if (iface->device.driver == NULL)
450 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
451 &iface->device.driver);
456 static dbus_bool_t get_vendor(DBusConnection *conn,
457 DBusMessageIter *iter, void *data)
459 struct connman_iface *iface = data;
461 DBG("iface %p", iface);
463 if (iface->device.vendor == NULL)
466 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
467 &iface->device.vendor);
472 static dbus_bool_t get_product(DBusConnection *conn,
473 DBusMessageIter *iter, void *data)
475 struct connman_iface *iface = data;
477 DBG("iface %p", iface);
479 if (iface->device.product == NULL)
482 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
483 &iface->device.product);
488 static GDBusPropertyTable iface_properties[] = {
489 { "Type", "s", get_type },
490 { "Address", "s", get_address },
491 { "Driver", "s", get_driver },
492 { "Vendor", "s", get_vendor },
493 { "Product", "s", get_product },
497 static void device_free(void *data)
499 struct connman_iface *iface = data;
501 DBG("iface %p", iface);
503 connman_iface_clear_ipv4(iface);
505 if (iface->driver && iface->driver->remove)
506 iface->driver->remove(iface);
510 g_free(iface->sysfs);
511 g_free(iface->device.driver);
512 g_free(iface->device.vendor);
513 g_free(iface->device.product);
517 static void detect_device_info(LibHalContext *ctx, struct connman_iface *iface)
519 char *parent, *subsys, *value;
521 parent = libhal_device_get_property_string(ctx, iface->udi,
522 "info.parent", NULL);
524 subsys = libhal_device_get_property_string(ctx, iface->udi,
525 "linux.subsystem", NULL);
527 value = libhal_device_get_property_string(ctx, iface->udi,
528 "info.linux.driver", NULL);
530 value = libhal_device_get_property_string(ctx, parent,
531 "info.linux.driver", NULL);
533 iface->device.driver = g_strdup(value);
536 if (strcmp(subsys, "net") == 0) {
537 value = libhal_device_get_property_string(ctx, parent,
538 "info.vendor", NULL);
540 iface->device.vendor = g_strdup(value);
542 value = libhal_device_get_property_string(ctx, parent,
543 "info.product", NULL);
545 iface->device.product = g_strdup(value);
549 static int probe_device(LibHalContext *ctx,
550 struct connman_iface_driver *driver, const char *udi)
552 DBusConnection *conn;
553 struct connman_iface *iface;
557 DBG("ctx %p driver %p udi %s", ctx, driver, udi);
562 iface = g_try_new0(struct connman_iface, 1);
566 temp = g_path_get_basename(udi);
567 iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
570 iface->udi = g_strdup(udi);
572 DBG("path %s", iface->path);
574 sysfs = libhal_device_get_property_string(ctx, udi,
575 "linux.sysfs_path", NULL);
577 iface->sysfs = g_strdup(sysfs);
579 detect_device_info(ctx, iface);
583 if (g_str_has_prefix(driver->capability, "net") == TRUE)
584 iface->index = libhal_device_get_property_int(ctx, udi,
585 "net.linux.ifindex", NULL);
587 iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
589 iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
591 DBG("iface %p", iface);
593 err = driver->probe(iface);
599 iface->driver = driver;
601 conn = libhal_ctx_get_dbus_connection(ctx);
603 g_dbus_register_object(conn, iface->path, iface, device_free);
605 interfaces = g_slist_append(interfaces, iface);
607 if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
608 if (driver->get_ipv4)
609 driver->get_ipv4(iface, &iface->ipv4);
611 connman_iface_get_ipv4(iface, &iface->ipv4);
613 DBG("address %s", inet_ntoa(iface->ipv4.address));
616 g_dbus_register_interface(conn, iface->path,
617 CONNMAN_IFACE_INTERFACE,
618 iface_methods, NULL, iface_properties);
620 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
621 CONNMAN_MANAGER_INTERFACE,
623 DBUS_TYPE_OBJECT_PATH, &iface->path,
629 static void device_added(LibHalContext *ctx, const char *udi)
633 DBG("ctx %p udi %s", ctx, udi);
635 for (list = drivers; list; list = list->next) {
636 struct connman_iface_driver *driver = list->data;
638 if (driver->capability == NULL)
641 if (libhal_device_query_capability(ctx, udi,
642 driver->capability, NULL) == TRUE) {
643 if (probe_device(ctx, driver, udi) == 0)
649 static void device_removed(LibHalContext *ctx, const char *udi)
651 DBusConnection *conn;
654 DBG("ctx %p udi %s", ctx, udi);
656 conn = libhal_ctx_get_dbus_connection(ctx);
658 for (list = interfaces; list; list = list->next) {
659 struct connman_iface *iface = list->data;
661 if (strcmp(udi, iface->udi) == 0) {
662 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
663 CONNMAN_MANAGER_INTERFACE,
665 DBUS_TYPE_OBJECT_PATH, &iface->path,
667 interfaces = g_slist_remove(interfaces, iface);
668 g_dbus_unregister_interface(conn, iface->path,
669 CONNMAN_IFACE_INTERFACE);
670 g_dbus_unregister_object(conn, iface->path);
676 static void probe_driver(LibHalContext *ctx,
677 struct connman_iface_driver *driver)
682 DBG("ctx %p driver %p", ctx, driver);
684 list = libhal_find_device_by_capability(ctx,
685 driver->capability, &num, NULL);
690 probe_device(ctx, driver, *tmp);
694 libhal_free_string_array(list);
698 static void find_devices(LibHalContext *ctx)
704 for (list = drivers; list; list = list->next) {
705 struct connman_iface_driver *driver = list->data;
707 DBG("driver %p", driver);
709 if (driver->capability == NULL)
712 probe_driver(ctx, driver);
716 static LibHalContext *hal_ctx = NULL;
718 static void hal_init(void *data)
720 DBusConnection *conn = data;
722 DBG("conn %p", conn);
727 hal_ctx = libhal_ctx_new();
731 if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
732 libhal_ctx_free(hal_ctx);
736 if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
737 libhal_ctx_free(hal_ctx);
741 libhal_ctx_set_device_added(hal_ctx, device_added);
742 libhal_ctx_set_device_removed(hal_ctx, device_removed);
744 //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
745 //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
747 find_devices(hal_ctx);
750 static void hal_cleanup(void *data)
752 DBusConnection *conn = data;
755 DBG("conn %p", conn);
760 for (list = interfaces; list; list = list->next) {
761 struct connman_iface *iface = list->data;
763 DBG("path %s", iface->path);
765 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
766 CONNMAN_MANAGER_INTERFACE,
768 DBUS_TYPE_OBJECT_PATH, &iface->path,
771 g_dbus_unregister_interface(conn, iface->path,
772 CONNMAN_IFACE_INTERFACE);
774 g_dbus_unregister_object(conn, iface->path);
777 g_slist_free(interfaces);
781 libhal_ctx_shutdown(hal_ctx, NULL);
783 libhal_ctx_free(hal_ctx);
788 static DBusConnection *connection = NULL;
789 static guint hal_watch = 0;
791 int __connman_iface_init(DBusConnection *conn)
793 DBG("conn %p", conn);
795 connection = dbus_connection_ref(conn);
796 if (connection == NULL)
799 hal_init(connection);
801 hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
802 hal_init, hal_cleanup, connection, NULL);
807 void __connman_iface_cleanup(void)
809 DBG("conn %p", connection);
811 g_dbus_remove_watch(connection, hal_watch);
813 hal_cleanup(connection);
815 dbus_connection_unref(connection);