net: better IFF_XMIT_DST_RELEASE support
[deliverable/linux.git] / net / ipv4 / ipip.c
index 62eaa005e14610237f9e8a6016c366ba6d6b09cf..37096d64730ef0c3c7c7278995f9c0c6e64896e9 100644 (file)
@@ -224,6 +224,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (IS_ERR(skb))
                goto out;
 
+       skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
        ip_tunnel_xmit(skb, dev, tiph, tiph->protocol);
        return NETDEV_TX_OK;
 
@@ -287,7 +289,7 @@ static void ipip_tunnel_setup(struct net_device *dev)
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_LLTX;
-       dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
+       netif_keep_dst(dev);
 
        dev->features           |= IPIP_FEATURES;
        dev->hw_features        |= IPIP_FEATURES;
@@ -301,7 +303,8 @@ static int ipip_tunnel_init(struct net_device *dev)
        memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
        memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
 
-       tunnel->hlen = 0;
+       tunnel->tun_hlen = 0;
+       tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
        tunnel->parms.iph.protocol = IPPROTO_IPIP;
        return ip_tunnel_init(dev);
 }
@@ -340,10 +343,53 @@ static void ipip_netlink_parms(struct nlattr *data[],
                parms->iph.frag_off = htons(IP_DF);
 }
 
+/* This function returns true when ENCAP attributes are present in the nl msg */
+static bool ipip_netlink_encap_parms(struct nlattr *data[],
+                                    struct ip_tunnel_encap *ipencap)
+{
+       bool ret = false;
+
+       memset(ipencap, 0, sizeof(*ipencap));
+
+       if (!data)
+               return ret;
+
+       if (data[IFLA_IPTUN_ENCAP_TYPE]) {
+               ret = true;
+               ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
+       }
+
+       if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
+               ret = true;
+               ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
+       }
+
+       if (data[IFLA_IPTUN_ENCAP_SPORT]) {
+               ret = true;
+               ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]);
+       }
+
+       if (data[IFLA_IPTUN_ENCAP_DPORT]) {
+               ret = true;
+               ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]);
+       }
+
+       return ret;
+}
+
 static int ipip_newlink(struct net *src_net, struct net_device *dev,
                        struct nlattr *tb[], struct nlattr *data[])
 {
        struct ip_tunnel_parm p;
+       struct ip_tunnel_encap ipencap;
+
+       if (ipip_netlink_encap_parms(data, &ipencap)) {
+               struct ip_tunnel *t = netdev_priv(dev);
+               int err = ip_tunnel_encap_setup(t, &ipencap);
+
+               if (err < 0)
+                       return err;
+       }
 
        ipip_netlink_parms(data, &p);
        return ip_tunnel_newlink(dev, tb, &p);
@@ -353,6 +399,15 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
                           struct nlattr *data[])
 {
        struct ip_tunnel_parm p;
+       struct ip_tunnel_encap ipencap;
+
+       if (ipip_netlink_encap_parms(data, &ipencap)) {
+               struct ip_tunnel *t = netdev_priv(dev);
+               int err = ip_tunnel_encap_setup(t, &ipencap);
+
+               if (err < 0)
+                       return err;
+       }
 
        ipip_netlink_parms(data, &p);
 
@@ -378,6 +433,14 @@ static size_t ipip_get_size(const struct net_device *dev)
                nla_total_size(1) +
                /* IFLA_IPTUN_PMTUDISC */
                nla_total_size(1) +
+               /* IFLA_IPTUN_ENCAP_TYPE */
+               nla_total_size(2) +
+               /* IFLA_IPTUN_ENCAP_FLAGS */
+               nla_total_size(2) +
+               /* IFLA_IPTUN_ENCAP_SPORT */
+               nla_total_size(2) +
+               /* IFLA_IPTUN_ENCAP_DPORT */
+               nla_total_size(2) +
                0;
 }
 
@@ -394,6 +457,17 @@ static int ipip_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))))
                goto nla_put_failure;
+
+       if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
+                       tunnel->encap.type) ||
+           nla_put_u16(skb, IFLA_IPTUN_ENCAP_SPORT,
+                       tunnel->encap.sport) ||
+           nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT,
+                       tunnel->encap.dport) ||
+           nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
+                       tunnel->encap.dport))
+               goto nla_put_failure;
+
        return 0;
 
 nla_put_failure:
@@ -407,6 +481,10 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
        [IFLA_IPTUN_TTL]                = { .type = NLA_U8 },
        [IFLA_IPTUN_TOS]                = { .type = NLA_U8 },
        [IFLA_IPTUN_PMTUDISC]           = { .type = NLA_U8 },
+       [IFLA_IPTUN_ENCAP_TYPE]         = { .type = NLA_U16 },
+       [IFLA_IPTUN_ENCAP_FLAGS]        = { .type = NLA_U16 },
+       [IFLA_IPTUN_ENCAP_SPORT]        = { .type = NLA_U16 },
+       [IFLA_IPTUN_ENCAP_DPORT]        = { .type = NLA_U16 },
 };
 
 static struct rtnl_link_ops ipip_link_ops __read_mostly = {
This page took 0.027788 seconds and 5 git commands to generate.