add rudimentary protocol handling
authorFelix Fietkau <nbd@openwrt.org>
Mon, 28 Mar 2011 23:16:59 +0000 (01:16 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 28 Mar 2011 23:16:59 +0000 (01:16 +0200)
CMakeLists.txt
interface.c
interface.h
proto.c [new file with mode: 0644]
proto.h [new file with mode: 0644]
ubus.c

index 262ee3b..496e9d5 100644 (file)
@@ -9,5 +9,5 @@ IF(DEBUG)
   ADD_DEFINITIONS(-DDEBUG -O0)
 ENDIF()
 
-ADD_EXECUTABLE(netifd main.c interface.c config.c device.c bridge.c vlan.c ubus.c system-dummy.c)
+ADD_EXECUTABLE(netifd main.c interface.c proto.c config.c device.c bridge.c vlan.c ubus.c system-dummy.c)
 TARGET_LINK_LIBRARIES(netifd ubox ubus uci)
index 0aa0b0d..78cfe12 100644 (file)
@@ -3,9 +3,10 @@
 #include <stdio.h>
 
 #include "netifd.h"
+#include "proto.h"
 #include "ubus.h"
 
-LIST_HEAD(interfaces);
+static LIST_HEAD(interfaces);
 
 static void
 clear_interface_errors(struct interface *iface)
@@ -52,42 +53,51 @@ void interface_add_error(struct interface *iface, const char *subsystem,
        error->data[n_data] = NULL;
 }
 
-static int
+static void
 interface_event(struct interface *iface, enum interface_event ev)
 {
-       if (!iface->state || !iface->state->event)
-               return 0;
-
-       return iface->state->event(iface->state, ev);
+       /* TODO */
 }
 
-static void
+static int
 __set_interface_up(struct interface *iface)
 {
-       if (iface->up)
-               return;
+       int ret;
 
-       if (claim_device(iface->main_dev.dev) < 0)
-               return;
+       if (iface->state != IFS_DOWN)
+               return 0;
 
-       if (interface_event(iface, IFEV_UP) < 0) {
-               release_device(iface->main_dev.dev);
-               return;
-       }
+       ret = claim_device(iface->main_dev.dev);
+       if (ret)
+               goto out;
+
+       iface->state = IFS_SETUP;
+       ret = iface->proto->handler(iface->proto, PROTO_CMD_SETUP, false);
+       if (ret)
+               goto release;
 
-       iface->up = true;
+       return 0;
+
+release:
+       release_device(iface->main_dev.dev);
+out:
+       iface->state = IFS_DOWN;
+       return ret;
 }
 
 static void
-__set_interface_down(struct interface *iface)
+__set_interface_down(struct interface *iface, bool force)
 {
        clear_interface_errors(iface);
 
-       if (!iface->up)
+       if (iface->state == IFS_DOWN ||
+               iface->state == IFS_TEARDOWN)
                return;
 
-       iface->up = false;
+       iface->state = IFS_TEARDOWN;
        interface_event(iface, IFEV_DOWN);
+
+       iface->proto->handler(iface->proto, PROTO_CMD_TEARDOWN, force);
        release_device(iface->main_dev.dev);
 }
 
@@ -116,9 +126,44 @@ interface_cb(struct device_user *dep, enum device_event ev)
 
        if (new_state) {
                if (iface->autostart)
-                       __set_interface_up(iface);
+                       set_interface_up(iface);
        } else
-               __set_interface_down(iface);
+               __set_interface_down(iface, true);
+}
+
+static void
+interface_proto_cb(struct interface_proto_state *state, enum interface_proto_event ev)
+{
+       struct interface *iface = state->iface;
+
+       switch (ev) {
+       case IFPEV_UP:
+               if (iface->state != IFS_SETUP)
+                       return;
+
+               iface->state = IFS_UP;
+               interface_event(iface, IFEV_UP);
+               break;
+       case IFPEV_DOWN:
+               iface->state = IFS_DOWN;
+               break;
+       }
+}
+
+void interface_set_proto_state(struct interface *iface, struct interface_proto_state *state)
+{
+       if (iface->proto) {
+               iface->proto->handler(iface->proto, PROTO_CMD_TEARDOWN, true);
+               iface->proto->free(iface->proto);
+               iface->proto = NULL;
+       }
+       iface->state = IFS_DOWN;
+       iface->proto = state;
+       if (!state)
+               return;
+
+       state->proto_event = interface_proto_cb;
+       state->iface = iface;
 }
 
 struct interface *
@@ -131,6 +176,13 @@ alloc_interface(const char *name)
                return iface;
 
        iface = calloc(1, sizeof(*iface));
+
+       interface_set_proto_state(iface, get_default_proto());
+       if (!iface->proto) {
+               free(iface);
+               return NULL;
+       }
+
        iface->main_dev.cb = interface_cb;
        iface->l3_iface = &iface->main_dev;
        strncpy(iface->name, name, sizeof(iface->name) - 1);
@@ -147,8 +199,8 @@ free_interface(struct interface *iface)
 {
        netifd_ubus_remove_interface(iface);
        list_del(&iface->list);
-       if (iface->state && iface->state->free)
-               iface->state->free(iface->state);
+       if (iface->proto->free)
+               iface->proto->free(iface->proto);
        free(iface);
 }
 
