Merge branch 'parisc-4.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.git] / net / core / flow_dissector.c
index 12e7003..a669dea 100644 (file)
 #include <net/flow_dissector.h>
 #include <scsi/fc/fc_fcoe.h>
 
-static bool dissector_uses_key(const struct flow_dissector *flow_dissector,
-                              enum flow_dissector_key_id key_id)
-{
-       return flow_dissector->used_keys & (1 << key_id);
-}
-
 static void dissector_set_key(struct flow_dissector *flow_dissector,
                              enum flow_dissector_key_id key_id)
 {
        flow_dissector->used_keys |= (1 << key_id);
 }
 
-static void *skb_flow_dissector_target(struct flow_dissector *flow_dissector,
-                                      enum flow_dissector_key_id key_id,
-                                      void *target_container)
-{
-       return ((char *) target_container) + flow_dissector->offset[key_id];
-}
-
 void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
                             const struct flow_dissector_key *key,
                             unsigned int key_count)
@@ -178,15 +165,16 @@ ip:
 
                ip_proto = iph->protocol;
 
-               if (!dissector_uses_key(flow_dissector,
-                                       FLOW_DISSECTOR_KEY_IPV4_ADDRS))
-                       break;
+               if (dissector_uses_key(flow_dissector,
+                                      FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+                       key_addrs = skb_flow_dissector_target(flow_dissector,
+                                                             FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                             target_container);
 
-               key_addrs = skb_flow_dissector_target(flow_dissector,
-                             FLOW_DISSECTOR_KEY_IPV4_ADDRS, target_container);
-               memcpy(&key_addrs->v4addrs, &iph->saddr,
-                      sizeof(key_addrs->v4addrs));
-               key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+                       memcpy(&key_addrs->v4addrs, &iph->saddr,
+                              sizeof(key_addrs->v4addrs));
+                       key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+               }
 
                if (ip_is_fragment(iph)) {
                        key_control->flags |= FLOW_DIS_IS_FRAGMENT;
@@ -219,13 +207,12 @@ ipv6:
 
                if (dissector_uses_key(flow_dissector,
                                       FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
-                       struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs;
-
-                       key_ipv6_addrs = skb_flow_dissector_target(flow_dissector,
-                                                                  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
-                                                                  target_container);
+                       key_addrs = skb_flow_dissector_target(flow_dissector,
+                                                             FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                             target_container);
 
-                       memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs));
+                       memcpy(&key_addrs->v6addrs, &iph->saddr,
+                              sizeof(key_addrs->v6addrs));
                        key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
                }
 
@@ -339,8 +326,11 @@ mpls:
        }
 
        case htons(ETH_P_FCOE):
-               key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
-               /* fall through */
+               if ((hlen - nhoff) < FCOE_HEADER_LEN)
+                       goto out_bad;
+
+               nhoff += FCOE_HEADER_LEN;
+               goto out_good;
        default:
                goto out_bad;
        }
@@ -447,13 +437,12 @@ ip_proto_again:
                key_control->flags |= FLOW_DIS_IS_FRAGMENT;
 
                nhoff += sizeof(_fh);
+               ip_proto = fh->nexthdr;
 
                if (!(fh->frag_off & htons(IP6_OFFSET))) {
                        key_control->flags |= FLOW_DIS_FIRST_FRAG;
-                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
-                               ip_proto = fh->nexthdr;
+                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)
                                goto ip_proto_again;
-                       }
                }
                goto out_good;
        }
@@ -740,6 +729,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
 {
        u32 poff = keys->control.thoff;
 
+       /* skip L4 headers for fragments after the first */
+       if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) &&
+           !(keys->control.flags & FLOW_DIS_FIRST_FRAG))
+               return poff;
+
        switch (keys->basic.ip_proto) {
        case IPPROTO_TCP: {
                /* access doff as u8 to avoid unaligned access */