]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv6/sit.c
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / net / ipv6 / sit.c
index 99853c6e33a8c3def99ecb56e288cce4a38a997b..2378503577b0c8823049b7d17f857466481077b3 100644 (file)
@@ -265,7 +265,7 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
        return nt;
 
 failed_free:
-       ipip6_dev_free(dev);
+       free_netdev(dev);
 failed:
        return NULL;
 }
@@ -881,11 +881,12 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        goto tx_error;
        }
 
-       rt = ip_route_output_ports(tunnel->net, &fl4, NULL,
-                                  dst, tiph->saddr,
-                                  0, 0,
-                                  IPPROTO_IPV6, RT_TOS(tos),
-                                  tunnel->parms.link);
+       flowi4_init_output(&fl4, tunnel->parms.link, tunnel->fwmark,
+                          RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6,
+                          0, dst, tiph->saddr, 0, 0,
+                          sock_net_uid(tunnel->net, NULL));
+       rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
+
        if (IS_ERR(rt)) {
                dev->stats.tx_carrier_errors++;
                goto tx_error_icmp;
@@ -1071,7 +1072,8 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
        }
 }
 
-static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
+static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
+                               __u32 fwmark)
 {
        struct net *net = t->net;
        struct sit_net *sitn = net_generic(net, sit_net_id);
@@ -1085,8 +1087,9 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
        ipip6_tunnel_link(sitn, t);
        t->parms.iph.ttl = p->iph.ttl;
        t->parms.iph.tos = p->iph.tos;
-       if (t->parms.link != p->link) {
+       if (t->parms.link != p->link || t->fwmark != fwmark) {
                t->parms.link = p->link;
+               t->fwmark = fwmark;
                ipip6_tunnel_bind_dev(t->dev);
        }
        dst_cache_reset(&t->dst_cache);
@@ -1220,7 +1223,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                                t = netdev_priv(dev);
                        }
 
-                       ipip6_tunnel_update(t, &p);
+                       ipip6_tunnel_update(t, &p, t->fwmark);
                }
 
                if (t) {
@@ -1333,7 +1336,6 @@ static void ipip6_dev_free(struct net_device *dev)
 
        dst_cache_destroy(&tunnel->dst_cache);
        free_percpu(dev->tstats);
-       free_netdev(dev);
 }
 
 #define SIT_FEATURES (NETIF_F_SG          | \
@@ -1348,7 +1350,8 @@ static void ipip6_tunnel_setup(struct net_device *dev)
        int t_hlen = tunnel->hlen + sizeof(struct iphdr);
 
        dev->netdev_ops         = &ipip6_netdev_ops;
-       dev->destructor         = ipip6_dev_free;
+       dev->needs_free_netdev  = true;
+       dev->priv_destructor    = ipip6_dev_free;
 
        dev->type               = ARPHRD_SIT;
        dev->hard_header_len    = LL_MAX_HEADER + t_hlen;
@@ -1418,7 +1421,8 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[])
 }
 
 static void ipip6_netlink_parms(struct nlattr *data[],
-                               struct ip_tunnel_parm *parms)
+                               struct ip_tunnel_parm *parms,
+                               __u32 *fwmark)
 {
        memset(parms, 0, sizeof(*parms));
 
@@ -1457,6 +1461,8 @@ static void ipip6_netlink_parms(struct nlattr *data[],
        if (data[IFLA_IPTUN_PROTO])
                parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
 
+       if (data[IFLA_IPTUN_FWMARK])
+               *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
 }
 
 /* This function returns true when ENCAP attributes are present in the nl msg */
@@ -1549,7 +1555,7 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
                        return err;
        }
 
-       ipip6_netlink_parms(data, &nt->parms);
+       ipip6_netlink_parms(data, &nt->parms, &nt->fwmark);
 
        if (ipip6_tunnel_locate(net, &nt->parms, 0))
                return -EEXIST;
@@ -1577,6 +1583,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
 #ifdef CONFIG_IPV6_SIT_6RD
        struct ip_tunnel_6rd ip6rd;
 #endif
+       __u32 fwmark = t->fwmark;
        int err;
 
        if (dev == sitn->fb_tunnel_dev)
@@ -1588,7 +1595,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
                        return err;
        }
 
-       ipip6_netlink_parms(data, &p);
+       ipip6_netlink_parms(data, &p, &fwmark);
 
        if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
            (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
@@ -1602,7 +1609,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
        } else
                t = netdev_priv(dev);
 
-       ipip6_tunnel_update(t, &p);
+       ipip6_tunnel_update(t, &p, fwmark);
 
 #ifdef CONFIG_IPV6_SIT_6RD
        if (ipip6_netlink_6rd_parms(data, &ip6rd))
@@ -1649,6 +1656,8 @@ static size_t ipip6_get_size(const struct net_device *dev)
                nla_total_size(2) +
                /* IFLA_IPTUN_ENCAP_DPORT */
                nla_total_size(2) +
+               /* IFLA_IPTUN_FWMARK */
+               nla_total_size(4) +
                0;
 }
 
@@ -1665,7 +1674,8 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
                       !!(parm->iph.frag_off & htons(IP_DF))) ||
            nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
-           nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
+           nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags) ||
+           nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
                goto nla_put_failure;
 
 #ifdef CONFIG_IPV6_SIT_6RD
@@ -1715,6 +1725,7 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
        [IFLA_IPTUN_ENCAP_FLAGS]        = { .type = NLA_U16 },
        [IFLA_IPTUN_ENCAP_SPORT]        = { .type = NLA_U16 },
        [IFLA_IPTUN_ENCAP_DPORT]        = { .type = NLA_U16 },
+       [IFLA_IPTUN_FWMARK]             = { .type = NLA_U32 },
 };
 
 static void ipip6_dellink(struct net_device *dev, struct list_head *head)