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_ipv6.h"
32 #include "nx_icmpv6.h"
33
34 #ifdef FEATURE_NX_IPV6
35
36
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _nx_ipv6_packet_receive PORTABLE C */
43 /* 6.1 */
44 /* AUTHOR */
45 /* */
46 /* Yuxin Zhou, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function receives IPv6 packets from the nx_ip_packet_receive. */
51 /* The packet is either processed here or placed it in a deferred */
52 /* processing queue, depending on the complexity of the packet. */
53 /* */
54 /* INPUT */
55 /* */
56 /* ip_ptr Pointer to IP control block */
57 /* packet_ptr Pointer to packet received */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* None */
62 /* */
63 /* CALLS */
64 /* */
65 /* _nx_packet_release Packet release function */
66 /* _nx_ip_dispatch_process The routine that examines */
67 /* other optional headers and */
68 /* upper layer protocols. */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Application I/O Driver */
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), */
80 /* resulting in version 6.1 */
81 /* */
82 /**************************************************************************/
_nx_ipv6_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)83 VOID _nx_ipv6_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
84 {
85
86 UINT error;
87 ULONG delta;
88 UINT pkt_length;
89 UCHAR next_header_type;
90 NX_IPV6_HEADER *ip_header_ptr;
91 NXD_IPV6_ADDRESS *interface_ipv6_address_next;
92 NXD_IPV6_ADDRESS *incoming_address = NX_NULL;
93 #ifndef NX_DISABLE_PACKET_CHAIN
94 NX_PACKET *before_last_packet;
95 NX_PACKET *last_packet;
96 #endif /* NX_DISABLE_PACKET_CHAIN */
97
98 #ifdef NX_ENABLE_IPV6_MULTICAST
99 INT i = 0;
100 #endif /* NX_ENABLE_IPV6_MULTICAST */
101
102
103 /* Add debug information. */
104 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
105
106 /* Points to the base of IPv6 header. */
107 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
108 ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
109
110 /* Byte swap WORD 1 to obtain IPv6 payload length. */
111 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
112
113 pkt_length = (UINT)((ip_header_ptr -> nx_ip_header_word_1 >> 16) + sizeof(NX_IPV6_HEADER));
114
115 /* Make sure the packet length field matches the payload length field in the IPv6 header. */
116 if (packet_ptr -> nx_packet_length != (ULONG)pkt_length)
117 {
118
119 /* Determine if the packet length is less than the size reported in the IP header. */
120 if (packet_ptr -> nx_packet_length < (ULONG)pkt_length)
121 {
122
123 /* The incoming packet has a wrong payload size. */
124 #ifndef NX_DISABLE_IP_INFO
125
126 /* Increment the IP invalid packet error. */
127 ip_ptr -> nx_ip_invalid_packets++;
128
129 /* Increment the IP receive packets dropped count. */
130 ip_ptr -> nx_ip_receive_packets_dropped++;
131 #endif
132
133 /* Release the packet! */
134 _nx_packet_release(packet_ptr);
135
136 /* In all cases, receive processing is finished. Return to caller. */
137 return;
138 }
139
140 /* Calculate the difference in the length. */
141 delta = packet_ptr -> nx_packet_length - pkt_length;
142
143 /* Adjust the packet length. */
144 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta;
145
146 /* Adjust the append pointer. */
147
148 #ifndef NX_DISABLE_PACKET_CHAIN
149 /* Loop to process adjustment that spans multiple packets. */
150 while (delta)
151 {
152
153 /* Determine if the packet is chained (or still chained after the adjustment). */
154 if (packet_ptr -> nx_packet_last == NX_NULL)
155 {
156
157 /* No, packet is not chained, simply adjust the append pointer in the packet. */
158 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
159
160 /* Break out of the loop, since the adjustment is complete. */
161 break;
162 }
163
164 /* Pickup the pointer to the last packet. */
165 last_packet = packet_ptr -> nx_packet_last;
166
167 /* Determine if the amount to adjust is less than the payload in the last packet. */
168 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
169 if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta)
170 {
171
172 /* Yes, simply adjust the append pointer of the last packet in the chain. */
173 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
174 last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta;
175
176 /* Get out of the loop, since the adjustment is complete. */
177 break;
178 }
179 else
180 {
181
182 /* Adjust the delta by the amount in the last packet. */
183 delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr));
184
185 /* Find the packet before the last packet. */
186 before_last_packet = packet_ptr;
187 while (before_last_packet -> nx_packet_next != last_packet)
188 {
189
190 /* Move to the next packet in the chain. */
191 before_last_packet = before_last_packet -> nx_packet_next;
192 }
193
194 /* At this point, we need to release the last packet and adjust the other packet
195 pointers. */
196
197 /* Ensure the next packet pointer is NULL in what is now the last packet. */
198 before_last_packet -> nx_packet_next = NX_NULL;
199
200 /* Determine if the packet is still chained. */
201 if (packet_ptr != before_last_packet)
202 {
203
204 /* Yes, the packet is still chained, setup the last packet pointer. */
205 packet_ptr -> nx_packet_last = before_last_packet;
206 }
207 else
208 {
209
210 /* The packet is no longer chained, set the last packet pointer to NULL. */
211 packet_ptr -> nx_packet_last = NX_NULL;
212 }
213
214 /* Release the last packet. */
215 _nx_packet_release(last_packet);
216 }
217 }
218 #else
219
220 /* Simply adjust the append pointer in the packet. */
221 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
222 #endif /* NX_DISABLE_PACKET_CHAIN */
223 }
224
225 /* Byte swap the rest of the IPv6 header fields. */
226 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
227 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
228 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
229
230 /* Get a pointer to the first address in the address list for this interface (e.g.
231 the interface the packet was received on). */
232 interface_ipv6_address_next = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nxd_interface_ipv6_address_list_head;
233
234 /* Check if this packet is intended for this host by looping through all the addresses in the IP interface table for a match. */
235 while (interface_ipv6_address_next)
236 {
237
238 /* Ignore invalid addresses. */
239 if (interface_ipv6_address_next -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_UNKNOWN)
240 {
241
242 /* Does the incoming packet match one of the IP interfaces? */
243 if (CHECK_IPV6_ADDRESSES_SAME(ip_header_ptr -> nx_ip_header_destination_ip,
244 interface_ipv6_address_next -> nxd_ipv6_address))
245 {
246
247 /* Yes, we found a match! */
248 incoming_address = interface_ipv6_address_next;
249
250 break;
251 }
252 /* Check for multicast address. */
253 else if (CHECK_IPV6_SOLICITED_NODE_MCAST_ADDRESS(ip_header_ptr -> nx_ip_header_destination_ip,
254 interface_ipv6_address_next -> nxd_ipv6_address))
255 {
256
257 /* Yes, this is a multicast address. */
258 incoming_address = interface_ipv6_address_next;
259
260 break;
261 }
262 }
263
264 /* No match yet, get the next address. */
265 interface_ipv6_address_next = interface_ipv6_address_next -> nxd_ipv6_address_next;
266 }
267
268 #ifdef NX_ENABLE_IPV6_MULTICAST
269
270 if ((incoming_address == NX_NULL) && ((ip_header_ptr -> nx_ip_header_destination_ip[0] & 0xFF000000) == 0xFF000000))
271 {
272
273 /* Search the address whether match our multicast join list. */
274 for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
275 {
276
277 /* Match the destination address with the multicast list */
278 if ((ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list == packet_ptr -> nx_packet_address.nx_packet_interface_ptr) &&
279 (CHECK_IPV6_ADDRESSES_SAME(ip_header_ptr -> nx_ip_header_destination_ip, (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list))))
280 {
281 incoming_address = ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list -> nxd_interface_ipv6_address_list_head;
282 break;
283 }
284 }
285 }
286 #endif /* NX_ENABLE_IPV6_MULTICAST */
287
288 /* Check for valid interface. */
289 if (incoming_address == NX_NULL)
290 {
291
292 /* The incoming packet has a destination address that does not match any of
293 the local interface addresses so its not for me. */
294
295 #ifndef NX_DISABLE_IP_INFO
296 /* Increment the IP receive packets dropped count. */
297 ip_ptr -> nx_ip_receive_packets_dropped++;
298 #endif
299
300 /* Release the packet. */
301 _nx_packet_release(packet_ptr);
302
303 /* In all cases, receive processing is finished. Return to caller. */
304 return;
305 }
306
307 /* Set the matching address to the packet address. */
308 packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = incoming_address;
309
310 /*
311 Update the IP header pointer, packet length and packet prepend pointer
312 to point to the next header (either IP option header or
313 upper layer protocol header.
314 */
315
316 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV6_HEADER);
317 packet_ptr -> nx_packet_length -= (ULONG)sizeof(NX_IPV6_HEADER);
318
319 packet_ptr -> nx_packet_option_offset = 6;
320 next_header_type = (UCHAR)((ip_header_ptr -> nx_ip_header_word_1 >> 8) & 0xFF);
321
322 /*
323 Search all the extension headers, terminate after upper layer protocols
324 (such as UDP, TCP, ICMP).
325
326 Also check the order of the optional headers. Once an out-of-order option
327 field is detected, the search is terminated and an ICMPv6 error message is
328 generated.
329 */
330
331 /* Initialize start of search for just passed the IP header. */
332 packet_ptr -> nx_packet_option_state = (UCHAR)IPV6_BASE_HEADER;
333 packet_ptr -> nx_packet_destination_header = 0;
334
335 #ifndef NX_DISABLE_IP_INFO
336
337 /* Increment the number of packets delivered. */
338 ip_ptr -> nx_ip_total_packets_delivered++;
339
340 /* Increment the IP packet bytes received (not including the header). */
341 ip_ptr -> nx_ip_total_bytes_received += packet_ptr -> nx_packet_length;
342 #endif
343
344 error = _nx_ip_dispatch_process(ip_ptr, packet_ptr, next_header_type);
345
346 if (error)
347 {
348 _nx_packet_release(packet_ptr);
349 }
350
351 return;
352 }
353
354
355 #endif /* FEATURE_NX_IPV6 */
356
357