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
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include <net/route.h>
37 #include <linux/netlink.h>
38 #include <linux/rtnetlink.h>
43 #include <hal/libhal.h>
47 static GSList *drivers = NULL;
49 int connman_iface_register(struct connman_iface_driver *driver)
51 DBG("driver %p", driver);
53 drivers = g_slist_append(drivers, driver);
58 void connman_iface_unregister(struct connman_iface_driver *driver)
60 DBG("driver %p", driver);
62 drivers = g_slist_remove(drivers, driver);
65 static GSList *interfaces = NULL;
67 struct connman_iface *__connman_iface_find(int index)
71 for (list = interfaces; list; list = list->next) {
72 struct connman_iface *iface = list->data;
74 if (iface->index == index)
81 void __connman_iface_list(DBusMessageIter *iter)
87 for (list = interfaces; list; list = list->next) {
88 struct connman_iface *iface = list->data;
90 dbus_message_iter_append_basic(iter,
91 DBUS_TYPE_OBJECT_PATH, &iface->path);
95 int connman_iface_update(struct connman_iface *iface,
96 enum connman_iface_state state)
99 case CONNMAN_IFACE_STATE_ACTIVE:
100 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
101 if (iface->driver->scan)
102 iface->driver->scan(iface);
104 if (iface->driver->connect)
105 iface->driver->connect(iface, NULL);
109 case CONNMAN_IFACE_STATE_CONNECTED:
110 __connman_dhcp_request(iface);
117 iface->state = state;
122 void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier)
124 DBG("iface %p carrier %d", iface, carrier);
127 int connman_iface_get_ipv4(struct connman_iface *iface,
128 struct connman_ipv4 *ipv4)
135 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
138 DBG("iface %p ipv4 %p", iface, ipv4);
140 memset(&req, 0, sizeof(req));
141 req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
142 req.hdr.nlmsg_type = RTM_GETADDR;
143 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
144 req.hdr.nlmsg_pid = 0;
145 req.hdr.nlmsg_seq = 4711;
146 req.msg.rtgen_family = AF_INET;
148 __connman_rtnl_send(&req, sizeof(req));
153 int connman_iface_set_ipv4(struct connman_iface *iface,
154 struct connman_ipv4 *ipv4)
158 struct sockaddr_in *addr;
161 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
164 DBG("iface %p ipv4 %p", iface, ipv4);
166 sk = socket(PF_INET, SOCK_DGRAM, 0);
170 memset(&ifr, 0, sizeof(ifr));
171 ifr.ifr_ifindex = iface->index;
173 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
178 DBG("ifname %s", ifr.ifr_name);
180 addr = (struct sockaddr_in *) &ifr.ifr_addr;
181 addr->sin_family = AF_INET;
182 addr->sin_addr = ipv4->address;
184 err = ioctl(sk, SIOCSIFADDR, &ifr);
187 DBG("address setting failed (%s)", strerror(errno));
189 addr = (struct sockaddr_in *) &ifr.ifr_netmask;
190 addr->sin_family = AF_INET;
191 addr->sin_addr = ipv4->netmask;
193 err = ioctl(sk, SIOCSIFNETMASK, &ifr);
196 DBG("netmask setting failed (%s)", strerror(errno));
198 addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
199 addr->sin_family = AF_INET;
200 addr->sin_addr = ipv4->broadcast;
202 err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
205 DBG("broadcast setting failed (%s)", strerror(errno));
207 memset(&rt, 0, sizeof(rt));
208 rt.rt_flags = RTF_UP | RTF_GATEWAY;
210 addr = (struct sockaddr_in *) &rt.rt_dst;
211 addr->sin_family = AF_INET;
212 addr->sin_addr.s_addr = INADDR_ANY;
214 addr = (struct sockaddr_in *) &rt.rt_gateway;
215 addr->sin_family = AF_INET;
216 addr->sin_addr = ipv4->gateway;
218 addr = (struct sockaddr_in *) &rt.rt_genmask;
219 addr->sin_family = AF_INET;
220 addr->sin_addr.s_addr = INADDR_ANY;
222 err = ioctl(sk, SIOCADDRT, &rt);
227 DBG("default route failed (%s)", strerror(errno));
234 int connman_iface_clear_ipv4(struct connman_iface *iface)
237 struct sockaddr_in *addr;
240 if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
243 DBG("iface %p", iface);
245 sk = socket(PF_INET, SOCK_DGRAM, 0);
249 memset(&ifr, 0, sizeof(ifr));
250 ifr.ifr_ifindex = iface->index;
252 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
257 DBG("ifname %s", ifr.ifr_name);
259 addr = (struct sockaddr_in *) &ifr.ifr_addr;
260 addr->sin_family = AF_INET;
261 addr->sin_addr.s_addr = INADDR_ANY;
263 //err = ioctl(sk, SIOCDIFADDR, &ifr);
264 err = ioctl(sk, SIOCSIFADDR, &ifr);
268 if (err < 0 && errno != EADDRNOTAVAIL) {
269 DBG("address removal failed (%s)", strerror(errno));
276 static DBusMessage *enable_iface(DBusConnection *conn,
277 DBusMessage *msg, void *data)
279 struct connman_iface *iface = data;
280 struct connman_iface_driver *driver = iface->driver;
283 DBG("conn %p", conn);
285 reply = dbus_message_new_method_return(msg);
289 if (driver->activate)
290 driver->activate(iface);
292 dbus_message_append_args(reply, DBUS_TYPE_INVALID);
297 static GDBusMethodTable iface_methods[] = {
298 { "Enable", "", "", enable_iface },
302 static dbus_bool_t get_type(DBusConnection *conn,
303 DBusMessageIter *iter, void *data)
305 struct connman_iface *iface = data;
308 DBG("iface %p", iface);
310 switch (iface->type) {
311 case CONNMAN_IFACE_TYPE_80203:
314 case CONNMAN_IFACE_TYPE_80211:
317 case CONNMAN_IFACE_TYPE_WIMAX:
320 case CONNMAN_IFACE_TYPE_BLUETOOTH:
328 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
333 static GDBusPropertyTable iface_properties[] = {
334 { "Type", "s", get_type },
338 static void device_free(void *data)
340 struct connman_iface *iface = data;
342 DBG("iface %p", iface);
344 connman_iface_clear_ipv4(iface);
346 if (iface->driver && iface->driver->remove)
347 iface->driver->remove(iface);
351 g_free(iface->sysfs);
355 static int probe_device(LibHalContext *ctx,
356 struct connman_iface_driver *driver, const char *udi)
358 DBusConnection *conn;
359 struct connman_iface *iface;
363 DBG("ctx %p driver %p udi %s", ctx, driver, udi);
368 iface = g_try_new0(struct connman_iface, 1);
372 temp = g_path_get_basename(udi);
373 iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
376 iface->udi = g_strdup(udi);
378 DBG("path %s", iface->path);
380 sysfs = libhal_device_get_property_string(ctx, udi,
381 "linux.sysfs_path", NULL);
383 iface->sysfs = g_strdup(sysfs);
387 if (g_str_has_prefix(driver->capability, "net") == TRUE)
388 iface->index = libhal_device_get_property_int(ctx, udi,
389 "net.linux.ifindex", NULL);
391 iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
393 iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
395 DBG("iface %p", iface);
397 err = driver->probe(iface);
403 iface->driver = driver;
405 conn = libhal_ctx_get_dbus_connection(ctx);
407 g_dbus_register_object(conn, iface->path, iface, device_free);
409 interfaces = g_slist_append(interfaces, iface);
411 if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) {
412 if (driver->get_ipv4)
413 driver->get_ipv4(iface, &iface->ipv4);
415 connman_iface_get_ipv4(iface, &iface->ipv4);
417 DBG("address %s", inet_ntoa(iface->ipv4.address));
420 g_dbus_register_interface(conn, iface->path,
421 CONNMAN_IFACE_INTERFACE,
422 iface_methods, NULL, iface_properties);
424 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
425 CONNMAN_MANAGER_INTERFACE,
427 DBUS_TYPE_OBJECT_PATH, &iface->path,
433 static void device_added(LibHalContext *ctx, const char *udi)
437 DBG("ctx %p udi %s", ctx, udi);
439 for (list = drivers; list; list = list->next) {
440 struct connman_iface_driver *driver = list->data;
442 if (driver->capability == NULL)
445 if (libhal_device_query_capability(ctx, udi,
446 driver->capability, NULL) == TRUE) {
447 if (probe_device(ctx, driver, udi) == 0)
453 static void device_removed(LibHalContext *ctx, const char *udi)
455 DBusConnection *conn;
458 DBG("ctx %p udi %s", ctx, udi);
460 conn = libhal_ctx_get_dbus_connection(ctx);
462 for (list = interfaces; list; list = list->next) {
463 struct connman_iface *iface = list->data;
465 if (strcmp(udi, iface->udi) == 0) {
466 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
467 CONNMAN_MANAGER_INTERFACE,
469 DBUS_TYPE_OBJECT_PATH, &iface->path,
471 interfaces = g_slist_remove(interfaces, iface);
472 g_dbus_unregister_interface(conn, iface->path,
473 CONNMAN_IFACE_INTERFACE);
474 g_dbus_unregister_object(conn, iface->path);
480 static void probe_driver(LibHalContext *ctx,
481 struct connman_iface_driver *driver)
486 DBG("ctx %p driver %p", ctx, driver);
488 list = libhal_find_device_by_capability(ctx,
489 driver->capability, &num, NULL);
494 probe_device(ctx, driver, *tmp);
498 libhal_free_string_array(list);
502 static void find_devices(LibHalContext *ctx)
508 for (list = drivers; list; list = list->next) {
509 struct connman_iface_driver *driver = list->data;
511 DBG("driver %p", driver);
513 if (driver->capability == NULL)
516 probe_driver(ctx, driver);
520 static LibHalContext *hal_ctx = NULL;
522 static void hal_init(void *data)
524 DBusConnection *conn = data;
526 DBG("conn %p", conn);
531 hal_ctx = libhal_ctx_new();
535 if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
536 libhal_ctx_free(hal_ctx);
540 if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
541 libhal_ctx_free(hal_ctx);
545 libhal_ctx_set_device_added(hal_ctx, device_added);
546 libhal_ctx_set_device_removed(hal_ctx, device_removed);
548 //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
549 //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
551 find_devices(hal_ctx);
554 static void hal_cleanup(void *data)
556 DBusConnection *conn = data;
559 DBG("conn %p", conn);
564 for (list = interfaces; list; list = list->next) {
565 struct connman_iface *iface = list->data;
567 DBG("path %s", iface->path);
569 g_dbus_emit_signal(conn, CONNMAN_MANAGER_PATH,
570 CONNMAN_MANAGER_INTERFACE,
572 DBUS_TYPE_OBJECT_PATH, &iface->path,
575 g_dbus_unregister_interface(conn, iface->path,
576 CONNMAN_IFACE_INTERFACE);
578 g_dbus_unregister_object(conn, iface->path);
581 g_slist_free(interfaces);
585 libhal_ctx_shutdown(hal_ctx, NULL);
587 libhal_ctx_free(hal_ctx);
592 static DBusConnection *connection = NULL;
593 static guint hal_watch = 0;
595 int __connman_iface_init(DBusConnection *conn)
597 DBG("conn %p", conn);
599 connection = dbus_connection_ref(conn);
600 if (connection == NULL)
603 hal_init(connection);
605 hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
606 hal_init, hal_cleanup, connection, NULL);
611 void __connman_iface_cleanup(void)
613 DBG("conn %p", connection);
615 g_dbus_remove_watch(connection, hal_watch);
617 hal_cleanup(connection);
619 dbus_connection_unref(connection);