@@ -203,18 +255,17 @@ set_interface_up(struct interface *iface)
                return -1;
        }
 
-       if (iface->up)
-               return -1;
+       if (iface->state != IFS_DOWN)
+               return 0;
 
-       __set_interface_up(iface);
-       return 0;
+       return __set_interface_up(iface);
 }
 
 int
 set_interface_down(struct interface *iface)
 {
        iface->autostart = false;
-       __set_interface_down(iface);
+       __set_interface_down(iface, false);
 
        return 0;
 }
index dd72389..87a7cb3 100644 (file)
@@ -2,31 +2,18 @@
 #define __NETIFD_INTERFACE_H
 
 struct interface;
-struct interface_proto;
 struct interface_proto_state;
 
-extern struct list_head interfaces;
-
 enum interface_event {
        IFEV_UP,
        IFEV_DOWN,
 };
 
-enum interface_proto_event {
-       PROTO_UP,
-       PROTO_DOWN,
-};
-
-struct interface_proto_state {
-       struct interface *iface;
-       const struct interface_proto *proto;
-
-       /* filled in by the protocol user */
-       int (*proto_event)(struct interface_proto_state *, enum interface_proto_event ev);
-
-       /* filled in by the protocol handler */
-       int (*event)(struct interface_proto_state *, enum interface_event ev);
-       void (*free)(struct interface_proto_state *);
+enum interface_state {
+       IFS_SETUP,
+       IFS_UP,
+       IFS_TEARDOWN,
+       IFS_DOWN,
 };
 
 struct interface_error {
@@ -45,10 +32,11 @@ struct interface {
 
        char name[IFNAMSIZ];
 
-       bool up;
        bool active;
        bool autostart;
 
+       enum interface_state state;
+
        /* main interface that the interface is bound to */
        struct device_user main_dev;
 
@@ -56,7 +44,7 @@ struct interface {
        struct device_user *l3_iface;
 
        /* primary protocol state */
-       struct interface_proto_state *state;
+       struct interface_proto_state *proto;
 
        /* errors/warnings while trying to bring up the interface */
        struct list_head errors;
diff --git a/proto.c b/proto.c
new file mode 100644 (file)
index 0000000..a345b35
--- /dev/null
+++ b/proto.c
@@ -0,0 +1,42 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "netifd.h"
+#include "proto.h"
+
+static void
+default_proto_free(struct interface_proto_state *proto)
+{
+       free(proto);
+}
+
+static int
+default_proto_handler(struct interface_proto_state *proto,
+                     enum interface_proto_cmd cmd, bool force)
+{
+       enum interface_event ev;
+
+       switch(cmd) {
+       case PROTO_CMD_SETUP:
+               ev = IFEV_UP;
+               break;
+       case PROTO_CMD_TEARDOWN:
+               ev = IFEV_DOWN;
+               break;
+       default:
+               return -EINVAL;
+       }
+       proto->proto_event(proto, ev);
+       return 0;
+}
+
+struct interface_proto_state *get_default_proto(void)
+{
+       struct interface_proto_state *proto;
+
+       proto = calloc(1, sizeof(*proto));
+       proto->handler = default_proto_handler;
+       proto->free = default_proto_free;
+       return proto;
+}
diff --git a/proto.h b/proto.h
new file mode 100644 (file)
index 0000000..92cef01
--- /dev/null
+++ b/proto.h
@@ -0,0 +1,29 @@
+#ifndef __NETIFD_PROTO_H
+#define __NETIFD_PROTO_H
+
+struct interface_proto_state;
+
+enum interface_proto_event {
+       IFPEV_UP,
+       IFPEV_DOWN,
+};
+
+enum interface_proto_cmd {
+       PROTO_CMD_SETUP,
+       PROTO_CMD_TEARDOWN,
+};
+
+struct interface_proto_state {
+       struct interface *iface;
+
+       /* filled in by the protocol user */
+       void (*proto_event)(struct interface_proto_state *, enum interface_proto_event ev);
+
+       /* filled in by the protocol handler */
+       int (*handler)(struct interface_proto_state *, enum interface_proto_cmd cmd, bool force);
+       void (*free)(struct interface_proto_state *);
+};
+
+struct interface_proto_state *get_default_proto(void);
+
+#endif
diff --git a/ubus.c b/ubus.c
index 159d5f5..e5df1fb 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -138,12 +138,18 @@ static int netifd_handle_status(struct ubus_context *ctx, struct ubus_object *ob
                                struct ubus_request_data *req, const char *method,
                                struct blob_attr *msg)
 {
+       static const char *iface_state[] = {
+               [IFS_SETUP] = "setup",
+               [IFS_UP] = "up",
+               [IFS_TEARDOWN] = "teardown",
+               [IFS_DOWN] = "down",
+       };
        struct interface *iface;
 
        iface = container_of(obj, struct interface, ubus);
 
        blob_buf_init(&b, 0);
-       blobmsg_add_u8(&b, "up", iface->up);
+       blobmsg_add_string(&b, "state", iface_state[iface->state]);
        blobmsg_add_u8(&b, "active", iface->active);
        blobmsg_add_u8(&b, "autostart", iface->autostart);
        if (iface->main_dev.dev) {