net/ethernet: Remove inserted L2 header buffer

The packet can be referenced somewhere else and letting the newly added
L2 header will generate corrupt packet. If the same packet is being
resent, ethernet will add again its L2 header. Thus the need to remove
such L2 header every time a packet has been sent, successfully or not.

Fixes #12560

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2019-01-18 08:03:53 +01:00 committed by Jukka Rissanen
commit 499ffd6573
5 changed files with 22 additions and 20 deletions

View file

@ -493,6 +493,18 @@ static void ethernet_update_tx_stats(struct net_if *iface, struct net_pkt *pkt)
} }
#endif /* CONFIG_NET_STATISTICS_ETHERNET */ #endif /* CONFIG_NET_STATISTICS_ETHERNET */
static void ethernet_remove_l2_header(struct net_pkt *pkt)
{
struct net_buf *buf;
/* Remove the buffer added in ethernet_fill_header() */
buf = pkt->buffer;
pkt->buffer = buf->frags;
buf->frags = NULL;
net_pkt_frag_unref(buf);
}
static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
{ {
const struct ethernet_api *api = net_if_get_device(iface)->driver_api; const struct ethernet_api *api = net_if_get_device(iface)->driver_api;
@ -570,12 +582,14 @@ send:
ret = api->send(net_if_get_device(iface), pkt); ret = api->send(net_if_get_device(iface), pkt);
if (ret != 0) { if (ret != 0) {
eth_stats_update_errors_tx(iface); eth_stats_update_errors_tx(iface);
ethernet_remove_l2_header(pkt);
goto error; goto error;
} }
#if defined(CONFIG_NET_STATISTICS_ETHERNET) #if defined(CONFIG_NET_STATISTICS_ETHERNET)
ethernet_update_tx_stats(iface, pkt); ethernet_update_tx_stats(iface, pkt);
#endif #endif
ret = net_pkt_get_len(pkt); ret = net_pkt_get_len(pkt);
ethernet_remove_l2_header(pkt);
net_pkt_unref(pkt); net_pkt_unref(pkt);
error: error:

View file

@ -190,11 +190,9 @@ static int eth_tx_offloading_disabled(struct device *dev, struct net_pkt *pkt)
memcpy(((struct net_eth_hdr *)net_pkt_data(pkt))->dst.addr, memcpy(((struct net_eth_hdr *)net_pkt_data(pkt))->dst.addr,
lladdr, sizeof(lladdr)); lladdr, sizeof(lladdr));
net_pkt_ref(pkt); if (net_recv_data(net_pkt_iface(pkt),
net_pkt_clone(pkt, K_NO_WAIT)) < 0) {
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) {
test_failed = true; test_failed = true;
net_pkt_unref(pkt);
zassert_true(false, "Packet %p receive failed\n", pkt); zassert_true(false, "Packet %p receive failed\n", pkt);
} }

View file

@ -1026,16 +1026,12 @@ static int tester_send(struct device *dev, struct net_pkt *pkt)
udp_hdr->dst_port = port; udp_hdr->dst_port = port;
net_udp_set_hdr(pkt, udp_hdr); net_udp_set_hdr(pkt, udp_hdr);
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) { if (net_recv_data(net_pkt_iface(pkt),
net_pkt_clone(pkt, K_NO_WAIT)) < 0) {
TC_ERROR("Data receive failed."); TC_ERROR("Data receive failed.");
goto out; goto out;
} }
/* L2 or net_if will unref the pkt, but we are pushing it
* to rx path, so let's reference it or it will be freed.
*/
net_pkt_ref(pkt);
timeout_token = 0; timeout_token = 0;
return 0; return 0;

View file

@ -247,16 +247,12 @@ static int tester_send(struct device *dev, struct net_pkt *pkt)
} }
/* Feed this data back to us */ /* Feed this data back to us */
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) { if (net_recv_data(net_pkt_iface(pkt),
net_pkt_clone(pkt, K_NO_WAIT)) < 0) {
TC_ERROR("Data receive failed."); TC_ERROR("Data receive failed.");
goto out; goto out;
} }
/* L2 will unref pkt, so since it got to rx path we need to ref it again
* or it will be freed.
*/
net_pkt_ref(pkt);
return 0; return 0;
out: out:

View file

@ -183,11 +183,9 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt)
udp_hdr->src_port = udp_hdr->dst_port; udp_hdr->src_port = udp_hdr->dst_port;
udp_hdr->dst_port = port; udp_hdr->dst_port = port;
net_pkt_ref(pkt); if (net_recv_data(net_pkt_iface(pkt),
net_pkt_clone(pkt, K_NO_WAIT)) < 0) {
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) {
test_failed = true; test_failed = true;
net_pkt_unref(pkt);
zassert_true(false, "Packet %p receive failed\n", pkt); zassert_true(false, "Packet %p receive failed\n", pkt);
} }