aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Neira Ayuso <[email protected]>2019-11-04 14:41:34 +0100
committerPablo Neira Ayuso <[email protected]>2019-11-13 10:41:42 +0100
commitf6ae9f120dada00abfb47313364c35118469455f (patch)
tree4e1fd4c024d8ef5e97184234a12a5cdb17922c15
parentbe193f5e21d0ec674badef9fde8eca71fb2d8546 (diff)
netfilter: nft_payload: add C-VLAN support
If the encapsulated ethertype announces another inner VLAN header and the offset falls within the boundaries of the inner VLAN header, then adjust arithmetics to include the extra VLAN header length and fetch the bytes from the vlan header in the skbuff data area that represents this inner VLAN header. Signed-off-by: Pablo Neira Ayuso <[email protected]>
-rw-r--r--net/netfilter/nft_payload.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 3db9c802ea62..0877d46b8605 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -43,27 +43,36 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
int mac_off = skb_mac_header(skb) - skb->data;
u8 *vlanh, *dst_u8 = (u8 *) d;
struct vlan_ethhdr veth;
+ u8 vlan_hlen = 0;
+
+ if ((skb->protocol == htons(ETH_P_8021AD) ||
+ skb->protocol == htons(ETH_P_8021Q)) &&
+ offset >= VLAN_ETH_HLEN && offset < VLAN_ETH_HLEN + VLAN_HLEN)
+ vlan_hlen += VLAN_HLEN;
vlanh = (u8 *) &veth;
- if (offset < VLAN_ETH_HLEN) {
+ if (offset < VLAN_ETH_HLEN + vlan_hlen) {
u8 ethlen = len;
- if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth))
+ if (vlan_hlen &&
+ skb_copy_bits(skb, mac_off, &veth, VLAN_ETH_HLEN) < 0)
+ return false;
+ else if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth))
return false;
- if (offset + len > VLAN_ETH_HLEN)
- ethlen -= offset + len - VLAN_ETH_HLEN;
+ if (offset + len > VLAN_ETH_HLEN + vlan_hlen)
+ ethlen -= offset + len - VLAN_ETH_HLEN + vlan_hlen;
- memcpy(dst_u8, vlanh + offset, ethlen);
+ memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen);
len -= ethlen;
if (len == 0)
return true;
dst_u8 += ethlen;
- offset = ETH_HLEN;
+ offset = ETH_HLEN + vlan_hlen;
} else {
- offset -= VLAN_HLEN;
+ offset -= VLAN_HLEN + vlan_hlen;
}
return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;