From 45541d278519384fe25be74a196254d281012019 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Apr 2008 06:01:07 +0200 Subject: [PATCH] Update state machine handling for wireless networks --- include/iface.h | 19 +++++---- src/connman.h | 7 +++- src/dhcp.c | 14 ++++++- src/iface-inet.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/iface-storage.c | 2 - src/iface.c | 97 ++++++++++++++++++++------------------------- src/rtnl.c | 16 +++++--- 7 files changed, 188 insertions(+), 77 deletions(-) diff --git a/include/iface.h b/include/iface.h index 37e6067..8b0e6c8 100644 --- a/include/iface.h +++ b/include/iface.h @@ -38,10 +38,15 @@ enum connman_iface_type { }; enum connman_iface_flags { - CONNMAN_IFACE_FLAG_RTNL = (1 << 0), - CONNMAN_IFACE_FLAG_IPV4 = (1 << 1), - CONNMAN_IFACE_FLAG_IPV6 = (1 << 2), - CONNMAN_IFACE_FLAG_SCANNING = (1 << 3), + CONNMAN_IFACE_FLAG_RTNL = (1 << 0), + CONNMAN_IFACE_FLAG_IPV4 = (1 << 1), + CONNMAN_IFACE_FLAG_IPV6 = (1 << 2), + CONNMAN_IFACE_FLAG_SCANNING = (1 << 3), + CONNMAN_IFACE_FLAG_NOCARRIER = (1 << 4), + + CONNMAN_IFACE_FLAG_STARTED = (1 << 16), + CONNMAN_IFACE_FLAG_RUNNING = (1 << 17), + CONNMAN_IFACE_FLAG_DHCP = (1 << 18), }; enum connman_iface_state { @@ -94,7 +99,7 @@ struct connman_iface { char *identifier; int index; enum connman_iface_type type; - enum connman_iface_flags flags; + unsigned long flags; enum connman_iface_state state; enum connman_iface_policy policy; struct connman_network network; @@ -146,8 +151,8 @@ static inline void connman_iface_set_data(struct connman_iface *iface, iface->driver_data = data; } -extern void connman_iface_indicate_enabled(struct connman_iface *iface); -extern void connman_iface_indicate_disabled(struct connman_iface *iface); +extern void connman_iface_indicate_ifup(struct connman_iface *iface); +extern void connman_iface_indicate_ifdown(struct connman_iface *iface); extern void connman_iface_indicate_connected(struct connman_iface *iface); extern void connman_iface_indicate_carrier_on(struct connman_iface *iface); extern void connman_iface_indicate_carrier_off(struct connman_iface *iface); diff --git a/src/connman.h b/src/connman.h index fbba1e6..e8ca3e7 100644 --- a/src/connman.h +++ b/src/connman.h @@ -69,8 +69,11 @@ void __connman_iface_list(DBusMessageIter *iter); int __connman_iface_create_identifier(struct connman_iface *iface); int __connman_iface_init_via_inet(struct connman_iface *iface); -int __connman_iface_up(struct connman_iface *iface); -int __connman_iface_down(struct connman_iface *iface); +int __connman_iface_start(struct connman_iface *iface); +int __connman_iface_stop(struct connman_iface *iface); +int __connman_iface_connect(struct connman_iface *iface, + struct connman_network *network); +int __connman_iface_disconnect(struct connman_iface *iface); char *__connman_iface_find_passphrase(struct connman_iface *iface, const char *network); diff --git a/src/dhcp.c b/src/dhcp.c index ecf61f2..3b6ba63 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -76,8 +76,13 @@ int __connman_dhcp_request(struct connman_iface *iface) { struct connman_dhcp_driver *driver = g_slist_nth_data(drivers, 0); - if (driver && driver->request) + if (iface->flags & CONNMAN_IFACE_FLAG_DHCP) + return -1; + + if (driver && driver->request) { + iface->flags |= CONNMAN_IFACE_FLAG_DHCP; return driver->request(iface); + } return -1; } @@ -86,8 +91,13 @@ int __connman_dhcp_release(struct connman_iface *iface) { struct connman_dhcp_driver *driver = g_slist_nth_data(drivers, 0); - if (driver && driver->release) + if (!(iface->flags & CONNMAN_IFACE_FLAG_DHCP)) + return -1; + + if (driver && driver->release) { + iface->flags &= ~CONNMAN_IFACE_FLAG_DHCP; return driver->release(iface); + } return -1; } diff --git a/src/iface-inet.c b/src/iface-inet.c index 927f568..7fd7489 100644 --- a/src/iface-inet.c +++ b/src/iface-inet.c @@ -103,13 +103,15 @@ int __connman_iface_init_via_inet(struct connman_iface *iface) else iface->state = CONNMAN_IFACE_STATE_OFF; - if (ifr.ifr_flags & IFF_RUNNING) - iface->state = CONNMAN_IFACE_STATE_CARRIER; + if (ifr.ifr_flags & IFF_RUNNING) { + if (!(iface->flags & CONNMAN_IFACE_FLAG_NOCARRIER)) + iface->state = CONNMAN_IFACE_STATE_CARRIER; + } return 0; } -int __connman_iface_up(struct connman_iface *iface) +static int __connman_iface_up(struct connman_iface *iface) { struct ifreq ifr; int sk, err; @@ -153,7 +155,7 @@ done: return err; } -int __connman_iface_down(struct connman_iface *iface) +static int __connman_iface_down(struct connman_iface *iface) { struct ifreq ifr; int sk, err; @@ -194,3 +196,103 @@ done: return err; } + +int __connman_iface_start(struct connman_iface *iface) +{ + int err; + + DBG("iface %p", iface); + + if (iface->flags & CONNMAN_IFACE_FLAG_STARTED) + return -EALREADY; + + err = __connman_iface_up(iface); + + if (iface->driver->start) { + err = iface->driver->start(iface); + if (err < 0) + return err; + } + + iface->flags |= CONNMAN_IFACE_FLAG_STARTED; + + return 0; +} + +int __connman_iface_stop(struct connman_iface *iface) +{ + int err; + + DBG("iface %p", iface); + + __connman_dhcp_release(iface); + + connman_iface_clear_ipv4(iface); + + if (iface->flags & CONNMAN_IFACE_FLAG_RUNNING) { + if (iface->driver->disconnect) + iface->driver->disconnect(iface); + iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING; + } + + if (!(iface->flags & CONNMAN_IFACE_FLAG_STARTED)) + return -EINVAL; + + if (iface->driver->stop) { + err = iface->driver->stop(iface); + if (err < 0) + return err; + } + + iface->flags &= ~CONNMAN_IFACE_FLAG_STARTED; + + err = __connman_iface_down(iface); + if (err < 0) + return err; + + return 0; +} + +int __connman_iface_connect(struct connman_iface *iface, + struct connman_network *network) +{ + DBG("iface %p name %s passphrase %s", iface, + network->identifier, network->passphrase); + + if (iface->flags & CONNMAN_IFACE_FLAG_RUNNING) { + __connman_dhcp_release(iface); + + connman_iface_clear_ipv4(iface); + + if (iface->driver->disconnect) + iface->driver->disconnect(iface); + + iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING; + } + + if (iface->driver->connect) + iface->driver->connect(iface, network); + + iface->flags |= CONNMAN_IFACE_FLAG_RUNNING; + + return 0; +} + +int __connman_iface_disconnect(struct connman_iface *iface) +{ + DBG("iface %p", iface); + + __connman_dhcp_release(iface); + + connman_iface_clear_ipv4(iface); + + if (!(iface->flags & CONNMAN_IFACE_FLAG_RUNNING)) + return -EINVAL; + + if (iface->driver->disconnect) + iface->driver->disconnect(iface); + + iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING; + + return 0; +} diff --git a/src/iface-storage.c b/src/iface-storage.c index 6694d99..8d2895f 100644 --- a/src/iface-storage.c +++ b/src/iface-storage.c @@ -41,8 +41,6 @@ char *__connman_iface_find_passphrase(struct connman_iface *iface, gsize list_len; int i; - DBG("iface %p", iface); - if (iface->identifier == NULL) return NULL; diff --git a/src/iface.c b/src/iface.c index a4e154e..f5753d8 100644 --- a/src/iface.c +++ b/src/iface.c @@ -157,14 +157,11 @@ static void state_changed(struct connman_iface *iface) switch (iface->state) { case CONNMAN_IFACE_STATE_OFF: - __connman_dhcp_release(iface); + __connman_iface_stop(iface); break; case CONNMAN_IFACE_STATE_ENABLED: - __connman_dhcp_release(iface); - connman_iface_clear_ipv4(iface); - if (iface->driver->disconnect) - iface->driver->disconnect(iface); + __connman_iface_start(iface); if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING) state = CONNMAN_IFACE_STATE_SCANNING; break; @@ -185,9 +182,7 @@ static void state_changed(struct connman_iface *iface) break; case CONNMAN_IFACE_STATE_SHUTDOWN: - __connman_dhcp_release(iface); - if (iface->driver->disconnect) - iface->driver->disconnect(iface); + __connman_iface_stop(iface); if (iface->policy != CONNMAN_IFACE_POLICY_AUTO) state = CONNMAN_IFACE_STATE_OFF; break; @@ -207,28 +202,19 @@ static void state_changed(struct connman_iface *iface) static void switch_policy(struct connman_iface *iface) { - DBG("iface %p", iface); + DBG("iface %p policy %d", iface, iface->policy); switch (iface->policy) { case CONNMAN_IFACE_POLICY_OFF: - iface->state = CONNMAN_IFACE_STATE_SHUTDOWN; - state_changed(iface); - connman_iface_clear_ipv4(iface); - if (iface->driver->stop) - iface->driver->stop(iface); - else - __connman_iface_down(iface); + __connman_iface_stop(iface); break; case CONNMAN_IFACE_POLICY_IGNORE: break; case CONNMAN_IFACE_POLICY_AUTO: - if (iface->driver->start) - iface->driver->start(iface); - else - __connman_iface_up(iface); - state_changed(iface); + case CONNMAN_IFACE_POLICY_ASK: + __connman_iface_start(iface); break; default: @@ -236,13 +222,12 @@ static void switch_policy(struct connman_iface *iface) } } -void connman_iface_indicate_enabled(struct connman_iface *iface) +void connman_iface_indicate_ifup(struct connman_iface *iface) { DBG("iface %p state %d", iface, iface->state); switch (iface->state) { case CONNMAN_IFACE_STATE_OFF: - case CONNMAN_IFACE_STATE_CARRIER: iface->state = CONNMAN_IFACE_STATE_ENABLED; state_changed(iface); break; @@ -251,17 +236,13 @@ void connman_iface_indicate_enabled(struct connman_iface *iface) } } -void connman_iface_indicate_disabled(struct connman_iface *iface) +void connman_iface_indicate_ifdown(struct connman_iface *iface) { DBG("iface %p state %d", iface, iface->state); - if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) { + if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) iface->state = CONNMAN_IFACE_STATE_ENABLED; - if (iface->driver->start) - iface->driver->start(iface); - else - __connman_iface_up(iface); - } else + else iface->state = CONNMAN_IFACE_STATE_SHUTDOWN; state_changed(iface); @@ -305,13 +286,10 @@ void connman_iface_indicate_carrier_off(struct connman_iface *iface) case CONNMAN_IFACE_STATE_CARRIER: case CONNMAN_IFACE_STATE_CONFIGURE: case CONNMAN_IFACE_STATE_READY: -#if 0 - if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING) { - if (iface->driver->disconnect) - iface->driver->disconnect(iface); + __connman_iface_disconnect(iface); + if (iface->flags & CONNMAN_IFACE_FLAG_SCANNING) iface->state = CONNMAN_IFACE_STATE_SCANNING; - } else -#endif + else iface->state = CONNMAN_IFACE_STATE_ENABLED; state_changed(iface); break; @@ -378,8 +356,16 @@ void connman_iface_indicate_station(struct connman_iface *iface, dbus_connection_send(connection, signal, NULL); dbus_message_unref(signal); - if (iface->state != CONNMAN_IFACE_STATE_SCANNING) + switch (iface->state) { + case CONNMAN_IFACE_STATE_CONNECT: + case CONNMAN_IFACE_STATE_CONNECTED: + case CONNMAN_IFACE_STATE_CARRIER: + case CONNMAN_IFACE_STATE_CONFIGURE: + case CONNMAN_IFACE_STATE_READY: return; + default: + break; + } len = strlen(name); ssid = strdup(name); @@ -399,11 +385,10 @@ void connman_iface_indicate_station(struct connman_iface *iface, g_free(iface->network.passphrase); iface->network.passphrase = passphrase; - if (iface->driver->connect) { - iface->driver->connect(iface, &iface->network); - iface->state = CONNMAN_IFACE_STATE_CONNECT; - state_changed(iface); - } + __connman_iface_connect(iface, &iface->network); + + iface->state = CONNMAN_IFACE_STATE_CONNECT; + state_changed(iface); } free(ssid); @@ -577,11 +562,19 @@ static DBusMessage *scan_iface(DBusConnection *conn, if (reply == NULL) return NULL; + dbus_message_append_args(reply, DBUS_TYPE_INVALID); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_CONNECT: + case CONNMAN_IFACE_STATE_CONFIGURE: + return reply; + default: + break; + } + if (driver->scan) driver->scan(iface); - dbus_message_append_args(reply, DBUS_TYPE_INVALID); - return reply; } @@ -844,11 +837,7 @@ static DBusMessage *set_network(DBusConnection *conn, dbus_message_unref(signal); } - if (iface->driver->disconnect) - iface->driver->disconnect(iface); - - if (iface->driver->connect) - iface->driver->connect(iface, &iface->network); + __connman_iface_connect(iface, &iface->network); } return reply; @@ -869,11 +858,7 @@ static DBusMessage *select_network(DBusConnection *conn, g_free(iface->network.identifier); iface->network.identifier = g_strdup(network); - if (iface->driver->disconnect) - iface->driver->disconnect(iface); - - if (iface->driver->connect) - iface->driver->connect(iface, &iface->network); + __connman_iface_connect(iface, &iface->network); reply = dbus_message_new_method_return(msg); if (reply == NULL) @@ -1177,6 +1162,8 @@ static int probe_device(LibHalContext *ctx, iface->driver = driver; + iface->policy = CONNMAN_IFACE_POLICY_AUTO; + __connman_iface_load(iface); DBG("iface %p network %s secret %s", iface, @@ -1209,6 +1196,8 @@ static int probe_device(LibHalContext *ctx, switch_policy(iface); + state_changed(iface); + return 0; } diff --git a/src/rtnl.c b/src/rtnl.c index c4fbf44..b18465d 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -105,21 +105,25 @@ static void rtnl_link(struct nlmsghdr *hdr) return; if ((data->ifi_flags & IFF_RUNNING) != (msg->ifi_flags & IFF_RUNNING)) { - if (msg->ifi_flags & IFF_RUNNING) - connman_iface_indicate_carrier_on(iface); - else - connman_iface_indicate_carrier_off(iface); + if (!(iface->flags & CONNMAN_IFACE_FLAG_NOCARRIER)) { + if (msg->ifi_flags & IFF_RUNNING) + connman_iface_indicate_carrier_on(iface); + else + connman_iface_indicate_carrier_off(iface); + } } if ((data->ifi_flags & IFF_UP) != (msg->ifi_flags & IFF_UP)) { if (msg->ifi_flags & IFF_UP) - connman_iface_indicate_enabled(iface); + connman_iface_indicate_ifup(iface); else - connman_iface_indicate_disabled(iface); + connman_iface_indicate_ifdown(iface); } data->ifi_flags = msg->ifi_flags; + return; + for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { -- 2.7.4