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