1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.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 #define _GNU_SOURCE 15 #include <string.h> 16 #include <stdlib.h> 17 #include <stdio.h> 18 19 #include <uci.h> 20 21 #include <libubox/blobmsg_json.h> 22 23 #include "netifd.h" 24 #include "interface.h" 25 #include "interface-ip.h" 26 #include "iprule.h" 27 #include "proto.h" 28 #include "config.h" 29 #include "ubus.h" 30 #include "system.h" 31 #include "ucode.h" 32 33 bool config_init = false; 34 35 static struct uci_context *uci_ctx; 36 static struct uci_package *uci_network; 37 static struct blob_attr *board_netdevs; 38 static struct blob_buf b; 39 static LIST_HEAD(config_vlans); 40 static LIST_HEAD(config_ifaces); 41 42 struct vlan_config_entry { 43 struct list_head list; 44 struct blob_attr *data; 45 char *dev_name; 46 char name[]; 47 }; 48 49 static bool 50 config_bridge_has_vlans(const char *br_name) 51 { 52 struct vlan_config_entry *e; 53 54 list_for_each_entry(e, &config_vlans, list) 55 if (!strcmp(e->dev_name, br_name)) 56 return true; 57 58 return false; 59 } 60 61 static void 62 config_fixup_bridge_var(struct uci_section *s, const char *name, const char *val) 63 { 64 struct uci_ptr ptr = { 65 .p = s->package, 66 .s = s, 67 .option = name, 68 .value = val, 69 }; 70 71 uci_lookup_ptr(uci_ctx, &ptr, NULL, false); 72 if (ptr.o) 73 return; 74 75 uci_set(uci_ctx, &ptr); 76 } 77 78 /** 79 * config_fixup_bridge_ports - translate deprecated configs 80 * 81 * Old configs used "ifname" option for specifying bridge ports. For backward 82 * compatibility translate it into the new "ports" option. 83 */ 84 static void config_fixup_bridge_ports(struct uci_section *s) 85 { 86 struct uci_ptr ptr = { 87 .p = s->package, 88 .s = s, 89 .option = "ifname", 90 }; 91 92 if (uci_lookup_option(uci_ctx, s, "ports")) 93 return; 94 95 uci_lookup_ptr(uci_ctx, &ptr, NULL, false); 96 if (!ptr.o) 97 return; 98 99 ptr.value = "ports"; 100 uci_rename(uci_ctx, &ptr); 101 } 102 103 static void 104 config_fixup_bridge_vlan_filtering(struct uci_section *s, const char *name) 105 { 106 bool has_vlans = config_bridge_has_vlans(name); 107 108 config_fixup_bridge_var(s, "__has_vlans", has_vlans ? "1" : ""); 109 110 if (!has_vlans) 111 return; 112 113 config_fixup_bridge_var(s, "vlan_filtering", "1"); 114 } 115 116 static int 117 config_parse_bridge_interface(struct uci_section *s, struct device_type *devtype) 118 { 119 char *name; 120 121 name = alloca(strlen(s->e.name) + strlen(devtype->name_prefix) + 2); 122 sprintf(name, "%s-%s", devtype->name_prefix, s->e.name); 123 blobmsg_add_string(&b, "name", name); 124 125 config_fixup_bridge_ports(s); 126 config_fixup_bridge_vlan_filtering(s, name); 127 uci_to_blob(&b, s, devtype->config_params); 128 if (!device_create(name, devtype, b.head)) { 129 D(INTERFACE, "Failed to create '%s' device for interface '%s'", 130 devtype->name, s->e.name); 131 } 132 133 blob_buf_init(&b, 0); 134 blobmsg_add_string(&b, "ifname", name); 135 return 0; 136 } 137 138 static void 139 config_parse_interface(struct uci_section *s, bool alias) 140 { 141 struct interface *iface; 142 const char *type = NULL, *disabled; 143 struct blob_attr *config; 144 bool bridge = false; 145 struct device_type *devtype = NULL; 146 147 disabled = uci_lookup_option_string(uci_ctx, s, "disabled"); 148 if (disabled && (!strcmp(disabled, "1") || !strcmp(disabled, "true"))) 149 return; 150 151 blob_buf_init(&b, 0); 152 153 if (!alias) 154 type = uci_lookup_option_string(uci_ctx, s, "type"); 155 156 if (type) 157 devtype = device_type_get(type); 158 159 if (devtype && devtype->bridge_capability) { 160 if (config_parse_bridge_interface(s, devtype)) 161 return; 162 163 bridge = true; 164 } 165 166 uci_to_blob(&b, s, &interface_attr_list); 167 168 iface = interface_alloc(s->e.name, b.head, false); 169 if (!iface) 170 return; 171 172 if (iface->proto_handler) { 173 if (iface->proto_handler->config_load) 174 iface->proto_handler->config_load(iface->proto_handler, s, &b); 175 else if (iface->proto_handler->config_params) 176 uci_to_blob(&b, s, iface->proto_handler->config_params); 177 } 178 179 if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params)) 180 iface->device_config = true; 181 182 config = blob_memdup(b.head); 183 if (!config) 184 goto error; 185 186 if (alias) { 187 if (!interface_add_alias(iface, config)) 188 goto error_free_config; 189 } else { 190 if (!interface_add(iface, config)) 191 goto error_free_config; 192 } 193 return; 194 195 error_free_config: 196 free(config); 197 error: 198 interface_free(iface); 199 } 200 201 static void 202 config_parse_route(struct uci_section *s, bool v6) 203 { 204 void *route; 205 206 blob_buf_init(&b, 0); 207 route = blobmsg_open_array(&b, "route"); 208 uci_to_blob(&b, s, &route_attr_list); 209 blobmsg_close_array(&b, route); 210 interface_ip_add_route(NULL, blob_data(b.head), v6); 211 } 212 213 static void 214 config_parse_neighbor(struct uci_section *s, bool v6) 215 { 216 void *neighbor; 217 blob_buf_init(&b,0); 218 neighbor = blobmsg_open_array(&b, "neighbor"); 219 uci_to_blob(&b,s, &neighbor_attr_list); 220 blobmsg_close_array(&b, neighbor); 221 interface_ip_add_neighbor(NULL, blob_data(b.head), v6); 222 } 223 224 static void 225 config_parse_rule(struct uci_section *s, bool v6) 226 { 227 void *rule; 228 229 blob_buf_init(&b, 0); 230 rule = blobmsg_open_array(&b, "rule"); 231 uci_to_blob(&b, s, &rule_attr_list); 232 blobmsg_close_array(&b, rule); 233 iprule_add(blob_data(b.head), v6); 234 } 235 236 static void 237 config_insert_vlan_entry(const char *name, const char *dev_name, struct blob_attr *data) 238 { 239 struct vlan_config_entry *e, *tmp; 240 struct blob_attr *attrbuf; 241 char *dev_name_buf; 242 243 list_for_each_entry_safe(e, tmp, &config_vlans, list) { 244 if (strcmp(e->name, name) != 0 || 245 strcmp(e->dev_name, dev_name) != 0) 246 continue; 247 248 list_del(&e->list); 249 free(e); 250 } 251 252 e = calloc_a(sizeof(*e) + strlen(name) + 1, 253 &attrbuf, blob_pad_len(data), 254 &dev_name_buf, strlen(dev_name) + 1); 255 e->data = memcpy(attrbuf, data, blob_pad_len(data)); 256 e->dev_name = strcpy(dev_name_buf, dev_name); 257 strcpy(e->name, name); 258 list_add_tail(&e->list, &config_vlans); 259 } 260 261 static void 262 config_device_add(const char *name, struct device_type *devtype, 263 struct blob_attr *config) 264 { 265 struct device *dev; 266 267 if (devtype) { 268 dev = device_create(name, devtype, config); 269 if (!dev) 270 return; 271 } else { 272 dev = device_get(name, 1); 273 if (!dev) 274 return; 275 276 dev->current_config = true; 277 device_apply_config(dev, dev->type, config); 278 } 279 280 dev->default_config = false; 281 } 282 283 static void 284 config_procd_device_cb(struct blob_attr *data) 285 { 286 static const struct blobmsg_policy policy = 287 { "type", BLOBMSG_TYPE_STRING }; 288 const char *name = blobmsg_name(data); 289 struct device_type *devtype = NULL; 290 struct blob_attr *attr; 291 292 blobmsg_parse_attr(&policy, 1, &attr, data); 293 if (attr) { 294 const char *type_name = blobmsg_get_string(attr); 295 296 if (!strcmp(type_name, "bridge")) 297 return; 298 299 devtype = device_type_get(type_name); 300 if (!devtype) 301 return; 302 } 303 304 config_device_add(name, devtype, data); 305 } 306 307 static void 308 config_procd_bridge_cb(struct blob_attr *data) 309 { 310 enum { 311 PROCD_DEV_ATTR_TYPE, 312 PROCD_DEV_ATTR_VLANS, 313 __PROCD_DEV_ATTR_MAX 314 }; 315 static const struct blobmsg_policy policy[] = { 316 [PROCD_DEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING }, 317 [PROCD_DEV_ATTR_VLANS] = { "vlans", BLOBMSG_TYPE_TABLE }, 318 }; 319 const char *name = blobmsg_name(data); 320 struct blob_attr *tb[__PROCD_DEV_ATTR_MAX], *attr, *cur; 321 struct device_type *devtype; 322 struct device *dev; 323 int len = 0; 324 size_t rem; 325 326 blobmsg_parse_attr(policy, ARRAY_SIZE(policy), tb, data); 327 if (!tb[PROCD_DEV_ATTR_TYPE] || 328 strcmp(blobmsg_get_string(tb[PROCD_DEV_ATTR_TYPE]), "bridge") != 0) 329 return; 330 331 devtype = device_type_get("bridge"); 332 if (!devtype) 333 return; 334 335 attr = tb[PROCD_DEV_ATTR_VLANS]; 336 if (attr) 337 len = blobmsg_check_array(attr, BLOBMSG_TYPE_TABLE); 338 if (len < 0) 339 return; 340 341 if (len > 0 || config_bridge_has_vlans(name)) { 342 blob_buf_init(&b, 0); 343 blob_put_raw(&b, blobmsg_data(data), blobmsg_len(data)); 344 blobmsg_add_u8(&b, "vlan_filtering", 1); 345 data = b.head; 346 } 347 348 dev = device_create(name, devtype, data); 349 if (!dev || !dev->vlans.update || !len) 350 return; 351 352 blobmsg_for_each_attr(cur, attr, rem) 353 config_insert_vlan_entry(blobmsg_name(cur), name, cur); 354 } 355 356 static void 357 config_init_devices(bool bridge) 358 { 359 struct uci_element *e; 360 361 uci_foreach_element(&uci_network->sections, e) { 362 const struct uci_blob_param_list *params = NULL; 363 struct uci_section *s = uci_to_section(e); 364 struct device_type *devtype = NULL; 365 const char *type, *name; 366 367 if (strcmp(s->type, "device") != 0) 368 continue; 369 370 name = uci_lookup_option_string(uci_ctx, s, "name"); 371 if (!name) 372 continue; 373 374 type = uci_lookup_option_string(uci_ctx, s, "type"); 375 if (type) 376 devtype = device_type_get(type); 377 378 if (bridge != (devtype && devtype->bridge_capability)) 379 continue; 380 381 if (devtype) 382 params = devtype->config_params; 383 if (!params) 384 params = simple_device_type.config_params; 385 386 if (devtype && devtype->bridge_capability) { 387 config_fixup_bridge_ports(s); 388 config_fixup_bridge_vlan_filtering(s, name); 389 } 390 391 blob_buf_init(&b, 0); 392 uci_to_blob(&b, s, params); 393 config_device_add(name, devtype, b.head); 394 } 395 396 netifd_ubus_get_procd_data("network-device", 397 bridge ? config_procd_bridge_cb : config_procd_device_cb); 398 } 399 400 enum { 401 BRVLAN_ATTR_VID, 402 BRVLAN_ATTR_LOCAL, 403 BRVLAN_ATTR_PORTS, 404 BRVLAN_ATTR_ALIAS, 405 __BRVLAN_ATTR_MAX, 406 }; 407 408 static const struct blobmsg_policy vlan_attrs[__BRVLAN_ATTR_MAX] = { 409 [BRVLAN_ATTR_VID] = { "vlan", BLOBMSG_TYPE_INT32 }, 410 [BRVLAN_ATTR_LOCAL] = { "local", BLOBMSG_TYPE_BOOL }, 411 [BRVLAN_ATTR_PORTS] = { "ports", BLOBMSG_TYPE_ARRAY }, 412 [BRVLAN_ATTR_ALIAS] = { "alias", BLOBMSG_TYPE_ARRAY }, 413 }; 414 415 static void 416 config_init_vlan_entry(struct vlan_config_entry *e) 417 { 418 struct blob_attr *tb[__BRVLAN_ATTR_MAX]; 419 struct blob_attr *cur; 420 struct bridge_vlan_port *port; 421 struct bridge_vlan *vlan; 422 struct device *dev; 423 unsigned int vid; 424 char *name_buf; 425 int name_len = 0; 426 int n_ports = 0; 427 size_t rem; 428 429 dev = device_get(e->dev_name, 0); 430 if (!dev || !dev->vlans.update) 431 return; 432 433 blobmsg_parse_attr(vlan_attrs, __BRVLAN_ATTR_MAX, tb, e->data); 434 435 if (!tb[BRVLAN_ATTR_VID]) 436 return; 437 438 vid = blobmsg_get_u32(tb[BRVLAN_ATTR_VID]); 439 if (!vid || vid > 4095) 440 return; 441 442 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { 443 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || 444 !blobmsg_check_attr(cur, false)) 445 continue; 446 447 name_len += strlen(blobmsg_get_string(cur)) + 1; 448 n_ports++; 449 } 450 451 vlan = calloc(1, sizeof(*vlan) + n_ports * sizeof(*port) + name_len); 452 if (!vlan) 453 return; 454 455 vlan->vid = vid; 456 vlan->local = true; 457 if (tb[BRVLAN_ATTR_LOCAL]) 458 vlan->local = blobmsg_get_bool(tb[BRVLAN_ATTR_LOCAL]); 459 460 vlan->n_ports = n_ports; 461 vlan->ports = port = (struct bridge_vlan_port *)&vlan[1]; 462 INIT_LIST_HEAD(&vlan->hotplug_ports); 463 name_buf = (char *)&port[n_ports]; 464 465 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { 466 char *sep; 467 468 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || 469 !blobmsg_check_attr(cur, false)) 470 continue; 471 472 port->ifname = name_buf; 473 port->flags = BRVLAN_F_UNTAGGED; 474 strcpy(name_buf, blobmsg_get_string(cur)); 475 476 sep = strchr(name_buf, ':'); 477 if (sep) { 478 for (*sep = 0, sep++; *sep; sep++) 479 switch (*sep) { 480 case '*': 481 port->flags |= BRVLAN_F_PVID; 482 break; 483 case 't': 484 port->flags &= ~BRVLAN_F_UNTAGGED; 485 break; 486 } 487 } 488 489 name_buf += strlen(name_buf) + 1; 490 port++; 491 } 492 493 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_ALIAS], rem) { 494 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || 495 !blobmsg_check_attr(cur, false)) 496 continue; 497 498 kvlist_set(&dev->vlan_aliases, blobmsg_get_string(cur), &vid); 499 } 500 501 vlist_add(&dev->vlans, &vlan->node, &vlan->vid); 502 } 503 504 static void 505 config_load_vlan(const char *dev_name, struct uci_section *s) 506 { 507 static const struct uci_blob_param_info vlan_attr_info[__BRVLAN_ATTR_MAX] = { 508 [BRVLAN_ATTR_PORTS] = { .type = BLOBMSG_TYPE_STRING }, 509 [BRVLAN_ATTR_ALIAS] = { .type = BLOBMSG_TYPE_STRING }, 510 }; 511 static const struct uci_blob_param_list vlan_attr_list = { 512 .n_params = __BRVLAN_ATTR_MAX, 513 .params = vlan_attrs, 514 .info = vlan_attr_info, 515 }; 516 517 blob_buf_init(&b, 0); 518 uci_to_blob(&b, s, &vlan_attr_list); 519 config_insert_vlan_entry(s->e.name, dev_name, b.head); 520 } 521 522 static void 523 config_procd_vlan_cb(struct blob_attr *data) 524 { 525 static const struct blobmsg_policy policy = 526 { "device", BLOBMSG_TYPE_STRING }; 527 struct blob_attr *attr; 528 529 blobmsg_parse_attr(&policy, 1, &attr, data); 530 if (!attr) 531 return; 532 533 config_insert_vlan_entry(blobmsg_name(data), blobmsg_get_string(attr), data); 534 } 535 536 static void 537 config_load_vlans(void) 538 { 539 struct uci_element *e; 540 541 uci_foreach_element(&uci_network->sections, e) { 542 struct uci_section *s = uci_to_section(e); 543 const char *name; 544 545 if (strcmp(s->type, "bridge-vlan") != 0) 546 continue; 547 548 name = uci_lookup_option_string(uci_ctx, s, "device"); 549 if (!name) 550 continue; 551 552 config_load_vlan(name, s); 553 } 554 555 netifd_ubus_get_procd_data("bridge-vlan", config_procd_vlan_cb); 556 } 557 558 static void 559 config_init_vlans(void) 560 { 561 struct vlan_config_entry *e; 562 563 device_vlan_update(false); 564 list_for_each_entry(e, &config_vlans, list) 565 config_init_vlan_entry(e); 566 device_vlan_update(true); 567 } 568 569 static void 570 config_free_vlans(void) 571 { 572 struct vlan_config_entry *e, *tmp; 573 574 list_for_each_entry_safe(e, tmp, &config_vlans, list) { 575 list_del(&e->list); 576 free(e); 577 } 578 } 579 580 static struct uci_package * 581 config_init_package(const char *config) 582 { 583 struct uci_context *ctx = uci_ctx; 584 struct uci_package *p = NULL; 585 586 if (!ctx) { 587 ctx = uci_alloc_context(); 588 uci_ctx = ctx; 589 590 ctx->flags &= ~UCI_FLAG_STRICT; 591 if (config_path) 592 uci_set_confdir(ctx, config_path); 593 594 #ifdef DUMMY_MODE 595 uci_set_savedir(ctx, "./tmp"); 596 #endif 597 } else { 598 p = uci_lookup_package(ctx, config); 599 if (p) 600 uci_unload(ctx, p); 601 } 602 603 if (uci_load(ctx, config, &p)) 604 return NULL; 605 606 return p; 607 } 608 609 static void 610 config_procd_interface_cb(struct blob_attr *data) 611 { 612 struct interface *iface; 613 const char *name = blobmsg_name(data); 614 615 iface = interface_alloc(name, data, false); 616 if (!iface) 617 return; 618 619 data = blob_memdup(data); 620 if (!data) { 621 interface_free(iface); 622 return; 623 } 624 625 iface->config = data; 626 list_add(&iface->node.avl.list, &config_ifaces); 627 } 628 629 static void 630 config_init_interfaces(void) 631 { 632 struct interface *iface; 633 struct uci_element *e; 634 635 uci_foreach_element(&uci_network->sections, e) { 636 struct uci_section *s = uci_to_section(e); 637 638 if (!strcmp(s->type, "interface")) 639 config_parse_interface(s, false); 640 } 641 642 uci_foreach_element(&uci_network->sections, e) { 643 struct uci_section *s = uci_to_section(e); 644 645 if (!strcmp(s->type, "alias")) 646 config_parse_interface(s, true); 647 } 648 649 netifd_ubus_get_procd_data("network-interface", config_procd_interface_cb); 650 while (!list_empty(&config_ifaces)) { 651 iface = list_first_entry(&config_ifaces, struct interface, node.avl.list); 652 list_del(&iface->node.avl.list); 653 654 if (!interface_add(iface, iface->config)) 655 interface_free(iface); 656 } 657 } 658 659 static void 660 config_init_ip(void) 661 { 662 struct interface *iface; 663 struct uci_element *e; 664 665 vlist_for_each_element(&interfaces, iface, node) 666 interface_ip_update_start(&iface->config_ip); 667 668 uci_foreach_element(&uci_network->sections, e) { 669 struct uci_section *s = uci_to_section(e); 670 671 if (!strcmp(s->type, "route")) 672 config_parse_route(s, false); 673 else if (!strcmp(s->type, "route6")) 674 config_parse_route(s, true); 675 if (!strcmp(s->type, "neighbor")) 676 config_parse_neighbor(s, false); 677 else if (!strcmp(s->type, "neighbor6")) 678 config_parse_neighbor(s, true); 679 } 680 681 vlist_for_each_element(&interfaces, iface, node) 682 interface_ip_update_complete(&iface->config_ip); 683 } 684 685 static void 686 config_init_rules(void) 687 { 688 struct uci_element *e; 689 690 iprule_update_start(); 691 692 uci_foreach_element(&uci_network->sections, e) { 693 struct uci_section *s = uci_to_section(e); 694 695 if (!strcmp(s->type, "rule")) 696 config_parse_rule(s, false); 697 else if (!strcmp(s->type, "rule6")) 698 config_parse_rule(s, true); 699 } 700 701 iprule_update_complete(); 702 } 703 704 static void 705 config_init_globals(void) 706 { 707 struct uci_section *globals = uci_lookup_section( 708 uci_ctx, uci_network, "globals"); 709 if (!globals) 710 return; 711 712 const char *ula_prefix = uci_lookup_option_string( 713 uci_ctx, globals, "ula_prefix"); 714 interface_ip_set_ula_prefix(ula_prefix); 715 716 const char *tcp_l3mdev = uci_lookup_option_string( 717 uci_ctx, globals, "tcp_l3mdev"); 718 if (tcp_l3mdev) 719 system_tcp_l3mdev(!strcmp(tcp_l3mdev, "1")); 720 721 const char *udp_l3mdev = uci_lookup_option_string( 722 uci_ctx, globals, "udp_l3mdev"); 723 if (udp_l3mdev) 724 system_udp_l3mdev(!strcmp(udp_l3mdev, "1")); 725 } 726 727 static struct blob_attr * 728 config_find_blobmsg_attr(struct blob_attr *attr, const char *name, int type) 729 { 730 struct blobmsg_policy policy = { .name = name, .type = type }; 731 struct blob_attr *cur; 732 733 blobmsg_parse_attr(&policy, 1, &cur, attr); 734 735 return cur; 736 } 737 738 struct ether_addr *config_get_default_macaddr(const char *ifname) 739 { 740 struct blob_attr *cur; 741 742 if (!board_netdevs) 743 return NULL; 744 745 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 746 if (!cur) 747 return NULL; 748 749 cur = config_find_blobmsg_attr(cur, "macaddr", BLOBMSG_TYPE_STRING); 750 if (!cur) 751 return NULL; 752 753 return ether_aton(blobmsg_get_string(cur)); 754 } 755 756 int config_get_default_gro(const char *ifname) 757 { 758 struct blob_attr *cur; 759 760 if (!board_netdevs) 761 return -1; 762 763 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 764 if (!cur) 765 return -1; 766 767 cur = config_find_blobmsg_attr(cur, "gro", BLOBMSG_TYPE_BOOL); 768 if (!cur) 769 return -1; 770 771 return blobmsg_get_bool(cur); 772 } 773 774 const char *config_get_default_conduit(const char *ifname) 775 { 776 struct blob_attr *cur; 777 778 if (!board_netdevs) 779 return NULL; 780 781 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 782 if (!cur) 783 return NULL; 784 785 cur = config_find_blobmsg_attr(cur, "conduit", BLOBMSG_TYPE_STRING); 786 if (!cur) 787 return NULL; 788 789 return blobmsg_get_string(cur); 790 } 791 792 static void 793 config_init_board(void) 794 { 795 struct blob_attr *cur; 796 797 blob_buf_init(&b, 0); 798 799 if (!blobmsg_add_json_from_file(&b, DEFAULT_BOARD_JSON)) 800 return; 801 802 free(board_netdevs); 803 board_netdevs = NULL; 804 805 cur = config_find_blobmsg_attr(b.head, "network_device", 806 BLOBMSG_TYPE_TABLE); 807 if (!cur) 808 return; 809 810 board_netdevs = blob_memdup(cur); 811 } 812 813 int 814 config_init_all(void) 815 { 816 int ret = 0; 817 char *err; 818 819 uci_network = config_init_package("network"); 820 if (!uci_network) { 821 uci_get_errorstr(uci_ctx, &err, NULL); 822 netifd_log_message(L_CRIT, "Failed to load network config (%s)\n", err); 823 free(err); 824 return -1; 825 } 826 827 config_init_board(); 828 829 vlist_update(&interfaces); 830 config_init = true; 831 832 device_reset_config(); 833 config_load_vlans(); 834 config_init_devices(true); 835 config_init_vlans(); 836 config_init_devices(false); 837 netifd_ucode_config_load(false); 838 config_init_interfaces(); 839 config_free_vlans(); 840 config_init_ip(); 841 config_init_rules(); 842 config_init_globals(); 843 844 config_init = false; 845 846 device_reset_old(); 847 device_init_pending(); 848 vlist_flush(&interfaces); 849 interface_refresh_assignments(false); 850 interface_start_pending(); 851 netifd_ucode_config_load(true); 852 853 return ret; 854 } 855
This page was automatically generated by LXR 0.3.1. • OpenWrt