summaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorAhmed Abdelsalam <amsalam20@gmail.com>2017-08-30 10:50:37 +0200
committerDavid S. Miller <davem@davemloft.net>2017-08-30 15:19:25 -0700
commit5829d70b0b6cd055e7a9af3abe573927e919e30b (patch)
tree0e47f759557d431c89cf79fef24d81667fcb52cd /net/ipv6
parent35aed4acb9cec6e4e250674dd3060044dbda6e68 (diff)
downloadlinux-5829d70b0b6cd055e7a9af3abe573927e919e30b.tar.bz2
ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200"
IPv6 packet may carry more than one extension header, and IPv6 nodes must accept and attempt to process extension headers in any order and occurring any number of times in the same packet. Hence, there should be no assumption that Segment Routing extension header is to appear immediately after the IPv6 header. Moreover, section 4.1 of RFC 8200 gives a recommendation on the order of appearance of those extension headers within an IPv6 packet. According to this recommendation, Segment Routing extension header should appear after Hop-by-Hop and Destination Options headers (if they present). This patch fixes the get_srh(), so it gets the segment routing header regardless of its position in the chain of the extension headers in IPv6 packet, and makes sure that the IPv6 routing extension header is of Type 4. Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com> Acked-by: David Lebrun <david.lebrun@uclouvain.be> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/seg6_local.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 9c1a885ee482..7ff54db73a48 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -62,17 +62,23 @@ static struct seg6_local_lwt *seg6_local_lwtunnel(struct lwtunnel_state *lwt)
static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb)
{
struct ipv6_sr_hdr *srh;
- struct ipv6hdr *hdr;
- int len;
+ int len, srhoff = 0;
+
+ if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
+ return NULL;
+
+ if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
+ return NULL;
+
+ srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
- hdr = ipv6_hdr(skb);
- if (hdr->nexthdr != IPPROTO_ROUTING)
+ /* make sure it's a Segment Routing header (Routing Type 4) */
+ if (srh->type != IPV6_SRCRT_TYPE_4)
return NULL;
- srh = (struct ipv6_sr_hdr *)(hdr + 1);
len = (srh->hdrlen + 1) << 3;
- if (!pskb_may_pull(skb, sizeof(*hdr) + len))
+ if (!pskb_may_pull(skb, srhoff + len))
return NULL;
if (!seg6_validate_srh(srh, len))