device: gracefully handle device names exceeding IFNAMESIZ
[project/netifd.git] / veth.c
1 /*
2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5 * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <net/ethernet.h>
22
23 #ifdef linux
24 #include <netinet/ether.h>
25 #endif
26
27 #include "netifd.h"
28 #include "device.h"
29 #include "interface.h"
30 #include "system.h"
31
32 enum {
33 VETH_ATTR_MACADDR,
34 VETH_ATTR_PEER_NAME,
35 VETH_ATTR_PEER_MACADDR,
36 __VETH_ATTR_MAX
37 };
38
39 static const struct blobmsg_policy veth_attrs[__VETH_ATTR_MAX] = {
40 [VETH_ATTR_MACADDR] = { "macaddr", BLOBMSG_TYPE_STRING },
41 [VETH_ATTR_PEER_NAME] = { "peer_name", BLOBMSG_TYPE_STRING },
42 [VETH_ATTR_PEER_MACADDR] = { "peer_macaddr", BLOBMSG_TYPE_STRING },
43 };
44
45 static const struct uci_blob_param_list veth_attr_list = {
46 .n_params = __VETH_ATTR_MAX,
47 .params = veth_attrs,
48
49 .n_next = 1,
50 .next = { &device_attr_list },
51 };
52
53 struct veth {
54 struct device dev;
55
56 device_state_cb set_state;
57
58 struct blob_attr *config_data;
59 struct veth_config config;
60 };
61
62 static int
63 veth_set_down(struct veth *veth)
64 {
65 veth->set_state(&veth->dev, false);
66 system_veth_del(&veth->dev);
67
68 return 0;
69 }
70
71 static int
72 veth_set_up(struct veth *veth)
73 {
74 int ret;
75
76 ret = system_veth_add(&veth->dev, &veth->config);
77 if (ret < 0)
78 return ret;
79
80 ret = veth->set_state(&veth->dev, true);
81 if (ret)
82 goto delete;
83
84 return 0;
85
86 delete:
87 system_veth_del(&veth->dev);
88 return ret;
89 }
90
91 static int
92 veth_set_state(struct device *dev, bool up)
93 {
94 struct veth *veth;
95
96 D(SYSTEM, "veth_set_state(%s, %u)\n", dev->ifname, up);
97
98 veth = container_of(dev, struct veth, dev);
99 if (up)
100 return veth_set_up(veth);
101 else
102 return veth_set_down(veth);
103 }
104
105 static void
106 veth_free(struct device *dev)
107 {
108 struct veth *veth;
109
110 veth = container_of(dev, struct veth, dev);
111 free(veth->config_data);
112 free(veth);
113 }
114
115 static void
116 veth_dump_info(struct device *dev, struct blob_buf *b)
117 {
118 struct veth *veth;
119
120 veth = container_of(dev, struct veth, dev);
121 if (veth->config.flags & VETH_OPT_PEER_NAME)
122 blobmsg_add_string(b, "peer", veth->config.peer_name);
123 system_if_dump_info(dev, b);
124 }
125
126 static void
127 veth_config_init(struct device *dev)
128 {
129 device_set_present(dev, true);
130 }
131
132 static void
133 veth_apply_settings(struct veth *veth, struct blob_attr **tb)
134 {
135 struct veth_config *cfg = &veth->config;
136 struct blob_attr *cur;
137 struct ether_addr *ea;
138
139 cfg->flags = 0;
140
141 if ((cur = tb[VETH_ATTR_MACADDR]))
142 {
143 ea = ether_aton(blobmsg_data(cur));
144 if (ea) {
145 memcpy(cfg->macaddr, ea, 6);
146 cfg->flags |= VETH_OPT_MACADDR;
147 }
148 }
149
150 if ((cur = tb[VETH_ATTR_PEER_NAME]))
151 {
152 strncpy(cfg->peer_name, blobmsg_get_string(cur), sizeof(cfg->peer_name)-1);
153 cfg->flags |= VETH_OPT_PEER_NAME;
154 }
155
156 if ((cur = tb[VETH_ATTR_PEER_MACADDR]))
157 {
158 ea = ether_aton(blobmsg_data(cur));
159 if (ea) {
160 memcpy(cfg->peer_macaddr, ea, 6);
161 cfg->flags |= VETH_OPT_PEER_MACADDR;
162 }
163 }
164 }
165
166 static enum dev_change_type
167 veth_reload(struct device *dev, struct blob_attr *attr)
168 {
169 struct blob_attr *tb_dev[__DEV_ATTR_MAX];
170 struct blob_attr *tb_mv[__VETH_ATTR_MAX];
171 enum dev_change_type ret = DEV_CONFIG_APPLIED;
172 struct veth *veth;
173
174 veth = container_of(dev, struct veth, dev);
175 attr = blob_memdup(attr);
176
177 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
178 blob_data(attr), blob_len(attr));
179 blobmsg_parse(veth_attrs, __VETH_ATTR_MAX, tb_mv,
180 blob_data(attr), blob_len(attr));
181
182 device_init_settings(dev, tb_dev);
183 veth_apply_settings(veth, tb_mv);
184
185 if (veth->config_data) {
186 struct blob_attr *otb_dev[__DEV_ATTR_MAX];
187 struct blob_attr *otb_mv[__VETH_ATTR_MAX];
188
189 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev,
190 blob_data(veth->config_data), blob_len(veth->config_data));
191
192 if (uci_blob_diff(tb_dev, otb_dev, &device_attr_list, NULL))
193 ret = DEV_CONFIG_RESTART;
194
195 blobmsg_parse(veth_attrs, __VETH_ATTR_MAX, otb_mv,
196 blob_data(veth->config_data), blob_len(veth->config_data));
197
198 if (uci_blob_diff(tb_mv, otb_mv, &veth_attr_list, NULL))
199 ret = DEV_CONFIG_RESTART;
200
201 veth_config_init(dev);
202 }
203
204 free(veth->config_data);
205 veth->config_data = attr;
206 return ret;
207 }
208
209 static struct device *
210 veth_create(const char *name, struct device_type *devtype,
211 struct blob_attr *attr)
212 {
213 struct veth *veth;
214 struct device *dev = NULL;
215
216 veth = calloc(1, sizeof(*veth));
217 if (!veth)
218 return NULL;
219
220 dev = &veth->dev;
221 if (device_init(dev, devtype, name) < 0) {
222 device_cleanup(dev);
223 free(veth);
224 return NULL;
225 }
226
227 dev->config_pending = true;
228
229 veth->set_state = dev->set_state;
230 dev->set_state = veth_set_state;
231
232 dev->hotplug_ops = NULL;
233
234 veth_reload(dev, attr);
235
236 return dev;
237 }
238
239 static struct device_type veth_device_type = {
240 .name = "veth",
241 .config_params = &veth_attr_list,
242 .create = veth_create,
243 .config_init = veth_config_init,
244 .reload = veth_reload,
245 .free = veth_free,
246 .dump_info = veth_dump_info,
247 };
248
249 static void __init veth_device_type_init(void)
250 {
251 device_type_add(&veth_device_type);
252 }