return path + 1;
}
+static void system_bridge_set_wireless(const char *bridge, const char *dev)
+{
+ snprintf(dev_buf, sizeof(dev_buf),
+ "/sys/devices/virtual/net/%s/brif/%s/multicast_to_unicast",
+ bridge, dev);
+ system_set_sysctl(dev_buf, "1");
+}
+
int system_bridge_addif(struct device *bridge, struct device *dev)
{
char *oldbr;
+ int ret = 0;
oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
- if (oldbr && !strcmp(oldbr, bridge->ifname))
- return 0;
+ if (!oldbr || strcmp(oldbr, bridge->ifname) != 0)
+ ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
- return system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
+ if (dev->wireless)
+ system_bridge_set_wireless(bridge->ifname, dev->ifname);
+
+ return ret;
}
int system_bridge_delif(struct device *bridge, struct device *dev)
system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping",
bridge->ifname, cfg->igmp_snoop ? "1" : "0");
+ system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier",
+ bridge->ifname, cfg->igmp_snoop ? "1" : "0");
+
args[0] = BRCTL_SET_BRIDGE_PRIORITY;
args[1] = cfg->priority;
system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
return -ENOMEM;
}
-static int system_link_del(struct device *dev)
+static int system_link_del(const char *ifname)
{
struct nl_msg *msg;
struct ifinfomsg iim = {
return -1;
nlmsg_append(msg, &iim, sizeof(iim), 0);
- nla_put_string(msg, IFLA_IFNAME, dev->ifname);
+ nla_put_string(msg, IFLA_IFNAME, ifname);
return system_rtnl_call(msg);
}
int system_macvlan_del(struct device *macvlan)
{
- return system_link_del(macvlan);
+ return system_link_del(macvlan->ifname);
}
static int system_vlan(struct device *dev, int id)
int system_vlandev_del(struct device *vlandev)
{
- return system_link_del(vlandev);
+ return system_link_del(vlandev->ifname);
}
static void
s->ipv6 = !strtoul(buf, NULL, 0);
s->flags |= DEV_OPT_IPV6;
}
+
+ if (ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr) == 0) {
+ s->promisc = ifr.ifr_flags & IFF_PROMISC;
+ s->flags |= DEV_OPT_PROMISC;
+ }
}
void
}
if (s->flags & DEV_OPT_IPV6 & apply_mask)
system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
+ if (s->flags & DEV_OPT_PROMISC & apply_mask) {
+ if (system_if_flags(dev->ifname, s->promisc ? IFF_PROMISC : 0,
+ !s->promisc ? IFF_PROMISC : 0) < 0)
+ s->flags &= ~DEV_OPT_PROMISC;
+ }
}
int system_if_up(struct device *dev)
if (table == RT_TABLE_UNSPEC)
return false;
- /* do not consider main table special */
- if (table == RT_TABLE_MAIN)
- table = RT_TABLE_UNSPEC;
-
*id = table;
return true;
}
+bool system_is_default_rt_table(unsigned int id)
+{
+ return (id == RT_TABLE_MAIN);
+}
+
static int system_iprule(struct iprule *rule, int cmd)
{
int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16;
return ioctl(sock_ioctl, cmd, &ifr);
}
-int system_del_ip_tunnel(const char *name)
+#ifdef IFLA_IPTUN_MAX
+static int system_add_gre_tunnel(const char *name, const char *kind,
+ const unsigned int link, struct blob_attr **tb, bool v6)
{
- return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
+ struct nl_msg *nlm;
+ struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
+ struct blob_attr *cur;
+ uint32_t ikey = 0, okey = 0;
+ uint16_t iflags = 0, oflags = 0;
+ int ret = 0, ttl = 64;
+
+ nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
+ if (!nlm)
+ return -1;
+
+ nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
+ nla_put_string(nlm, IFLA_IFNAME, name);
+
+ struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
+ if (!linkinfo) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ nla_put_string(nlm, IFLA_INFO_KIND, kind);
+ struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
+ if (!infodata) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ if (link)
+ nla_put_u32(nlm, IFLA_GRE_LINK, link);
+
+ if ((cur = tb[TUNNEL_ATTR_TTL]))
+ ttl = blobmsg_get_u32(cur);
+
+ nla_put_u8(nlm, IFLA_GRE_TTL, ttl);
+
+ if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
+ uint8_t icsum, ocsum, iseqno, oseqno;
+ if (sscanf(blobmsg_get_string(cur), "%u,%u,%hhu,%hhu,%hhu,%hhu",
+ &ikey, &okey, &icsum, &ocsum, &iseqno, &oseqno) < 6) {
+ ret = -EINVAL;
+ goto failure;
+ }
+
+ if (ikey)
+ iflags |= GRE_KEY;
+
+ if (okey)
+ oflags |= GRE_KEY;
+
+ if (icsum)
+ iflags |= GRE_CSUM;
+
+ if (ocsum)
+ oflags |= GRE_CSUM;
+
+ if (iseqno)
+ iflags |= GRE_SEQ;
+
+ if (oseqno)
+ oflags |= GRE_SEQ;
+ }
+
+ if (v6) {
+ struct in6_addr in6buf;
+ if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
+ if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
+ ret = -EINVAL;
+ goto failure;
+ }
+ nla_put(nlm, IFLA_GRE_LOCAL, sizeof(in6buf), &in6buf);
+ }
+
+ if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
+ if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
+ ret = -EINVAL;
+ goto failure;
+ }
+ nla_put(nlm, IFLA_GRE_REMOTE, sizeof(in6buf), &in6buf);
+ }
+ nla_put_u8(nlm, IFLA_GRE_ENCAP_LIMIT, 4);
+ } else {
+ struct in_addr inbuf;
+ bool set_df = true;
+
+ if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
+ if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
+ ret = -EINVAL;
+ goto failure;
+ }
+ nla_put(nlm, IFLA_GRE_LOCAL, sizeof(inbuf), &inbuf);
+ }
+
+ if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
+ if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
+ ret = -EINVAL;
+ goto failure;
+ }
+ nla_put(nlm, IFLA_GRE_REMOTE, sizeof(inbuf), &inbuf);
+
+ if (IN_MULTICAST(ntohl(inbuf.s_addr))) {
+ if (!okey) {
+ okey = inbuf.s_addr;
+ oflags |= GRE_KEY;
+ }
+
+ if (!ikey) {
+ ikey = inbuf.s_addr;
+ iflags |= GRE_KEY;
+ }
+ }
+ }
+
+ if ((cur = tb[TUNNEL_ATTR_DF]))
+ set_df = blobmsg_get_bool(cur);
+
+ nla_put_u8(nlm, IFLA_GRE_PMTUDISC, set_df ? 1 : 0);
+ }
+
+ if (oflags)
+ nla_put_u16(nlm, IFLA_GRE_OFLAGS, oflags);
+
+ if (iflags)
+ nla_put_u16(nlm, IFLA_GRE_IFLAGS, iflags);
+
+ if (okey)
+ nla_put_u32(nlm, IFLA_GRE_OKEY, okey);
+
+ if (ikey)
+ nla_put_u32(nlm, IFLA_GRE_IKEY, ikey);
+
+ nla_nest_end(nlm, infodata);
+ nla_nest_end(nlm, linkinfo);
+
+ return system_rtnl_call(nlm);
+
+failure:
+ nlmsg_free(nlm);
+ return ret;
+}
+#endif
+
+static int __system_del_ip_tunnel(const char *name, struct blob_attr **tb)
+{
+ struct blob_attr *cur;
+ const char *str;
+
+ if (!(cur = tb[TUNNEL_ATTR_TYPE]))
+ return -EINVAL;
+ str = blobmsg_data(cur);
+
+ if (!strcmp(str, "greip") || !strcmp(str, "gretapip") ||
+ !strcmp(str, "greip6") || !strcmp(str, "gretapip6"))
+ return system_link_del(name);
+ else
+ return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
+}
+
+int system_del_ip_tunnel(const char *name, struct blob_attr *attr)
+{
+ struct blob_attr *tb[__TUNNEL_ATTR_MAX];
+
+ blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
+ blob_data(attr), blob_len(attr));
+
+ return __system_del_ip_tunnel(name, tb);
}
int system_update_ipv6_mtu(struct device *dev, int mtu)
bool set_df = true;
const char *str;
- system_del_ip_tunnel(name);
-
blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
blob_data(attr), blob_len(attr));
+ __system_del_ip_tunnel(name, tb);
+
if (!(cur = tb[TUNNEL_ATTR_TYPE]))
return -EINVAL;
str = blobmsg_data(cur);
}
if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) {
- system_del_ip_tunnel(name);
+ __system_del_ip_tunnel(name, tb);
return -1;
}
}
#endif
+#ifdef IFLA_IPTUN_MAX
} else if (!strcmp(str, "ipip6")) {
struct nl_msg *nlm = nlmsg_alloc_simple(RTM_NEWLINK,
NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
failure:
nlmsg_free(nlm);
return ret;
+ } else if (!strcmp(str, "greip")) {
+ return system_add_gre_tunnel(name, "gre", link, tb, false);
+ } else if (!strcmp(str, "gretapip")) {
+ return system_add_gre_tunnel(name, "gretap", link, tb, false);
+ } else if (!strcmp(str, "greip6")) {
+ return system_add_gre_tunnel(name, "ip6gre", link, tb, true);
+ } else if (!strcmp(str, "gretapip6")) {
+ return system_add_gre_tunnel(name, "ip6gretap", link, tb, true);
+#endif
}
else
return -EINVAL;