From d3ad57f2adff903961edfdec45b60e5813107eff Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jan 2008 06:17:23 +0100 Subject: [PATCH] Add more detailed interface state machine --- include/iface.h | 33 ++++++----- plugins/supplicant.c | 3 +- src/dhcp.c | 13 ++--- src/iface-helper.c | 8 ++- src/iface.c | 154 +++++++++++++++++++++++++++++++++++++++++---------- src/rtnl.c | 49 +++++++++++----- 6 files changed, 189 insertions(+), 71 deletions(-) diff --git a/include/iface.h b/include/iface.h index 96e9c4f..57a4d72 100644 --- a/include/iface.h +++ b/include/iface.h @@ -48,11 +48,13 @@ enum connman_iface_state { CONNMAN_IFACE_STATE_UNKNOWN = 0, CONNMAN_IFACE_STATE_OFF = 1, CONNMAN_IFACE_STATE_ENABLED = 2, - CONNMAN_IFACE_STATE_CONNECT = 3, - CONNMAN_IFACE_STATE_CONFIG = 4, - CONNMAN_IFACE_STATE_CARRIER = 5, - CONNMAN_IFACE_STATE_READY = 6, - CONNMAN_IFACE_STATE_SHUTDOWN = 7, + CONNMAN_IFACE_STATE_SCANNING = 3, + CONNMAN_IFACE_STATE_CONNECT = 4, + CONNMAN_IFACE_STATE_CONNECTED = 5, + CONNMAN_IFACE_STATE_CARRIER = 6, + CONNMAN_IFACE_STATE_CONFIGURE = 7, + CONNMAN_IFACE_STATE_READY = 8, + CONNMAN_IFACE_STATE_SHUTDOWN = 9, }; enum connman_iface_policy { @@ -90,7 +92,6 @@ struct connman_iface { char *sysfs; char *identifier; int index; - int carrier; enum connman_iface_type type; enum connman_iface_flags flags; enum connman_iface_state state; @@ -101,6 +102,8 @@ struct connman_iface { struct connman_iface_driver *driver; void *driver_data; + void *rtnl_data; + struct { char *driver; char *vendor; @@ -113,12 +116,7 @@ struct connman_iface_driver { const char *capability; int (*probe) (struct connman_iface *iface); void (*remove) (struct connman_iface *iface); - int (*activate) (struct connman_iface *iface); - int (*shutdown) (struct connman_iface *iface); - int (*get_ipv4) (struct connman_iface *iface, - struct connman_ipv4 *ipv4); - int (*set_ipv4) (struct connman_iface *iface, - struct connman_ipv4 *ipv4); + int (*scan) (struct connman_iface *iface); int (*connect) (struct connman_iface *iface, struct connman_network *network); @@ -148,11 +146,12 @@ static inline void connman_iface_set_data(struct connman_iface *iface, iface->driver_data = data; } -extern int connman_iface_update(struct connman_iface *iface, - enum connman_iface_state state); - -extern void connman_iface_indicate_carrier(struct connman_iface *iface, - int carrier); +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_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); +extern void connman_iface_indicate_configured(struct connman_iface *iface); extern int connman_iface_get_ipv4(struct connman_iface *iface, struct connman_ipv4 *ipv4); diff --git a/plugins/supplicant.c b/plugins/supplicant.c index de74ce5..3c02abd 100644 --- a/plugins/supplicant.c +++ b/plugins/supplicant.c @@ -94,8 +94,7 @@ static gboolean control_event(GIOChannel *chan, if (g_str_has_prefix(buf + 3, "CTRL-EVENT-CONNECTED") == TRUE) { printf("[SUPPLICANT] connected\n"); - connman_iface_update(task->iface, - CONNMAN_IFACE_STATE_CARRIER); + connman_iface_indicate_connected(task->iface); } if (g_str_has_prefix(buf + 3, "CTRL-EVENT-DISCONNECTED") == TRUE) { diff --git a/src/dhcp.c b/src/dhcp.c index 3613224..ecf61f2 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -63,15 +63,10 @@ int connman_dhcp_update(struct connman_iface *iface, ipv4->method = CONNMAN_IPV4_METHOD_DHCP; - if (iface->driver->set_ipv4) { - iface->driver->set_ipv4(iface, ipv4); - iface->ipv4 = *ipv4; - } else { - connman_iface_set_ipv4(iface, ipv4); - iface->ipv4 = *ipv4; - } - - connman_iface_update(iface, CONNMAN_IFACE_STATE_READY); + connman_iface_set_ipv4(iface, ipv4); + iface->ipv4 = *ipv4; + + connman_iface_indicate_configured(iface); } return 0; diff --git a/src/iface-helper.c b/src/iface-helper.c index 4fe4b64..06642fb 100644 --- a/src/iface-helper.c +++ b/src/iface-helper.c @@ -56,12 +56,16 @@ const char *__connman_iface_state2string(enum connman_iface_state state) return "off"; case CONNMAN_IFACE_STATE_ENABLED: return "enabled"; + case CONNMAN_IFACE_STATE_SCANNING: + return "scanning"; case CONNMAN_IFACE_STATE_CONNECT: return "connect"; - case CONNMAN_IFACE_STATE_CONFIG: - return "config"; + case CONNMAN_IFACE_STATE_CONNECTED: + return "connected"; case CONNMAN_IFACE_STATE_CARRIER: return "carrier"; + case CONNMAN_IFACE_STATE_CONFIGURE: + return "configure"; case CONNMAN_IFACE_STATE_READY: return "ready"; case CONNMAN_IFACE_STATE_SHUTDOWN: diff --git a/src/iface.c b/src/iface.c index a6b0ba2..2e63866 100644 --- a/src/iface.c +++ b/src/iface.c @@ -95,51 +95,161 @@ void __connman_iface_list(DBusMessageIter *iter) } } -int connman_iface_update(struct connman_iface *iface, - enum connman_iface_state state) +static void state_changed(struct connman_iface *iface) { - const char *str; - - iface->state = state; + const char *str = __connman_iface_state2string(iface->state); + enum connman_iface_state state = iface->state; - str = __connman_iface_state2string(iface->state); + DBG("%s", str); g_dbus_emit_signal(connection, iface->path, CONNMAN_IFACE_INTERFACE, "StateChanged", DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); - switch (state) { + switch (iface->state) { case CONNMAN_IFACE_STATE_OFF: __connman_dhcp_release(iface); break; case CONNMAN_IFACE_STATE_ENABLED: if (iface->type == CONNMAN_IFACE_TYPE_80211) { - if (iface->driver->connect) + state = CONNMAN_IFACE_STATE_SCANNING; + if (iface->driver->connect) { iface->driver->connect(iface, NULL); + state = CONNMAN_IFACE_STATE_CONNECT; + } } break; case CONNMAN_IFACE_STATE_CARRIER: + if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) + state = CONNMAN_IFACE_STATE_CONFIGURE; + break; + + case CONNMAN_IFACE_STATE_CONFIGURE: __connman_dhcp_request(iface); break; case CONNMAN_IFACE_STATE_SHUTDOWN: __connman_dhcp_release(iface); - if (iface->driver->shutdown) - iface->driver->shutdown(iface); + if (iface->driver->disconnect) + iface->driver->disconnect(iface); + if (iface->policy != CONNMAN_IFACE_POLICY_AUTO) + state = CONNMAN_IFACE_STATE_OFF; break; default: break; } - return 0; + if (iface->state != state) { + iface->state = state; + state_changed(iface); + } +} + +static void switch_policy(struct connman_iface *iface) +{ + DBG("iface %p", iface); + + switch (iface->policy) { + case CONNMAN_IFACE_POLICY_OFF: + iface->state = CONNMAN_IFACE_STATE_SHUTDOWN; + state_changed(iface); + __connman_iface_down(iface); + break; + + case CONNMAN_IFACE_POLICY_IGNORE: + break; + + case CONNMAN_IFACE_POLICY_AUTO: + __connman_iface_up(iface); + break; + + default: + break; + } } -void connman_iface_indicate_carrier(struct connman_iface *iface, int carrier) +void connman_iface_indicate_enabled(struct connman_iface *iface) { - DBG("iface %p carrier %d", iface, carrier); + DBG("iface %p state %d", iface, iface->state); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_OFF: + iface->state = CONNMAN_IFACE_STATE_ENABLED; + state_changed(iface); + break; + default: + break; + } +} + +void connman_iface_indicate_disabled(struct connman_iface *iface) +{ + DBG("iface %p state %d", iface, iface->state); + + iface->state = CONNMAN_IFACE_STATE_SHUTDOWN; + state_changed(iface); +} + +void connman_iface_indicate_connected(struct connman_iface *iface) +{ + DBG("iface %p state %d", iface, iface->state); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_CONNECT: + iface->state = CONNMAN_IFACE_STATE_CONNECTED; + state_changed(iface); + break; + default: + break; + } +} + +void connman_iface_indicate_carrier_on(struct connman_iface *iface) +{ + DBG("iface %p state %d", iface, iface->state); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_ENABLED: + case CONNMAN_IFACE_STATE_CONNECT: + case CONNMAN_IFACE_STATE_CONNECTED: + iface->state = CONNMAN_IFACE_STATE_CARRIER; + state_changed(iface); + break; + default: + break; + } +} + +void connman_iface_indicate_carrier_off(struct connman_iface *iface) +{ + DBG("iface %p state %d", iface, iface->state); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_CONFIGURE: + case CONNMAN_IFACE_STATE_READY: + iface->state = CONNMAN_IFACE_STATE_ENABLED; + state_changed(iface); + break; + default: + break; + } +} + +void connman_iface_indicate_configured(struct connman_iface *iface) +{ + DBG("iface %p state %d", iface, iface->state); + + switch (iface->state) { + case CONNMAN_IFACE_STATE_CONFIGURE: + iface->state = CONNMAN_IFACE_STATE_READY; + state_changed(iface); + break; + default: + break; + } } int connman_iface_get_ipv4(struct connman_iface *iface, @@ -501,13 +611,7 @@ static DBusMessage *set_policy(DBusConnection *conn, iface->policy = new_policy; __connman_iface_store(iface); - if (new_policy == CONNMAN_IFACE_POLICY_AUTO) { - if (iface->driver->activate) - iface->driver->activate(iface); - } else - connman_iface_update(iface, - CONNMAN_IFACE_STATE_SHUTDOWN); - + switch_policy(iface); policy = __connman_iface_policy2string(new_policy); g_dbus_emit_signal(conn, iface->path, CONNMAN_IFACE_INTERFACE, @@ -908,10 +1012,7 @@ static int probe_device(LibHalContext *ctx, interfaces = g_slist_append(interfaces, iface); if (iface->flags & CONNMAN_IFACE_FLAG_IPV4) { - if (driver->get_ipv4) - driver->get_ipv4(iface, &iface->ipv4); - else - connman_iface_get_ipv4(iface, &iface->ipv4); + connman_iface_get_ipv4(iface, &iface->ipv4); DBG("address %s", inet_ntoa(iface->ipv4.address)); } @@ -928,10 +1029,7 @@ static int probe_device(LibHalContext *ctx, DBUS_TYPE_OBJECT_PATH, &iface->path, DBUS_TYPE_INVALID); - if (iface->policy == CONNMAN_IFACE_POLICY_AUTO) { - if (driver->activate) - driver->activate(iface); - } + switch_policy(iface); return 0; } diff --git a/src/rtnl.c b/src/rtnl.c index fd61d0d..3e26dbf 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -37,6 +37,21 @@ #include "connman.h" +struct rtnl_data { + unsigned ifi_flags; +}; + +static struct rtnl_data *get_rtnl_data(struct connman_iface *iface) +{ + if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0) + return NULL; + + if (iface->rtnl_data == NULL) + iface->rtnl_data = g_try_new0(struct rtnl_data, 1); + + return iface->rtnl_data; +} + static inline void print_inet(struct rtattr *attr, const char *name, int family) { if (family == AF_INET) { @@ -72,6 +87,7 @@ static inline void print_attr(struct rtattr *attr, const char *name) static void rtnl_link(struct nlmsghdr *hdr) { struct connman_iface *iface; + struct rtnl_data *data; struct ifinfomsg *msg; struct rtattr *attr; int bytes; @@ -85,17 +101,26 @@ static void rtnl_link(struct nlmsghdr *hdr) if (iface == NULL) return; - if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0) + data = get_rtnl_data(iface); + if (data == NULL) return; - if (iface->carrier != ((msg->ifi_flags & IFF_RUNNING) != 0)) { - iface->carrier = ((msg->ifi_flags & IFF_RUNNING) != 0); - if (iface->driver->rtnl_carrier) - iface->driver->rtnl_carrier(iface, iface->carrier); + 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(iface, iface->carrier); + 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); + else + connman_iface_indicate_disabled(iface); + } + + data->ifi_flags = msg->ifi_flags; + for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { @@ -162,6 +187,7 @@ static void rtnl_link(struct nlmsghdr *hdr) static void rtnl_addr(struct nlmsghdr *hdr) { struct connman_iface *iface; + struct rtnl_data *data; struct ifaddrmsg *msg; struct rtattr *attr; int bytes; @@ -175,7 +201,8 @@ static void rtnl_addr(struct nlmsghdr *hdr) if (iface == NULL) return; - if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0) + data = get_rtnl_data(iface); + if (data == NULL) return; for (attr = IFA_RTA(msg); RTA_OK(attr, bytes); @@ -328,10 +355,8 @@ static gboolean netlink_event(GIOChannel *chan, gsize len; GIOError err; - if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { - g_io_channel_unref(chan); + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) return FALSE; - } memset(buf, 0, sizeof(buf)); @@ -339,7 +364,6 @@ static gboolean netlink_event(GIOChannel *chan, if (err) { if (err == G_IO_ERROR_AGAIN) return TRUE; - g_io_channel_unref(chan); return FALSE; } @@ -394,8 +418,6 @@ int __connman_rtnl_init(void) G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, netlink_event, NULL); - g_io_channel_unref(channel); - return 0; } @@ -403,6 +425,7 @@ void __connman_rtnl_cleanup(void) { DBG(""); + g_io_channel_shutdown(channel, TRUE, NULL); g_io_channel_unref(channel); channel = NULL; -- 2.7.4