add a section pointer to the proto attach callback
[project/netifd.git] / proto.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include "netifd.h"
6 #include "interface.h"
7 #include "proto.h"
8
9 static struct avl_tree handlers;
10
11 void add_proto_handler(struct proto_handler *p)
12 {
13         if (!handlers.comp)
14                 avl_init(&handlers, avl_strcmp, false, NULL);
15
16         if (p->avl.key)
17                 return;
18
19         p->avl.key = p->name;
20         avl_insert(&handlers, &p->avl);
21 }
22
23 static void
24 default_proto_free(struct interface_proto_state *proto)
25 {
26         free(proto);
27 }
28
29 static int
30 invalid_proto_handler(struct interface_proto_state *proto,
31                       enum interface_proto_cmd cmd, bool force)
32 {
33         return -1;
34 }
35
36 static int
37 no_proto_handler(struct interface_proto_state *proto,
38                       enum interface_proto_cmd cmd, bool force)
39 {
40         return 0;
41 }
42
43 static struct interface_proto_state *get_default_proto(void)
44 {
45         struct interface_proto_state *proto;
46
47         proto = calloc(1, sizeof(*proto));
48         proto->free = default_proto_free;
49         proto->flags = PROTO_FLAG_IMMEDIATE;
50
51         return proto;
52 }
53
54 void proto_attach_interface(struct interface *iface, struct uci_section *s)
55 {
56         struct interface_proto_state *state = NULL;
57         struct proto_handler *proto = NULL;
58         const char *proto_name;
59         const char *error = NULL;
60
61         proto_name = uci_lookup_option_string(uci_ctx, s, "proto");
62         if (!proto_name) {
63                 error = "NO_PROTO";
64                 goto error;
65         }
66
67         if (!strcmp(proto_name, "none")) {
68                 state = get_default_proto();
69                 state->handler = no_proto_handler;
70                 goto out;
71         }
72
73         if (handlers.comp)
74                 proto = avl_find_element(&handlers, proto_name, proto, avl);
75
76         if (!proto) {
77                 error = "INVALID_PROTO";
78                 goto error;
79         }
80
81         state = proto->attach(proto, iface, s);
82
83 error:
84         if (error) {
85                 interface_add_error(iface, "proto", error, NULL, 0);
86                 state = get_default_proto();
87                 state->handler = invalid_proto_handler;
88         }
89
90 out:
91         interface_set_proto_state(iface, state);
92 }
93
94
95 int interface_proto_event(struct interface_proto_state *proto,
96                           enum interface_proto_cmd cmd, bool force)
97 {
98         enum interface_event ev;
99         int ret;
100
101         ret = proto->handler(proto, cmd, force);
102         if (ret || !(proto->flags & PROTO_FLAG_IMMEDIATE))
103                 goto out;
104
105         switch(cmd) {
106         case PROTO_CMD_SETUP:
107                 ev = IFEV_UP;
108                 break;
109         case PROTO_CMD_TEARDOWN:
110                 ev = IFEV_DOWN;
111                 break;
112         default:
113                 return -EINVAL;
114         }
115         proto->proto_event(proto, ev);
116
117 out:
118         return ret;
119 }