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")) 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 && iface->proto_handler->config_params) 173 uci_to_blob(&b, s, iface->proto_handler->config_params); 174 175 if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params)) 176 iface->device_config = true; 177 178 config = blob_memdup(b.head); 179 if (!config) 180 goto error; 181 182 if (alias) { 183 if (!interface_add_alias(iface, config)) 184 goto error_free_config; 185 } else { 186 if (!interface_add(iface, config)) 187 goto error_free_config; 188 } 189 return; 190 191 error_free_config: 192 free(config); 193 error: 194 interface_free(iface); 195 } 196 197 static void 198 config_parse_route(struct uci_section *s, bool v6) 199 { 200 void *route; 201 202 blob_buf_init(&b, 0); 203 route = blobmsg_open_array(&b, "route"); 204 uci_to_blob(&b, s, &route_attr_list); 205 blobmsg_close_array(&b, route); 206 interface_ip_add_route(NULL, blob_data(b.head), v6); 207 } 208 209 static void 210 config_parse_neighbor(struct uci_section *s, bool v6) 211 { 212 void *neighbor; 213 blob_buf_init(&b,0); 214 neighbor = blobmsg_open_array(&b, "neighbor"); 215 uci_to_blob(&b,s, &neighbor_attr_list); 216 blobmsg_close_array(&b, neighbor); 217 interface_ip_add_neighbor(NULL, blob_data(b.head), v6); 218 } 219 220 static void 221 config_parse_rule(struct uci_section *s, bool v6) 222 { 223 void *rule; 224 225 blob_buf_init(&b, 0); 226 rule = blobmsg_open_array(&b, "rule"); 227 uci_to_blob(&b, s, &rule_attr_list); 228 blobmsg_close_array(&b, rule); 229 iprule_add(blob_data(b.head), v6); 230 } 231 232 static void 233 config_insert_vlan_entry(const char *name, const char *dev_name, struct blob_attr *data) 234 { 235 struct vlan_config_entry *e, *tmp; 236 struct blob_attr *attrbuf; 237 char *dev_name_buf; 238 239 list_for_each_entry_safe(e, tmp, &config_vlans, list) { 240 if (strcmp(e->name, name) != 0) 241 continue; 242 243 list_del(&e->list); 244 free(e); 245 } 246 247 e = calloc_a(sizeof(*e) + strlen(name) + 1, 248 &attrbuf, blob_pad_len(data), 249 &dev_name_buf, strlen(dev_name) + 1); 250 e->data = memcpy(attrbuf, data, blob_pad_len(data)); 251 e->dev_name = strcpy(dev_name_buf, dev_name); 252 strcpy(e->name, name); 253 list_add_tail(&e->list, &config_vlans); 254 } 255 256 static void 257 config_device_add(const char *name, struct device_type *devtype, 258 struct blob_attr *config) 259 { 260 struct device *dev; 261 262 if (devtype) { 263 dev = device_create(name, devtype, config); 264 } else { 265 dev = device_get(name, 1); 266 if (!dev) 267 return; 268 269 dev->current_config = true; 270 device_apply_config(dev, dev->type, config); 271 } 272 273 dev->default_config = false; 274 } 275 276 static void 277 config_procd_device_cb(struct blob_attr *data) 278 { 279 static const struct blobmsg_policy policy = 280 { "type", BLOBMSG_TYPE_STRING }; 281 const char *name = blobmsg_name(data); 282 struct device_type *devtype = NULL; 283 struct blob_attr *attr; 284 285 blobmsg_parse_attr(&policy, 1, &attr, data); 286 if (attr) { 287 const char *type_name = blobmsg_get_string(attr); 288 289 if (!strcmp(type_name, "bridge")) 290 return; 291 292 devtype = device_type_get(type_name); 293 if (!devtype) 294 return; 295 } 296 297 config_device_add(name, devtype, data); 298 } 299 300 static void 301 config_procd_bridge_cb(struct blob_attr *data) 302 { 303 enum { 304 PROCD_DEV_ATTR_TYPE, 305 PROCD_DEV_ATTR_VLANS, 306 __PROCD_DEV_ATTR_MAX 307 }; 308 static const struct blobmsg_policy policy[] = { 309 [PROCD_DEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING }, 310 [PROCD_DEV_ATTR_VLANS] = { "vlans", BLOBMSG_TYPE_TABLE }, 311 }; 312 const char *name = blobmsg_name(data); 313 struct blob_attr *tb[__PROCD_DEV_ATTR_MAX], *attr, *cur; 314 struct device_type *devtype; 315 struct device *dev; 316 int len = 0; 317 size_t rem; 318 319 blobmsg_parse_attr(policy, ARRAY_SIZE(policy), tb, data); 320 if (!tb[PROCD_DEV_ATTR_TYPE] || 321 strcmp(blobmsg_get_string(tb[PROCD_DEV_ATTR_TYPE]), "bridge") != 0) 322 return; 323 324 devtype = device_type_get("bridge"); 325 if (!devtype) 326 return; 327 328 attr = tb[PROCD_DEV_ATTR_VLANS]; 329 if (attr) 330 len = blobmsg_check_array(attr, BLOBMSG_TYPE_TABLE); 331 if (len < 0) 332 return; 333 334 if (len > 0 || config_bridge_has_vlans(name)) { 335 blob_buf_init(&b, 0); 336 blob_put_raw(&b, blobmsg_data(data), blobmsg_len(data)); 337 blobmsg_add_u8(&b, "vlan_filtering", 1); 338 data = b.head; 339 } 340 341 dev = device_create(name, devtype, data); 342 if (!dev || !dev->vlans.update || !len) 343 return; 344 345 blobmsg_for_each_attr(cur, attr, rem) 346 config_insert_vlan_entry(blobmsg_name(cur), name, cur); 347 } 348 349 static void 350 config_init_devices(bool bridge) 351 { 352 struct uci_element *e; 353 354 uci_foreach_element(&uci_network->sections, e) { 355 const struct uci_blob_param_list *params = NULL; 356 struct uci_section *s = uci_to_section(e); 357 struct device_type *devtype = NULL; 358 const char *type, *name; 359 360 if (strcmp(s->type, "device") != 0) 361 continue; 362 363 name = uci_lookup_option_string(uci_ctx, s, "name"); 364 if (!name) 365 continue; 366 367 type = uci_lookup_option_string(uci_ctx, s, "type"); 368 if (type) 369 devtype = device_type_get(type); 370 371 if (bridge != (devtype && devtype->bridge_capability)) 372 continue; 373 374 if (devtype) 375 params = devtype->config_params; 376 if (!params) 377 params = simple_device_type.config_params; 378 379 if (devtype && devtype->bridge_capability) { 380 config_fixup_bridge_ports(s); 381 config_fixup_bridge_vlan_filtering(s, name); 382 } 383 384 blob_buf_init(&b, 0); 385 uci_to_blob(&b, s, params); 386 config_device_add(name, devtype, b.head); 387 } 388 389 netifd_ubus_get_procd_data("network-device", 390 bridge ? config_procd_bridge_cb : config_procd_device_cb); 391 } 392 393 enum { 394 BRVLAN_ATTR_VID, 395 BRVLAN_ATTR_LOCAL, 396 BRVLAN_ATTR_PORTS, 397 BRVLAN_ATTR_ALIAS, 398 __BRVLAN_ATTR_MAX, 399 }; 400 401 static const struct blobmsg_policy vlan_attrs[__BRVLAN_ATTR_MAX] = { 402 [BRVLAN_ATTR_VID] = { "vlan", BLOBMSG_TYPE_INT32 }, 403 [BRVLAN_ATTR_LOCAL] = { "local", BLOBMSG_TYPE_BOOL }, 404 [BRVLAN_ATTR_PORTS] = { "ports", BLOBMSG_TYPE_ARRAY }, 405 [BRVLAN_ATTR_ALIAS] = { "alias", BLOBMSG_TYPE_ARRAY }, 406 }; 407 408 static void 409 config_init_vlan_entry(struct vlan_config_entry *e) 410 { 411 struct blob_attr *tb[__BRVLAN_ATTR_MAX]; 412 struct blob_attr *cur; 413 struct bridge_vlan_port *port; 414 struct bridge_vlan *vlan; 415 struct device *dev; 416 unsigned int vid; 417 char *name_buf; 418 int name_len = 0; 419 int n_ports = 0; 420 size_t rem; 421 422 dev = device_get(e->dev_name, 0); 423 if (!dev || !dev->vlans.update) 424 return; 425 426 blobmsg_parse_attr(vlan_attrs, __BRVLAN_ATTR_MAX, tb, e->data); 427 428 if (!tb[BRVLAN_ATTR_VID]) 429 return; 430 431 vid = blobmsg_get_u32(tb[BRVLAN_ATTR_VID]); 432 if (!vid || vid > 4095) 433 return; 434 435 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { 436 name_len += strlen(blobmsg_get_string(cur)) + 1; 437 n_ports++; 438 } 439 440 vlan = calloc(1, sizeof(*vlan) + n_ports * sizeof(*port) + name_len); 441 if (!vlan) 442 return; 443 444 vlan->vid = vid; 445 vlan->local = true; 446 if (tb[BRVLAN_ATTR_LOCAL]) 447 vlan->local = blobmsg_get_bool(tb[BRVLAN_ATTR_LOCAL]); 448 449 vlan->n_ports = n_ports; 450 vlan->ports = port = (struct bridge_vlan_port *)&vlan[1]; 451 INIT_LIST_HEAD(&vlan->hotplug_ports); 452 name_buf = (char *)&port[n_ports]; 453 454 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { 455 char *sep; 456 457 port->ifname = name_buf; 458 port->flags = BRVLAN_F_UNTAGGED; 459 strcpy(name_buf, blobmsg_get_string(cur)); 460 461 sep = strchr(name_buf, ':'); 462 if (sep) { 463 for (*sep = 0, sep++; *sep; sep++) 464 switch (*sep) { 465 case '*': 466 port->flags |= BRVLAN_F_PVID; 467 break; 468 case 't': 469 port->flags &= ~BRVLAN_F_UNTAGGED; 470 break; 471 } 472 } 473 474 name_buf += strlen(name_buf) + 1; 475 port++; 476 } 477 478 blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_ALIAS], rem) 479 kvlist_set(&dev->vlan_aliases, blobmsg_get_string(cur), &vid); 480 481 vlist_add(&dev->vlans, &vlan->node, &vlan->vid); 482 } 483 484 static void 485 config_load_vlan(const char *dev_name, struct uci_section *s) 486 { 487 static const struct uci_blob_param_info vlan_attr_info[__BRVLAN_ATTR_MAX] = { 488 [BRVLAN_ATTR_PORTS] = { .type = BLOBMSG_TYPE_STRING }, 489 [BRVLAN_ATTR_ALIAS] = { .type = BLOBMSG_TYPE_STRING }, 490 }; 491 static const struct uci_blob_param_list vlan_attr_list = { 492 .n_params = __BRVLAN_ATTR_MAX, 493 .params = vlan_attrs, 494 .info = vlan_attr_info, 495 }; 496 497 blob_buf_init(&b, 0); 498 uci_to_blob(&b, s, &vlan_attr_list); 499 config_insert_vlan_entry(s->e.name, dev_name, b.head); 500 } 501 502 static void 503 config_procd_vlan_cb(struct blob_attr *data) 504 { 505 static const struct blobmsg_policy policy = 506 { "device", BLOBMSG_TYPE_STRING }; 507 struct blob_attr *attr; 508 509 blobmsg_parse_attr(&policy, 1, &attr, data); 510 if (!attr) 511 return; 512 513 config_insert_vlan_entry(blobmsg_name(data), blobmsg_get_string(attr), data); 514 } 515 516 static void 517 config_load_vlans(void) 518 { 519 struct uci_element *e; 520 521 uci_foreach_element(&uci_network->sections, e) { 522 struct uci_section *s = uci_to_section(e); 523 const char *name; 524 525 if (strcmp(s->type, "bridge-vlan") != 0) 526 continue; 527 528 name = uci_lookup_option_string(uci_ctx, s, "device"); 529 if (!name) 530 continue; 531 532 config_load_vlan(name, s); 533 } 534 535 netifd_ubus_get_procd_data("bridge-vlan", config_procd_vlan_cb); 536 } 537 538 static void 539 config_init_vlans(void) 540 { 541 struct vlan_config_entry *e; 542 543 device_vlan_update(false); 544 while (!list_empty(&config_vlans)) { 545 e = list_first_entry(&config_vlans, struct vlan_config_entry, list); 546 list_del(&e->list); 547 config_init_vlan_entry(e); 548 free(e); 549 } 550 device_vlan_update(true); 551 } 552 553 static struct uci_package * 554 config_init_package(const char *config) 555 { 556 struct uci_context *ctx = uci_ctx; 557 struct uci_package *p = NULL; 558 559 if (!ctx) { 560 ctx = uci_alloc_context(); 561 uci_ctx = ctx; 562 563 ctx->flags &= ~UCI_FLAG_STRICT; 564 if (config_path) 565 uci_set_confdir(ctx, config_path); 566 567 #ifdef DUMMY_MODE 568 uci_set_savedir(ctx, "./tmp"); 569 #endif 570 } else { 571 p = uci_lookup_package(ctx, config); 572 if (p) 573 uci_unload(ctx, p); 574 } 575 576 if (uci_load(ctx, config, &p)) 577 return NULL; 578 579 return p; 580 } 581 582 static void 583 config_procd_interface_cb(struct blob_attr *data) 584 { 585 struct interface *iface; 586 const char *name = blobmsg_name(data); 587 588 iface = interface_alloc(name, data, false); 589 if (!iface) 590 return; 591 592 data = blob_memdup(data); 593 if (!data) { 594 interface_free(iface); 595 return; 596 } 597 598 iface->config = data; 599 list_add(&iface->node.avl.list, &config_ifaces); 600 } 601 602 static void 603 config_init_interfaces(void) 604 { 605 struct interface *iface; 606 struct uci_element *e; 607 608 uci_foreach_element(&uci_network->sections, e) { 609 struct uci_section *s = uci_to_section(e); 610 611 if (!strcmp(s->type, "interface")) 612 config_parse_interface(s, false); 613 } 614 615 uci_foreach_element(&uci_network->sections, e) { 616 struct uci_section *s = uci_to_section(e); 617 618 if (!strcmp(s->type, "alias")) 619 config_parse_interface(s, true); 620 } 621 622 netifd_ubus_get_procd_data("network-interface", config_procd_interface_cb); 623 while (!list_empty(&config_ifaces)) { 624 iface = list_first_entry(&config_ifaces, struct interface, node.avl.list); 625 list_del(&iface->node.avl.list); 626 627 if (!interface_add(iface, iface->config)) 628 interface_free(iface); 629 } 630 } 631 632 static void 633 config_init_ip(void) 634 { 635 struct interface *iface; 636 struct uci_element *e; 637 638 vlist_for_each_element(&interfaces, iface, node) 639 interface_ip_update_start(&iface->config_ip); 640 641 uci_foreach_element(&uci_network->sections, e) { 642 struct uci_section *s = uci_to_section(e); 643 644 if (!strcmp(s->type, "route")) 645 config_parse_route(s, false); 646 else if (!strcmp(s->type, "route6")) 647 config_parse_route(s, true); 648 if (!strcmp(s->type, "neighbor")) 649 config_parse_neighbor(s, false); 650 else if (!strcmp(s->type, "neighbor6")) 651 config_parse_neighbor(s, true); 652 } 653 654 vlist_for_each_element(&interfaces, iface, node) 655 interface_ip_update_complete(&iface->config_ip); 656 } 657 658 static void 659 config_init_rules(void) 660 { 661 struct uci_element *e; 662 663 iprule_update_start(); 664 665 uci_foreach_element(&uci_network->sections, e) { 666 struct uci_section *s = uci_to_section(e); 667 668 if (!strcmp(s->type, "rule")) 669 config_parse_rule(s, false); 670 else if (!strcmp(s->type, "rule6")) 671 config_parse_rule(s, true); 672 } 673 674 iprule_update_complete(); 675 } 676 677 static void 678 config_init_globals(void) 679 { 680 struct uci_section *globals = uci_lookup_section( 681 uci_ctx, uci_network, "globals"); 682 if (!globals) 683 return; 684 685 const char *ula_prefix = uci_lookup_option_string( 686 uci_ctx, globals, "ula_prefix"); 687 interface_ip_set_ula_prefix(ula_prefix); 688 689 const char *tcp_l3mdev = uci_lookup_option_string( 690 uci_ctx, globals, "tcp_l3mdev"); 691 if (tcp_l3mdev) 692 system_tcp_l3mdev(!strcmp(tcp_l3mdev, "1")); 693 694 const char *udp_l3mdev = uci_lookup_option_string( 695 uci_ctx, globals, "udp_l3mdev"); 696 if (udp_l3mdev) 697 system_udp_l3mdev(!strcmp(udp_l3mdev, "1")); 698 } 699 700 static struct blob_attr * 701 config_find_blobmsg_attr(struct blob_attr *attr, const char *name, int type) 702 { 703 struct blobmsg_policy policy = { .name = name, .type = type }; 704 struct blob_attr *cur; 705 706 blobmsg_parse_attr(&policy, 1, &cur, attr); 707 708 return cur; 709 } 710 711 struct ether_addr *config_get_default_macaddr(const char *ifname) 712 { 713 struct blob_attr *cur; 714 715 if (!board_netdevs) 716 return NULL; 717 718 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 719 if (!cur) 720 return NULL; 721 722 cur = config_find_blobmsg_attr(cur, "macaddr", BLOBMSG_TYPE_STRING); 723 if (!cur) 724 return NULL; 725 726 return ether_aton(blobmsg_get_string(cur)); 727 } 728 729 int config_get_default_gro(const char *ifname) 730 { 731 struct blob_attr *cur; 732 733 if (!board_netdevs) 734 return -1; 735 736 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 737 if (!cur) 738 return -1; 739 740 cur = config_find_blobmsg_attr(cur, "gro", BLOBMSG_TYPE_BOOL); 741 if (!cur) 742 return -1; 743 744 return blobmsg_get_bool(cur); 745 } 746 747 const char *config_get_default_conduit(const char *ifname) 748 { 749 struct blob_attr *cur; 750 751 if (!board_netdevs) 752 return NULL; 753 754 cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE); 755 if (!cur) 756 return NULL; 757 758 cur = config_find_blobmsg_attr(cur, "conduit", BLOBMSG_TYPE_STRING); 759 if (!cur) 760 return NULL; 761 762 return blobmsg_get_string(cur); 763 } 764 765 static void 766 config_init_board(void) 767 { 768 struct blob_attr *cur; 769 770 blob_buf_init(&b, 0); 771 772 if (!blobmsg_add_json_from_file(&b, DEFAULT_BOARD_JSON)) 773 return; 774 775 free(board_netdevs); 776 board_netdevs = NULL; 777 778 cur = config_find_blobmsg_attr(b.head, "network_device", 779 BLOBMSG_TYPE_TABLE); 780 if (!cur) 781 return; 782 783 board_netdevs = blob_memdup(cur); 784 } 785 786 int 787 config_init_all(void) 788 { 789 int ret = 0; 790 char *err; 791 792 uci_network = config_init_package("network"); 793 if (!uci_network) { 794 uci_get_errorstr(uci_ctx, &err, NULL); 795 netifd_log_message(L_CRIT, "Failed to load network config (%s)\n", err); 796 free(err); 797 return -1; 798 } 799 800 config_init_board(); 801 802 vlist_update(&interfaces); 803 config_init = true; 804 805 device_reset_config(); 806 config_load_vlans(); 807 config_init_devices(true); 808 config_init_vlans(); 809 config_init_devices(false); 810 config_init_interfaces(); 811 config_init_ip(); 812 config_init_rules(); 813 config_init_globals(); 814 netifd_ucode_config_load(false); 815 816 config_init = false; 817 818 device_reset_old(); 819 device_init_pending(); 820 vlist_flush(&interfaces); 821 interface_refresh_assignments(false); 822 interface_start_pending(); 823 netifd_ucode_config_load(true); 824 825 return ret; 826 } 827
This page was automatically generated by LXR 0.3.1. • OpenWrt