1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Component */
17 /** */
18 /** Internet Protocol Checksum Computation */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "nx_api.h"
29 #include "nx_icmp.h"
30 #include "nx_icmpv6.h"
31 #include "nx_ip.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _nx_ip_checksum_compute PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* Yuxin Zhou, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function computes the checksum from the supplied packet */
47 /* pointer and IP address fields required for the pseudo header. */
48 /* */
49 /* INPUT */
50 /* */
51 /* packet_ptr Pointer to packet */
52 /* protocol Protocol type */
53 /* data_length Size of the protocol payload */
54 /* src_ip_addr IPv4 or IPv6 address, used in */
55 /* constructing pseudo header.*/
56 /* dest_ip_addr IPv4 or IPv6 address, used in */
57 /* constructing pseudo header.*/
58 /* */
59 /* OUTPUT */
60 /* */
61 /* computed checksum */
62 /* */
63 /* CALLS */
64 /* */
65 /* None */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* NetX Duo internal routines */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
76 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* */
79 /**************************************************************************/
_nx_ip_checksum_compute(NX_PACKET * packet_ptr,ULONG protocol,UINT data_length,ULONG * src_ip_addr,ULONG * dest_ip_addr)80 USHORT _nx_ip_checksum_compute(NX_PACKET *packet_ptr, ULONG protocol,
81 UINT data_length, ULONG *src_ip_addr,
82 ULONG *dest_ip_addr)
83 {
84
85 ULONG checksum = 0;
86 USHORT tmp;
87 USHORT *short_ptr;
88 ULONG *long_ptr;
89 #ifndef NX_DISABLE_PACKET_CHAIN
90 ULONG packet_size;
91 #endif /* NX_DISABLE_PACKET_CHAIN */
92 NX_PACKET *current_packet;
93 ALIGN_TYPE end_ptr;
94 #ifdef FEATURE_NX_IPV6
95 UINT i;
96 #endif
97
98 /* For computing TCP/UDP/ICMPv6, we need to include the pseudo header.
99 The ICMPv4 checksum does not cover the pseudo header. */
100 if ((protocol == NX_PROTOCOL_UDP) ||
101 #ifdef FEATURE_NX_IPV6
102 (protocol == NX_PROTOCOL_ICMPV6) ||
103 #endif /* FEATURE_NX_IPV6 */
104 (protocol == NX_PROTOCOL_TCP))
105 {
106
107 USHORT *src_ip_short, *dest_ip_short;
108
109 checksum = protocol;
110
111 /* The addresses must not be null. */
112 NX_ASSERT((src_ip_addr != NX_NULL) && (dest_ip_addr != NX_NULL));
113
114 /*lint -e{929} -e{740} suppress cast of pointer to pointer, since it is necessary */
115 src_ip_short = (USHORT *)src_ip_addr;
116
117 /*lint -e{929} -e{740} suppress cast of pointer to pointer, since it is necessary */
118 dest_ip_short = (USHORT *)dest_ip_addr;
119
120
121 checksum += src_ip_short[0];
122 checksum += src_ip_short[1];
123 checksum += dest_ip_short[0];
124 checksum += dest_ip_short[1];
125
126 #ifdef FEATURE_NX_IPV6
127
128 /* Note that the IPv6 address is 128 bits/4 words
129 compared with the 32 IPv4 address.*/
130 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
131 {
132
133 for (i = 2; i < 8; i++)
134 {
135
136 checksum += dest_ip_short[i];
137 checksum += src_ip_short[i];
138 }
139 }
140 #endif /* FEATURE_NX_IPV6 */
141
142 /* Take care of data length */
143 checksum += data_length;
144
145 /* Fold a 4-byte value into a two byte value */
146 checksum = (checksum >> 16) + (checksum & 0xFFFF);
147
148 /* Do it again in case previous operation generates an overflow */
149 checksum = (checksum >> 16) + (checksum & 0xFFFF);
150
151 /* Convert to network byte order. */
152 tmp = (USHORT)checksum;
153 NX_CHANGE_USHORT_ENDIAN(tmp);
154 checksum = tmp;
155 }
156
157 /* Now we need to go through the payloads */
158
159 /* Setup the pointer to the start of the packet. */
160 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
161 long_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr;
162
163 /* Initialize the current packet to the input packet pointer. */
164 current_packet = packet_ptr;
165
166 #ifndef NX_DISABLE_PACKET_CHAIN
167 /* Loop the packet. */
168 while (current_packet)
169 {
170
171 /* Calculate current packet size. */
172 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
173 packet_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr);
174
175 /* Calculate the end address in this packet. */
176 if (data_length > (UINT)packet_size)
177 {
178
179 /*lint -e{927} -e{923} -e{826} suppress cast of pointer to pointer, since it is necessary */
180 end_ptr = ((ALIGN_TYPE)current_packet -> nx_packet_append_ptr) & (ALIGN_TYPE)(~3);
181 }
182 else
183 {
184 #endif /* NX_DISABLE_PACKET_CHAIN */
185 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
186 end_ptr = (ALIGN_TYPE)current_packet -> nx_packet_prepend_ptr + data_length - 3;
187 #ifndef NX_DISABLE_PACKET_CHAIN
188 }
189 #endif /* NX_DISABLE_PACKET_CHAIN */
190
191 /* Set the start address in this packet. */
192 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
193 long_ptr = (ULONG *)current_packet -> nx_packet_prepend_ptr;
194
195 /*lint -e{946} suppress pointer subtraction, since it is necessary. */
196 if ((ALIGN_TYPE)long_ptr < end_ptr)
197 {
198
199 /* Calculate the data_length. */
200 /*lint -e{923} suppress cast of pointer to ULONG. */
201 data_length -= (UINT)(((end_ptr + 3) & (ALIGN_TYPE)(~3llu)) - (ALIGN_TYPE)long_ptr);
202
203 /* Loop to calculate the packet's checksum. */
204 /*lint -e{946} suppress pointer subtraction, since it is necessary. */
205 while ((ALIGN_TYPE)long_ptr < end_ptr)
206 {
207 checksum += (*long_ptr & NX_LOWER_16_MASK);
208 checksum += (*long_ptr >> NX_SHIFT_BY_16);
209 long_ptr++;
210 }
211 }
212 #ifndef NX_DISABLE_PACKET_CHAIN
213
214 /* Determine if we are at the end of the current packet. */
215 if ((data_length > 0) && (current_packet -> nx_packet_next))
216 {
217
218 /* Is append_ptr two bytes aligned but not four bytes aligned? */
219 /*lint -e{923} suppress cast of pointer to ULONG. */
220 if ((((ALIGN_TYPE)current_packet -> nx_packet_append_ptr) & 3) == 2)
221 {
222
223 /* Yes it is. Process the last two bytes in chaining packets. */
224 /*lint -e{929} -e{740} suppress cast of pointer to pointer, since it is necessary */
225 short_ptr = (USHORT *)long_ptr;
226
227 /*lint -e{929} -e{740} suppress cast of pointer to pointer, since it is necessary */
228 checksum += *short_ptr;
229 data_length -= 2;
230 }
231
232 /* We have crossed the packet boundary. Move to the next packet
233 structure. */
234 current_packet = current_packet -> nx_packet_next;
235 }
236 else
237 {
238
239 /* End the loop. */
240 current_packet = NX_NULL;
241 }
242 }
243 #endif /* NX_DISABLE_PACKET_CHAIN */
244
245 /* Determine if there is only one byte left. */
246 if (data_length)
247 {
248
249 /* Set the short_ptr. */
250 short_ptr = (USHORT *)(long_ptr);
251
252 /* Check the data length. */
253 if (data_length == 1)
254 {
255 *((UCHAR *)short_ptr + 1) = 0;
256 }
257 else if (data_length == 3)
258 {
259 checksum += *short_ptr;
260 short_ptr++;
261
262 *((UCHAR *)short_ptr + 1) = 0;
263 }
264
265 checksum += *short_ptr;
266 }
267
268 /* Fold a 4-byte value into a two byte value */
269 checksum = (checksum >> 16) + (checksum & 0xFFFF);
270
271 /* Do it again in case previous operation generates an overflow */
272 checksum = (checksum >> 16) + (checksum & 0xFFFF);
273
274 /* Convert to host byte order. */
275 tmp = (USHORT)checksum;
276 NX_CHANGE_USHORT_ENDIAN(tmp);
277
278 /* Return the computed checksum. */
279 return(tmp);
280 }
281
282