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 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "nx_ip.h"
30 #include "nx_ipv6.h"
31 #include "nx_packet.h"
32 #include "nx_icmpv6.h"
33 
34 #if defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_FRAGMENTATION)
35 
36 
37 
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _nx_ipv6_process_fragment_option                    PORTABLE C      */
43 /*                                                           6.1          */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Yuxin Zhou, Microsoft Corporation                                   */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function processes the IPv6 Fragmentation Option header.       */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    ip_ptr                                Pointer to IP control block   */
55 /*    packet_ptr                            Pointer to packet to process  */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    NX_SUCCESS                            Successful completion         */
60 /*    NX_CONTINUE                           Continue processing           */
61 /*    NX_OPTION_HEADER_ERROR                Error with fragment option    */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    _nx_ip_dispatch_process               Process IPv6 optional headers */
66 /*    NX_ICMPV6_SEND_PARAMETER_PROBLEM      Report IPv6 errors via ICMP   */
67 /*                                            message                     */
68 /*    tx_event_flags_set                    Wake up the IP helper thread  */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    _nx_ip_dispatch_process               Process IPv6 optional header  */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
79 /*  09-30-2020     Yuxin Zhou               Modified comment(s), improved */
80 /*                                            packet length verification, */
81 /*                                            resulting in version 6.1    */
82 /*                                                                        */
83 /**************************************************************************/
_nx_ipv6_process_fragment_option(NX_IP * ip_ptr,NX_PACKET * packet_ptr)84 UINT _nx_ipv6_process_fragment_option(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
85 {
86 
87 TX_INTERRUPT_SAVE_AREA
88 NX_IPV6_HEADER_FRAGMENT_OPTION *fragment_option;
89 
90 
91 
92     /* Add debug information. */
93     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
94 
95 #ifndef NX_DISABLE_IP_INFO
96 
97     /* Increment the IP receive fragments count */
98     ip_ptr -> nx_ip_total_fragments_received++;
99 
100 #endif /* NX_DISABLE_IP_INFO */
101 
102     /* If fragmentation is not enabled, we drop this packet. */
103     if (!ip_ptr -> nx_ip_fragment_assembly)
104     {
105         return(NX_OPTION_HEADER_ERROR);
106     }
107 
108     /* Check packet length is at least sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION). */
109     if (packet_ptr -> nx_packet_length < sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION))
110     {
111         return(NX_OPTION_HEADER_ERROR);
112     }
113 
114     /* Set a pointer to the starting of the fragment option. */
115     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
116     fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)packet_ptr -> nx_packet_prepend_ptr;
117 
118     /* Byte swap the offset_flag.  The identification field is only used for checking matches.
119        The absolute value of the Id is not used in arithmatic operations.  Therefore there is
120        need to byte-swap this field. */
121     NX_CHANGE_USHORT_ENDIAN(fragment_option -> nx_ipv6_header_fragment_option_offset_flag);
122 
123     /* Check whether or not the payload size is not multiple of 8 bytes if the
124        M bit is set. */
125     if (fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0x0001) /* M bit is set */
126     {
127 
128     NX_IPV6_HEADER *ip_header;
129     ULONG           payload_length;
130 
131         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
132         ip_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header;
133 
134         payload_length = ip_header -> nx_ip_header_word_1 >> 16;
135 
136         /* If not multiple of 8 bytes... */
137         if ((payload_length & 0xFFF8) != payload_length)
138         {
139 
140             /* Return the option header error status and abort. */
141 
142 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
143 
144             /* Cover offset flag field. */
145             NX_CHANGE_USHORT_ENDIAN(fragment_option -> nx_ipv6_header_fragment_option_offset_flag);
146 
147             /*lint -e{835} -e{845} suppress operating on zero. */
148             NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 0, 4);
149 #endif
150             return(NX_OPTION_HEADER_ERROR);
151         }
152     }
153     /* M bit is clear: This is the last (tail) packet fragment. */
154     else if ((fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8) == 0)
155     {
156 
157         /* Continue processing. */
158         return(NX_CONTINUE);
159     }
160 
161     /* Payload size cannot exceeding 65535. */
162     if (((fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8) + packet_ptr -> nx_packet_length -
163          sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION)) > 65535)
164     {
165 
166 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
167 
168         /* Cover offset flag field. */
169         NX_CHANGE_USHORT_ENDIAN(fragment_option -> nx_ipv6_header_fragment_option_offset_flag);
170 
171         /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
172         /*lint -e{835} -e{845} suppress operating on zero. */
173         NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 0,
174                                          (ULONG)((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header) + 2));
175 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
176 
177         /* Return an Option header error status. */
178         return(NX_OPTION_HEADER_ERROR);
179     }
180 
181     /* Disable interrupt */
182     TX_DISABLE
183 
184     /* In IPv6 IP fragmentation is required. */
185 
186     /* Determine if the queue is empty.  */
187     if (ip_ptr -> nx_ip_received_fragment_head)
188     {
189 
190         /* Raw receive queue is not empty, add this packet to the end of the queue.  */
191         (ip_ptr -> nx_ip_received_fragment_tail) -> nx_packet_queue_next =  packet_ptr;
192         packet_ptr -> nx_packet_queue_next =  NX_NULL;
193         ip_ptr -> nx_ip_received_fragment_tail =  packet_ptr;
194     }
195     else
196     {
197 
198         /* Raw receive queue is empty.  Just set the head and tail pointers
199            to point to this packet.  */
200         ip_ptr -> nx_ip_received_fragment_head =  packet_ptr;
201         ip_ptr -> nx_ip_received_fragment_tail =  packet_ptr;
202         packet_ptr -> nx_packet_queue_next     =  NX_NULL;
203     }
204 
205     /* Add debug information. */
206     NX_PACKET_DEBUG(NX_PACKET_IP_FRAGMENT_QUEUE, __LINE__, packet_ptr);
207 
208     /* Restore interrupts.  */
209     TX_RESTORE
210 
211 #ifndef NX_FRAGMENT_IMMEDIATE_ASSEMBLY
212     /* Wakeup IP helper thread to process the IP fragment re-assembly.  */
213     tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_UNFRAG_EVENT, TX_OR);
214 #else
215     /* Process the IP fragment reassemble.  */
216     (ip_ptr -> nx_ip_fragment_assembly)(ip_ptr);
217 #endif /* NX_FRAGMENT_IMMEDIATE_ASSEMBLY */
218 
219     return(NX_SUCCESS);
220 }
221 
222 #endif /* FEATURE_NX_IPV6 && NX_DISABLE_FRAGMENTATION*/
223 
224