#include <linux/tcp.h>
 #include <net/flow_dissector.h>
 #include <scsi/fc/fc_fcoe.h>
+#include <uapi/linux/batadv_packet.h>
 
 static void dissector_set_key(struct flow_dissector *flow_dissector,
                              enum flow_dissector_key_id key_id)
        return FLOW_DISSECT_RET_PROTO_AGAIN;
 }
 
+/**
+ * __skb_flow_dissect_batadv() - dissect batman-adv header
+ * @skb: sk_buff to with the batman-adv header
+ * @key_control: flow dissectors control key
+ * @data: raw buffer pointer to the packet, if NULL use skb->data
+ * @p_proto: pointer used to update the protocol to process next
+ * @p_nhoff: pointer used to update inner network header offset
+ * @hlen: packet header length
+ * @flags: any combination of FLOW_DISSECTOR_F_*
+ *
+ * ETH_P_BATMAN packets are tried to be dissected. Only
+ * &struct batadv_unicast packets are actually processed because they contain an
+ * inner ethernet header and are usually followed by actual network header. This
+ * allows the flow dissector to continue processing the packet.
+ *
+ * Return: FLOW_DISSECT_RET_PROTO_AGAIN when &struct batadv_unicast was found,
+ *  FLOW_DISSECT_RET_OUT_GOOD when dissector should stop after encapsulation,
+ *  otherwise FLOW_DISSECT_RET_OUT_BAD
+ */
+static enum flow_dissect_ret
+__skb_flow_dissect_batadv(const struct sk_buff *skb,
+                         struct flow_dissector_key_control *key_control,
+                         void *data, __be16 *p_proto, int *p_nhoff, int hlen,
+                         unsigned int flags)
+{
+       struct {
+               struct batadv_unicast_packet batadv_unicast;
+               struct ethhdr eth;
+       } *hdr, _hdr;
+
+       hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+                                  &_hdr);
+       if (!hdr)
+               return FLOW_DISSECT_RET_OUT_BAD;
+
+       if (hdr->batadv_unicast.version != BATADV_COMPAT_VERSION)
+               return FLOW_DISSECT_RET_OUT_BAD;
+
+       if (hdr->batadv_unicast.packet_type != BATADV_UNICAST)
+               return FLOW_DISSECT_RET_OUT_BAD;
+
+       *p_proto = hdr->eth.h_proto;
+       *p_nhoff += sizeof(*hdr);
+
+       key_control->flags |= FLOW_DIS_ENCAPSULATION;
+       if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
+               return FLOW_DISSECT_RET_OUT_GOOD;
+
+       return FLOW_DISSECT_RET_PROTO_AGAIN;
+}
+
 static void
 __skb_flow_dissect_tcp(const struct sk_buff *skb,
                       struct flow_dissector *flow_dissector,
                                               nhoff, hlen);
                break;
 
+       case htons(ETH_P_BATMAN):
+               fdret = __skb_flow_dissect_batadv(skb, key_control, data,
+                                                 &proto, &nhoff, hlen, flags);
+               break;
+
        default:
                fdret = FLOW_DISSECT_RET_OUT_BAD;
                break;