@@ -228,6 +228,123 @@ 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+ static int eth_xmc4xxx_clear_checksum (struct net_pkt * pkt )
267+ {
268+ int ret = 0 ;
269+ uint16_t p_type ;
270+ uint8_t next_header = -1 ;
271+ struct net_eth_hdr * eth_hdr = NET_ETH_HDR (pkt );
272+ struct net_pkt_cursor backup ;
273+ bool overwrite ;
274+ const char * msg = NULL ;
275+ const char * p_type_str ;
276+ const char * next_header_str = "<does not apply>" ;
277+
278+ overwrite = net_pkt_is_being_overwritten (pkt );
279+ net_pkt_cursor_backup (pkt , & backup );
280+ net_pkt_cursor_init (pkt );
281+ net_pkt_set_overwrite (pkt , true);
282+ eth_hdr = NET_ETH_HDR (pkt );
283+ net_pkt_skip (pkt , sizeof (struct net_eth_hdr ));
284+ p_type = ntohs (eth_hdr -> type );
285+ switch (p_type ) {
286+ case NET_ETH_PTYPE_IP : {
287+ NET_PKT_DATA_ACCESS_DEFINE (ip_access , struct net_ipv4_hdr );
288+ struct net_ipv4_hdr * ip_hdr ;
289+
290+ p_type_str = "IPv4" ;
291+ ip_hdr = (struct net_ipv4_hdr * )net_pkt_get_data (pkt , & ip_access );
292+ next_header = ip_hdr -> proto ;
293+ net_pkt_skip (pkt , sizeof (struct net_ipv4_hdr ));
294+
295+ break ;
296+ }
297+ case NET_ETH_PTYPE_IPV6 : {
298+ NET_PKT_DATA_ACCESS_DEFINE (ip_access , struct net_ipv6_hdr );
299+ struct net_ipv6_hdr * ip_hdr ;
300+
301+ p_type_str = "IPv6" ;
302+ ip_hdr = (struct net_ipv6_hdr * )net_pkt_get_data (pkt , & ip_access );
303+ next_header = ip_hdr -> nexthdr ;
304+ net_pkt_skip (pkt , sizeof (struct net_ipv6_hdr ));
305+
306+ break ;
307+ }
308+ case NET_ETH_PTYPE_ARP :
309+ p_type_str = "ARP" ;
310+ goto end ;
311+ default :
312+ p_type_str = "Unknown" ;
313+ msg = "Unknown protocol type" ;
314+ goto end ;
315+ }
316+
317+ switch (next_header ) {
318+ case IPPROTO_TCP :
319+ next_header_str = "TCP" ;
320+ break ;
321+ case IPPROTO_UDP :
322+ next_header_str = "UDP" ;
323+ break ;
324+ case IPPROTO_ICMP :
325+ next_header_str = "ICMPv4" ;
326+ ret = eth_xmc4xxx_clear_checksum_icmpv4 (pkt );
327+ break ;
328+ case IPPROTO_ICMPV6 :
329+ next_header_str = "ICMPv6" ;
330+ break ;
331+ default :
332+ next_header_str = "Unknown" ;
333+ msg = "Unknown next header" ;
334+ break ;
335+ }
336+
337+ end :
338+ net_pkt_cursor_restore (pkt , & backup );
339+ net_pkt_set_overwrite (pkt , overwrite );
340+ if (msg ) {
341+ LOG_DBG ("p_type = 0x%04x (%s), next_header = 0x%02x (%s)\n" , p_type , p_type_str ,
342+ next_header , next_header_str );
343+ pkt_hexdump (pkt , msg );
344+ }
345+ return ret ;
346+ }
347+
231348static int eth_xmc4xxx_send (const struct device * dev , struct net_pkt * pkt )
232349{
233350 struct eth_xmc4xxx_data * dev_data = dev -> data ;
@@ -338,6 +455,19 @@ static int eth_xmc4xxx_send(const struct device *dev, struct net_pkt *pkt)
338455 return - EIO ;
339456 }
340457
458+ /* Due to checksum offloading, the checksum field must be zero before
459+ * sending the packet to the ethernet controller, otherwise the computed
460+ * checksum will be incorrect.
461+ *
462+ * If the packet is bridged, it already has the correct checksum in
463+ * place, which will cause the automatically computed checksum to
464+ * incorrectly become zero.
465+ *
466+ * Here we give bridged packets the special attention they need. */
467+ if (net_pkt_is_l2_bridged (pkt )) {
468+ eth_xmc4xxx_clear_checksum (pkt );
469+ }
470+
341471 unsigned int key = irq_lock ();
342472
343473 /* label last dma descriptor as last segment and trigger interrupt on last segment */
0 commit comments