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 (IP) */
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_ip.h"
30 #include "nx_packet.h"
31
32
33 #if !defined(NX_DISABLE_FRAGMENTATION) && !defined(NX_DISABLE_IPV4)
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _nx_ip_fragment_forward_packet PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* Yuxin Zhou, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function breaks the supplied forward packet into fragments and */
47 /* sends them out. This function uses the already built IP header and */
48 /* source packet structure for each packet fragment. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ip_ptr Pointer to IP control block */
53 /* source_packet Pointer to packet to send */
54 /* destination_ip Destination IP address */
55 /* fragment Don't fragment bit */
56 /* next_hop_address Next Hop address */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* None */
61 /* */
62 /* CALLS */
63 /* */
64 /* _nx_ip_packet_checksum_compute Compute checksum */
65 /* _nx_packet_allocate Allocate packet for fragment */
66 /* _nx_packet_data_append Copies the specified data */
67 /* _nx_packet_release Packet release */
68 /* _nx_packet_transmit_release Transmit packet release */
69 /* _nx_ip_driver_packet_send Send the IP packet */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* _nx_ip_forward_packet_process Process the forward packet */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
80 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* */
83 /**************************************************************************/
_nx_ip_fragment_forward_packet(NX_IP * ip_ptr,NX_PACKET * source_packet,ULONG destination_ip,ULONG fragment,ULONG next_hop_address)84 VOID _nx_ip_fragment_forward_packet(NX_IP *ip_ptr, NX_PACKET *source_packet, ULONG destination_ip, ULONG fragment, ULONG next_hop_address)
85 {
86
87 UINT status;
88 ULONG checksum;
89 ULONG temp;
90 UCHAR *source_ptr;
91 ULONG remaining_bytes;
92 ULONG fragment_size;
93 ULONG copy_size;
94 ULONG copy_remaining_size;
95 ULONG more_fragment;
96 ULONG fragment_offset;
97 NX_PACKET *fragment_packet;
98 NX_IPV4_HEADER *source_header_ptr;
99 NX_IPV4_HEADER *fragment_header_ptr;
100
101
102 /* Add debug information. */
103 NX_PACKET_DEBUG(__FILE__, __LINE__, source_packet);
104
105 #ifndef NX_DISABLE_IP_INFO
106
107 /* Increment the total number of fragment requests. */
108 ip_ptr -> nx_ip_total_fragment_requests++;
109 #endif
110
111 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
112
113 /* Compute checksum for upper layer protocol. */
114 if (source_packet -> nx_packet_interface_capability_flag)
115 {
116 _nx_ip_packet_checksum_compute(source_packet);
117 }
118 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
119
120 /* Build a pointer to the source IP header. */
121 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
122 source_header_ptr = (NX_IPV4_HEADER *)source_packet -> nx_packet_prepend_ptr;
123
124 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
125 swap the endian of the IP header. */
126 NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_0);
127 NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_1);
128 NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_2);
129 NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_source_ip);
130 NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_destination_ip);
131
132 /* Pickup the length of the packet and the starting pointer. */
133 remaining_bytes = (source_packet -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER));
134 source_ptr = source_packet -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER);
135 more_fragment = source_header_ptr -> nx_ip_header_word_1 & NX_IP_MORE_FRAGMENT;
136 fragment_offset = (source_header_ptr -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK) * NX_IP_ALIGN_FRAGS;
137
138 /* Clear the fragment bits and offset mask. */
139 source_header_ptr -> nx_ip_header_word_1 &= 0xFFFF0000;
140
141 /* Derive the fragment size. */
142 fragment_size = (source_packet -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size - (ULONG)sizeof(NX_IPV4_HEADER));
143 fragment_size = (fragment_size / NX_IP_ALIGN_FRAGS) * NX_IP_ALIGN_FRAGS;
144
145 /* Loop to break the source packet into fragments and send each out through
146 the associated driver. */
147 while (remaining_bytes)
148 {
149 /* Allocate a packet from the default packet pool. */
150 status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &fragment_packet,
151 NX_IPv4_PACKET, TX_NO_WAIT);
152
153 /* Determine if there is a packet available. */
154 if (status)
155 {
156
157 #ifndef NX_DISABLE_IP_INFO
158
159 /* Increment the fragment failure count. */
160 ip_ptr -> nx_ip_fragment_failures++;
161
162 /* Increment the IP send packets dropped count. */
163 ip_ptr -> nx_ip_send_packets_dropped++;
164
165 /* Increment the IP transmit resource error count. */
166 ip_ptr -> nx_ip_transmit_resource_errors++;
167 #endif
168
169 /* Error, not enough packets to perform the fragmentation... release the
170 source packet and return. */
171 _nx_packet_transmit_release(source_packet);
172 return;
173 }
174
175 /* Add debug information. */
176 NX_PACKET_DEBUG(__FILE__, __LINE__, fragment_packet);
177
178 /* Set the proper interface. */
179 /*lint -e{644} suppress variable might not be initialized, since "fragment_packet" was initialized in _nx_packet_allocate. */
180 fragment_packet -> nx_packet_address.nx_packet_interface_ptr = source_packet -> nx_packet_address.nx_packet_interface_ptr;
181
182 /* Calculate the size of this fragment. */
183 if (remaining_bytes > fragment_size)
184 {
185 copy_remaining_size = fragment_size;
186 remaining_bytes -= fragment_size;
187 }
188 else
189 {
190 copy_remaining_size = remaining_bytes;
191 remaining_bytes = 0;
192 }
193
194 /* Copy data. */
195 while (copy_remaining_size)
196 {
197
198 /* We need to copy the remaining bytes into the new packet and then move to the next
199 packet. */
200 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
201 if (copy_remaining_size > (ULONG)(source_packet -> nx_packet_append_ptr - source_ptr))
202 {
203
204 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
205 copy_size = (ULONG)(source_packet -> nx_packet_append_ptr - source_ptr);
206 }
207 else
208 {
209 copy_size = copy_remaining_size;
210 }
211
212 status = _nx_packet_data_append(fragment_packet, source_ptr, copy_size, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT);
213
214 /* Determine if there is a packet available. */
215 if (status)
216 {
217
218 #ifndef NX_DISABLE_IP_INFO
219
220 /* Increment the fragment failure count. */
221 ip_ptr -> nx_ip_fragment_failures++;
222
223 /* Increment the IP send packets dropped count. */
224 ip_ptr -> nx_ip_send_packets_dropped++;
225
226 /* Increment the IP transmit resource error count. */
227 ip_ptr -> nx_ip_transmit_resource_errors++;
228 #endif
229
230 /* Error, not enough packets to perform the fragmentation... release the
231 source packet and return. */
232 _nx_packet_transmit_release(source_packet);
233 _nx_packet_release(fragment_packet);
234 return;
235 }
236
237 /* Reduce the remaining size. */
238 copy_remaining_size -= copy_size;
239
240 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
241 if (copy_size == (ULONG)(source_packet -> nx_packet_append_ptr - source_ptr))
242 {
243
244 /* Move to the next physical packet in the source message. */
245 /* Determine if there is a next packet. */
246 if (source_packet -> nx_packet_next)
247 {
248
249 /* Move to the next physical packet in the source message. */
250 source_packet = source_packet -> nx_packet_next;
251
252 /* Setup new source pointer. */
253 source_ptr = source_packet -> nx_packet_prepend_ptr;
254 }
255 else if (remaining_bytes)
256 {
257
258 /* Error, no next packet but current packet is exhausted and there are
259 remaining bytes. */
260
261 #ifndef NX_DISABLE_IP_INFO
262
263 /* Increment the invalid transmit packet count. */
264 ip_ptr -> nx_ip_invalid_transmit_packets++;
265
266 /* Increment the fragment failures count. */
267 ip_ptr -> nx_ip_fragment_failures++;
268 #endif
269
270 /* Error, not enough packets to perform the fragmentation... release the
271 source packet and return. */
272 _nx_packet_transmit_release(source_packet);
273 _nx_packet_release(fragment_packet);
274 return;
275 }
276 }
277 else
278 {
279
280 /* Copy finished. */
281 source_ptr += copy_size;
282 }
283 }
284
285 /* Setup the fragment packet pointers. */
286 fragment_packet -> nx_packet_prepend_ptr = (fragment_packet -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER));
287 fragment_packet -> nx_packet_length += (ULONG)sizeof(NX_IPV4_HEADER);
288
289 /* Setup the fragment's IP header. */
290 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
291 fragment_header_ptr = (NX_IPV4_HEADER *)fragment_packet -> nx_packet_prepend_ptr;
292
293 /* Setup the new IP header. */
294 fragment_header_ptr -> nx_ip_header_word_0 = (source_header_ptr -> nx_ip_header_word_0 & ~NX_LOWER_16_MASK) |
295 fragment_packet -> nx_packet_length;
296 fragment_header_ptr -> nx_ip_header_word_1 = source_header_ptr -> nx_ip_header_word_1 | (fragment_offset / 8);
297 fragment_header_ptr -> nx_ip_header_word_2 = source_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK;
298 fragment_header_ptr -> nx_ip_header_source_ip = source_header_ptr -> nx_ip_header_source_ip;
299 fragment_header_ptr -> nx_ip_header_destination_ip = source_header_ptr -> nx_ip_header_destination_ip;
300
301 /* Determine if this is the last fragment. */
302 /*lint -e{539} suppress positive indentation. */
303 if (remaining_bytes)
304 {
305
306 /* Not the last fragment, so set the more fragments bit. */
307 fragment_header_ptr -> nx_ip_header_word_1 = fragment_header_ptr -> nx_ip_header_word_1 | NX_IP_MORE_FRAGMENT;
308 }
309 else
310 {
311
312 /* Set the more fragments bit. */
313 fragment_header_ptr -> nx_ip_header_word_1 = fragment_header_ptr -> nx_ip_header_word_1 | more_fragment;
314 }
315
316 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
317 if (!(fragment_packet -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM))
318 {
319 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
320
321 /* Build the IP checksum for this fragment. */
322 temp = fragment_header_ptr -> nx_ip_header_word_0;
323 checksum = (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK);
324 temp = fragment_header_ptr -> nx_ip_header_word_1;
325 checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK);
326 temp = fragment_header_ptr -> nx_ip_header_word_2;
327 checksum += (temp >> NX_SHIFT_BY_16);
328 temp = fragment_header_ptr -> nx_ip_header_source_ip;
329 checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK);
330 temp = fragment_header_ptr -> nx_ip_header_destination_ip;
331 checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK);
332
333 /* Add in the carry bits into the checksum. */
334 checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
335
336 /* Do it again in case previous operation generates an overflow. */
337 checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
338
339 /* Now store the checksum in the IP fragment header. */
340 fragment_header_ptr -> nx_ip_header_word_2 = fragment_header_ptr -> nx_ip_header_word_2 | (NX_LOWER_16_MASK & (~checksum));
341 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
342 }
343 else
344 {
345 /* Clear checksum. */
346 fragment_header_ptr -> nx_ip_header_word_2 &= 0xFFFF0000;
347 fragment_packet -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
348 }
349 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
350 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
351 swap the endian of the IP header. */
352 NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_0);
353 NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_1);
354 NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_2);
355 NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_source_ip);
356 NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_destination_ip);
357
358 #ifndef NX_DISABLE_IP_INFO
359 /* Increment the IP fragments sent count. */
360 ip_ptr -> nx_ip_total_fragments_sent++;
361
362 /* Increment the IP packet sent count. */
363 ip_ptr -> nx_ip_total_packets_sent++;
364
365 /* Increment the IP bytes sent count. */
366 ip_ptr -> nx_ip_total_bytes_sent += (fragment_packet -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER));
367 #endif
368
369 /* Add debug information. */
370 NX_PACKET_DEBUG(__FILE__, __LINE__, fragment_packet);
371
372 /* Call the function to directly forward the packet. */
373 _nx_ip_driver_packet_send(ip_ptr, fragment_packet, destination_ip, fragment, next_hop_address);
374
375 /* Increase offset. */
376 fragment_offset += fragment_size;
377 }
378
379 #ifndef NX_DISABLE_IP_INFO
380
381 /* Increment the total number of successful fragment requests. */
382 ip_ptr -> nx_ip_successful_fragment_requests++;
383 #endif
384
385 /* The original packet has been sent out in fragments... release it! */
386 _nx_packet_transmit_release(source_packet);
387 }
388 #endif /* !defined(NX_DISABLE_FRAGMENTATION) && !defined(NX_DISABLE_IPV4) */
389
390