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