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 /** NetX Component */
16 /** */
17 /** Internet Control Message Protocol (ICMP) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SOURCE_CODE
23 /* Include necessary system files. */
24
25 #include "nx_api.h"
26 #include "nx_packet.h"
27 #include "nx_ip.h"
28 #include "nx_ipv6.h"
29 #include "nx_icmpv6.h"
30
31 #ifdef FEATURE_NX_IPV6
32
33 #ifndef NX_DISABLE_ICMPV6_ROUTER_ADVERTISEMENT_PROCESS
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _nx_icmpv6_process_ra PORTABLE C */
40 /* 6.1.11 */
41 /* AUTHOR */
42 /* */
43 /* Yuxin Zhou, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function processes incoming ICMPv6 router advertisement */
48 /* messages. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ip_ptr Pointer to IP control block */
53 /* packet_ptr ICMP packet pointer */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _nxd_ipv6_default_router_add_interanl Sets IPv6 router */
62 /* _nx_ipv6_multicast_join Join IPv6 multicast group */
63 /* _nx_ipv6_prefix_list_delete Remove an entry from the */
64 /* prefix list */
65 /* _nx_ipv6_prefix_list_add_entry Add an entry to the prefix */
66 /* list */
67 /* _nx_nd_cache_add Add an ND cache entry */
68 /* [ipv6_address_change_notify] User callback function */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* _nx_icmpv6_packet_process Main ICMP packet pocess */
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 /* option length verification, */
81 /* resulting in version 6.1 */
82 /* 04-25-2022 Yuxin Zhou Modified comment(s), and */
83 /* added internal ip address */
84 /* change notification, */
85 /* resulting in version 6.1.11 */
86 /* */
87 /**************************************************************************/
_nx_icmpv6_process_ra(NX_IP * ip_ptr,NX_PACKET * packet_ptr)88 VOID _nx_icmpv6_process_ra(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
89 {
90
91 INT router_type;
92 INT packet_length;
93 INT prefix_length;
94 UINT i;
95 UINT status;
96 ULONG time_val;
97 ND_CACHE_ENTRY *nd_entry;
98 NX_ICMPV6_HEADER *header_ptr;
99 NX_ICMPV6_RA *ra_ptr;
100 NX_ICMPV6_OPTION *option_ptr;
101 NX_ICMPV6_OPTION_PREFIX *prefix_ptr;
102 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
103 NX_ICMPV6_OPTION_MTU *mtu_ptr = NULL;
104 #endif
105 NX_INTERFACE *if_ptr;
106 NX_IPV6_HEADER *ipv6_header;
107 NX_IPV6_DEFAULT_ROUTER_ENTRY *rt_entry;
108 #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
109 UINT interface_index;
110 #endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
111
112 /* Add debug information. */
113 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
114
115 /* Initialize the ND cache table entry to NULL */
116 nd_entry = NX_NULL;
117
118 /* Get a pointer to the ICMP message header. */
119 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
120 header_ptr = (NX_ICMPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
121
122 /* If the RA message is invalid, we simply return. */
123 if (_nx_icmpv6_validate_ra(packet_ptr) != NX_SUCCESS)
124 {
125
126 #ifndef NX_DISABLE_ICMP_INFO
127
128 /* Increment the ICMP invalid packet error. */
129 ip_ptr -> nx_ip_icmp_invalid_packets++;
130 #endif /* NX_DISABLE_ICMP_INFO */
131
132 _nx_packet_release(packet_ptr);
133 return;
134 }
135
136 /* Get a pointer to the router advertisement packet structure. */
137 /*lint -e{929} suppress cast of pointer to pointer, since it is necessary */
138 ra_ptr = (NX_ICMPV6_RA *)header_ptr;
139
140 /* If router advertisement flag callback is set, invoke the callback function. */
141 if (ip_ptr -> nx_icmpv6_ra_flag_callback)
142 {
143 ip_ptr -> nx_icmpv6_ra_flag_callback(ip_ptr, (UINT)ra_ptr -> nx_icmpv6_ra_flag);
144 }
145
146 /* Set a pointer to the IPv6 header. */
147 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
148 ipv6_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header;
149
150 /* Obtain the pointer to the incoming interface. */
151 if_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached;
152
153 /* (1) Determine if this message comes from a periodic refresh
154 or this is in response to a router solicitation.
155 This is a periodic refresh if the destination address is an all-router multicast address.
156 */
157
158 if (ra_ptr -> nx_icmpv6_ra_router_lifetime == 0)
159 {
160
161 NXD_ADDRESS router_address;
162
163 /* This router is no long valid. */
164
165 /* Copy the source address from the IPv6 header to a router address data
166 which we will use to delete it from the router table. */
167 router_address.nxd_ip_version = NX_IP_VERSION_V6;
168 router_address.nxd_ip_address.v6[0] = ipv6_header -> nx_ip_header_source_ip[0];
169 router_address.nxd_ip_address.v6[1] = ipv6_header -> nx_ip_header_source_ip[1];
170 router_address.nxd_ip_address.v6[2] = ipv6_header -> nx_ip_header_source_ip[2];
171 router_address.nxd_ip_address.v6[3] = ipv6_header -> nx_ip_header_source_ip[3];
172
173
174 /* Delete it from our default router table.*/
175 _nxd_ipv6_default_router_delete(ip_ptr, &router_address);
176 }
177
178 /* Does the RA packet have a valid retrans_timer? */
179 if (ra_ptr -> nx_icmpv6_ra_retrans_time)
180 {
181 /* Pickup the retrans_time value.*/
182 time_val = ra_ptr -> nx_icmpv6_ra_retrans_time;
183
184 /* Byte swapping. */
185 NX_CHANGE_ULONG_ENDIAN(time_val);
186
187 /* Yes; Reset our re-trans timer. */
188 /* Conver timer ticks (in ms) into IP fast timeout value. */
189 ip_ptr -> nx_ipv6_retrans_timer_ticks = time_val * NX_IP_FAST_TIMER_RATE / 1000;
190
191 /* If the retrans_timer is smaller than tick resolution, set it to 1. */
192 if (ip_ptr -> nx_ipv6_retrans_timer_ticks == 0)
193 {
194 ip_ptr -> nx_ipv6_retrans_timer_ticks = 1;
195 }
196 }
197
198 /* Does the router advertisement have a valid reachable time? */
199 if (ra_ptr -> nx_icmpv6_ra_reachable_time)
200 {
201
202
203 /* Yes; set a local variable to store it. */
204 time_val = ra_ptr -> nx_icmpv6_ra_reachable_time;
205
206 /* Byte swapping. */
207 NX_CHANGE_ULONG_ENDIAN(time_val);
208
209 /* Convert reachable timer to seconds. */
210 ip_ptr -> nx_ipv6_reachable_timer = time_val / 1000;
211
212 /* In case the reachable timer is less than 1 second, set reachable timer to 1 second. */
213 if (ip_ptr -> nx_ipv6_reachable_timer == 0)
214 {
215 ip_ptr -> nx_ipv6_reachable_timer = 1;
216 }
217 }
218
219 if (IPv6_Address_Type(ipv6_header -> nx_ip_header_destination_ip) & IPV6_ALL_NODE_MCAST)
220 {
221
222 /* The destination address points to all-nodes (unsolicited) multicast. Therefore this
223 is a periodic refresh. */
224 router_type = NX_IPV6_ROUTE_TYPE_UNSOLICITATED;
225 }
226 else
227 {
228 router_type = NX_IPV6_ROUTE_TYPE_SOLICITATED;
229 }
230
231 /* (2) Process option field */
232 packet_length = (INT)packet_ptr -> nx_packet_length - (INT)sizeof(NX_ICMPV6_RA);
233
234 /*lint -e{923} suppress cast between pointer and ULONG, since it is necessary */
235 option_ptr = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(ra_ptr, sizeof(NX_ICMPV6_RA));
236
237 /* Going through the rest of the packet options. */
238 while (packet_length > 0)
239 {
240
241 /* If there are prefix info options, we pick the last one. */
242
243 /* Is the current option a prefix option? */
244 if (option_ptr -> nx_icmpv6_option_type == ICMPV6_OPTION_TYPE_PREFIX_INFO)
245 {
246
247 /* Validate option length before cast to avoid OOB access. */
248 if ((UINT)(option_ptr -> nx_icmpv6_option_length << 3) < sizeof(NX_ICMPV6_OPTION_PREFIX))
249 {
250 #ifndef NX_DISABLE_ICMP_INFO
251
252 /* Increment the ICMP invalid packet error. */
253 ip_ptr -> nx_ip_icmp_invalid_packets++;
254 #endif /* NX_DISABLE_ICMP_INFO */
255
256 _nx_packet_release(packet_ptr);
257 return;
258 }
259
260 /* Yes, set a local pointer to the option. */
261 /*lint -e{929} -e{826} -e{740} suppress cast of pointer to pointer, since it is necessary */
262 prefix_ptr = (NX_ICMPV6_OPTION_PREFIX *)option_ptr;
263
264 /* Take care of the endian-ness of the prefix address. */
265 NX_IPV6_ADDRESS_CHANGE_ENDIAN(prefix_ptr -> nx_icmpv6_option_prefix);
266
267 /* Is this a link local address (prefix)? */
268 if ((prefix_ptr -> nx_icmpv6_option_prefix[0] & (ULONG)0xFFC00000) == (ULONG)0xFE800000)
269 {
270
271 /* Yes. Ignore (skip) this option, as per RFC 4861 6.3.4
272 and RFC 4862 5.5.3, and continue. */
273 packet_length -= (option_ptr -> nx_icmpv6_option_length << 3);
274
275 /* Get the next option. */
276 /*lint -e{923} suppress cast between pointer and ULONG, since it is necessary */
277 option_ptr = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(option_ptr, ((option_ptr -> nx_icmpv6_option_length) << 3));
278
279 continue;
280 }
281
282 /* So far the prefix information is valid.
283 So take care of the endian-ness. */
284 NX_CHANGE_ULONG_ENDIAN(prefix_ptr -> nx_icmpv6_option_prefix_valid_lifetime);
285 NX_CHANGE_ULONG_ENDIAN(prefix_ptr -> nx_icmpv6_option_prefix_preferred_lifetime);
286
287 /* Does the prefix have a valid lifetime? */
288 if (prefix_ptr -> nx_icmpv6_option_prefix_preferred_lifetime > prefix_ptr -> nx_icmpv6_option_prefix_valid_lifetime)
289 {
290
291 /* Ignore this option, according to RFC 4862 5.5.3(c) and continue. */
292 packet_length -= (option_ptr -> nx_icmpv6_option_length << 3);
293
294 /* Get a pointer to the next option. Abort processing the current option any further. */
295 /*lint -e{923} suppress cast between pointer and ULONG, since it is necessary */
296 option_ptr = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(option_ptr, ((option_ptr -> nx_icmpv6_option_length) << 3));
297
298 continue;
299 }
300
301 /* Determine whether or not the on-link flag is set. */
302 /* Ignore the prefix information option when it is link-local. Page 55, Section 6.3.4, RFC 4861. */
303 if (prefix_ptr -> nx_icmpv6_option_prefix_flag & 0x80)
304 {
305
306 /* This prefix option contains onlink prefix information. */
307 /* The following process follows RFC 4861 6.3.4 */
308
309 prefix_length = prefix_ptr -> nx_icmpv6_option_prefix_length;
310
311 if (prefix_ptr -> nx_icmpv6_option_prefix_valid_lifetime == 0)
312 {
313
314 /* Invalidate the prefix list entry, RFC 4861 6.3.4, p55. */
315 /* Stateless address with this prefix is deleted when prefix is deleted. */
316 _nx_ipv6_prefix_list_delete(ip_ptr, prefix_ptr -> nx_icmpv6_option_prefix, prefix_length);
317 }
318 else
319 {
320
321 /* This prefix is onlink, and valid_lifetime is non-zero.
322 So add the prefix to our list. RFC 4861 6.3.4 p55.*/
323 status = _nx_ipv6_prefix_list_add_entry(ip_ptr, prefix_ptr -> nx_icmpv6_option_prefix,
324 (ULONG)prefix_length, prefix_ptr -> nx_icmpv6_option_prefix_valid_lifetime);
325
326 /* Check for "A" bit. */
327 if ((prefix_ptr -> nx_icmpv6_option_prefix_flag & 0x40) &&
328 (prefix_ptr -> nx_icmpv6_option_prefix_length == (128 - NX_IPV6_HOST_ID_LENGTH)) &&
329 (status == NX_SUCCESS))
330 {
331 /* The autonomous flag is set */
332
333 /* Set first_unused to be an invalid entry. */
334 UINT first_unused = NX_MAX_IPV6_ADDRESSES;
335 ULONG word2, word3;
336 ULONG address[4];
337 NXD_IPV6_ADDRESS *ipv6_address;
338
339 /* Find an entry that shares the same prefix. */
340 /* Note: RFC 4862 5.5.3(d) specifies that the search is limited to IPv6
341 addresses formed by address autoconfiguration. Towards the end of 5.5.3(d),
342 the RFC explains that the search may still lead to address conflict (by not
343 searching for addresses configured manually or via DHCP. Therefore this
344 implemenation chooses to search the entire IPv6 global address, in order to
345 avoid conflict IP addresses. */
346 for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
347 {
348
349 if (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid == NX_FALSE)
350 {
351
352 /* Found the first unused entry. */
353 first_unused = i;
354 break;
355 }
356 }
357
358 if ((first_unused != NX_MAX_IPV6_ADDRESSES)
359 #ifdef NX_IPV6_STATELESS_AUTOCONFIG_CONTROL
360 && (if_ptr -> nx_ipv6_stateless_address_autoconfig_status == NX_STATELESS_ADDRESS_AUTOCONFIG_ENABLED)
361 #endif /* NX_IPV6_STATELESS_AUTOCONFIG_CONTROL */
362 )
363 {
364
365 /* If there are no global addresses with such a prefix, and there is an unused entry,
366 a new global address is formed. RFC 4862 5.5.3(d), p18 */
367
368 ipv6_address = &ip_ptr -> nx_ipv6_address[first_unused];
369
370 /* Find 64-bit interface ID. See RFC 4291 */
371 word2 = if_ptr -> nx_interface_physical_address_msw << 16 |
372 ((if_ptr -> nx_interface_physical_address_lsw & 0xFF000000) >> 16) | 0xFF;
373
374 /* Fix the 2nd lower-order bit of the 1st byte */
375 word2 = (word2 & 0xFDFFFFFF) | (~(word2 | 0xFDFFFFFF));
376 word3 = (if_ptr -> nx_interface_physical_address_lsw & 0x00FFFFFF) | 0xFE000000;
377
378 ipv6_address -> nxd_ipv6_address_valid = NX_TRUE;
379 ipv6_address -> nxd_ipv6_address_type = NX_IP_VERSION_V6;
380
381 ipv6_address -> nxd_ipv6_address_attached = if_ptr;
382 ipv6_address -> nxd_ipv6_address[0] = prefix_ptr -> nx_icmpv6_option_prefix[0];
383 ipv6_address -> nxd_ipv6_address[1] = prefix_ptr -> nx_icmpv6_option_prefix[1];
384 ipv6_address -> nxd_ipv6_address[2] = word2;
385 ipv6_address -> nxd_ipv6_address[3] = word3;
386
387 ipv6_address -> nxd_ipv6_address_next = if_ptr -> nxd_interface_ipv6_address_list_head;
388 if_ptr -> nxd_interface_ipv6_address_list_head = ipv6_address;
389
390 #ifndef NX_DISABLE_IPV6_DAD
391 /* Set the address to Tentative, so the stack can start DAD process. */
392 ipv6_address -> nxd_ipv6_address_state = NX_IPV6_ADDR_STATE_TENTATIVE;
393 #else /* !NX_DISABLE_IPV6_DAD */
394 /* DAD is disabled. Set the address to VALID. */
395 ipv6_address -> nxd_ipv6_address_state = NX_IPV6_ADDR_STATE_VALID;
396 #endif /* NX_DISABLE_IPV6_DAD */
397
398 /* Join the solicited-node multicast group */
399 /* FF02::1:FFXX:XXXX */
400 SET_SOLICITED_NODE_MULTICAST_ADDRESS(address, ipv6_address -> nxd_ipv6_address);
401 _nx_ipv6_multicast_join(ip_ptr, address, ipv6_address -> nxd_ipv6_address_attached);
402
403 ipv6_address -> nxd_ipv6_address_prefix_length = (UCHAR)prefix_length;
404 ipv6_address -> nxd_ipv6_address_ConfigurationMethod = NX_IPV6_ADDRESS_BASED_ON_INTERFACE;
405 #ifndef NX_DISABLE_IPV6_DAD
406 ipv6_address -> nxd_ipv6_address_DupAddrDetectTransmit = NX_IPV6_DAD_TRANSMITS - 1;
407 #endif /* NX_DISABLE_IPV6_DAD */
408
409 #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
410 if (ip_ptr -> nx_ipv6_address_change_notify)
411 {
412 interface_index = if_ptr -> nx_interface_index;
413 (ip_ptr -> nx_ipv6_address_change_notify)(ip_ptr, NX_IPV6_ADDRESS_STATELESS_AUTO_CONFIG, interface_index,
414 first_unused, &ipv6_address -> nxd_ipv6_address[0]);
415 }
416 if ((ip_ptr -> nx_ipv6_address_change_notify_internal) && (ipv6_address -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID))
417 {
418 interface_index = if_ptr -> nx_interface_index;
419 (ip_ptr -> nx_ipv6_address_change_notify_internal)(ip_ptr, NX_IPV6_ADDRESS_STATELESS_AUTO_CONFIG, interface_index,
420 first_unused, &ipv6_address -> nxd_ipv6_address[0]);
421 }
422 #endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
423 }
424 }
425 }
426 }
427 }
428 else if (option_ptr -> nx_icmpv6_option_type == ICMPV6_OPTION_TYPE_SRC_LINK_ADDR)
429 {
430
431 status = _nx_nd_cache_find_entry(ip_ptr, ipv6_header -> nx_ip_header_source_ip, &nd_entry);
432
433 /* Find the IP address from our local nd cache. */
434 if (status != NX_SUCCESS)
435 {
436
437 /* If the source IP address is not in our nd cache, add it. */
438 /*lint -e{929} -e{826} -e{740} suppress cast of pointer to pointer, since it is necessary */
439 _nx_nd_cache_add(ip_ptr, ipv6_header -> nx_ip_header_source_ip, if_ptr,
440 (CHAR *)&option_ptr -> nx_icmpv6_option_data, 0, ND_CACHE_STATE_STALE,
441 packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr, &nd_entry);
442 }
443 else
444 {
445 /* This entry already exists. If the mac address is the same, do not update the entry.
446 Otherwise, update the entry and set the state to STALE (RFC2461 7.2.3) */
447 ULONG mac_msw, mac_lsw, new_msw, new_lsw;
448
449 /*lint -e{928} suppress cast from pointer to pointer, since it is necessary */
450 UCHAR *new_mac = (UCHAR *)&option_ptr -> nx_icmpv6_option_data;
451
452 /* build two MAC addresses for comparison. */
453 /*lint --e{613} -e{644} suppress possible use of null pointer, since "nd_entry" was set to none NULL by _nx_nd_cache_find_entry. */
454 mac_msw = ((ULONG)(nd_entry -> nx_nd_cache_mac_addr[0]) << 8) | (nd_entry -> nx_nd_cache_mac_addr[1]);
455 mac_lsw = ((ULONG)(nd_entry -> nx_nd_cache_mac_addr[2]) << 24) | ((ULONG)(nd_entry -> nx_nd_cache_mac_addr[3]) << 16) |
456 ((ULONG)(nd_entry -> nx_nd_cache_mac_addr[4]) << 8) | nd_entry -> nx_nd_cache_mac_addr[5];
457 new_msw = ((ULONG)(new_mac[0]) << 8) | (new_mac[1]);
458 new_lsw = ((ULONG)(new_mac[2]) << 24) | ((ULONG)(new_mac[3]) << 16) | ((ULONG)(new_mac[4]) << 8) | new_mac[5]; /* lgtm[cpp/overflow-buffer] */
459 if ((mac_msw != new_msw) || (mac_lsw != new_lsw))
460 {
461
462 /* Router updates its MAC address. We update our entry as well, and place the
463 entry into STALE state for a quick address check. */
464
465 /* Set the mac address. */
466 for (i = 0; i < 6; i++)
467 {
468 nd_entry -> nx_nd_cache_mac_addr[i] = new_mac[i];
469 }
470
471 /* Set the state to STALE. */
472 nd_entry -> nx_nd_cache_nd_status = ND_CACHE_STATE_STALE;
473
474 /* Set the interface. */
475 nd_entry -> nx_nd_cache_interface_ptr = if_ptr;
476 }
477
478
479 /* Since we received source LLA, we shall transmit any packets that are pending
480 address resolution of this target. */
481 if (nd_entry -> nx_nd_cache_packet_waiting_head) /* There are packets waiting to be transmitted */
482 {
483
484 _nx_icmpv6_send_queued_packets(ip_ptr, nd_entry);
485 }
486 }
487 }
488 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
489
490 /* Check for an MTU update from the router. */
491 else if (option_ptr -> nx_icmpv6_option_type == ICMPV6_OPTION_TYPE_MTU)
492 {
493
494 NX_IPV6_DESTINATION_ENTRY *dest_entry_ptr;
495 UINT mtu_size;
496
497 /* Get a local pointer to the MTU option data. */
498 /*lint -e{929} -e{826} -e{740} suppress cast of pointer to pointer, since it is necessary */
499 mtu_ptr = (NX_ICMPV6_OPTION_MTU *)option_ptr;
500
501 mtu_size = mtu_ptr -> nx_icmpv6_option_mtu_path_mtu;
502
503 NX_CHANGE_ULONG_ENDIAN(mtu_size);
504
505
506 /* Make sure the MTU size does not exceed the link MTU size. */
507 if (mtu_size > if_ptr -> nx_interface_ip_mtu_size)
508 {
509 mtu_size = if_ptr -> nx_interface_ip_mtu_size;
510 }
511
512 /* Add destination table entry. */
513 _nx_icmpv6_dest_table_add(ip_ptr, ipv6_header -> nx_ip_header_source_ip, &dest_entry_ptr,
514 ipv6_header -> nx_ip_header_source_ip /* Next Hop address */,
515 mtu_size, NX_WAIT_FOREVER,
516 packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr);
517 }
518 #endif
519
520 /* Update the amount of packet option data remaining. */
521 packet_length -= (option_ptr -> nx_icmpv6_option_length << 3);
522
523 /* Get a pointer to the next option. */
524 /*lint -e{923} suppress cast between pointer and ULONG , since it is necessary */
525 option_ptr = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(option_ptr, ((option_ptr -> nx_icmpv6_option_length) << 3));
526 }
527
528 /* All options are processed. No errors encountered. */
529
530 /* (3) Add this entry to the routing table. */
531 if (ra_ptr -> nx_icmpv6_ra_router_lifetime)
532 {
533
534 NX_CHANGE_USHORT_ENDIAN(ra_ptr -> nx_icmpv6_ra_router_lifetime);
535
536 /* Add the router into our default router table. */
537 _nxd_ipv6_default_router_add_internal(ip_ptr, ipv6_header -> nx_ip_header_source_ip, /* Next Hop address */
538 ra_ptr -> nx_icmpv6_ra_router_lifetime, if_ptr,
539 router_type, &rt_entry);
540
541 /* Link router entry and its corresponding nd_entry.
542 Note that at this point, nd_entry may not be valid.
543 When a packet is transmitted using this router, and the nd_entry is invalid (NX_NULL)
544 ipv6 send routine shall use neighbor discovery process to find the address. */
545 /*lint -e{644} suppress variable might not be initialized, since "rt_entry" was initialized in _nxd_ipv6_default_router_add_internal. */
546 if (rt_entry && nd_entry)
547 {
548 rt_entry -> nx_ipv6_default_router_entry_neighbor_cache_ptr = (void *)nd_entry;
549 nd_entry -> nx_nd_cache_is_router = rt_entry;
550 }
551
552 if (ra_ptr -> nx_icmpv6_ra_hop_limit)
553 {
554 ip_ptr -> nx_ipv6_hop_limit = ra_ptr -> nx_icmpv6_ra_hop_limit;
555 }
556
557 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
558
559 /* Special case destination table entry, the router itself. Note that the destination is the.
560 same as the next hop. Adding the router to the destination table gives us a place to
561 store path MTU updates as RAs (router advertisements) containing MTU option data. */
562
563 /* Have we already established path MTU for this router? */
564 if (mtu_ptr == 0)
565 {
566
567 NX_IPV6_DESTINATION_ENTRY *dest_entry_ptr;
568
569 /* No, create an entry in the destination table for it, and set
570 the path MTU to our default path MTU. */
571 _nx_icmpv6_dest_table_add(ip_ptr, ipv6_header -> nx_ip_header_source_ip, &dest_entry_ptr,
572 ipv6_header -> nx_ip_header_source_ip,
573 if_ptr -> nx_interface_ip_mtu_size, NX_WAIT_FOREVER,
574 packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr);
575 }
576 #endif
577 }
578
579 #ifndef NX_DISABLE_ICMPV6_ROUTER_SOLICITATION
580
581 /* Received a valid RS... Stop RA if it is still running. */
582 if_ptr -> nx_ipv6_rtr_solicitation_count = 0;
583
584 #endif
585
586 /* release packet and return. */
587 _nx_packet_release(packet_ptr);
588 }
589
590 #endif /* NX_DISABLE_ICMPV6_ROUTER_ADVERTISEMENT_PROCESS */
591
592 #endif /* FEATURE_NX_IPV6 */
593
594