From d5202486636818e3ff48ede9d3e06c886c659c0a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 29 Mar 2011 01:16:59 +0200 Subject: [PATCH] add rudimentary protocol handling --- CMakeLists.txt | 2 +- interface.c | 107 ++++++++++++++++++++++++++++++++++++++++++--------------- interface.h | 28 +++++---------- proto.c | 42 ++++++++++++++++++++++ proto.h | 29 ++++++++++++++++ ubus.c | 8 ++++- 6 files changed, 166 insertions(+), 50 deletions(-) create mode 100644 proto.c create mode 100644 proto.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 262ee3b..496e9d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/interface.c b/interface.c index 0aa0b0d..78cfe12 100644 --- a/interface.c +++ b/interface.c @@ -3,9 +3,10 @@ #include #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; } diff --git a/interface.h b/interface.h index dd72389..87a7cb3 100644 --- a/interface.h +++ b/interface.h @@ -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 index 0000000..a345b35 --- /dev/null +++ b/proto.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#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 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 --- 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) { -- 2.11.0