1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Component */
16 /** */
17 /** Internet Protocol (IP) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 #include "nx_packet.h"
30 #include "nx_icmpv4.h"
31
32 #include "nx_ipv6.h"
33 #include "nx_icmpv6.h"
34
35 #ifndef NX_DISABLE_FRAGMENTATION
36 /**************************************************************************/
37 /* */
38 /* FUNCTION RELEASE */
39 /* */
40 /* _nx_ip_fragment_timeout_cleanup PORTABLE C */
41 /* 6.1 */
42 /* AUTHOR */
43 /* */
44 /* Yuxin Zhou, Microsoft Corporation */
45 /* */
46 /* DESCRIPTION */
47 /* */
48 /* This internal function cleans up outstanding IP fragments. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ip_ptr Pointer to IP instance */
53 /* fragment The head of an IP fragment */
54 /* that needs to be cleaned. */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* None */
59 /* */
60 /* CALLS */
61 /* */
62 /* _nx_packet_release Release packet */
63 /* IPv6_Address_Type Find IPv6 address type. */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* _nx_ip_fragment_timeout_check */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
74 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
75 /* resulting in version 6.1 */
76 /* */
77 /**************************************************************************/
_nx_ip_fragment_cleanup(NX_IP * ip_ptr,NX_PACKET * fragment)78 static VOID _nx_ip_fragment_cleanup(NX_IP *ip_ptr, NX_PACKET *fragment)
79 {
80
81 NX_PACKET *next_fragment;
82 #if !defined(NX_DISABLE_IPV4) && !defined(NX_DISABLE_ICMPV4_ERROR_MESSAGE)
83 NX_IPV4_HEADER *ipv4_header;
84 #endif /* !NX_DISABLE_IPV4 && !NX_DISABLE_ICMPV4_ERROR_MESSAGE */
85 #if defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_ICMPV6_ERROR_MESSAGE)
86 NX_IPV6_HEADER_FRAGMENT_OPTION *fragment_option;
87 NX_IPV6_HEADER *ipv6_header;
88 #endif /* FEATURE_NX_IPV6 && !NX_DISABLE_ICMPV6_ERROR_MESSAGE */
89
90 #ifndef NX_DISABLE_IP_INFO
91 /* Increment the re-assembly failures count. */
92 ip_ptr -> nx_ip_reassembly_failures++;
93 #endif
94
95 #if !defined(NX_DISABLE_IPV4) && !defined(NX_DISABLE_ICMPV4_ERROR_MESSAGE)
96 /* If ICMPv4 is enabled, send Destination unreachable. */
97 if (fragment -> nx_packet_ip_version == NX_IP_VERSION_V4)
98 {
99
100 /* Setup header pointer for this packet. */
101 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
102 ipv4_header = (NX_IPV4_HEADER *)fragment -> nx_packet_ip_header;
103
104 /* Time Exceeded Message, RFC 792, P2. */
105 /* Check if the fragment zero is available. */
106 if ((ipv4_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK) == 0)
107 {
108
109 /* Send a time exceeded message if fragmented datagram cannot complete the reassembly. */
110 NX_ICMPV4_SEND_TIME_EXCEED(ip_ptr, fragment, NX_ICMP_FRT_EXCEEDED_CODE);
111 }
112 }
113 #endif /* !NX_DISABLE_IPV4 && !NX_DISABLE_ICMPV4_ERROR_MESSAGE */
114
115 #if defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_ICMPV6_ERROR_MESSAGE)
116 /* If the packet is IPv6 type, we need to send out ICMP error message. */
117 if (fragment -> nx_packet_ip_version == NX_IP_VERSION_V6)
118 {
119
120 /* Send out ICMP Time Exceeded message, if the first fragment has been received
121 as per RFC2460 4.5 */
122 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
123 fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)fragment -> nx_packet_prepend_ptr;
124
125 if ((fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8) == 0)
126 {
127
128 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
129 ipv6_header = (NX_IPV6_HEADER *)fragment -> nx_packet_ip_header;
130
131 /* First fragment has been received. Send ICMP error message, if the destination
132 is not multicast. */
133
134 if (!(IPv6_Address_Type(ipv6_header -> nx_ip_header_destination_ip) & IPV6_ADDRESS_MULTICAST))
135 {
136
137 /* Cover offset flag field. */
138 NX_CHANGE_USHORT_ENDIAN(fragment_option -> nx_ipv6_header_fragment_option_offset_flag);
139 NX_ICMPV6_SEND_TIME_EXCEED(ip_ptr, fragment, 1);
140 }
141 }
142 }
143 #endif /* FEATURE_NX_IPV6 && !NX_DISABLE_ICMPV6_ERROR_MESSAGE */
144
145 /* Walk the chain of fragments for this fragment re-assembly. */
146 do
147 {
148
149 #ifndef NX_DISABLE_IP_INFO
150
151 /* Increment the IP receive packets dropped count. */
152 ip_ptr -> nx_ip_receive_packets_dropped++;
153 #endif
154
155 /* Pickup the next fragment. */
156 next_fragment = fragment -> nx_packet_union_next.nx_packet_fragment_next;
157
158 /* Reset tcp_queue_next before releasing. */
159 /*lint -e{923} suppress cast of ULONG to pointer. */
160 fragment -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
161
162 /* Release this fragment. */
163 _nx_packet_release(fragment);
164
165 /* Reassign the fragment pointer. */
166 fragment = next_fragment;
167 } while (fragment);
168 }
169
170
171
172 /**************************************************************************/
173 /* */
174 /* FUNCTION RELEASE */
175 /* */
176 /* _nx_ip_fragment_timeout_check PORTABLE C */
177 /* 6.1 */
178 /* AUTHOR */
179 /* */
180 /* Yuxin Zhou, Microsoft Corporation */
181 /* */
182 /* DESCRIPTION */
183 /* */
184 /* This function checks for timeout conditions on the first fragment */
185 /* in the IP re-assembly list. If the head pointer is the same */
186 /* between execution of this routine, the head fragment is deleted and */
187 /* its packets are released. */
188 /* */
189 /* INPUT */
190 /* */
191 /* ip_ptr Pointer to IP instance */
192 /* */
193 /* OUTPUT */
194 /* */
195 /* None */
196 /* */
197 /* CALLS */
198 /* */
199 /* _nx_packet_release Release packet */
200 /* */
201 /* CALLED BY */
202 /* */
203 /* Application */
204 /* */
205 /* RELEASE HISTORY */
206 /* */
207 /* DATE NAME DESCRIPTION */
208 /* */
209 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
210 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
211 /* resulting in version 6.1 */
212 /* */
213 /**************************************************************************/
_nx_ip_fragment_timeout_check(NX_IP * ip_ptr)214 VOID _nx_ip_fragment_timeout_check(NX_IP *ip_ptr)
215 {
216
217 NX_PACKET *fragment;
218 NX_PACKET *next_fragment;
219 NX_PACKET *previous_fragment = NX_NULL;
220
221
222 /* Set a pointer to the head packet of the fragmented packet queue. */
223 fragment = ip_ptr -> nx_ip_fragment_assembly_head;
224
225
226 /* Loop through all the fragmented packets in the queue. */
227 while (fragment)
228 {
229
230 /* Check if the timeout has expired. */
231 if (fragment -> nx_packet_reassembly_time == 0)
232 {
233
234 /* Timeout occured. */
235 next_fragment = fragment -> nx_packet_queue_next;
236
237 /* Remove the packet from the queue and connect the linked list around it. */
238 if (previous_fragment == NX_NULL)
239 {
240 ip_ptr -> nx_ip_fragment_assembly_head = next_fragment;
241 }
242 else
243 {
244 previous_fragment -> nx_packet_queue_next = next_fragment;
245 }
246
247 /* Send out an error message, release the packet fragments in this chain. */
248 _nx_ip_fragment_cleanup(ip_ptr, fragment);
249
250 /* If this was the last one in the queue, reset the tail to
251 the previous fragment. */
252 if (fragment == ip_ptr -> nx_ip_fragment_assembly_tail)
253 {
254 ip_ptr -> nx_ip_fragment_assembly_tail = previous_fragment;
255 }
256
257 /* Get the next fragmented packet awaiting assembly. */
258 fragment = next_fragment;
259 }
260 else
261 {
262
263 /* Decrement the time remaining to assemble the whole packet. */
264 fragment -> nx_packet_reassembly_time--;
265
266 /* Get the next packet fragment. */
267 previous_fragment = fragment;
268 fragment = fragment -> nx_packet_queue_next;
269 }
270 }
271 }
272 #endif /* NX_DISABLE_FRAGMENTATION */
273
274