diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_gre.c | 27 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 25 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.c | 8 |
3 files changed, 37 insertions, 23 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d828821d88d7..3e37402147f3 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -256,34 +256,41 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, { struct net *net = dev_net(skb->dev); struct metadata_dst *tun_dst = NULL; + struct erspan_base_hdr *ershdr; + struct erspan_metadata *pkt_md; struct ip_tunnel_net *itn; struct ip_tunnel *tunnel; - struct erspanhdr *ershdr; const struct iphdr *iph; - __be32 index; + int ver; int len; itn = net_generic(net, erspan_net_id); len = gre_hdr_len + sizeof(*ershdr); + /* Check based hdr len */ if (unlikely(!pskb_may_pull(skb, len))) return -ENOMEM; iph = ip_hdr(skb); - ershdr = (struct erspanhdr *)(skb->data + gre_hdr_len); + ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); + ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; /* The original GRE header does not have key field, * Use ERSPAN 10-bit session ID as key. */ tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); - index = ershdr->md.index; + pkt_md = (struct erspan_metadata *)(ershdr + 1); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); if (tunnel) { + len = gre_hdr_len + erspan_hdr_len(ver); + if (unlikely(!pskb_may_pull(skb, len))) + return -ENOMEM; + if (__iptunnel_pull_header(skb, - gre_hdr_len + sizeof(*ershdr), + len, htons(ETH_P_TEB), false, false) < 0) goto drop; @@ -307,12 +314,12 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (!md) return PACKET_REJECT; - md->index = index; + memcpy(md, pkt_md, sizeof(*md)); info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); } else { - tunnel->index = ntohl(index); + tunnel->index = ntohl(pkt_md->u.index); } skb_reset_mac_header(skb); @@ -571,7 +578,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, key = &tun_info->key; /* ERSPAN has fixed 8 byte GRE header */ - tunnel_hlen = 8 + sizeof(struct erspanhdr); + tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); if (!rt) @@ -590,7 +597,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, goto err_free_rt; erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), - ntohl(md->index), truncate, true); + ntohl(md->u.index), truncate, true); gre_build_header(skb, 8, TUNNEL_SEQ, htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); @@ -1238,7 +1245,7 @@ static int erspan_tunnel_init(struct net_device *dev) tunnel->tun_hlen = 8; tunnel->parms.iph.protocol = IPPROTO_GRE; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + - sizeof(struct erspanhdr); + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; t_hlen = tunnel->hlen + sizeof(struct iphdr); dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4562579797d1..1303d0c44c36 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -501,25 +501,32 @@ static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, struct tnl_ptk_info *tpi) { + struct erspan_base_hdr *ershdr; + struct erspan_metadata *pkt_md; const struct ipv6hdr *ipv6h; - struct erspanhdr *ershdr; struct ip6_tnl *tunnel; - __be32 index; + u8 ver; ipv6h = ipv6_hdr(skb); - ershdr = (struct erspanhdr *)skb->data; + ershdr = (struct erspan_base_hdr *)skb->data; if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) return PACKET_REJECT; + ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); - index = ershdr->md.index; + pkt_md = (struct erspan_metadata *)(ershdr + 1); tunnel = ip6gre_tunnel_lookup(skb->dev, &ipv6h->saddr, &ipv6h->daddr, tpi->key, tpi->proto); if (tunnel) { - if (__iptunnel_pull_header(skb, sizeof(*ershdr), + int len = erspan_hdr_len(ver); + + if (unlikely(!pskb_may_pull(skb, len))) + return -ENOMEM; + + if (__iptunnel_pull_header(skb, len, htons(ETH_P_TEB), false, false) < 0) return PACKET_REJECT; @@ -545,14 +552,14 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, if (!md) return PACKET_REJECT; - md->index = index; + memcpy(md, pkt_md, sizeof(*md)); info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); } else { - tunnel->parms.index = ntohl(index); + tunnel->parms.index = ntohl(pkt_md->u.index); ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error); } @@ -921,7 +928,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, goto tx_err; erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), - ntohl(md->index), truncate, false); + ntohl(md->u.index), truncate, false); } else { switch (skb->protocol) { @@ -1657,7 +1664,7 @@ static int ip6erspan_tap_init(struct net_device *dev) tunnel->tun_hlen = 8; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + - sizeof(struct erspanhdr); + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; t_hlen = tunnel->hlen + sizeof(struct ipv6hdr); dev->hard_header_len = LL_MAX_HEADER + t_hlen; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 624ea74353dd..bce1f78b0de5 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -644,12 +644,12 @@ static int erspan_tun_opt_from_nlattr(const struct nlattr *attr, BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); memset(&opts, 0, sizeof(opts)); - opts.index = nla_get_be32(attr); + opts.u.index = nla_get_be32(attr); /* Index has only 20-bit */ - if (ntohl(opts.index) & ~INDEX_MASK) { + if (ntohl(opts.u.index) & ~INDEX_MASK) { OVS_NLERR(log, "ERSPAN index number %x too large.", - ntohl(opts.index)); + ntohl(opts.u.index)); return -EINVAL; } @@ -907,7 +907,7 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb, return -EMSGSIZE; else if (output->tun_flags & TUNNEL_ERSPAN_OPT && nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, - ((struct erspan_metadata *)tun_opts)->index)) + ((struct erspan_metadata *)tun_opts)->u.index)) return -EMSGSIZE; } |