diff --git a/subsys/net/ip/ipv4_fragment.c b/subsys/net/ip/ipv4_fragment.c index d61dd246075..53cd72a8748 100644 --- a/subsys/net/ip/ipv4_fragment.c +++ b/subsys/net/ip/ipv4_fragment.c @@ -480,9 +480,9 @@ static int send_ipv4_fragment(struct net_pkt *pkt, uint16_t rand_id, uint16_t fi ipv4_hdr->len = htons((fit_len + net_pkt_ip_hdr_len(pkt))); ipv4_hdr->chksum = 0; - if (net_if_need_calc_tx_checksum(net_pkt_iface(frag_pkt))) { - ipv4_hdr->chksum = net_calc_chksum_ipv4(frag_pkt); - } + ipv4_hdr->chksum = net_calc_chksum_ipv4(frag_pkt); + + net_pkt_set_chksum_done(frag_pkt, true); net_pkt_set_data(frag_pkt, &ipv4_access); @@ -554,6 +554,35 @@ int net_ipv4_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, pkt_len -= net_pkt_ip_hdr_len(pkt); + /* Calculate the L4 checksum (if not done already) before the fragmentation. */ + if (!net_pkt_is_chksum_done(pkt)) { + struct net_pkt_cursor backup; + + net_pkt_cursor_backup(pkt, &backup); + net_pkt_acknowledge_data(pkt, &frag_access); + + switch (frag_hdr->proto) { + case IPPROTO_ICMP: + ret = net_icmpv4_finalize(pkt, true); + break; + case IPPROTO_TCP: + ret = net_tcp_finalize(pkt, true); + break; + case IPPROTO_UDP: + ret = net_udp_finalize(pkt, true); + break; + default: + ret = 0; + break; + } + + if (ret < 0) { + return ret; + } + + net_pkt_cursor_restore(pkt, &backup); + } + while (frag_offset < pkt_len) { bool final = false;