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