|
@@ -122,125 +122,6 @@ static int ipgre_tunnel_init(struct net_device *dev);
|
|
|
static int ipgre_net_id __read_mostly;
|
|
|
static int gre_tap_net_id __read_mostly;
|
|
|
|
|
|
-static int ip_gre_calc_hlen(__be16 o_flags)
|
|
|
-{
|
|
|
- int addend = 4;
|
|
|
-
|
|
|
- if (o_flags & TUNNEL_CSUM)
|
|
|
- addend += 4;
|
|
|
- if (o_flags & TUNNEL_KEY)
|
|
|
- addend += 4;
|
|
|
- if (o_flags & TUNNEL_SEQ)
|
|
|
- addend += 4;
|
|
|
- return addend;
|
|
|
-}
|
|
|
-
|
|
|
-static __be16 gre_flags_to_tnl_flags(__be16 flags)
|
|
|
-{
|
|
|
- __be16 tflags = 0;
|
|
|
-
|
|
|
- if (flags & GRE_CSUM)
|
|
|
- tflags |= TUNNEL_CSUM;
|
|
|
- if (flags & GRE_ROUTING)
|
|
|
- tflags |= TUNNEL_ROUTING;
|
|
|
- if (flags & GRE_KEY)
|
|
|
- tflags |= TUNNEL_KEY;
|
|
|
- if (flags & GRE_SEQ)
|
|
|
- tflags |= TUNNEL_SEQ;
|
|
|
- if (flags & GRE_STRICT)
|
|
|
- tflags |= TUNNEL_STRICT;
|
|
|
- if (flags & GRE_REC)
|
|
|
- tflags |= TUNNEL_REC;
|
|
|
- if (flags & GRE_VERSION)
|
|
|
- tflags |= TUNNEL_VERSION;
|
|
|
-
|
|
|
- return tflags;
|
|
|
-}
|
|
|
-
|
|
|
-static __be16 tnl_flags_to_gre_flags(__be16 tflags)
|
|
|
-{
|
|
|
- __be16 flags = 0;
|
|
|
-
|
|
|
- if (tflags & TUNNEL_CSUM)
|
|
|
- flags |= GRE_CSUM;
|
|
|
- if (tflags & TUNNEL_ROUTING)
|
|
|
- flags |= GRE_ROUTING;
|
|
|
- if (tflags & TUNNEL_KEY)
|
|
|
- flags |= GRE_KEY;
|
|
|
- if (tflags & TUNNEL_SEQ)
|
|
|
- flags |= GRE_SEQ;
|
|
|
- if (tflags & TUNNEL_STRICT)
|
|
|
- flags |= GRE_STRICT;
|
|
|
- if (tflags & TUNNEL_REC)
|
|
|
- flags |= GRE_REC;
|
|
|
- if (tflags & TUNNEL_VERSION)
|
|
|
- flags |= GRE_VERSION;
|
|
|
-
|
|
|
- return flags;
|
|
|
-}
|
|
|
-
|
|
|
-static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
|
|
|
- bool *csum_err)
|
|
|
-{
|
|
|
- const struct gre_base_hdr *greh;
|
|
|
- __be32 *options;
|
|
|
- int hdr_len;
|
|
|
-
|
|
|
- if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
|
|
- if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- tpi->flags = gre_flags_to_tnl_flags(greh->flags);
|
|
|
- hdr_len = ip_gre_calc_hlen(tpi->flags);
|
|
|
-
|
|
|
- if (!pskb_may_pull(skb, hdr_len))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
|
|
- tpi->proto = greh->protocol;
|
|
|
-
|
|
|
- options = (__be32 *)(greh + 1);
|
|
|
- if (greh->flags & GRE_CSUM) {
|
|
|
- if (skb_checksum_simple_validate(skb)) {
|
|
|
- *csum_err = true;
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
|
|
|
- null_compute_pseudo);
|
|
|
- options++;
|
|
|
- }
|
|
|
-
|
|
|
- if (greh->flags & GRE_KEY) {
|
|
|
- tpi->key = *options;
|
|
|
- options++;
|
|
|
- } else {
|
|
|
- tpi->key = 0;
|
|
|
- }
|
|
|
- if (unlikely(greh->flags & GRE_SEQ)) {
|
|
|
- tpi->seq = *options;
|
|
|
- options++;
|
|
|
- } else {
|
|
|
- tpi->seq = 0;
|
|
|
- }
|
|
|
- /* WCCP version 1 and 2 protocol decoding.
|
|
|
- * - Change protocol to IP
|
|
|
- * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
|
|
|
- */
|
|
|
- if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
|
|
|
- tpi->proto = htons(ETH_P_IP);
|
|
|
- if ((*(u8 *)options & 0xF0) != 0x40) {
|
|
|
- hdr_len += 4;
|
|
|
- if (!pskb_may_pull(skb, hdr_len))
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
- return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
|
|
|
-}
|
|
|
-
|
|
|
static void ipgre_err(struct sk_buff *skb, u32 info,
|
|
|
const struct tnl_ptk_info *tpi)
|
|
|
{
|
|
@@ -340,12 +221,16 @@ static void gre_err(struct sk_buff *skb, u32 info)
|
|
|
const int code = icmp_hdr(skb)->code;
|
|
|
struct tnl_ptk_info tpi;
|
|
|
bool csum_err = false;
|
|
|
+ int hdr_len;
|
|
|
|
|
|
- if (parse_gre_header(skb, &tpi, &csum_err)) {
|
|
|
+ if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len)) {
|
|
|
if (!csum_err) /* ignore csum errors. */
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
|
|
|
+ return;
|
|
|
+
|
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
|
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
|
|
skb->dev->ifindex, 0, IPPROTO_GRE, 0);
|
|
@@ -419,6 +304,7 @@ static int gre_rcv(struct sk_buff *skb)
|
|
|
{
|
|
|
struct tnl_ptk_info tpi;
|
|
|
bool csum_err = false;
|
|
|
+ int hdr_len;
|
|
|
|
|
|
#ifdef CONFIG_NET_IPGRE_BROADCAST
|
|
|
if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
|
|
@@ -428,7 +314,10 @@ static int gre_rcv(struct sk_buff *skb)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- if (parse_gre_header(skb, &tpi, &csum_err) < 0)
|
|
|
+ if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len) < 0)
|
|
|
+ goto drop;
|
|
|
+
|
|
|
+ if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
|
|
|
goto drop;
|
|
|
|
|
|
if (ipgre_rcv(skb, &tpi) == PACKET_RCVD)
|
|
@@ -460,7 +349,7 @@ static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
|
|
|
|
|
|
skb_reset_transport_header(skb);
|
|
|
greh = (struct gre_base_hdr *)skb->data;
|
|
|
- greh->flags = tnl_flags_to_gre_flags(flags);
|
|
|
+ greh->flags = gre_tnl_flags_to_gre_flags(flags);
|
|
|
greh->protocol = proto;
|
|
|
|
|
|
if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
|
|
@@ -552,7 +441,7 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
fl.saddr);
|
|
|
}
|
|
|
|
|
|
- tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
|
|
|
+ tunnel_hlen = gre_calc_hlen(key->tun_flags);
|
|
|
|
|
|
min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
|
|
|
+ tunnel_hlen + sizeof(struct iphdr);
|
|
@@ -694,8 +583,8 @@ static int ipgre_tunnel_ioctl(struct net_device *dev,
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
- p.i_flags = tnl_flags_to_gre_flags(p.i_flags);
|
|
|
- p.o_flags = tnl_flags_to_gre_flags(p.o_flags);
|
|
|
+ p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
|
|
|
+ p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
|
|
|
|
|
|
if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
|
|
|
return -EFAULT;
|
|
@@ -739,7 +628,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
|
|
iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph));
|
|
|
greh = (struct gre_base_hdr *)(iph+1);
|
|
|
- greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags);
|
|
|
+ greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
|
|
|
greh->protocol = htons(type);
|
|
|
|
|
|
memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
|
|
@@ -840,7 +729,7 @@ static void __gre_tunnel_init(struct net_device *dev)
|
|
|
int t_hlen;
|
|
|
|
|
|
tunnel = netdev_priv(dev);
|
|
|
- tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
|
|
|
+ tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
|
|
|
tunnel->parms.iph.protocol = IPPROTO_GRE;
|
|
|
|
|
|
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
|
|
@@ -1155,8 +1044,10 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
|
struct ip_tunnel_parm *p = &t->parms;
|
|
|
|
|
|
if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
|
|
|
- nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
|
|
|
- nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
|
|
|
+ nla_put_be16(skb, IFLA_GRE_IFLAGS,
|
|
|
+ gre_tnl_flags_to_gre_flags(p->i_flags)) ||
|
|
|
+ nla_put_be16(skb, IFLA_GRE_OFLAGS,
|
|
|
+ gre_tnl_flags_to_gre_flags(p->o_flags)) ||
|
|
|
nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
|
|
|
nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
|
|
|
nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
|