1 /*---------------------------------------------------------------
2  * Copyright (c) 2018
3  * Broadcom Corporation
4  * All Rights Reserved.
5  *---------------------------------------------------------------
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated
8  * documentation files (the "Software"), to deal in the Software
9  * without restriction, including without limitation the
10  * rights to use, copy, modify, merge, publish, distribute,
11  * sublicense, and/or sell copies of the Software, and to permit
12  * persons to whom the Software is furnished to do
13  * so, subject to the following conditions:
14  *
15  *
16  * Redistributions of source code must retain the above
17  * copyright notice, this list of conditions and
18  * the following disclaimers.
19  *
20  *
21  * Redistributions in binary form must reproduce the above
22  * copyright notice, this list of conditions and the following
23  * disclaimers in the documentation and/or other materials
24  * provided with the distribution.
25  *
26  *
27  * Neither the name of Broadcom Coporation,
28  * nor the names of its contributors may be used to endorse
29  * or promote products derived from this Software without
30  * specific prior written permission.
31  *
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
34  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
36  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
37  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
38  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40  * ________________________________________________________________
41  *
42  * UDP checksums v4 and v6
43  *
44  * The checksum calculation is defined in RFC 768
45  * hints as to how to calculate it efficiently are in RFC 1071
46  *
47  * by Robert J. McMahon (rjmcmahon@rjmcmahon.com, bob.mcmahon@broadcom.com)
48  * -------------------------------------------------------------------
49  */
50 #include "headers.h"
51 
52 /*
53  *
54  * Compute Internet Checksum for UDP packets (assumes 32 bit system)
55  *
56  * IPV4 Notes:
57  *
58  *                     User Datagram Header Format
59  *                 0      7 8     15 16    23 24    31
60  *                +--------+--------+--------+--------+
61  *                |     Source      |   Destination   |
62  *                |      Port       |      Port       |
63  *                +--------+--------+--------+--------+
64  *                |                 |                 |
65  *                |     Length      |    Checksum     |
66  *                +--------+--------+--------+--------+
67  *                |
68  *                |          data octets ...
69  *                +---------------- ...
70  *
71  *
72  * Checksum is the 16-bit one's complement of the one's complement sum of a
73  * pseudo header of information from the IP header, the UDP header, and the
74  * data,  padded  with zero octets  at the end (if  necessary)  to  make  a
75  * multiple of two octets.
76  *
77  * The ipv4 pseudo  header  conceptually prefixed to the UDP header contains the
78  * source  address,  the destination  address,  the protocol,  and the  UDP
79  * length.   This information gives protection against misrouted datagrams.
80  * This checksum procedure is the same as is used in TCP.
81  *
82  *                 0      7 8     15 16    23 24    31
83  *                +--------+--------+--------+--------+
84  *                |          source address           |
85  *                +--------+--------+--------+--------+
86  *                |        destination address        |
87  *                +--------+--------+--------+--------+
88  *                |  zero  |protocol|   UDP length    |
89  *                +--------+--------+--------+--------+
90  *
91  * If the computed  checksum  is zero,  it is transmitted  as all ones (the
92  * equivalent  in one's complement  arithmetic).   An all zero  transmitted
93  * checksum  value means that the transmitter  generated  no checksum  (for
94  * debugging or for higher level protocols that don't care).
95  *
96  *
97  *  IPV6 Notes:
98  *
99  *  Any transport or other upper-layer protocol that includes the
100  *  addresses from the IP header in its checksum computation must be
101  *  modified for use over IPv6, to include the 128-bit IPv6 addresses
102  *  instead of 32-bit IPv4 addresses.  In particular, the following
103  *  illustration shows the TCP and UDP "pseudo-header" for IPv6:
104  *
105  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106  *  |                                                               |
107  *  +                                                               +
108  *  |                                                               |
109  *  +                         Source Address                        +
110  *  |                                                               |
111  *  +                                                               +
112  *  |                                                               |
113  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114  *  |                                                               |
115  *  +                                                               +
116  *  |                                                               |
117  *  +                      Destination Address                      +
118  *  |                                                               |
119  *  +                                                               +
120  *  |                                                               |
121  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122  *  |                   Upper-Layer Packet Length                   |
123  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124  *  |                      zero                     |  Next Header  |
125  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126  *
127  *     o  If the IPv6 packet contains a Routing header, the Destination
128  *        Address used in the pseudo-header is that of the final
129  *        destination.  At the originating node, that address will be in
130  *        the last element of the Routing header; at the recipient(s),
131  *        that address will be in the Destination Address field of the
132  *        IPv6 header.
133  *
134  *     o  The Next Header value in the pseudo-header identifies the
135  *        upper-layer protocol (e.g., 6 for TCP, or 17 for UDP).  It will
136  *        differ from the Next Header value in the IPv6 header if there
137  *        are extension headers between the IPv6 header and the upper-
138  *        layer header.
139  *
140  *     o  The Upper-Layer Packet Length in the pseudo-header is the
141  *        length of the upper-layer header and data (e.g., TCP header
142  *        plus TCP data).  Some upper-layer protocols carry their own
143  *        length information (e.g., the Length field in the UDP header);
144  *        for such protocols, that is the length used in the pseudo-
145  *        header.  Other protocols (such as TCP) do not carry their own
146  *        length information, in which case the length used in the
147  *        pseudo-header is the Payload Length from the IPv6 header, minus
148  *        the length of any extension headers present between the IPv6
149  *        header and the upper-layer header.
150  *
151  *     o  Unlike IPv4, when UDP packets are originated by an IPv6 node,
152  *        the UDP checksum is not optional.  That is, whenever
153  *        originating a UDP packet, an IPv6 node must compute a UDP
154  *        checksum over the packet and the pseudo-header, and, if that
155  *        computation yields a result of zero, it must be changed to hex
156  *        FFFF for placement in the UDP header.  IPv6 receivers must
157  *        discard UDP packets containing a zero checksum, and should log
158  *        the error.
159  *
160  *
161  *  Returns zero on checksum success, non zero otherwise
162  */
163 
164 #define IPV4SRCOFFSET 12  // the ipv4 source address offset from the l3 pdu
165 #define IPV6SRCOFFSET 8 // the ipv6 source address offset
166 #define IPV6SIZE 8 // units is number of 16 bits, i.e. 128 bits is eight 16 bits
167 #define IPV4SIZE 2 // v4 is two 16 bits (32 bits)
168 #define UDPPROTO 17 // UDP protocol value for psuedo header
udpchecksum(const void * l3pdu,const void * l4pdu,int udplen,int v6)169 uint32_t udpchecksum(const void *l3pdu, const void *l4pdu, int udplen, int v6) {
170     register uint32_t sum = 0;
171     const uint16_t *data;
172     int i;
173 
174     const struct udphdr *udp_hdr = (const struct udphdr *)l4pdu;
175     if (!udp_hdr->check) {
176 	if (v6)
177 	    // v6 requires checksums
178 	    return -1;
179 	else
180 	    // v4 checksums are optional
181 	    return 0;
182     }
183 
184     /*
185      *	Build pseudo headers, partially from the packet
186      *  (which are in network byte order) and
187      *  the protocol of UDP (value of 17).  Also, the IP dst
188      *  addr immediately follows the src so double the size
189      *  per each loop to cover both addrs
190      */
191     if (v6) {
192 	// skip to the ip header v6 src field, offset 8 (see ipv6 header)
193 	data = (const uint16_t *)((char *)l3pdu + IPV6SRCOFFSET);
194 	for (i = 0; i < (2 * IPV6SIZE); i++) {
195 	    sum += *data++;
196 	}
197     } else {
198 	// skip to the ip header v4 src field, offset 12 (see ipv4 header)
199 	data = (const uint16_t *)((char *)l3pdu + IPV4SRCOFFSET);
200 	for (i = 0; i < (2 * IPV4SIZE); i++) {
201 	    sum += *data++;
202 	}
203     }
204     //  These should work for both v4 and v6 even though
205     //  v6 psuedo header uses 32 bit values because the
206     //  uppers in v6 will be zero
207     sum += htons(UDPPROTO); // proto of UDP is 17
208     sum += htons(udplen); // For UDP, the pseudo hdr len equals udp len
209 
210     /*
211      * UDP hdr + payload
212      */
213     data = (const uint16_t *) l4pdu;
214     while( udplen > 1 )  {
215 	sum += *data++;
216 	udplen -= 2;
217     }
218     /*  Add left-over byte, if any */
219     if( udplen > 0 )
220 	sum += * (uint8_t *) data;
221 
222     /*  Fold 32-bit sum to 16 bits */
223     while (sum>>16)
224 	sum = (sum & 0xffff) + (sum >> 16);
225 
226     /* return ones complement */
227     sum = (sum ^ 0xffff);
228     return sum;
229 }
230