add an install target
[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, astr, 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_proto_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 = IFPEV_UP;
182                 break;
183         case PROTO_CMD_TEARDOWN:
184                 ev = IFPEV_DOWN;
185                 break;
186         default:
187                 return -EINVAL;
188         }
189         proto->proto_event(proto, ev);
190
191 out:
192         return ret;
193 }