directly pass the device name to the device create function
[project/netifd.git] / proto.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7
8 #include "netifd.h"
9 #include "interface.h"
10 #include "interface-ip.h"
11 #include "proto.h"
12
13 static struct avl_tree handlers;
14
15 unsigned int
16 parse_netmask_string(const char *str, bool v6)
17 {
18 struct in_addr addr;
19 unsigned int ret;
20 char *err = NULL;
21
22 if (!strchr(str, '.')) {
23 ret = strtoul(str, &err, 0);
24 if (err && *err)
25 goto error;
26
27 return ret;
28 }
29
30 if (v6)
31 goto error;
32
33 if (inet_aton(str, &addr) != 1)
34 goto error;
35
36 return 32 - fls(~(ntohl(addr.s_addr)));
37
38 error:
39 return ~0;
40 }
41
42 static bool
43 split_netmask(char *str, unsigned int *netmask, bool v6)
44 {
45 char *delim = strchr(str, '/');
46
47 if (delim) {
48 *(delim++) = 0;
49
50 *netmask = parse_netmask_string(delim, v6);
51 }
52 return true;
53 }
54
55 static int
56 parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask)
57 {
58 char *astr = alloca(strlen(str) + 1);
59
60 strcpy(astr, str);
61 if (!split_netmask(astr, netmask, af == AF_INET6))
62 return 0;
63
64 if (af == AF_INET6) {
65 if (*netmask > 128)
66 return 0;
67 } else {
68 if (*netmask > 32)
69 return 0;
70 }
71
72 return inet_pton(af, astr, addr);
73 }
74
75 struct device_addr *
76 proto_parse_ip_addr_string(const char *str, bool v6, int mask)
77 {
78 struct device_addr *addr;
79 int af = v6 ? AF_INET6 : AF_INET;
80
81 addr = calloc(1, sizeof(*addr));
82 addr->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
83 addr->mask = mask;
84 if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) {
85 free(addr);
86 return NULL;
87 }
88 return addr;
89 }
90
91
92 void add_proto_handler(struct proto_handler *p)
93 {
94 if (!handlers.comp)
95 avl_init(&handlers, avl_strcmp, false, NULL);
96
97 if (p->avl.key)
98 return;
99
100 p->avl.key = p->name;
101 avl_insert(&handlers, &p->avl);
102 }
103
104 static void
105 default_proto_free(struct interface_proto_state *proto)
106 {
107 free(proto);
108 }
109
110 static int
111 invalid_proto_handler(struct interface_proto_state *proto,
112 enum interface_proto_cmd cmd, bool force)
113 {
114 return -1;
115 }
116
117 static int
118 no_proto_handler(struct interface_proto_state *proto,
119 enum interface_proto_cmd cmd, bool force)
120 {
121 return 0;
122 }
123
124 static struct interface_proto_state *
125 default_proto_attach(const struct proto_handler *h,
126 struct interface *iface, struct blob_attr *attr)
127 {
128 struct interface_proto_state *proto;
129
130 proto = calloc(1, sizeof(*proto));
131 proto->free = default_proto_free;
132 proto->cb = no_proto_handler;
133
134 return proto;
135 }
136
137 static const struct proto_handler no_proto = {
138 .name = "none",
139 .flags = PROTO_FLAG_IMMEDIATE,
140 .attach = default_proto_attach,
141 };
142
143 static const struct proto_handler *
144 get_proto_handler(const char *name)
145 {
146 struct proto_handler *proto;
147
148 if (!strcmp(name, "none"))
149 return &no_proto;
150
151 if (!handlers.comp)
152 return NULL;
153
154 return avl_find_element(&handlers, name, proto, avl);
155 }
156
157 void
158 proto_init_interface(struct interface *iface, struct blob_attr *attr)
159 {
160 const struct proto_handler *proto = iface->proto_handler;
161 struct interface_proto_state *state = NULL;
162
163 if (proto)
164 state = proto->attach(proto, iface, attr);
165
166 if (!state) {
167 state = no_proto.attach(&no_proto, iface, attr);
168 state->cb = invalid_proto_handler;
169 }
170
171 state->handler = proto;
172 interface_set_proto_state(iface, state);
173 }
174
175 void
176 proto_attach_interface(struct interface *iface, const char *proto_name)
177 {
178 const struct proto_handler *proto = NULL;
179
180 if (!proto_name) {
181 interface_add_error(iface, "proto", "NO_PROTO", NULL, 0);
182 return;
183 }
184
185 proto = get_proto_handler(proto_name);
186 if (!proto)
187 interface_add_error(iface, "proto", "INVALID_PROTO", NULL, 0);
188
189 iface->proto_handler = proto;
190 }
191
192 int
193 interface_proto_event(struct interface_proto_state *proto,
194 enum interface_proto_cmd cmd, bool force)
195 {
196 enum interface_proto_event ev;
197 int ret;
198
199 ret = proto->cb(proto, cmd, force);
200 if (ret || !(proto->handler->flags & PROTO_FLAG_IMMEDIATE))
201 goto out;
202
203 switch(cmd) {
204 case PROTO_CMD_SETUP:
205 ev = IFPEV_UP;
206 break;
207 case PROTO_CMD_TEARDOWN:
208 ev = IFPEV_DOWN;
209 break;
210 default:
211 return -EINVAL;
212 }
213 proto->proto_event(proto, ev);
214
215 out:
216 return ret;
217 }