Loading net/ipv4/ipip.c +141 −24 Original line number Diff line number Diff line Loading @@ -249,6 +249,32 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) rcu_assign_pointer(*tp, t); } static int ipip_tunnel_create(struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); struct net *net = dev_net(dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); int err; err = ipip_tunnel_init(dev); if (err < 0) goto out; err = register_netdevice(dev); if (err < 0) goto out; strcpy(t->parms.name, dev->name); dev->rtnl_link_ops = &ipip_link_ops; dev_hold(dev); ipip_tunnel_link(ipn, t); return 0; out: return err; } static struct ip_tunnel *ipip_tunnel_locate(struct net *net, struct ip_tunnel_parm *parms, int create) { Loading Loading @@ -283,17 +309,9 @@ static struct ip_tunnel *ipip_tunnel_locate(struct net *net, nt = netdev_priv(dev); nt->parms = *parms; if (ipip_tunnel_init(dev) < 0) if (ipip_tunnel_create(dev) < 0) goto failed_free; if (register_netdevice(dev) < 0) goto failed_free; strcpy(nt->parms.name, dev->name); dev->rtnl_link_ops = &ipip_link_ops; dev_hold(dev); ipip_tunnel_link(ipn, nt); return nt; failed_free: Loading Loading @@ -622,6 +640,28 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) dev->iflink = tunnel->parms.link; } static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) { struct net *net = dev_net(t->dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); ipip_tunnel_unlink(ipn, t); synchronize_net(); t->parms.iph.saddr = p->iph.saddr; t->parms.iph.daddr = p->iph.daddr; memcpy(t->dev->dev_addr, &p->iph.saddr, 4); memcpy(t->dev->broadcast, &p->iph.daddr, 4); ipip_tunnel_link(ipn, t); t->parms.iph.ttl = p->iph.ttl; t->parms.iph.tos = p->iph.tos; t->parms.iph.frag_off = p->iph.frag_off; if (t->parms.link != p->link) { t->parms.link = p->link; ipip_tunnel_bind_dev(t->dev); } netdev_state_change(t->dev); } static int ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) { Loading Loading @@ -682,21 +722,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = netdev_priv(dev); } ipip_tunnel_unlink(ipn, t); synchronize_net(); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); ipip_tunnel_link(ipn, t); t->parms.iph.ttl = p.iph.ttl; t->parms.iph.tos = p.iph.tos; t->parms.iph.frag_off = p.iph.frag_off; if (t->parms.link != p.link) { t->parms.link = p.link; ipip_tunnel_bind_dev(dev); } netdev_state_change(dev); ipip_tunnel_update(t, &p); } if (t) { Loading Loading @@ -822,6 +848,84 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev) return 0; } static void ipip_netlink_parms(struct nlattr *data[], struct ip_tunnel_parm *parms) { memset(parms, 0, sizeof(*parms)); parms->iph.version = 4; parms->iph.protocol = IPPROTO_IPIP; parms->iph.ihl = 5; if (!data) return; if (data[IFLA_IPTUN_LINK]) parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); if (data[IFLA_IPTUN_LOCAL]) parms->iph.saddr = nla_get_u32(data[IFLA_IPTUN_LOCAL]); if (data[IFLA_IPTUN_REMOTE]) parms->iph.daddr = nla_get_u32(data[IFLA_IPTUN_REMOTE]); if (data[IFLA_IPTUN_TTL]) { parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); if (parms->iph.ttl) parms->iph.frag_off = htons(IP_DF); } if (data[IFLA_IPTUN_TOS]) parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) parms->iph.frag_off = htons(IP_DF); } static int ipip_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct net *net = dev_net(dev); struct ip_tunnel *nt; nt = netdev_priv(dev); ipip_netlink_parms(data, &nt->parms); if (ipip_tunnel_locate(net, &nt->parms, 0)) return -EEXIST; return ipip_tunnel_create(dev); } static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct ip_tunnel *t; struct ip_tunnel_parm p; struct net *net = dev_net(dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); if (dev == ipn->fb_tunnel_dev) return -EINVAL; ipip_netlink_parms(data, &p); if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) return -EINVAL; t = ipip_tunnel_locate(net, &p, 0); if (t) { if (t->dev != dev) return -EEXIST; } else t = netdev_priv(dev); ipip_tunnel_update(t, &p); return 0; } static size_t ipip_get_size(const struct net_device *dev) { return Loading Loading @@ -859,10 +963,23 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) return -EMSGSIZE; } static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, }; static struct rtnl_link_ops ipip_link_ops __read_mostly = { .kind = "ipip", .maxtype = IFLA_IPTUN_MAX, .policy = ipip_policy, .priv_size = sizeof(struct ip_tunnel), .setup = ipip_tunnel_setup, .newlink = ipip_newlink, .changelink = ipip_changelink, .get_size = ipip_get_size, .fill_info = ipip_fill_info, }; Loading Loading
net/ipv4/ipip.c +141 −24 Original line number Diff line number Diff line Loading @@ -249,6 +249,32 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) rcu_assign_pointer(*tp, t); } static int ipip_tunnel_create(struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); struct net *net = dev_net(dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); int err; err = ipip_tunnel_init(dev); if (err < 0) goto out; err = register_netdevice(dev); if (err < 0) goto out; strcpy(t->parms.name, dev->name); dev->rtnl_link_ops = &ipip_link_ops; dev_hold(dev); ipip_tunnel_link(ipn, t); return 0; out: return err; } static struct ip_tunnel *ipip_tunnel_locate(struct net *net, struct ip_tunnel_parm *parms, int create) { Loading Loading @@ -283,17 +309,9 @@ static struct ip_tunnel *ipip_tunnel_locate(struct net *net, nt = netdev_priv(dev); nt->parms = *parms; if (ipip_tunnel_init(dev) < 0) if (ipip_tunnel_create(dev) < 0) goto failed_free; if (register_netdevice(dev) < 0) goto failed_free; strcpy(nt->parms.name, dev->name); dev->rtnl_link_ops = &ipip_link_ops; dev_hold(dev); ipip_tunnel_link(ipn, nt); return nt; failed_free: Loading Loading @@ -622,6 +640,28 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) dev->iflink = tunnel->parms.link; } static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) { struct net *net = dev_net(t->dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); ipip_tunnel_unlink(ipn, t); synchronize_net(); t->parms.iph.saddr = p->iph.saddr; t->parms.iph.daddr = p->iph.daddr; memcpy(t->dev->dev_addr, &p->iph.saddr, 4); memcpy(t->dev->broadcast, &p->iph.daddr, 4); ipip_tunnel_link(ipn, t); t->parms.iph.ttl = p->iph.ttl; t->parms.iph.tos = p->iph.tos; t->parms.iph.frag_off = p->iph.frag_off; if (t->parms.link != p->link) { t->parms.link = p->link; ipip_tunnel_bind_dev(t->dev); } netdev_state_change(t->dev); } static int ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) { Loading Loading @@ -682,21 +722,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = netdev_priv(dev); } ipip_tunnel_unlink(ipn, t); synchronize_net(); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); ipip_tunnel_link(ipn, t); t->parms.iph.ttl = p.iph.ttl; t->parms.iph.tos = p.iph.tos; t->parms.iph.frag_off = p.iph.frag_off; if (t->parms.link != p.link) { t->parms.link = p.link; ipip_tunnel_bind_dev(dev); } netdev_state_change(dev); ipip_tunnel_update(t, &p); } if (t) { Loading Loading @@ -822,6 +848,84 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev) return 0; } static void ipip_netlink_parms(struct nlattr *data[], struct ip_tunnel_parm *parms) { memset(parms, 0, sizeof(*parms)); parms->iph.version = 4; parms->iph.protocol = IPPROTO_IPIP; parms->iph.ihl = 5; if (!data) return; if (data[IFLA_IPTUN_LINK]) parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); if (data[IFLA_IPTUN_LOCAL]) parms->iph.saddr = nla_get_u32(data[IFLA_IPTUN_LOCAL]); if (data[IFLA_IPTUN_REMOTE]) parms->iph.daddr = nla_get_u32(data[IFLA_IPTUN_REMOTE]); if (data[IFLA_IPTUN_TTL]) { parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); if (parms->iph.ttl) parms->iph.frag_off = htons(IP_DF); } if (data[IFLA_IPTUN_TOS]) parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) parms->iph.frag_off = htons(IP_DF); } static int ipip_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct net *net = dev_net(dev); struct ip_tunnel *nt; nt = netdev_priv(dev); ipip_netlink_parms(data, &nt->parms); if (ipip_tunnel_locate(net, &nt->parms, 0)) return -EEXIST; return ipip_tunnel_create(dev); } static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct ip_tunnel *t; struct ip_tunnel_parm p; struct net *net = dev_net(dev); struct ipip_net *ipn = net_generic(net, ipip_net_id); if (dev == ipn->fb_tunnel_dev) return -EINVAL; ipip_netlink_parms(data, &p); if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) return -EINVAL; t = ipip_tunnel_locate(net, &p, 0); if (t) { if (t->dev != dev) return -EEXIST; } else t = netdev_priv(dev); ipip_tunnel_update(t, &p); return 0; } static size_t ipip_get_size(const struct net_device *dev) { return Loading Loading @@ -859,10 +963,23 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) return -EMSGSIZE; } static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, }; static struct rtnl_link_ops ipip_link_ops __read_mostly = { .kind = "ipip", .maxtype = IFLA_IPTUN_MAX, .policy = ipip_policy, .priv_size = sizeof(struct ip_tunnel), .setup = ipip_tunnel_setup, .newlink = ipip_newlink, .changelink = ipip_changelink, .get_size = ipip_get_size, .fill_info = ipip_fill_info, }; Loading