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 49 struct vlandev_device { 50 struct device dev; 51 struct device_user parent; 52 53 device_state_cb set_state; 54 55 struct blob_attr *config_data; 56 struct blob_attr *ifname; 57 struct blob_attr *vid; 58 bool vid_invalid; 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 /* local buffer: chained vlan devices re-enter this function with 68 * the vlan attribute pointing into the caller's buffer */ 69 struct blob_buf b = {}; 70 void *a; 71 int ret; 72 73 dev = mvdev->parent.dev; 74 if (!dev || !dev->hotplug_ops) 75 return UBUS_STATUS_NOT_SUPPORTED; 76 77 blob_buf_init(&b, 0); 78 a = blobmsg_open_array(&b, "vlans"); 79 blobmsg_printf(&b, NULL, "%d:u", mvdev->config.vid); 80 if (vlan && blobmsg_len(vlan)) 81 blob_put_raw(&b, blobmsg_data(vlan), blobmsg_len(vlan)); 82 blobmsg_close_array(&b, a); 83 84 if (add) 85 ret = dev->hotplug_ops->add(dev, member, blobmsg_data(b.head)); 86 else 87 ret = dev->hotplug_ops->del(dev, member, blobmsg_data(b.head)); 88 89 blob_buf_free(&b); 90 return ret; 91 } 92 93 static int 94 vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) 95 { 96 return __vlandev_hotplug_op(dev, member, vlan, true); 97 } 98 99 static int 100 vlandev_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) 101 { 102 return __vlandev_hotplug_op(dev, member, vlan, false); 103 } 104 105 static int 106 vlandev_hotplug_prepare(struct device *dev, struct device **bridge_dev) 107 { 108 struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev); 109 110 dev = mvdev->parent.dev; 111 if (!dev || !dev->hotplug_ops) 112 return UBUS_STATUS_NOT_SUPPORTED; 113 114 return dev->hotplug_ops->prepare(dev, bridge_dev); 115 } 116 117 static void vlandev_hotplug_check(struct vlandev_device *mvdev) 118 { 119 static const struct device_hotplug_ops hotplug_ops = { 120 .prepare = vlandev_hotplug_prepare, 121 .add = vlandev_hotplug_add, 122 .del = vlandev_hotplug_del 123 }; 124 struct device *dev = mvdev->parent.dev; 125 126 if (!dev || !dev->hotplug_ops || avl_is_empty(&dev->vlans.avl) || 127 mvdev->dev.type != &vlan8021q_device_type) { 128 mvdev->dev.hotplug_ops = NULL; 129 return; 130 } 131 132 mvdev->dev.hotplug_ops = &hotplug_ops; 133 } 134 135 136 static void 137 vlandev_base_cb(struct device_user *dev, enum device_event ev) 138 { 139 struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, parent); 140 141 switch (ev) { 142 case DEV_EVENT_ADD: 143 device_set_present(&mvdev->dev, true); 144 break; 145 case DEV_EVENT_REMOVE: 146 device_set_present(&mvdev->dev, false); 147 break; 148 case DEV_EVENT_UPDATE_IFNAME: 149 vlandev_hotplug_check(mvdev); 150 break; 151 case DEV_EVENT_TOPO_CHANGE: 152 /* Propagate topo changes */ 153 device_broadcast_event(&mvdev->dev, DEV_EVENT_TOPO_CHANGE); 154 break; 155 default: 156 return; 157 } 158 } 159 160 static int 161 vlandev_set_down(struct vlandev_device *mvdev) 162 { 163 mvdev->set_state(&mvdev->dev, false); 164 system_vlandev_del(&mvdev->dev); 165 device_release(&mvdev->parent); 166 167 return 0; 168 } 169 170 static int 171 vlandev_set_up(struct vlandev_device *mvdev) 172 { 173 int ret; 174 175 if (mvdev->vid_invalid) 176 return -EINVAL; 177 178 ret = device_claim(&mvdev->parent); 179 if (ret < 0) 180 return ret; 181 182 ret = system_vlandev_add(&mvdev->dev, mvdev->parent.dev, &mvdev->config); 183 if (ret < 0) 184 goto release; 185 186 ret = mvdev->set_state(&mvdev->dev, true); 187 if (ret) 188 goto delete; 189 190 return 0; 191 192 delete: 193 system_vlandev_del(&mvdev->dev); 194 release: 195 device_release(&mvdev->parent); 196 return ret; 197 } 198 199 static int 200 vlandev_set_state(struct device *dev, bool up) 201 { 202 struct vlandev_device *mvdev; 203 204 D(SYSTEM, "vlandev_set_state(%s, %u)", dev->ifname, up); 205 206 mvdev = container_of(dev, struct vlandev_device, dev); 207 if (up) 208 return vlandev_set_up(mvdev); 209 else 210 return vlandev_set_down(mvdev); 211 } 212 213 static void 214 vlandev_free(struct device *dev) 215 { 216 struct vlandev_device *mvdev; 217 218 mvdev = container_of(dev, struct vlandev_device, dev); 219 device_remove_user(&mvdev->parent); 220 free(mvdev->config_data); 221 vlist_simple_flush_all(&mvdev->config.ingress_qos_mapping_list); 222 vlist_simple_flush_all(&mvdev->config.egress_qos_mapping_list); 223 free(mvdev); 224 } 225 226 static void vlandev_qos_mapping_dump(struct blob_buf *b, const char *name, const struct vlist_simple_tree *qos_mapping_li) 227 { 228 const struct vlan_qos_mapping *elem; 229 void *a, *t; 230 231 a = blobmsg_open_array(b, name); 232 233 vlist_simple_for_each_element(qos_mapping_li, elem, node) { 234 t = blobmsg_open_table(b, NULL); 235 236 blobmsg_add_u32(b, "from", elem->from); 237 blobmsg_add_u32(b, "to", elem->to); 238 239 blobmsg_close_table(b, t); 240 } 241 242 blobmsg_close_array(b, a); 243 } 244 245 static void 246 vlandev_dump_info(struct device *dev, struct blob_buf *b) 247 { 248 struct vlandev_device *mvdev; 249 250 mvdev = container_of(dev, struct vlandev_device, dev); 251 if (mvdev->parent.dev) 252 blobmsg_add_string(b, "parent", mvdev->parent.dev->ifname); 253 system_if_dump_info(dev, b); 254 blobmsg_add_u32(b, "vid", mvdev->config.vid); 255 vlandev_qos_mapping_dump(b, "ingress_qos_mapping", &mvdev->config.ingress_qos_mapping_list); 256 vlandev_qos_mapping_dump(b, "egress_qos_mapping", &mvdev->config.egress_qos_mapping_list); 257 } 258 259 static int 260 vlandev_get_vid(struct device *dev, const char *id_str) 261 { 262 unsigned long id; 263 unsigned int *alias_id; 264 char *err; 265 266 id = strtoul(id_str, &err, 10); 267 if (err && *err) { 268 if (!dev) 269 return -1; 270 271 alias_id = kvlist_get(&dev->vlan_aliases, id_str); 272 if (!alias_id) { 273 D(DEVICE, "Failed to resolve vlan alias '%s'", id_str); 274 return -1; 275 } 276 277 id = *alias_id; 278 } 279 280 /* the kernel rejects vids above 4094; 0 is valid (priority tagging) */ 281 if (id > 4094) 282 return -1; 283 284 return (int)id; 285 } 286 287 static void 288 vlandev_config_init(struct device *dev) 289 { 290 struct vlandev_device *mvdev; 291 struct device *basedev = NULL; 292 293 int vid = 1; 294 295 mvdev = container_of(dev, struct vlandev_device, dev); 296 if (mvdev->ifname) 297 basedev = device_get(blobmsg_data(mvdev->ifname), true); 298 299 if (mvdev->vid) 300 vid = vlandev_get_vid(basedev, blobmsg_get_string(mvdev->vid)); 301 302 mvdev->vid_invalid = vid < 0; 303 mvdev->config.vid = vid < 0 ? 0 : vid; 304 305 device_add_user(&mvdev->parent, basedev); 306 vlandev_hotplug_check(mvdev); 307 } 308 309 static void vlandev_qos_mapping_list_apply(struct vlist_simple_tree *qos_mapping_li, struct blob_attr *list) 310 { 311 struct blob_attr *cur; 312 struct vlan_qos_mapping *qos_mapping; 313 size_t rem; 314 int rc; 315 316 blobmsg_for_each_attr(cur, list, rem) { 317 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 318 continue; 319 320 if (!blobmsg_check_attr(cur, false)) 321 continue; 322 323 qos_mapping = calloc(1, sizeof(*qos_mapping)); 324 if (!qos_mapping) 325 continue; 326 327 rc = sscanf(blobmsg_data(cur), "%" PRIu32 ":%" PRIu32, &qos_mapping->from, &qos_mapping->to); 328 if (rc != 2) { 329 free(qos_mapping); 330 continue; 331 } 332 vlist_simple_add(qos_mapping_li, &qos_mapping->node); 333 } 334 } 335 336 static void 337 vlandev_apply_settings(struct vlandev_device *mvdev, struct blob_attr **tb) 338 { 339 struct vlandev_config *cfg = &mvdev->config; 340 struct blob_attr *cur; 341 342 cfg->proto = (mvdev->dev.type == &vlan8021q_device_type) ? 343 VLAN_PROTO_8021Q : VLAN_PROTO_8021AD; 344 345 vlist_simple_update(&cfg->ingress_qos_mapping_list); 346 vlist_simple_update(&cfg->egress_qos_mapping_list); 347 348 if ((cur = tb[VLANDEV_ATTR_INGRESS_QOS_MAPPING])) 349 vlandev_qos_mapping_list_apply(&cfg->ingress_qos_mapping_list, cur); 350 351 if ((cur = tb[VLANDEV_ATTR_EGRESS_QOS_MAPPING])) 352 vlandev_qos_mapping_list_apply(&cfg->egress_qos_mapping_list, cur); 353 354 vlist_simple_flush(&cfg->ingress_qos_mapping_list); 355 vlist_simple_flush(&cfg->egress_qos_mapping_list); 356 } 357 358 static enum dev_change_type 359 vlandev_reload(struct device *dev, struct blob_attr *attr, 360 struct blob_attr **tb_dev) 361 { 362 struct blob_attr *tb_mv[__VLANDEV_ATTR_MAX]; 363 enum dev_change_type ret = DEV_CONFIG_APPLIED; 364 struct vlandev_device *mvdev; 365 366 mvdev = container_of(dev, struct vlandev_device, dev); 367 attr = blob_memdup(attr); 368 369 blobmsg_parse_attr(vlandev_attrs, __VLANDEV_ATTR_MAX, tb_mv, attr); 370 371 vlandev_apply_settings(mvdev, tb_mv); 372 mvdev->ifname = tb_mv[VLANDEV_ATTR_IFNAME]; 373 mvdev->vid = tb_mv[VLANDEV_ATTR_VID]; 374 375 if (mvdev->config_data) { 376 struct blob_attr *otb_mv[__VLANDEV_ATTR_MAX]; 377 378 blobmsg_parse_attr(vlandev_attrs, __VLANDEV_ATTR_MAX, otb_mv, 379 mvdev->config_data); 380 381 if (uci_blob_diff(tb_mv, otb_mv, &vlandev_attr_list, NULL)) 382 ret = DEV_CONFIG_RESTART; 383 384 vlandev_config_init(dev); 385 } 386 387 free(mvdev->config_data); 388 mvdev->config_data = attr; 389 return ret; 390 } 391 392 static struct device * 393 vlandev_create(const char *name, struct device_type *devtype, 394 struct blob_attr *attr) 395 { 396 struct vlandev_device *mvdev; 397 struct device *dev = NULL; 398 399 mvdev = calloc(1, sizeof(*mvdev)); 400 if (!mvdev) 401 return NULL; 402 403 vlist_simple_init(&mvdev->config.ingress_qos_mapping_list, 404 struct vlan_qos_mapping, node); 405 vlist_simple_init(&mvdev->config.egress_qos_mapping_list, 406 struct vlan_qos_mapping, node); 407 408 dev = &mvdev->dev; 409 410 if (device_init(dev, devtype, name) < 0) { 411 device_cleanup(dev); 412 free(mvdev); 413 return NULL; 414 } 415 416 dev->config_pending = true; 417 418 mvdev->set_state = dev->set_state; 419 dev->set_state = vlandev_set_state; 420 421 dev->hotplug_ops = NULL; 422 mvdev->parent.cb = vlandev_base_cb; 423 424 device_init_config(dev, attr); 425 426 return dev; 427 } 428 429 static struct device_type vlan8021ad_device_type = { 430 .name = "8021ad", 431 .config_params = &vlandev_attr_list, 432 .create = vlandev_create, 433 .config_init = vlandev_config_init, 434 .reload = vlandev_reload, 435 .free = vlandev_free, 436 .dump_info = vlandev_dump_info, 437 }; 438 439 static struct device_type vlan8021q_device_type = { 440 .name = "8021q", 441 .config_params = &vlandev_attr_list, 442 .create = vlandev_create, 443 .config_init = vlandev_config_init, 444 .reload = vlandev_reload, 445 .free = vlandev_free, 446 .dump_info = vlandev_dump_info, 447 }; 448 449 static void __init vlandev_device_type_init(void) 450 { 451 device_type_add(&vlan8021ad_device_type); 452 device_type_add(&vlan8021q_device_type); 453 } 454
This page was automatically generated by LXR 0.3.1. • OpenWrt