|
@@ -254,21 +254,18 @@ static bool icmphdr_ok(struct sk_buff *skb)
|
|
|
|
|
|
static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
|
|
{
|
|
|
+ unsigned short frag_off;
|
|
|
+ unsigned int payload_ofs = 0;
|
|
|
unsigned int nh_ofs = skb_network_offset(skb);
|
|
|
unsigned int nh_len;
|
|
|
- int payload_ofs;
|
|
|
struct ipv6hdr *nh;
|
|
|
- uint8_t nexthdr;
|
|
|
- __be16 frag_off;
|
|
|
- int err;
|
|
|
+ int err, nexthdr, flags = 0;
|
|
|
|
|
|
err = check_header(skb, nh_ofs + sizeof(*nh));
|
|
|
if (unlikely(err))
|
|
|
return err;
|
|
|
|
|
|
nh = ipv6_hdr(skb);
|
|
|
- nexthdr = nh->nexthdr;
|
|
|
- payload_ofs = (u8 *)(nh + 1) - skb->data;
|
|
|
|
|
|
key->ip.proto = NEXTHDR_NONE;
|
|
|
key->ip.tos = ipv6_get_dsfield(nh);
|
|
@@ -277,10 +274,9 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
|
|
key->ipv6.addr.src = nh->saddr;
|
|
|
key->ipv6.addr.dst = nh->daddr;
|
|
|
|
|
|
- payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off);
|
|
|
-
|
|
|
- if (frag_off) {
|
|
|
- if (frag_off & htons(~0x7))
|
|
|
+ nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags);
|
|
|
+ if (flags & IP6_FH_F_FRAG) {
|
|
|
+ if (frag_off)
|
|
|
key->ip.frag = OVS_FRAG_TYPE_LATER;
|
|
|
else
|
|
|
key->ip.frag = OVS_FRAG_TYPE_FIRST;
|
|
@@ -288,11 +284,11 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
|
|
key->ip.frag = OVS_FRAG_TYPE_NONE;
|
|
|
}
|
|
|
|
|
|
- /* Delayed handling of error in ipv6_skip_exthdr() as it
|
|
|
- * always sets frag_off to a valid value which may be
|
|
|
+ /* Delayed handling of error in ipv6_find_hdr() as it
|
|
|
+ * always sets flags and frag_off to a valid value which may be
|
|
|
* used to set key->ip.frag above.
|
|
|
*/
|
|
|
- if (unlikely(payload_ofs < 0))
|
|
|
+ if (unlikely(nexthdr < 0))
|
|
|
return -EPROTO;
|
|
|
|
|
|
nh_len = payload_ofs - nh_ofs;
|