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