only use -g3 with -DDEBUG
[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, struct blob_attr *attr)
46 {
47         struct interface_proto_state *proto;
48
49         proto = calloc(1, sizeof(*proto));
50         proto->free = default_proto_free;
51         proto->cb = no_proto_handler;
52
53         return proto;
54 }
55
56 static const struct proto_handler no_proto = {
57         .name = "none",
58         .flags = PROTO_FLAG_IMMEDIATE,
59         .attach = default_proto_attach,
60 };
61
62 static const struct proto_handler *
63 get_proto_handler(const char *name)
64 {
65         struct proto_handler *proto;
66
67         if (!strcmp(name, "none"))
68             return &no_proto;
69
70         if (!handlers.comp)
71                 return NULL;
72
73         return avl_find_element(&handlers, name, proto, avl);
74 }
75
76 void
77 proto_init_interface(struct interface *iface, struct blob_attr *attr)
78 {
79         const struct proto_handler *proto = iface->proto_handler;
80         struct interface_proto_state *state = NULL;
81
82         if (proto)
83                 state = proto->attach(proto, iface, attr);
84
85         if (!state) {
86                 state = no_proto.attach(&no_proto, iface, attr);
87                 state->cb = invalid_proto_handler;
88         }
89
90         state->handler = proto;
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->cb(proto, cmd, force);
119         if (ret || !(proto->handler->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 }