Add more detailed interface state machine
authorMarcel Holtmann <marcel@holtmann.org>
Mon, 14 Jan 2008 05:17:23 +0000 (06:17 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Mon, 14 Jan 2008 05:17:23 +0000 (06:17 +0100)
include/iface.h
plugins/supplicant.c
src/dhcp.c
src/iface-helper.c
src/iface.c
src/rtnl.c

index 96e9c4f..57a4d72 100644 (file)
@@ -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);
index de74ce5..3c02abd 100644 (file)
@@ -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) {
index 3613224..ecf61f2 100644 (file)
@@ -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;
index 4fe4b64..06642fb 100644 (file)
@@ -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:
index a6b0ba2..2e63866 100644 (file)
@@ -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;
 }
index fd61d0d..3e26dbf 100644 (file)
 
 #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;