99f083c60025c045897387c9febd29c8249667f0
[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 static bool
16 split_netmask(char *str, unsigned int *netmask)
17 {
18 char *delim, *err = NULL;
19
20 delim = strchr(str, '/');
21 if (delim) {
22 *(delim++) = 0;
23
24 *netmask = strtoul(delim, &err, 10);
25 if (err && *err)
26 return false;
27 }
28 return true;
29 }
30
31 static int
32 parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask)
33 {
34 char *astr = alloca(strlen(str) + 1);
35
36 strcpy(astr, str);
37 if (!split_netmask(astr, netmask))
38 return 0;
39
40 if (af == AF_INET6) {
41 if (*netmask > 128)
42 return 0;
43 } else {
44 if (*netmask > 32)
45 return 0;
46 }
47
48 return inet_pton(af, str, addr);
49 }
50
51 struct device_addr *
52 proto_parse_ip_addr_string(const char *str, bool v6, int mask)
53 {
54 struct device_addr *addr;
55 int af = v6 ? AF_INET6 : AF_INET;
56
57 addr = calloc(1, sizeof(*addr));
58 addr->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
59 addr->mask = mask;
60 if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) {
61 free(addr);
62 return NULL;
63 }
64 return addr;
65 }
66
67
68 void add_proto_handler(struct proto_handler *p)
69 {
70 if (!handlers.comp)
71 avl_init(&handlers, avl_strcmp, false, NULL);
72
73 if (p->avl.key)
74 return;
75
76 p->avl.key = p->name;
77 avl_insert(&handlers, &p->avl);
78 }
79
80 static void
81 default_proto_free(struct interface_proto_state *proto)
82 {
83 free(proto);
84 }
85
86 static int
87 invalid_proto_handler(struct interface_proto_state *proto,
88 enum interface_proto_cmd cmd, bool force)
89 {
90 return -1;
91 }
92
93 static int
94 no_proto_handler(struct interface_proto_state *proto,
95 enum interface_proto_cmd cmd, bool force)
96 {
97 return 0;
98 }
99
100 static struct interface_proto_state *
101 default_proto_attach(const struct proto_handler *h,
102 struct interface *iface, struct blob_attr *attr)
103 {
104 struct interface_proto_state *proto;
105
106 proto = calloc(1, sizeof(*proto));
107 proto->free = default_proto_free;
108 proto->cb = no_proto_handler;
109
110 return proto;
111 }
112
113 static const struct proto_handler no_proto = {
114 .name = "none",
115 .flags = PROTO_FLAG_IMMEDIATE,
116 .attach = default_proto_attach,
117 };
118
119 static const struct proto_handler *
120 get_proto_handler(const char *name)
121 {
122 struct proto_handler *proto;
123
124 if (!strcmp(name, "none"))
125 return &no_proto;
126
127 if (!handlers.comp)
128 return NULL;
129
130 return avl_find_element(&handlers, name, proto, avl);
131 }
132
133 void
134 proto_init_interface(struct interface *iface, struct blob_attr *attr)
135 {
136 const struct proto_handler *proto = iface->proto_handler;
137 struct interface_proto_state *state = NULL;
138
139 if (proto)
140 state = proto->attach(proto, iface, attr);
141
142 if (!state) {
143 state = no_proto.attach(&no_proto, iface, attr);
144 state->cb = invalid_proto_handler;
145 }
146
147 state->handler = proto;
148 interface_set_proto_state(iface, state);
149 }
150
151 void
152 proto_attach_interface(struct interface *iface, const char *proto_name)
153 {
154 const struct proto_handler *proto = NULL;
155
156 if (!proto_name) {
157 interface_add_error(iface, "proto", "NO_PROTO", NULL, 0);
158 return;
159 }
160
161 proto = get_proto_handler(proto_name);
162 if (!proto)
163 interface_add_error(iface, "proto", "INVALID_PROTO", NULL, 0);
164
165 iface->proto_handler = proto;
166 }
167
168 int
169 interface_proto_event(struct interface_proto_state *proto,
170 enum interface_proto_cmd cmd, bool force)
171 {
172 enum interface_event ev;
173 int ret;
174
175 ret = proto->cb(proto, cmd, force);
176 if (ret || !(proto->handler->flags & PROTO_FLAG_IMMEDIATE))
177 goto out;
178
179 switch(cmd) {
180 case PROTO_CMD_SETUP:
181 ev = IFEV_UP;
182 break;
183 case PROTO_CMD_TEARDOWN:
184 ev = IFEV_DOWN;
185 break;
186 default:
187 return -EINVAL;
188 }
189 proto->proto_event(proto, ev);
190
191 out:
192 return ret;
193 }