Currently, ICMP(v4) checksums are calculated using in_cksum(), which
requires the following m_data/m_len dance:

        hlen = ip->ip_hl << 2;
        m->m_data += hlen;
        m->m_len -= hlen;
        icp = mtod(m, struct icmp *);
        icp->icmp_cksum = 0;
        icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
        m->m_data -= hlen;
        m->m_len += hlen;

blambert@ and I found that the ICMP checksum can be calculated using
in4_cksum() instead, which avoids that dance and shortens the code:

        hlen = ip->ip_hl << 2;
        icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
        icp->icmp_cksum = 0;
        icp->icmp_cksum = in4_cksum(m, 0, hlen, ntohs(ip->ip_len) - hlen);

Note that the implementation of in_cksum() and in4_cksum() may be
architecture-specific on various architectures.

I have tested this diff on amd64, hppa, i386, loongson, macppc, sgi, and
sparc64.  abieber@ has also tested it independently on macppc.

Comments? OK?


Index: ip_icmp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.99
diff -u -p -U7 -p -r1.99 ip_icmp.c
--- ip_icmp.c   3 May 2013 09:35:20 -0000       1.99
+++ ip_icmp.c   21 May 2013 21:52:59 -0000
@@ -343,24 +343,20 @@ icmp_input(struct mbuf *m, ...)
        }
        i = hlen + min(icmplen, ICMP_ADVLENMIN);
        if (m->m_len < i && (m = m_pullup(m, i)) == NULL) {
                icmpstat.icps_tooshort++;
                return;
        }
        ip = mtod(m, struct ip *);
-       m->m_len -= hlen;
-       m->m_data += hlen;
-       icp = mtod(m, struct icmp *);
-       if (in_cksum(m, icmplen)) {
+       if (in4_cksum(m, 0, hlen, icmplen)) {
                icmpstat.icps_checksum++;
                goto freeit;
        }
-       m->m_len += hlen;
-       m->m_data -= hlen;
 
+       icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
 #ifdef ICMPPRINTFS
        /*
         * Message type specific processing.
         */
        if (icmpprintfs)
                printf("icmp_input, type %d code %d\n", icp->icmp_type,
                    icp->icmp_code);
@@ -803,21 +799,17 @@ void
 icmp_send(struct mbuf *m, struct mbuf *opts)
 {
        struct ip *ip = mtod(m, struct ip *);
        int hlen;
        struct icmp *icp;
 
        hlen = ip->ip_hl << 2;
-       m->m_data += hlen;
-       m->m_len -= hlen;
-       icp = mtod(m, struct icmp *);
+       icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
        icp->icmp_cksum = 0;
-       icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
-       m->m_data -= hlen;
-       m->m_len += hlen;
+       icp->icmp_cksum = in4_cksum(m, 0, hlen, ntohs(ip->ip_len) - hlen);
 #ifdef ICMPPRINTFS
        if (icmpprintfs) {
                char buf[4 * sizeof("123")];
 
                strlcpy(buf, inet_ntoa(ip->ip_dst), sizeof buf);
                printf("icmp_send dst %s src %s\n",
                    buf, inet_ntoa(ip->ip_src));
Index: ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.239
diff -u -p -U7 -p -r1.239 ip_output.c
--- ip_output.c 24 Apr 2013 12:34:15 -0000      1.239
+++ ip_output.c 21 May 2013 21:52:59 -0000
@@ -2122,17 +2122,13 @@ in_proto_cksum_out(struct mbuf *m, struc
                }
        } else if (m->m_pkthdr.csum_flags & M_ICMP_CSUM_OUT) {
                struct ip *ip = mtod(m, struct ip *);
                int hlen;
                struct icmp *icp;
 
                hlen = ip->ip_hl << 2;
-               m->m_data += hlen;
-               m->m_len -= hlen;
-               icp = mtod(m, struct icmp *);
+               icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
                icp->icmp_cksum = 0;
-               icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
-               m->m_data -= hlen;
-               m->m_len += hlen;
+               icp->icmp_cksum = in4_cksum(m, 0, hlen, ntohs(ip->ip_len) - 
hlen);
                m->m_pkthdr.csum_flags &= ~M_ICMP_CSUM_OUT; /* Clear */
        }
 }

Reply via email to