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 /** NetX Component */
14 /** */
15 /** Internet Protocol version 6 Default Router Table (IPv6 router) */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19 #define NX_SOURCE_CODE
20
21
22 /* Include necessary system files. */
23
24 #include "nx_api.h"
25 #include "nx_ipv6.h"
26 #include "nx_nd_cache.h"
27 #include "nx_icmpv6.h"
28
29
30 #ifdef FEATURE_NX_IPV6
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nxd_ipv6_router_lookup PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function finds a valid router from the default router table, */
44 /* and this function also return the pointer to the router's cache */
45 /* entry in the NetX Duo cache table. */
46 /* */
47 /* INPUT */
48 /* */
49 /* ip_ptr IP instance pointer */
50 /* if_ptr Pointer to interface */
51 /* router_address Pointer to default router */
52 /* nd_cache_entry Pointer to associated ND entry*/
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Non zero status */
57 /* router not found */
58 /* Zero status, router found */
59 /* */
60 /* CALLS */
61 /* */
62 /* None */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _nx_icmpv6_process_redirect */
67 /* _nx_ipv6_packet_send */
68 /* */
69 /* NOTE */
70 /* */
71 /* Internal Function. Caller must have acquired IP protection mutex. */
72 /* This function should not be called from ISR. Although it has no */
73 /* blocking calls it will slow down response time. */
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), */
81 /* resulting in version 6.1 */
82 /* */
83 /**************************************************************************/
_nxd_ipv6_router_lookup(NX_IP * ip_ptr,NX_INTERFACE * if_ptr,ULONG * router_address,void ** nd_cache_entry)84 UINT _nxd_ipv6_router_lookup(NX_IP *ip_ptr, NX_INTERFACE *if_ptr, ULONG *router_address, void **nd_cache_entry)
85 {
86
87 UINT i;
88 UINT table_size;
89 UINT routers_checked;
90 NX_IPV6_DEFAULT_ROUTER_ENTRY *rt_entry;
91 ND_CACHE_ENTRY *NDCacheEntry;
92
93 NX_ASSERT(nd_cache_entry != NX_NULL)
94
95 /* Initialize cache pointer to NULL (if no router found). */
96 *nd_cache_entry = NULL;
97
98 /* Set a local variable for convenience. */
99 table_size = ip_ptr -> nx_ipv6_default_router_table_size;
100
101 /* Check if there have been any routers added to the table. */
102 if (table_size == 0)
103 {
104
105 /* Return a non zero (e.g. unsuccessful) error status. */
106 return(NX_NOT_SUCCESSFUL);
107 }
108
109 /* Loop to check the router table. */
110 for (i = 0; table_size && (i < NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE); i++)
111 {
112
113 /* Local pointer for convenience. */
114 rt_entry = &(ip_ptr -> nx_ipv6_default_router_table[i]);
115
116 /* Does this slot contain a valid router? */
117 if ((rt_entry -> nx_ipv6_default_router_entry_flag & NX_IPV6_ROUTE_TYPE_VALID) &&
118 (rt_entry -> nx_ipv6_default_router_entry_interface_ptr == if_ptr))
119 {
120
121 /* Keep track of valid entries we have checked. */
122 NDCacheEntry = rt_entry -> nx_ipv6_default_router_entry_neighbor_cache_ptr;
123
124 /* Is this router reachable? */
125 if (!NDCacheEntry ||
126 (NDCacheEntry -> nx_nd_cache_nd_status < ND_CACHE_STATE_REACHABLE) ||
127 (NDCacheEntry -> nx_nd_cache_nd_status > ND_CACHE_STATE_PROBE))
128 {
129
130 /* No, skip over. */
131 table_size--;
132 continue;
133 }
134
135 /* Yes, copy this router address into the return pointer. */
136 COPY_IPV6_ADDRESS(ip_ptr -> nx_ipv6_default_router_table[i].nx_ipv6_default_router_entry_router_address, router_address);
137
138 /* Copy the router's cache entry pointer to the supplied cache table pointer. */
139 *nd_cache_entry = ip_ptr -> nx_ipv6_default_router_table[i].nx_ipv6_default_router_entry_neighbor_cache_ptr;
140
141 /* We're done. Break out of the search. */
142 return(NX_SUCCESS);
143 }
144 }
145
146 /* If we are here, we did not find a suitable default router. Do a search
147 of routers previously reachable. */
148
149 /* Start at the round robin index so we don't always choose the first
150 less-than-reachable router in the table. */
151 i = ip_ptr -> nx_ipv6_default_router_table_round_robin_index;
152
153 /* Find a router with previously known reachability. */
154 for (routers_checked = 0; routers_checked < NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE; routers_checked++)
155 {
156
157 /* Local pointer for convenience. */
158 rt_entry = &(ip_ptr -> nx_ipv6_default_router_table[i]);
159
160 /* Does this slot contain a valid router? */
161 if ((rt_entry -> nx_ipv6_default_router_entry_flag & NX_IPV6_ROUTE_TYPE_VALID) &&
162 (rt_entry -> nx_ipv6_default_router_entry_interface_ptr == if_ptr))
163 {
164
165 /* Yes, copy this router to the return pointer. */
166 COPY_IPV6_ADDRESS(rt_entry -> nx_ipv6_default_router_entry_router_address, router_address);
167
168 /* Copy the router's cache entry pointer to the supplied cache table pointer. */
169 *nd_cache_entry = rt_entry -> nx_ipv6_default_router_entry_neighbor_cache_ptr;
170
171 /* Update the index so the same router is not chosen again if there
172 any other less-than-reachable routers we can choose, RFC 2461 6.3.6. */
173 ip_ptr -> nx_ipv6_default_router_table_round_robin_index++;
174
175 /* Do we need wrap the index? */
176 if (ip_ptr -> nx_ipv6_default_router_table_round_robin_index == NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE)
177 {
178
179 /* Yes, start back at the first slot. */
180 ip_ptr -> nx_ipv6_default_router_table_round_robin_index = 0;
181 }
182
183 /* We're done. Return successful outcome status. */
184 return(NX_SUCCESS);
185 }
186
187 /* Are we past the end of the table? */
188 if (i == NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE - 1)
189 {
190 /* Yes, wrap to the first slot.*/
191 i = 0;
192 }
193 else
194 {
195 i++;
196 }
197 }
198
199 /* Router not found. */
200 return(NX_NOT_SUCCESSFUL);
201 }
202
203
204 #endif /* FEATURE_NX_IPV6 */
205
206