1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2014 Gioacchino Mazzurco <gio@eigenlab.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 7 * as published by the Free Software Foundation 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #include <string.h> 16 #include <inttypes.h> 17 18 #include "netifd.h" 19 #include "device.h" 20 #include "interface.h" 21 #include "system.h" 22 #include "utils.h" 23 24 enum { 25 VLANDEV_ATTR_IFNAME, 26 VLANDEV_ATTR_VID, 27 VLANDEV_ATTR_INGRESS_QOS_MAPPING, 28 VLANDEV_ATTR_EGRESS_QOS_MAPPING, 29 __VLANDEV_ATTR_MAX 30 }; 31 32 static const struct blobmsg_policy vlandev_attrs[__VLANDEV_ATTR_MAX] = { 33 [VLANDEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_STRING }, 34 [VLANDEV_ATTR_VID] = { "vid", BLOBMSG_TYPE_STRING }, 35 [VLANDEV_ATTR_INGRESS_QOS_MAPPING] = { "ingress_qos_mapping", BLOBMSG_TYPE_ARRAY }, 36 [VLANDEV_ATTR_EGRESS_QOS_MAPPING] = { "egress_qos_mapping", BLOBMSG_TYPE_ARRAY }, 37 }; 38 39 static const struct uci_blob_param_list vlandev_attr_list = { 40 .n_params = __VLANDEV_ATTR_MAX, 41 .params = vlandev_attrs, 42 43 .n_next = 1, 44 .next = { &device_attr_list }, 45 }; 46 47 static struct device_type vlan8021q_device_type; 48 static struct blob_buf b; 49 50 struct vlandev_device { 51 struct device dev; 52 struct device_user parent; 53 54 device_state_cb set_state; 55 56 struct blob_attr *config_data; 57 struct blob_attr *ifname; 58 struct blob_attr *vid; 59 60 struct vlandev_config config; 61 }; 62 63 static int 64 __vlandev_hotplug_op(struct device *dev, struct device *member, struct blob_attr *vlan, bool add) 65 { 66 struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev); 67 void *a; 68 69 dev = mvdev->parent.dev; 70 if (!dev || !dev->hotplug_ops) 71 return UBUS_STATUS_NOT_SUPPORTED; 72 73 blob_buf_init(&b, 0); 74 a = blobmsg_open_array(&b, "vlans"); 75 blobmsg_printf(&b, NULL, "%d", mvdev->config.vid); 76 blobmsg_close_array(&b, a); 77 78 if (add) 79 return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); 80 else 81 return dev->hotplug_ops->del(dev, member, blobmsg_data(b.head)); 82 } 83 84 static int 85 vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) 86 { 87 return __vlandev_hotplug_op(dev, member, vlan, true); 88 } 89 90 static int 91 vlandev_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) 92 { 93 return __vlandev_hotplug_op(dev, member, vlan, false); 94 } 95 96 static int 97 vlandev_hotplug_prepare(struct device *dev, struct device **bridge_dev) 98 { 99 struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev); 100 101 dev = mvdev->parent.dev; 102 if (!dev || !dev->hotplug_ops) 103 return UBUS_STATUS_NOT_SUPPORTED; 104 105 return dev->hotplug_ops->prepare(dev, bridge_dev); 106 } 107 108 static void vlandev_hotplug_check(struct vlandev_device *mvdev) 109 { 110 static const struct device_hotplug_ops hotplug_ops = { 111 .prepare = vlandev_hotplug_prepare, 112 .add = vlandev_hotplug_add, 113 .del = vlandev_hotplug_del 114 }; 115 struct device *dev = mvdev->parent.dev; 116 117 if (!dev || !dev->hotplug_ops || avl_is_empty(&dev->vlans.avl) || 118 mvdev->dev.type != &vlan8021q_device_type) { 119 mvdev->dev.hotplug_ops = NULL; 120 return; 121 } 122 123 mvdev->dev.hotplug_ops = &hotplug_ops; 124 } 125 126 127 static void 128 vlandev_base_cb(struct device_user *dev, enum device_event ev) 129 { 130 struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, parent); 131 132 switch (ev) { 133 case DEV_EVENT_ADD: 134 device_set_present(&mvdev->dev, true); 135 break; 136 case DEV_EVENT_REMOVE: 137 device_set_present(&mvdev->dev, false); 138 break; 139 case DEV_EVENT_UPDATE_IFNAME: 140 vlandev_hotplug_check(mvdev); 141 break; 142 default: 143 return; 144 } 145 } 146 147 static int 148 vlandev_set_down(struct vlandev_device *mvdev) 149 { 150 mvdev->set_state(&mvdev->dev, false); 151 system_vlandev_del(&mvdev->dev); 152 device_release(&mvdev->parent); 153 154 return 0; 155 } 156 157 static int 158 vlandev_set_up(struct vlandev_device *mvdev) 159 { 160 int ret; 161 162 ret = device_claim(&mvdev->parent); 163 if (ret < 0) 164 return ret; 165 166 ret = system_vlandev_add(&mvdev->dev, mvdev->parent.dev, &mvdev->config); 167 if (ret < 0) 168 goto release; 169 170 ret = mvdev->set_state(&mvdev->dev, true); 171 if (ret) 172 goto delete; 173 174 return 0; 175 176 delete: 177 system_vlandev_del(&mvdev->dev); 178 release: 179 device_release(&mvdev->parent); 180 return ret; 181 } 182 183 static int 184 vlandev_set_state(struct device *dev, bool up) 185 { 186 struct vlandev_device *mvdev; 187 188 D(SYSTEM, "vlandev_set_state(%s, %u)\n", dev->ifname, up); 189 190 mvdev = container_of(dev, struct vlandev_device, dev); 191 if (up) 192 return vlandev_set_up(mvdev); 193 else 194 return vlandev_set_down(mvdev); 195 } 196 197 static void 198 vlandev_free(struct device *dev) 199 { 200 struct vlandev_device *mvdev; 201 202 mvdev = container_of(dev, struct vlandev_device, dev); 203 device_remove_user(&mvdev->parent); 204 free(mvdev->config_data); 205 vlist_simple_flush_all(&mvdev->config.ingress_qos_mapping_list); 206 vlist_simple_flush_all(&mvdev->config.egress_qos_mapping_list); 207 free(mvdev); 208 } 209 210 static void vlandev_qos_mapping_dump(struct blob_buf *b, const char *name, const struct vlist_simple_tree *qos_mapping_li) 211 { 212 const struct vlan_qos_mapping *elem; 213 void *a, *t; 214 215 a = blobmsg_open_array(b, name); 216 217 vlist_simple_for_each_element(qos_mapping_li, elem, node) { 218 t = blobmsg_open_table(b, NULL); 219 220 blobmsg_add_u32(b, "from", elem->from); 221 blobmsg_add_u32(b, "to", elem->to); 222 223 blobmsg_close_table(b, t); 224 } 225 226 blobmsg_close_array(b, a); 227 } 228 229 static void 230 vlandev_dump_info(struct device *dev, struct blob_buf *b) 231 { 232 struct vlandev_device *mvdev; 233 234 mvdev = container_of(dev, struct vlandev_device, dev); 235 blobmsg_add_string(b, "parent", mvdev->parent.dev->ifname); 236 system_if_dump_info(dev, b); 237 blobmsg_add_u32(b, "vid", mvdev->config.vid); 238 vlandev_qos_mapping_dump(b, "ingress_qos_mapping", &mvdev->config.ingress_qos_mapping_list); 239 vlandev_qos_mapping_dump(b, "egress_qos_mapping", &mvdev->config.egress_qos_mapping_list); 240 } 241 242 static uint16_t 243 vlandev_get_vid(struct device *dev, const char *id_str) 244 { 245 unsigned long id; 246 uint16_t *alias_id; 247 char *err; 248 249 id = strtoul(id_str, &err, 10); 250 if (err && *err) { 251 if (!dev) 252 return 1; 253 254 alias_id = kvlist_get(&dev->vlan_aliases, id_str); 255 if (!alias_id) 256 return 1; 257 258 id = *alias_id; 259 } 260 261 return (uint16_t)id; 262 } 263 264 static void 265 vlandev_config_init(struct device *dev) 266 { 267 struct vlandev_device *mvdev; 268 struct device *basedev = NULL; 269 270 mvdev = container_of(dev, struct vlandev_device, dev); 271 if (mvdev->ifname) 272 basedev = device_get(blobmsg_data(mvdev->ifname), true); 273 274 if (mvdev->vid) 275 mvdev->config.vid = vlandev_get_vid(basedev, blobmsg_get_string(mvdev->vid)); 276 else 277 mvdev->config.vid = 1; 278 279 device_add_user(&mvdev->parent, basedev); 280 vlandev_hotplug_check(mvdev); 281 } 282 283 static void vlandev_qos_mapping_list_apply(struct vlist_simple_tree *qos_mapping_li, struct blob_attr *list) 284 { 285 struct blob_attr *cur; 286 struct vlan_qos_mapping *qos_mapping; 287 int rem, rc; 288 289 blobmsg_for_each_attr(cur, list, rem) { 290 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 291 continue; 292 293 if (!blobmsg_check_attr(cur, false)) 294 continue; 295 296 qos_mapping = calloc(1, sizeof(*qos_mapping)); 297 if (!qos_mapping) 298 continue; 299 300 rc = sscanf(blobmsg_data(cur), "%" PRIu32 ":%" PRIu32, &qos_mapping->from, &qos_mapping->to); 301 if (rc != 2) { 302 free(qos_mapping); 303 continue; 304 } 305 vlist_simple_add(qos_mapping_li, &qos_mapping->node); 306 } 307 } 308 309 static void 310 vlandev_apply_settings(struct vlandev_device *mvdev, struct blob_attr **tb) 311 { 312 struct vlandev_config *cfg = &mvdev->config; 313 struct blob_attr *cur; 314 315 cfg->proto = (mvdev->dev.type == &vlan8021q_device_type) ? 316 VLAN_PROTO_8021Q : VLAN_PROTO_8021AD; 317 318 vlist_simple_update(&cfg->ingress_qos_mapping_list); 319 vlist_simple_update(&cfg->egress_qos_mapping_list); 320 321 if ((cur = tb[VLANDEV_ATTR_INGRESS_QOS_MAPPING])) 322 vlandev_qos_mapping_list_apply(&cfg->ingress_qos_mapping_list, cur); 323 324 if ((cur = tb[VLANDEV_ATTR_EGRESS_QOS_MAPPING])) 325 vlandev_qos_mapping_list_apply(&cfg->egress_qos_mapping_list, cur); 326 327 vlist_simple_flush(&cfg->ingress_qos_mapping_list); 328 vlist_simple_flush(&cfg->egress_qos_mapping_list); 329 } 330 331 static enum dev_change_type 332 vlandev_reload(struct device *dev, struct blob_attr *attr) 333 { 334 struct blob_attr *tb_dev[__DEV_ATTR_MAX]; 335 struct blob_attr *tb_mv[__VLANDEV_ATTR_MAX]; 336 enum dev_change_type ret = DEV_CONFIG_APPLIED; 337 struct vlandev_device *mvdev; 338 339 mvdev = container_of(dev, struct vlandev_device, dev); 340 attr = blob_memdup(attr); 341 342 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev, 343 blob_data(attr), blob_len(attr)); 344 blobmsg_parse(vlandev_attrs, __VLANDEV_ATTR_MAX, tb_mv, 345 blob_data(attr), blob_len(attr)); 346 347 device_init_settings(dev, tb_dev); 348 vlandev_apply_settings(mvdev, tb_mv); 349 mvdev->ifname = tb_mv[VLANDEV_ATTR_IFNAME]; 350 mvdev->vid = tb_mv[VLANDEV_ATTR_VID]; 351 352 if (mvdev->config_data) { 353 struct blob_attr *otb_dev[__DEV_ATTR_MAX]; 354 struct blob_attr *otb_mv[__VLANDEV_ATTR_MAX]; 355 356 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev, 357 blob_data(mvdev->config_data), blob_len(mvdev->config_data)); 358 359 if (uci_blob_diff(tb_dev, otb_dev, &device_attr_list, NULL)) 360 ret = DEV_CONFIG_RESTART; 361 362 blobmsg_parse(vlandev_attrs, __VLANDEV_ATTR_MAX, otb_mv, 363 blob_data(mvdev->config_data), blob_len(mvdev->config_data)); 364 365 if (uci_blob_diff(tb_mv, otb_mv, &vlandev_attr_list, NULL)) 366 ret = DEV_CONFIG_RESTART; 367 368 vlandev_config_init(dev); 369 } 370 371 free(mvdev->config_data); 372 mvdev->config_data = attr; 373 return ret; 374 } 375 376 static struct device * 377 vlandev_create(const char *name, struct device_type *devtype, 378 struct blob_attr *attr) 379 { 380 struct vlandev_device *mvdev; 381 struct device *dev = NULL; 382 383 mvdev = calloc(1, sizeof(*mvdev)); 384 if (!mvdev) 385 return NULL; 386 387 vlist_simple_init(&mvdev->config.ingress_qos_mapping_list, 388 struct vlan_qos_mapping, node); 389 vlist_simple_init(&mvdev->config.egress_qos_mapping_list, 390 struct vlan_qos_mapping, node); 391 392 dev = &mvdev->dev; 393 394 if (device_init(dev, devtype, name) < 0) { 395 device_cleanup(dev); 396 free(mvdev); 397 return NULL; 398 } 399 400 dev->config_pending = true; 401 402 mvdev->set_state = dev->set_state; 403 dev->set_state = vlandev_set_state; 404 405 dev->hotplug_ops = NULL; 406 mvdev->parent.cb = vlandev_base_cb; 407 408 vlandev_reload(dev, attr); 409 410 return dev; 411 } 412 413 static struct device_type vlan8021ad_device_type = { 414 .name = "8021ad", 415 .config_params = &vlandev_attr_list, 416 .create = vlandev_create, 417 .config_init = vlandev_config_init, 418 .reload = vlandev_reload, 419 .free = vlandev_free, 420 .dump_info = vlandev_dump_info, 421 }; 422 423 static struct device_type vlan8021q_device_type = { 424 .name = "8021q", 425 .config_params = &vlandev_attr_list, 426 .create = vlandev_create, 427 .config_init = vlandev_config_init, 428 .reload = vlandev_reload, 429 .free = vlandev_free, 430 .dump_info = vlandev_dump_info, 431 }; 432 433 static void __init vlandev_device_type_init(void) 434 { 435 device_type_add(&vlan8021ad_device_type); 436 device_type_add(&vlan8021q_device_type); 437 } 438
This page was automatically generated by LXR 0.3.1. • OpenWrt