...
 
Commits (11)
......@@ -112,6 +112,9 @@ config_parse_interface(struct uci_section *s, bool alias)
if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params))
iface->device_config = true;
if (type && !strcmp(type, "anywan"))
iface->anywan = true;
config = blob_memdup(b.head);
if (!config)
goto error;
......@@ -351,6 +354,28 @@ config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section
wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
}
bool
config_is_wireless_interface(const char *name)
{
struct uci_element *e;
const char *wl_name;
if (!uci_wireless) {
return false;
}
uci_foreach_element(&uci_wireless->sections, e) {
struct uci_section *s = uci_to_section(e);
if (strcmp(s->type, "wifi-iface") != 0)
continue;
wl_name = uci_lookup_option_string(uci_ctx, s, "ifname");
if (wl_name && strcmp(wl_name, name) == 0) {
return true;
}
}
return false;
}
static void
config_init_wireless(void)
{
......
......@@ -20,5 +20,6 @@
extern bool config_init;
int config_init_all(void);
bool config_is_wireless_interface(const char *name);
#endif
......@@ -555,7 +555,7 @@ device_get(const char *name, int create)
{
struct device *dev;
if (strchr(name, '.'))
if (strchr(name, '.') && (!config_is_wireless_interface(name)))
return get_vlan_device_chain(name, create);
if (name[0] == '@')
......
......@@ -613,6 +613,8 @@ interface_claim_device(struct interface *iface)
{
struct interface *parent;
struct device *dev = NULL;
char *ifname = NULL;
char if_buf[1024] = {0};
if (iface->parent_iface.iface)
interface_remove_user(&iface->parent_iface);
......@@ -625,13 +627,27 @@ interface_claim_device(struct interface *iface)
interface_add_user(&iface->parent_iface, parent);
} else if (iface->ifname &&
!(iface->proto_handler->flags & PROTO_FLAG_NODEV)) {
dev = device_get(iface->ifname, true);
if (!iface->anywan)
dev = device_get(iface->ifname, true);
interface_set_device_config(iface, dev);
} else {
dev = iface->ext_dev.dev;
}
if (dev)
if (iface->anywan) {
strncpy(if_buf, iface->ifname, sizeof(if_buf) - 1);
ifname = strtok((char*)if_buf, " ");
while (ifname != NULL)
{
dev = device_get(ifname, true);
if (dev && dev->present) {
interface_set_main_dev(iface, dev);
break;
}
ifname = strtok(NULL, " ");
}
}
else if (dev)
interface_set_main_dev(iface, dev);
device_unlock();
......@@ -1194,6 +1210,43 @@ interface_device_config_changed(struct interface *if_old, struct interface *if_n
return diff;
}
static int
interface_main_dev_changed(struct interface *if_old, struct interface *if_new)
{
char *main_dev, *ifname;
char if_buf[1024] = {0};
struct device *dev;
if (!if_old || !if_new)
return 0;
main_dev = if_old->main_dev.dev->ifname;
/* only applicable for anywan */
if (!if_new->anywan)
return 0;
strncpy(if_buf, if_new->ifname, sizeof(if_buf) - 1);
ifname = strtok((char*)if_buf, " ");
while (ifname != NULL) {
dev = device_get(ifname, true);
/* if device is not present, check next */
if (!dev || !dev->present) {
ifname = strtok(NULL, " ");
continue;
}
/* if first encountered present device is main dev - no change */
if (strncmp(ifname, main_dev, IFNAMSIZ) == 0)
return 0;
/* first present device in list is not main dev - change */
return 1;
}
return 0;
}
static void
interface_change_config(struct interface *if_old, struct interface *if_new)
{
......@@ -1214,6 +1267,9 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
if (!reload && interface_device_config_changed(if_old, if_new))
reload = true;
if (!reload && interface_main_dev_changed(if_old, if_new))
reload = true;
if (FIELD_CHANGED_STR(ifname) ||
if_old->proto_handler != if_new->proto_handler)
reload = true;
......@@ -1247,6 +1303,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
if_old->proto_handler = if_new->proto_handler;
if_old->force_link = if_new->force_link;
if_old->dns_metric = if_new->dns_metric;
if_old->anywan = if_new->anywan;
if (if_old->proto_ip.no_delegation != if_new->proto_ip.no_delegation) {
if_old->proto_ip.no_delegation = if_new->proto_ip.no_delegation;
......
......@@ -117,6 +117,7 @@ struct interface {
bool link_state;
bool force_link;
bool dynamic;
bool anywan;
bool policy_rules_set;
bool link_up_event;
......
......@@ -42,7 +42,6 @@ _wdev_prepare_channel() {
json_get_vars channel hwmode
auto_channel=0
enable_ht=0
htmode=
hwmode="${hwmode##11}"
hwmode_n="${hwmode##n}"
......@@ -58,6 +57,25 @@ _wdev_prepare_channel() {
;;
esac
json_get_vars htmode
enable_ht=1
case "$hwmode" in
a|b|g|bg)
enable_ht=0
htmode=
;;
esac
}
_wdev_prepare_channel_unused() {
json_get_vars channel hwmode
enable_ht=0
htmode=
hwmode="${hwmode##11}"
hwmode_n="${hwmode##n}"
[[ "$hwmode_n" = "$hwmode" ]] || {
enable_ht=1
hwmode="$hwmode_n"
......@@ -272,7 +290,7 @@ _wireless_set_brsnoop_isolation() {
json_get_var isolate isolate
[ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
[ ${multicast_to_unicast:-1} -gt 0 ] && json_add_boolean isolate 1
##[ ${multicast_to_unicast:-1} -gt 0 ] && json_add_boolean isolate 1
}
for_each_interface() {
......
......@@ -251,6 +251,17 @@ system_tos_aton(const char *src, unsigned *dst)
return true;
}
static bool
vlanconf_exists(void)
{
struct stat buf;
if (stat("/sbin/vlanconf", &buf) == 0)
return true;
else
return false;
}
int system_init(void)
{
static struct event_socket rtnl_event;
......@@ -1349,20 +1360,60 @@ static int system_vlan(struct device *dev, int id)
int system_vlan_add(struct device *dev, int id)
{
if(vlanconf_exists()) {
char cmd[256];
snprintf(cmd, 256, "/sbin/vlanconf create --name %s.%d --ifname %s --vlan-id %d", dev->ifname, id, dev->ifname, id);
return system(cmd);
}
return system_vlan(dev, id);
}
int system_vlan_del(struct device *dev)
{
if(vlanconf_exists()) {
char cmd[256];
snprintf(cmd, 256, "/sbin/vlanconf delete --name %s", dev->ifname);
return system(cmd);
}
return system_vlan(dev, -1);
}
int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg)
{
char proto[20];
char cmd[256];
switch (cfg->proto) {
case VLAN_PROTO_UNTAGGED:
strcpy(proto, "untagged");
break;
case VLAN_PROTO_8021Q:
strcpy(proto, "8021q");
break;
case VLAN_PROTO_8021AD:
strcpy(proto, "8021ad");
break;
}
if(vlanconf_exists()) {
snprintf(cmd, 256,
"/sbin/vlanconf create --name %s --ifname %s --type %s \
--vlan-id %d --priority %d --inner-vlan-id %d --inner-priority %d --dscp %d \
--unicast-mode %s --multicast-mode %s",
vlandev->ifname, dev->ifname, proto,
cfg->vid, cfg->priority, cfg->inner_vid, cfg->inner_priority, cfg->dscp,
(cfg->ucmode == UNICAST_MODE_TRANS) ? "trans":"reg",
(cfg->mcmode == MULTICAST_MODE_ONT) ? "ont":"rg");
return system(cmd);
}
struct nl_msg *msg;
struct nlattr *linkinfo, *data;
struct nlattr *linkinfo, *data, *qos;
struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
int rv;
struct ifla_vlan_qos_mapping map;
int rv, i;
msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
......@@ -1383,6 +1434,19 @@ int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlande
nla_put_u16(msg, IFLA_VLAN_ID, cfg->vid);
if (cfg->priority > 0) {
if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
goto nla_put_failure;
for (i=0; i<8; i++) {
map.from=i;
map.to=cfg->priority;
nla_put(msg, IFLA_VLAN_QOS_MAPPING, sizeof(struct ifla_vlan_qos_mapping),
&map);
}
nla_nest_end(msg, qos);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
nla_put_u16(msg, IFLA_VLAN_PROTOCOL, htons(cfg->proto));
#else
......@@ -1406,6 +1470,12 @@ nla_put_failure:
int system_vlandev_del(struct device *vlandev)
{
if(vlanconf_exists()) {
char cmd[256];
snprintf(cmd, 256, "/sbin/vlanconf delete --name %s", vlandev->ifname);
return system(cmd);
}
return system_link_del(vlandev->ifname);
}
......
......@@ -154,13 +154,27 @@ struct veth_config {
};
enum vlan_proto {
VLAN_PROTO_UNTAGGED = 0x0,
VLAN_PROTO_8021Q = 0x8100,
VLAN_PROTO_8021AD = 0x88A8
};
enum iface_mode {
MULTICAST_MODE_RG,
MULTICAST_MODE_ONT,
UNICAST_MODE_TRANS,
UNICAST_MODE_REG,
};
struct vlandev_config {
enum vlan_proto proto;
enum iface_mode ucmode;
enum iface_mode mcmode;
uint16_t vid;
uint16_t priority;
uint16_t inner_vid;
uint16_t inner_priority;
uint16_t dscp;
};
static inline int system_get_addr_family(unsigned int flags)
......
......@@ -17,6 +17,9 @@
#include "netifd.h"
#include "system.h"
#include "vlandev.h"
extern void vlandev_base_cb(struct device_user *dev, enum device_event ev);
struct vlan_device {
struct device dev;
......@@ -105,18 +108,24 @@ static struct device *get_vlan_device(struct device *dev, int id, bool create)
.free = free_vlan_if,
};
struct vlan_device *vldev;
struct vlandev_device *vlandev;
struct device_user *dep;
/* look for an existing interface before creating a new one */
list_for_each_entry(dep, &dev->users.list, list.list) {
if (dep->cb != vlan_dev_cb)
continue;
if (dep->cb == vlan_dev_cb) {
vldev = container_of(dep, struct vlan_device, dep);
if (vldev->id == id)
return &vldev->dev;
vldev = container_of(dep, struct vlan_device, dep);
if (vldev->id != id)
continue;
/* Device can have been created as a vlandev. */
} else if (dep->cb == vlandev_base_cb) {
vlandev = container_of(dep, struct vlandev_device, parent);
return &vldev->dev;
if (vlandev->config.vid == id)
return &vlandev->dev;
}
}
if (!create)
......
......@@ -18,16 +18,29 @@
#include "device.h"
#include "interface.h"
#include "system.h"
#include "vlandev.h"
enum {
VLANDEV_ATTR_IFNAME,
VLANDEV_ATTR_VID,
VLANDEV_ATTR_PRIORITY,
VLANDEV_ATTR_INNER_VID,
VLANDEV_ATTR_INNER_PRIORITY,
VLANDEV_ATTR_DSCP,
VLANDEV_ATTR_UCMODE,
VLANDEV_ATTR_MCMODE,
__VLANDEV_ATTR_MAX
};
static const struct blobmsg_policy vlandev_attrs[__VLANDEV_ATTR_MAX] = {
[VLANDEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_STRING },
[VLANDEV_ATTR_VID] = { "vid", BLOBMSG_TYPE_INT32 },
[VLANDEV_ATTR_PRIORITY] = { "priority", BLOBMSG_TYPE_INT32 },
[VLANDEV_ATTR_INNER_VID] = { "inner_vid", BLOBMSG_TYPE_INT32 },
[VLANDEV_ATTR_INNER_PRIORITY] = { "inner_priority", BLOBMSG_TYPE_INT32 },
[VLANDEV_ATTR_DSCP] = { "dscp", BLOBMSG_TYPE_INT32 },
[VLANDEV_ATTR_UCMODE] = { "ucmode", BLOBMSG_TYPE_STRING },
[VLANDEV_ATTR_MCMODE] = { "mcmode", BLOBMSG_TYPE_STRING },
};
static const struct uci_blob_param_list vlandev_attr_list = {
......@@ -39,19 +52,14 @@ static const struct uci_blob_param_list vlandev_attr_list = {
};
static struct device_type vlan8021q_device_type;
static struct device_type vlanuntagged_device_type;
struct vlandev_device {
struct device dev;
struct device_user parent;
const char ucmode_trans[] = "trans";
const char ucmode_reg[] = "reg";
const char mcmode_rg[] = "rg";
const char mcmode_ont[] = "ont";
device_state_cb set_state;
struct blob_attr *config_data;
struct blob_attr *ifname;
struct vlandev_config config;
};
static void
void
vlandev_base_cb(struct device_user *dev, enum device_event ev)
{
struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, parent);
......@@ -157,13 +165,48 @@ vlandev_apply_settings(struct vlandev_device *mvdev, struct blob_attr **tb)
{
struct vlandev_config *cfg = &mvdev->config;
struct blob_attr *cur;
const char *mode;
cfg->proto = (mvdev->dev.type == &vlan8021q_device_type) ?
VLAN_PROTO_8021Q : VLAN_PROTO_8021AD;
cfg->vid = 1;
cfg->priority = 0;
if (mvdev->dev.type == &vlanuntagged_device_type)
cfg->proto = VLAN_PROTO_UNTAGGED;
if ((cur = tb[VLANDEV_ATTR_VID]))
cfg->vid = (uint16_t) blobmsg_get_u32(cur);
if ((cur = tb[VLANDEV_ATTR_PRIORITY]))
cfg->priority = (uint16_t) blobmsg_get_u32(cur);
if ((cur = tb[VLANDEV_ATTR_INNER_VID]))
cfg->inner_vid = (uint16_t) blobmsg_get_u32(cur);
if ((cur = tb[VLANDEV_ATTR_INNER_PRIORITY]))
cfg->inner_priority = (uint16_t) blobmsg_get_u32(cur);
if ((cur = tb[VLANDEV_ATTR_DSCP]))
cfg->dscp = (uint16_t) blobmsg_get_u32(cur);
if ((cur = tb[VLANDEV_ATTR_UCMODE])) {
mode = blobmsg_get_string(tb[VLANDEV_ATTR_UCMODE]);
if (strncmp(mode, ucmode_trans, strlen(ucmode_trans)) == 0)
cfg->ucmode = UNICAST_MODE_TRANS;
else if (strncmp(mode, ucmode_reg, strlen(ucmode_reg)) == 0)
cfg->ucmode = UNICAST_MODE_REG;
}
if ((cur = tb[VLANDEV_ATTR_MCMODE])) {
mode = blobmsg_get_string(tb[VLANDEV_ATTR_MCMODE]);
if (strncmp(mode, mcmode_rg, strlen(mcmode_rg) == 0))
cfg->mcmode = MULTICAST_MODE_RG;
else if (strncmp(mode, mcmode_ont, strlen(mcmode_ont) == 0))
cfg->mcmode = MULTICAST_MODE_ONT;
}
}
static enum dev_change_type
......@@ -202,9 +245,10 @@ vlandev_reload(struct device *dev, struct blob_attr *attr)
if (uci_blob_diff(tb_mv, otb_mv, &vlandev_attr_list, NULL))
ret = DEV_CONFIG_RESTART;
vlandev_config_init(dev);
}
vlandev_config_init(dev);
free(mvdev->config_data);
mvdev->config_data = attr;
return ret;
......@@ -262,8 +306,19 @@ static struct device_type vlan8021q_device_type = {
.dump_info = vlandev_dump_info,
};
static struct device_type vlanuntagged_device_type = {
.name = "untagged",
.config_params = &vlandev_attr_list,
.create = vlandev_create,
.config_init = vlandev_config_init,
.reload = vlandev_reload,
.free = vlandev_free,
.dump_info = vlandev_dump_info,
};
static void __init vlandev_device_type_init(void)
{
device_type_add(&vlan8021ad_device_type);
device_type_add(&vlan8021q_device_type);
device_type_add(&vlanuntagged_device_type);
}
#ifndef __NETIFD_VLANDEV_H
#define __NETIFD_VLANDEV_H
struct vlandev_device {
struct device dev;
struct device_user parent;
device_state_cb set_state;
struct blob_attr *config_data;
struct blob_attr *ifname;
struct vlandev_config config;
};
void
vlandev_base_cb(struct device_user *dev, enum device_event ev);
#endif /* __NETIFD_VLANDEV_H */