X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;ds=sidebyside;f=config.c;h=526a20f0d1aba99f31b2f734a15bdabb5f15db33;hb=24ce1eab4910869576406bafd0489daf0d3e6e28;hp=34d2f2b9cd26056d9ec06ea02536b74b05843040;hpb=258b79f7a912abc84a3066c90266d8835597362e;p=project%2Fnetifd.git diff --git a/config.c b/config.c index 34d2f2b..526a20f 100644 --- a/config.c +++ b/config.c @@ -52,19 +52,63 @@ config_section_idx(struct uci_section *s) return -1; } +static bool +config_bridge_has_vlans(const char *br_name) +{ + struct uci_element *e; + + uci_foreach_element(&uci_network->sections, e) { + struct uci_section *s = uci_to_section(e); + const char *name; + + if (strcmp(s->type, "bridge-vlan") != 0) + continue; + + name = uci_lookup_option_string(uci_ctx, s, "device"); + if (!name) + continue; + + if (!strcmp(name, br_name)) + return true; + } + + return false; +} + +static void +config_fixup_bridge_vlan_filtering(struct uci_section *s, const char *name) +{ + struct uci_ptr ptr = { + .p = s->package, + .s = s, + .option = "vlan_filtering", + .value = "1", + }; + + if (!config_bridge_has_vlans(name)) + return; + + uci_lookup_ptr(uci_ctx, &ptr, NULL, false); + if (ptr.o) + return; + + uci_set(uci_ctx, &ptr); +} + static int -config_parse_bridge_interface(struct uci_section *s) +config_parse_bridge_interface(struct uci_section *s, struct device_type *devtype) { char *name; - name = alloca(strlen(s->e.name) + 4); - sprintf(name, "br-%s", s->e.name); + name = alloca(strlen(s->e.name) + strlen(devtype->name_prefix) + 2); + sprintf(name, "%s-%s", devtype->name_prefix, s->e.name); blobmsg_add_string(&b, "name", name); - uci_to_blob(&b, s, bridge_device_type.config_params); - if (!device_create(name, &bridge_device_type, b.head)) { - D(INTERFACE, "Failed to create bridge for interface '%s'\n", s->e.name); - return -EINVAL; + config_fixup_bridge_vlan_filtering(s, name); + uci_to_blob(&b, s, devtype->config_params); + if (!device_create(name, devtype, b.head)) { + D(INTERFACE, "Failed to create '%s' device for interface '%s'\n", + devtype->name, s->e.name); } blob_buf_init(&b, 0); @@ -78,8 +122,8 @@ config_parse_interface(struct uci_section *s, bool alias) struct interface *iface; const char *type = NULL, *disabled; struct blob_attr *config; - struct device *dev; bool bridge = false; + struct device_type *devtype = NULL; disabled = uci_lookup_option_string(uci_ctx, s, "disabled"); if (disabled && !strcmp(disabled, "1")) @@ -89,8 +133,12 @@ config_parse_interface(struct uci_section *s, bool alias) if (!alias) type = uci_lookup_option_string(uci_ctx, s, "type"); - if (type && !strcmp(type, "bridge")) { - if (config_parse_bridge_interface(s)) + + if (type) + devtype = device_type_get(type); + + if (devtype && devtype->bridge_capability) { + if (config_parse_bridge_interface(s, devtype)) return; bridge = true; @@ -98,14 +146,14 @@ config_parse_interface(struct uci_section *s, bool alias) uci_to_blob(&b, s, &interface_attr_list); - iface = interface_alloc(s->e.name, b.head); + iface = interface_alloc(s->e.name, b.head, false); if (!iface) return; if (iface->proto_handler && iface->proto_handler->config_params) uci_to_blob(&b, s, iface->proto_handler->config_params); - if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params) > 1) + if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params)) iface->device_config = true; config = blob_memdup(b.head); @@ -116,29 +164,11 @@ config_parse_interface(struct uci_section *s, bool alias) if (!interface_add_alias(iface, config)) goto error_free_config; } else { - interface_add(iface, config); + if (!interface_add(iface, config)) + goto error_free_config; } - - /* - * need to look up the interface name again, in case of config update, - * the pointer will have changed - */ - iface = vlist_find(&interfaces, s->e.name, iface, node); - if (!iface) - return; - - dev = iface->main_dev.dev; - if (!dev || !dev->default_config) - return; - - blob_buf_init(&b, 0); - uci_to_blob(&b, s, dev->type->config_params); - if (blob_len(b.head) == 0) - return; - - if (iface->device_config) - device_set_config(dev, dev->type, b.head); return; + error_free_config: free(config); error: @@ -157,6 +187,17 @@ config_parse_route(struct uci_section *s, bool v6) interface_ip_add_route(NULL, blob_data(b.head), v6); } +static void +config_parse_neighbor(struct uci_section *s, bool v6) +{ + void *neighbor; + blob_buf_init(&b,0); + neighbor = blobmsg_open_array(&b, "neighbor"); + uci_to_blob(&b,s, &neighbor_attr_list); + blobmsg_close_array(&b, neighbor); + interface_ip_add_neighbor(NULL, blob_data(b.head), v6); +} + static void config_parse_rule(struct uci_section *s, bool v6) { @@ -177,7 +218,7 @@ config_init_devices(void) uci_foreach_element(&uci_network->sections, e) { const struct uci_blob_param_list *params = NULL; struct uci_section *s = uci_to_section(e); - const struct device_type *devtype = NULL; + struct device_type *devtype = NULL; struct device *dev; const char *type, *name; @@ -189,24 +230,17 @@ config_init_devices(void) continue; type = uci_lookup_option_string(uci_ctx, s, "type"); - if (type) { - if (!strcmp(type, "8021ad")) - devtype = &vlandev_device_type; - else if (!strcmp(type, "8021q")) - devtype = &vlandev_device_type; - else if (!strcmp(type, "bridge")) - devtype = &bridge_device_type; - else if (!strcmp(type, "macvlan")) - devtype = &macvlan_device_type; - else if (!strcmp(type, "tunnel")) - devtype = &tunnel_device_type; - } + if (type) + devtype = device_type_get(type); if (devtype) params = devtype->config_params; if (!params) params = simple_device_type.config_params; + if (devtype && devtype->bridge_capability) + config_fixup_bridge_vlan_filtering(s, name); + blob_buf_init(&b, 0); uci_to_blob(&b, s, params); if (devtype) { @@ -225,6 +259,127 @@ config_init_devices(void) } } +static void +config_parse_vlan(struct device *dev, struct uci_section *s) +{ + enum { + BRVLAN_ATTR_VID, + BRVLAN_ATTR_LOCAL, + BRVLAN_ATTR_PORTS, + __BRVLAN_ATTR_MAX, + }; + static const struct blobmsg_policy vlan_attrs[__BRVLAN_ATTR_MAX] = { + [BRVLAN_ATTR_VID] = { "vlan", BLOBMSG_TYPE_INT32 }, + [BRVLAN_ATTR_LOCAL] = { "local", BLOBMSG_TYPE_BOOL }, + [BRVLAN_ATTR_PORTS] = { "ports", BLOBMSG_TYPE_ARRAY }, + }; + static const struct uci_blob_param_info vlan_attr_info[__BRVLAN_ATTR_MAX] = { + [BRVLAN_ATTR_PORTS] = { .type = BLOBMSG_TYPE_STRING }, + }; + static const struct uci_blob_param_list vlan_attr_list = { + .n_params = __BRVLAN_ATTR_MAX, + .params = vlan_attrs, + .info = vlan_attr_info, + }; + struct blob_attr *tb[__BRVLAN_ATTR_MAX]; + struct blob_attr *cur; + struct bridge_vlan_port *port; + struct bridge_vlan *vlan; + unsigned int vid; + const char *val; + char *name_buf; + int name_len = 0; + int n_ports = 0; + int rem; + + val = uci_lookup_option_string(uci_ctx, s, "vlan"); + if (!val) + return; + + blob_buf_init(&b, 0); + uci_to_blob(&b, s, &vlan_attr_list); + blobmsg_parse(vlan_attrs, __BRVLAN_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); + + if (!tb[BRVLAN_ATTR_VID]) + return; + + vid = blobmsg_get_u32(tb[BRVLAN_ATTR_VID]); + if (!vid || vid > 4095) + return; + + blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { + name_len += strlen(blobmsg_get_string(cur)) + 1; + n_ports++; + } + + vlan = calloc(1, sizeof(*vlan) + n_ports * sizeof(*port) + name_len); + if (!vlan) + return; + + vlan->vid = vid; + vlan->local = true; + if (tb[BRVLAN_ATTR_LOCAL]) + vlan->local = blobmsg_get_bool(tb[BRVLAN_ATTR_LOCAL]); + + vlan->n_ports = n_ports; + vlan->ports = port = (struct bridge_vlan_port *)&vlan[1]; + name_buf = (char *)&port[n_ports]; + + blobmsg_for_each_attr(cur, tb[BRVLAN_ATTR_PORTS], rem) { + char *sep; + + port->ifname = name_buf; + port->flags = BRVLAN_F_UNTAGGED; + strcpy(name_buf, blobmsg_get_string(cur)); + + sep = strchr(name_buf, ':'); + if (sep) { + for (*sep = 0, sep++; *sep; sep++) + switch (*sep) { + case '*': + port->flags |= BRVLAN_F_PVID; + break; + case 't': + port->flags &= ~BRVLAN_F_UNTAGGED; + break; + } + } + + name_buf += strlen(name_buf) + 1; + port++; + } + + vlist_add(&dev->vlans, &vlan->node, &vlan->vid); +} + + +static void +config_init_vlans(void) +{ + struct uci_element *e; + struct device *dev; + + device_vlan_update(false); + uci_foreach_element(&uci_network->sections, e) { + struct uci_section *s = uci_to_section(e); + const char *name; + + if (strcmp(s->type, "bridge-vlan") != 0) + continue; + + name = uci_lookup_option_string(uci_ctx, s, "device"); + if (!name) + continue; + + dev = device_get(name, 0); + if (!dev || !dev->vlans.update) + continue; + + config_parse_vlan(dev, s); + } + device_vlan_update(true); +} + static struct uci_package * config_init_package(const char *config) { @@ -275,7 +430,7 @@ config_init_interfaces(void) } static void -config_init_routes(void) +config_init_ip(void) { struct interface *iface; struct uci_element *e; @@ -290,6 +445,10 @@ config_init_routes(void) config_parse_route(s, false); else if (!strcmp(s->type, "route6")) config_parse_route(s, true); + if (!strcmp(s->type, "neighbor")) + config_parse_neighbor(s, false); + else if (!strcmp(s->type, "neighbor6")) + config_parse_neighbor(s, true); } vlist_for_each_element(&interfaces, iface, node) @@ -347,7 +506,7 @@ config_parse_wireless_device(struct uci_section *s) wireless_device_create(drv, s->e.name, b.head); } -static void +static struct wireless_interface* config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s) { char *name; @@ -357,7 +516,33 @@ config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section blob_buf_init(&b, 0); uci_to_blob(&b, s, wdev->drv->interface.config); - wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); + return wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); +} + +static void +config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_section *s) +{ + char *name; + + name = alloca(strlen(s->type) + 16); + sprintf(name, "@%s[%d]", s->type, config_section_idx(s)); + + blob_buf_init(&b, 0); + uci_to_blob(&b, s, wdev->drv->vlan.config); + wireless_vlan_create(wdev, vif, b.head, s->anonymous ? name : s->e.name); +} + +static void +config_parse_wireless_station(struct wireless_device *wdev, char *vif, struct uci_section *s) +{ + char *name; + + name = alloca(strlen(s->type) + 16); + sprintf(name, "@%s[%d]", s->type, config_section_idx(s)); + + blob_buf_init(&b, 0); + uci_to_blob(&b, s, wdev->drv->station.config); + wireless_station_create(wdev, vif, b.head, s->anonymous ? name : s->e.name); } static void @@ -387,10 +572,16 @@ config_init_wireless(void) vlist_for_each_element(&wireless_devices, wdev, node) { wdev->vif_idx = 0; vlist_update(&wdev->interfaces); + wdev->vlan_idx = 0; + vlist_update(&wdev->vlans); + wdev->sta_idx = 0; + vlist_update(&wdev->stations); } uci_foreach_element(&uci_wireless->sections, e) { struct uci_section *s = uci_to_section(e); + struct wireless_interface *vif; + struct uci_element *f; if (strcmp(s->type, "wifi-iface") != 0) continue; @@ -405,23 +596,65 @@ config_init_wireless(void) continue; } - config_parse_wireless_interface(wdev, s); + vif = config_parse_wireless_interface(wdev, s); + + if (!vif || s->anonymous) + continue; + uci_foreach_element(&uci_wireless->sections, f) { + struct uci_section *s = uci_to_section(f); + const char *vif_name; + + if (strcmp(s->type, "wifi-vlan") != 0) + continue; + + vif_name = uci_lookup_option_string(uci_ctx, s, "iface"); + if (vif_name && strcmp(e->name, vif_name)) + continue; + config_parse_wireless_vlan(wdev, vif->name, s); + } + + uci_foreach_element(&uci_wireless->sections, f) { + struct uci_section *s = uci_to_section(f); + const char *vif_name; + + if (strcmp(s->type, "wifi-station") != 0) + continue; + + vif_name = uci_lookup_option_string(uci_ctx, s, "iface"); + if (vif_name && strcmp(e->name, vif_name)) + continue; + config_parse_wireless_station(wdev, vif->name, s); + } } - vlist_for_each_element(&wireless_devices, wdev, node) + vlist_for_each_element(&wireless_devices, wdev, node) { vlist_flush(&wdev->interfaces); + vlist_flush(&wdev->vlans); + vlist_flush(&wdev->stations); + } } -void +int config_init_all(void) { + int ret = 0; + char *err; + uci_network = config_init_package("network"); if (!uci_network) { - fprintf(stderr, "Failed to load network config\n"); - return; + uci_get_errorstr(uci_ctx, &err, NULL); + netifd_log_message(L_CRIT, "Failed to load network config (%s)\n", err); + free(err); + return -1; } uci_wireless = config_init_package("wireless"); + if (!uci_wireless && uci_ctx->err != UCI_ERR_NOTFOUND) { + uci_get_errorstr(uci_ctx, &err, NULL); + netifd_log_message(L_CRIT, "Failed to load wireless config (%s)\n", err); + free(err); + ret = -1; + } vlist_update(&interfaces); config_init = true; @@ -430,7 +663,8 @@ config_init_all(void) device_reset_config(); config_init_devices(); config_init_interfaces(); - config_init_routes(); + config_init_vlans(); + config_init_ip(); config_init_rules(); config_init_globals(); config_init_wireless(); @@ -445,4 +679,6 @@ config_init_all(void) interface_refresh_assignments(false); interface_start_pending(); wireless_start_pending(); + + return ret; }