[qca-nss-sfe] update PPPoE and VLAN to use kernel API
Change-Id: I6bd406f31b20cd9ebf73b98c42cb34bc819aa2c2
Signed-off-by: Nitin Shetty <quic_nitinsj@quicinc.com>
diff --git a/sfe.c b/sfe.c
index 1f451f7..182288f 100644
--- a/sfe.c
+++ b/sfe.c
@@ -562,12 +562,6 @@
static bool sfe_recv_parse_l2(struct net_device *dev, struct sk_buff *skb, struct sfe_l2_info *l2_info)
{
/*
- * l2_hdr_offset will not change as we parse more L2.5 headers
- * TODO: Move from storing offsets to storing pointers
- */
- sfe_l2_hdr_offset_set(l2_info, ((skb->data - ETH_HLEN) - skb->head));
-
- /*
* VLAN parsing
*/
if (unlikely(!sfe_vlan_check_and_parse_tag(skb, l2_info))) {
@@ -575,13 +569,9 @@
}
/*
- * PPPoE parsing
+ * Parse only PPPoE session packets
*/
if (htons(ETH_P_PPP_SES) == skb->protocol) {
- /*
- * Parse only PPPoE session packets
- * skb->data is pointing to PPPoE hdr
- */
if (!sfe_pppoe_parse_hdr(skb, l2_info)) {
/*
@@ -590,11 +580,6 @@
*/
return false;
}
-
- /*
- * Pull by L2 header size
- */
- __skb_pull(skb, sfe_l2_hdr_size_get(l2_info));
}
return true;
}
@@ -607,12 +592,17 @@
/*
* PPPoE undo
*/
- __skb_push(skb, sfe_l2_hdr_size_get(l2_info));
+ sfe_pppoe_undo_parse(skb, l2_info);
/*
* VLAN undo
*/
sfe_vlan_undo_parse(skb, l2_info);
+
+ /*
+ * packet is not handled by SFE, so reset the network header
+ */
+ skb_reset_network_header(skb);
}
/*
@@ -1278,7 +1268,6 @@
* Setting parse flags to 0 since l2_info is passed for non L2.5 header case as well
*/
l2_info.parse_flags = 0;
- l2_info.l2_hdr_size = 0;
l2_info.vlan_hdr_cnt = 0;
#ifdef CONFIG_NET_CLS_ACT
diff --git a/sfe.h b/sfe.h
index c117729..6cadbfe 100644
--- a/sfe.h
+++ b/sfe.h
@@ -65,9 +65,7 @@
*/
struct sfe_l2_info {
u16 parse_flags; /* Flags indicating L2.5 headers presence */
- u16 l2_hdr_offset; /* Offset of L2 header */
- u16 l2_hdr_size; /* L2 header size */
- u16 pppoe_hdr_offset; /* PPPOE header offset */
+ u16 pppoe_session_id; /* PPPOE header offset */
u16 protocol; /* L3 Protocol */
struct sfe_vlan_hdr vlan_hdr[SFE_MAX_VLAN_DEPTH];
/* VLAN tag(s) of ingress packet */
@@ -265,57 +263,21 @@
}
/*
- * sfe_l2_hdr_offset_get()
- * Get L2 header offset
+ * sfe_l2_pppoe_session_id_get()
+ * Get PPPPoE session ID from l2_info
*/
-static inline u16 sfe_l2_hdr_offset_get(struct sfe_l2_info *l2_info)
+static inline u16 sfe_l2_pppoe_session_id_get(struct sfe_l2_info *l2_info)
{
- return l2_info->l2_hdr_offset;
+ return l2_info->pppoe_session_id;
}
/*
- * sfe_l2_hdr_offset_set()
- * Set L2 header offset
+ * sfe_l2_pppoe_session_id_set()
+ * Set PPPoE session ID to l2_info
*/
-static inline void sfe_l2_hdr_offset_set(struct sfe_l2_info *l2_info, u16 offset)
+static inline void sfe_l2_pppoe_session_id_set(struct sfe_l2_info *l2_info, u16 session_id)
{
- l2_info->l2_hdr_offset = offset;
-}
-
-/*
- * sfe_l2_pppoe_hdr_offset_get()
- * Get L2 PPPoE header offset
- */
-static inline u16 sfe_l2_pppoe_hdr_offset_get(struct sfe_l2_info *l2_info)
-{
- return l2_info->pppoe_hdr_offset;
-}
-
-/*
- * sfe_l2_pppoe_hdr_offset_set()
- * Set L2 PPPoE header offset
- */
-static inline void sfe_l2_pppoe_hdr_offset_set(struct sfe_l2_info *l2_info, u16 offset)
-{
- l2_info->pppoe_hdr_offset = offset;
-}
-
-/*
- * sfe_l2_hdr_size_get()
- * Get L2 header size
- */
-static inline u16 sfe_l2_hdr_size_get(struct sfe_l2_info *l2_info)
-{
- return l2_info->l2_hdr_size;
-}
-
-/*
- * sfe_l2_hdr_size_set()
- * Set L2 header size
- */
-static inline void sfe_l2_hdr_size_set(struct sfe_l2_info *l2_info, u16 size)
-{
- l2_info->l2_hdr_size = size;
+ l2_info->pppoe_session_id = session_id;
}
/*
diff --git a/sfe_ipv4_tcp.c b/sfe_ipv4_tcp.c
index e957259..14283ea 100644
--- a/sfe_ipv4_tcp.c
+++ b/sfe_ipv4_tcp.c
@@ -499,8 +499,8 @@
* For PPPoE packets, match server MAC and session id
*/
if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
- struct pppoe_hdr *ph;
struct ethhdr *eth;
+ bool pppoe_match;
if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
rcu_read_unlock();
@@ -509,22 +509,27 @@
return 0;
}
- ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
- eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
- if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
- DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
- skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+ eth = eth_hdr(skb);
+
+ pppoe_match = (cm->pppoe_session_id == sfe_l2_pppoe_session_id_get(l2_info)) &&
+ ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source);
+
+ if (unlikely(!pppoe_match)) {
+ DEBUG_TRACE("%px: PPPoE session ID %d and %d or MAC %pM and %pM did not match\n",
+ skb, cm->pppoe_session_id, sfe_l2_pppoe_session_id_get(l2_info),
+ cm->pppoe_remote_mac, eth->h_source);
rcu_read_unlock();
sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
return 0;
}
+
skb->protocol = htons(l2_info->protocol);
this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
/*
- * If packet contains PPPoE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+ * If packet contains PPPoE header but CME doesn't contain PPPoE flag yet we are exceptioning
+ * the packet to linux
*/
if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_BRIDGE_FLOW))) {
rcu_read_unlock();
@@ -534,10 +539,10 @@
}
/*
- * For bridged flows when packet contains PPPoE header, restore the header back and forward to xmit interface
+ * For bridged flows when packet contains PPPoE header, restore the header back and forward
+ * to xmit interface
*/
__skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
- l2_info->l2_hdr_size -= (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr));
this_cpu_inc(si->stats_pcpu->pppoe_bridge_packets_forwarded64);
}
diff --git a/sfe_ipv4_udp.c b/sfe_ipv4_udp.c
index 1bef924..61ed28e 100644
--- a/sfe_ipv4_udp.c
+++ b/sfe_ipv4_udp.c
@@ -293,8 +293,8 @@
* For PPPoE packets, match server MAC and session id
*/
if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
- struct pppoe_hdr *ph;
struct ethhdr *eth;
+ bool pppoe_match;
if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
rcu_read_unlock();
@@ -303,22 +303,27 @@
return 0;
}
- ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
- eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
- if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
- DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
- skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+ eth = eth_hdr(skb);
+
+ pppoe_match = (cm->pppoe_session_id == sfe_l2_pppoe_session_id_get(l2_info)) &&
+ ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source);
+
+ if (unlikely(!pppoe_match)) {
+ DEBUG_TRACE("%px: PPPoE session ID %d and %d or MAC %pM and %pM did not match\n",
+ skb, cm->pppoe_session_id, sfe_l2_pppoe_session_id_get(l2_info),
+ cm->pppoe_remote_mac, eth->h_source);
rcu_read_unlock();
sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
return 0;
}
+
skb->protocol = htons(l2_info->protocol);
this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
/*
- * If packet contains PPPoE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+ * If packet contains PPPoE header but CME doesn't contain PPPoE flag yet we are exceptioning
+ * the packet to linux
*/
if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_BRIDGE_FLOW))) {
rcu_read_unlock();
@@ -329,10 +334,10 @@
}
/*
- * For bridged flows when packet contains PPPoE header, restore the header back and forward to xmit interface
+ * For bridged flows when packet contains PPPoE header, restore the header back and forward
+ * to xmit interface
*/
__skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
- l2_info->l2_hdr_size -= (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr));
this_cpu_inc(si->stats_pcpu->pppoe_bridge_packets_forwarded64);
}
diff --git a/sfe_ipv6_tcp.c b/sfe_ipv6_tcp.c
index 28cc541..1f377a2 100644
--- a/sfe_ipv6_tcp.c
+++ b/sfe_ipv6_tcp.c
@@ -508,29 +508,32 @@
* For PPPoE packets, match server MAC and session id
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
- struct pppoe_hdr *ph;
struct ethhdr *eth;
+ bool pppoe_match;
if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
rcu_read_unlock();
DEBUG_TRACE("%px: PPPoE header not present in packet for PPPoE rule\n", skb);
- sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+ sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
return 0;
}
- ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
- eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
+ eth = eth_hdr(skb);
- if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
- DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match \n",
- skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+ pppoe_match = (cm->pppoe_session_id == sfe_l2_pppoe_session_id_get(l2_info)) &&
+ ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source);
+
+ if (unlikely(!pppoe_match)) {
+ DEBUG_TRACE("%px: PPPoE sessions ID %d and %d or MAC %pM and %pM did not match\n",
+ skb, cm->pppoe_session_id, sfe_l2_pppoe_session_id_get(l2_info),
+ cm->pppoe_remote_mac, eth->h_source);
rcu_read_unlock();
sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
return 0;
}
+
skb->protocol = htons(l2_info->protocol);
this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
/*
@@ -548,7 +551,6 @@
* For bridged flows when packet contains PPPoE header, restore the header back and forward to xmit interface
*/
__skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
- l2_info->l2_hdr_size -= (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr));
this_cpu_inc(si->stats_pcpu->pppoe_bridge_packets_forwarded64);
}
diff --git a/sfe_ipv6_udp.c b/sfe_ipv6_udp.c
index 5ffefdd..3df6d51 100644
--- a/sfe_ipv6_udp.c
+++ b/sfe_ipv6_udp.c
@@ -300,8 +300,8 @@
* For PPPoE packets, match server MAC and session id
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
- struct pppoe_hdr *ph;
struct ethhdr *eth;
+ bool pppoe_match;
if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
rcu_read_unlock();
@@ -310,38 +310,40 @@
return 0;
}
- ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
- eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
- if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
- DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
- skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+ eth = eth_hdr(skb);
+
+ pppoe_match = (cm->pppoe_session_id == sfe_l2_pppoe_session_id_get(l2_info)) &&
+ ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source);
+
+ if (unlikely(!pppoe_match)) {
+ DEBUG_TRACE("%px: PPPoE sessions ID %d and %d or MAC %pM and %pM did not match\n",
+ skb, cm->pppoe_session_id, sfe_l2_pppoe_session_id_get(l2_info),
+ cm->pppoe_remote_mac, eth->h_source);
rcu_read_unlock();
sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
return 0;
}
+
skb->protocol = htons(l2_info->protocol);
this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
/*
* If packet contains PPPoE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
*/
-
if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_BRIDGE_FLOW))) {
rcu_read_unlock();
DEBUG_TRACE("%px: CME doesn't contain PPPoE flag but packet has PPPoE header\n", skb);
- sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
+ sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
return 0;
+
}
/*
* For bridged flows when packet contains PPPoE header, restore the header back and forward to xmit interface
*/
__skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
- l2_info->l2_hdr_size -= (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr));
this_cpu_inc(si->stats_pcpu->pppoe_bridge_packets_forwarded64);
-
}
/*
diff --git a/sfe_pppoe.c b/sfe_pppoe.c
index 4b20311..770a77d 100644
--- a/sfe_pppoe.c
+++ b/sfe_pppoe.c
@@ -20,6 +20,7 @@
#include <linux/skbuff.h>
#include <linux/if_pppox.h>
#include <linux/ppp_defs.h>
+#include <asm/unaligned.h>
#include "sfe_debug.h"
#include "sfe_api.h"
@@ -34,17 +35,20 @@
*/
void sfe_pppoe_add_header(struct sk_buff *skb, u16 pppoe_session_id, u16 ppp_protocol)
{
- u16 *l2_header;
struct pppoe_hdr *ph;
- struct sfe_ppp_hdr *ppp;
- u16 *l3_header = (u16 *)skb->data;
+ unsigned char *pp;
+ unsigned int data_len;
/*
- * PPPoE header (6 bytes) + PPP header (2 bytes)
- *
- * Hence move by 8 bytes to accomodate PPPoE header
+ * Insert the PPP header protocol
*/
- l2_header = l3_header - ((sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)) / 2);
+ pp = __skb_push(skb, 2);
+ put_unaligned_be16(ppp_protocol, pp);
+
+ data_len = skb->len;
+
+ ph = (struct pppoe_hdr *)__skb_push(skb, sizeof(*ph));
+ skb_reset_network_header(skb);
/*
* Headers in skb will look like in below sequence
@@ -53,24 +57,12 @@
* The length field in the PPPoE header indicates the length of the PPPoE payload which
* consists of a 2-byte PPP header plus a skb->len.
*/
- ph = (struct pppoe_hdr *)l2_header;
ph->ver = 1;
ph->type = 1;
ph->code = 0;
ph->sid = htons(pppoe_session_id);
- ph->length = htons(skb->len + sizeof(struct sfe_ppp_hdr));
+ ph->length = htons(data_len);
skb->protocol = htons(ETH_P_PPP_SES);
-
- /*
- * Insert the PPP header protocol
- */
- ppp = (struct sfe_ppp_hdr *)(l2_header + (sizeof(struct pppoe_hdr) / 2));
- ppp->protocol = htons(ppp_protocol);
-
- /*
- * L2 header offset will point to PPPoE header,
- */
- __skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
}
/*
@@ -84,7 +76,7 @@
unsigned int len;
int pppoe_len;
struct sfe_ppp_hdr *ppp;
- struct pppoe_hdr *ph = (struct pppoe_hdr *)skb->data;
+ struct pppoe_hdr *ph = pppoe_hdr(skb);
/*
* Check that we have space for PPPoE header here.
@@ -125,8 +117,24 @@
}
sfe_l2_parse_flag_set(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS);
- sfe_l2_pppoe_hdr_offset_set(l2_info, (skb->data - skb->head));
- sfe_l2_hdr_size_set(l2_info, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
+ sfe_l2_pppoe_session_id_set(l2_info, ntohs(ph->sid));
+
+ /*
+ * strip PPPoE header
+ */
+ __skb_pull(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
+ skb_reset_network_header(skb);
return true;
}
+
+/*
+ * sfe_pppoe_undo_parse()
+ * undo changes done to skb during PPPoE parsing
+ */
+void sfe_pppoe_undo_parse(struct sk_buff *skb, struct sfe_l2_info *l2_info)
+{
+ if (sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS)) {
+ __skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
+ }
+}
diff --git a/sfe_pppoe.h b/sfe_pppoe.h
index c797dc7..cb0af1e 100644
--- a/sfe_pppoe.h
+++ b/sfe_pppoe.h
@@ -34,5 +34,6 @@
void sfe_pppoe_add_header(struct sk_buff *skb, u16 pppoe_session_id, u16 ppp_protocol);
bool sfe_pppoe_parse_hdr(struct sk_buff *skb, struct sfe_l2_info *l2_info);
+void sfe_pppoe_undo_parse(struct sk_buff *skb, struct sfe_l2_info *l2_info);
#endif /* __SFE_PPPOE_H */
diff --git a/sfe_vlan.h b/sfe_vlan.h
index 505b24b..263b69a 100644
--- a/sfe_vlan.h
+++ b/sfe_vlan.h
@@ -101,8 +101,6 @@
{
struct vlan_hdr *vhdr;
- l2_info->vlan_hdr_cnt = 0;
-
while ((skb->protocol == htons(ETH_P_8021AD) || skb->protocol == htons(ETH_P_8021Q)) &&
l2_info->vlan_hdr_cnt < SFE_MAX_VLAN_DEPTH) {
if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) {
@@ -113,7 +111,11 @@
l2_info->vlan_hdr[l2_info->vlan_hdr_cnt].tci = ntohs(vhdr->h_vlan_TCI);
skb->protocol = vhdr->h_vlan_encapsulated_proto;
l2_info->vlan_hdr_cnt++;
+ /*
+ * strip VLAN header
+ */
__skb_pull(skb, VLAN_HLEN);
+ skb_reset_network_header(skb);
}
l2_info->protocol = htons(skb->protocol);
@@ -205,8 +207,7 @@
vlan += (count - 1);
for (i = 0; i < count; i++) {
- skb_push(skb, VLAN_HLEN);
- vhdr = (struct vlan_hdr *)skb->data;
+ vhdr = (struct vlan_hdr *)skb_push(skb, VLAN_HLEN);
vhdr->h_vlan_TCI = htons(vlan->tci);
vhdr->h_vlan_encapsulated_proto = skb->protocol;
skb->protocol = vlan->tpid;