implement uci-to-blobmsg conversion as an abstraction between uci and the rest of...
[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 *
44 get_default_proto(void)
45 {
46 struct interface_proto_state *proto;
47
48 proto = calloc(1, sizeof(*proto));
49 proto->free = default_proto_free;
50 proto->flags = PROTO_FLAG_IMMEDIATE;
51
52 return proto;
53 }
54
55 struct proto_handler *
56 get_proto_handler(const char *name)
57 {
58 struct proto_handler *proto;
59
60 if (!handlers.comp)
61 return NULL;
62
63 return avl_find_element(&handlers, name, proto, avl);
64 }
65
66 void
67 proto_attach_interface(struct interface *iface, struct uci_section *s)
68 {
69 struct interface_proto_state *state = NULL;
70 struct proto_handler *proto = NULL;
71 const char *proto_name;
72 const char *error = NULL;
73
74 proto_name = uci_lookup_option_string(uci_ctx, s, "proto");
75 if (!proto_name) {
76 error = "NO_PROTO";
77 goto error;
78 }
79
80 if (!strcmp(proto_name, "none")) {
81 state = get_default_proto();
82 state->handler = no_proto_handler;
83 goto out;
84 }
85
86 proto = get_proto_handler(proto_name);
87 if (!proto) {
88 error = "INVALID_PROTO";
89 goto error;
90 }
91
92 state = proto->attach(proto, iface, s);
93
94 error:
95 if (error) {
96 interface_add_error(iface, "proto", error, NULL, 0);
97 state = get_default_proto();
98 state->handler = invalid_proto_handler;
99 }
100
101 out:
102 interface_set_proto_state(iface, state);
103 }
104
105
106 int
107 interface_proto_event(struct interface_proto_state *proto,
108 enum interface_proto_cmd cmd, bool force)
109 {
110 enum interface_event ev;
111 int ret;
112
113 ret = proto->handler(proto, cmd, force);
114 if (ret || !(proto->flags & PROTO_FLAG_IMMEDIATE))
115 goto out;
116
117 switch(cmd) {
118 case PROTO_CMD_SETUP:
119 ev = IFEV_UP;
120 break;
121 case PROTO_CMD_TEARDOWN:
122 ev = IFEV_DOWN;
123 break;
124 default:
125 return -EINVAL;
126 }
127 proto->proto_event(proto, ev);
128
129 out:
130 return ret;
131 }