s/init_virtual_device/device_init_virtual/
[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 }