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