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