@@ -228,6 +228,124 @@ static inline void eth_xmc4xxx_trigger_dma_rx(ETH_GLOBAL_TypeDef *regs)
228228 regs -> RECEIVE_POLL_DEMAND = 0U ;
229229}
230230
231+ static void pkt_hexdump (struct net_pkt * pkt , const char * str )
232+ {
233+ struct net_buf * buf = pkt -> buffer ;
234+
235+ while (buf ) {
236+ LOG_HEXDUMP_DBG (buf -> data , buf -> len , str );
237+ buf = buf -> frags ;
238+ }
239+ }
240+
241+ /* Clears the checksum field of an ICMPv4 packet. */
242+ static int eth_xmc4xxx_clear_checksum_icmpv4 (struct net_pkt * pkt )
243+ {
244+ NET_PKT_DATA_ACCESS_DEFINE (icmpv4_access , struct net_icmp_hdr );
245+ struct net_icmp_hdr * icmp_hdr ;
246+
247+ if (IS_ENABLED (CONFIG_NET_IPV4_HDR_OPTIONS )) {
248+ if (net_pkt_skip (pkt , net_pkt_ipv4_opts_len (pkt ))) {
249+ return - ENOBUFS ;
250+ }
251+ }
252+
253+ icmp_hdr = (struct net_icmp_hdr * )net_pkt_get_data (pkt , & icmpv4_access );
254+ if (!icmp_hdr ) {
255+ return - ENOBUFS ;
256+ }
257+
258+ icmp_hdr -> chksum = 0 ;
259+ net_pkt_set_chksum_done (pkt , true);
260+
261+ return net_pkt_set_data (pkt , & icmpv4_access );
262+ }
263+
264+ /* Clears the checksum value in packets that will go through checksum
265+ * offloading.
266+ */
267+ static int eth_xmc4xxx_clear_checksum (struct net_pkt * pkt )
268+ {
269+ int ret = 0 ;
270+ uint16_t p_type ;
271+ uint8_t next_header = -1 ;
272+ struct net_eth_hdr * eth_hdr = NET_ETH_HDR (pkt );
273+ struct net_pkt_cursor backup ;
274+ bool overwrite ;
275+ const char * msg = NULL ;
276+ const char * p_type_str ;
277+ const char * next_header_str = "<does not apply>" ;
278+
279+ overwrite = net_pkt_is_being_overwritten (pkt );
280+ net_pkt_cursor_backup (pkt , & backup );
281+ net_pkt_cursor_init (pkt );
282+ net_pkt_set_overwrite (pkt , true);
283+ eth_hdr = NET_ETH_HDR (pkt );
284+ net_pkt_skip (pkt , sizeof (struct net_eth_hdr ));
285+ p_type = ntohs (eth_hdr -> type );
286+ switch (p_type ) {
287+ case NET_ETH_PTYPE_IP : {
288+ NET_PKT_DATA_ACCESS_DEFINE (ip_access , struct net_ipv4_hdr );
289+ struct net_ipv4_hdr * ip_hdr ;
290+
291+ p_type_str = "IPv4" ;
292+ ip_hdr = (struct net_ipv4_hdr * )net_pkt_get_data (pkt , & ip_access );
293+ next_header = ip_hdr -> proto ;
294+ net_pkt_skip (pkt , sizeof (struct net_ipv4_hdr ));
295+
296+ break ;
297+ }
298+ case NET_ETH_PTYPE_IPV6 : {
299+ NET_PKT_DATA_ACCESS_DEFINE (ip_access , struct net_ipv6_hdr );
300+ struct net_ipv6_hdr * ip_hdr ;
301+
302+ p_type_str = "IPv6" ;
303+ ip_hdr = (struct net_ipv6_hdr * )net_pkt_get_data (pkt , & ip_access );
304+ next_header = ip_hdr -> nexthdr ;
305+ net_pkt_skip (pkt , sizeof (struct net_ipv6_hdr ));
306+
307+ break ;
308+ }
309+ case NET_ETH_PTYPE_ARP :
310+ p_type_str = "ARP" ;
311+ goto end ;
312+ default :
313+ p_type_str = "Unknown" ;
314+ msg = "Unknown protocol type" ;
315+ goto end ;
316+ }
317+
318+ switch (next_header ) {
319+ case IPPROTO_TCP :
320+ next_header_str = "TCP" ;
321+ break ;
322+ case IPPROTO_UDP :
323+ next_header_str = "UDP" ;
324+ break ;
325+ case IPPROTO_ICMP :
326+ next_header_str = "ICMPv4" ;
327+ ret = eth_xmc4xxx_clear_checksum_icmpv4 (pkt );
328+ break ;
329+ case IPPROTO_ICMPV6 :
330+ next_header_str = "ICMPv6" ;
331+ break ;
332+ default :
333+ next_header_str = "Unknown" ;
334+ msg = "Unknown next header" ;
335+ break ;
336+ }
337+
338+ end :
339+ net_pkt_cursor_restore (pkt , & backup );
340+ net_pkt_set_overwrite (pkt , overwrite );
341+ if (msg ) {
342+ LOG_DBG ("p_type = 0x%04x (%s), next_header = 0x%02x (%s)\n" , p_type , p_type_str ,
343+ next_header , next_header_str );
344+ pkt_hexdump (pkt , msg );
345+ }
346+ return ret ;
347+ }
348+
231349static int eth_xmc4xxx_send (const struct device * dev , struct net_pkt * pkt )
232350{
233351 struct eth_xmc4xxx_data * dev_data = dev -> data ;
@@ -338,6 +456,20 @@ static int eth_xmc4xxx_send(const struct device *dev, struct net_pkt *pkt)
338456 return - EIO ;
339457 }
340458
459+ /* Due to checksum offloading, the checksum field must be zero before
460+ * sending the packet to the ethernet controller, otherwise the computed
461+ * checksum will be incorrect.
462+ *
463+ * If the packet is bridged, it already has the correct checksum in
464+ * place, which will cause the automatically computed checksum to
465+ * incorrectly become zero.
466+ *
467+ * Here we give bridged packets the special attention they need.
468+ */
469+ if (net_pkt_is_l2_bridged (pkt )) {
470+ eth_xmc4xxx_clear_checksum (pkt );
471+ }
472+
341473 unsigned int key = irq_lock ();
342474
343475 /* label last dma descriptor as last segment and trigger interrupt on last segment */
0 commit comments