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 /**************************************************************************/
14 /**                                                                       */
15 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Internet Protocol (IP)                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 /* Include necessary system files.  */
25 
26 #include "nx_api.h"
27 #include "nx_ipv6.h"
28 
29 #ifdef FEATURE_NX_IPV6
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _nxd_ipv6_interface_find                            PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Yuxin Zhou, Microsoft Corporation                                   */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function finds a suitable outgoing interface based on the      */
43 /*    destination IP address.                                             */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    ip_ptr                                Pointer to IP control block   */
48 /*    dest_address                          Destination IP address        */
49 /*    ipv6_interface_index                  Index interface to use as the */
50 /*                                            outgoing  interface.        */
51 /*    ipv6_address_index                    Address index to use as the   */
52 /*                                            source address              */
53 /*    if_ptr                                Outgoing interface if not null*/
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                                              */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    None                                                                */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    Internal function.                                                  */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
72 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
73 /*                                            resulting in version 6.1    */
74 /*                                                                        */
75 /**************************************************************************/
_nxd_ipv6_interface_find(NX_IP * ip_ptr,ULONG * dest_address,NXD_IPV6_ADDRESS ** ipv6_addr,NX_INTERFACE * if_ptr)76 UINT _nxd_ipv6_interface_find(NX_IP *ip_ptr, ULONG *dest_address,
77                               NXD_IPV6_ADDRESS **ipv6_addr, NX_INTERFACE *if_ptr)
78 {
79 
80 UINT                          i;
81 NXD_IPV6_ADDRESS             *ipv6_address;
82 NX_IPV6_DEFAULT_ROUTER_ENTRY *rt_entry;
83 UINT                          start_index;
84 UINT                          end_index;
85 ULONG                         address_type = IPv6_Address_Type(dest_address);
86 
87     /* ipv6_addr must not be NULL. */
88     NX_ASSERT(ipv6_addr != NX_NULL);
89 
90 #ifdef NX_ENABLE_IPV6_MULTICAST
91     /* Check for a multicast destination address.*/
92     if (address_type & IPV6_ADDRESS_MULTICAST)
93     {
94 
95 
96         /* Search the address whether match our mld join list.  */
97         for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
98         {
99 
100             /* Skip empty entries. */
101             if (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list == NX_NULL)
102             {
103                 continue;
104             }
105 
106             /* Skip not matched interface. */
107             if (if_ptr && (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list != if_ptr))
108             {
109                 continue;
110             }
111 
112             /* Skip multicast entry whose related interface is down. */
113             if (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list -> nx_interface_link_up == NX_FALSE)
114             {
115                 continue;
116             }
117 
118             if (CHECK_IPV6_ADDRESSES_SAME(ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list, dest_address))
119             {
120                 *ipv6_addr = ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list -> nxd_interface_ipv6_address_list_head;
121 
122                 /* Check whether there's address on the interface. */
123                 if (*ipv6_addr == NX_NULL)
124                 {
125                     return(NX_NO_INTERFACE_ADDRESS);
126                 }
127 
128                 /* The address must be valid in list queue of interface. */
129                 NX_ASSERT((*ipv6_addr) -> nxd_ipv6_address_valid);
130                 return(NX_SUCCESS);
131             }
132         }
133     }
134 #endif /* NX_ENABLE_IPV6_MULTICAST  */
135 
136     /* Loop through addresses. */
137     if (address_type & IPV6_ADDRESS_UNICAST)
138     {
139 
140         /* Unicast address. Is the destination one of local address? */
141         for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
142         {
143 
144             /* Compare the address. */
145             if ((ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid) &&
146                 (CHECK_IPV6_ADDRESSES_SAME(ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address, dest_address)))
147             {
148 
149                 /* Found a proper address. */
150                 *ipv6_addr = &(ip_ptr -> nx_ipv6_address[i]);
151                 return(NX_SUCCESS);
152             }
153         }
154     }
155 
156     if (if_ptr)
157     {
158 
159         /* Search addresses from specified interface only. */
160         start_index = if_ptr -> nx_interface_index;
161         end_index = (UINT)(if_ptr -> nx_interface_index + 1);
162     }
163     else
164     {
165 
166         /* Search addressed from all interfaces. */
167         start_index = 0;
168         end_index = NX_MAX_PHYSICAL_INTERFACES;
169     }
170 
171     /* Loop through interfaces. */
172     for (i = start_index; i < end_index; i++)
173     {
174 
175         /* Skip interface which is down. */
176         if (ip_ptr -> nx_ip_interface[i].nx_interface_link_up == NX_FALSE)
177         {
178             continue;
179         }
180 
181         /* Point to the first address unit in the interface. */
182         for (ipv6_address = ip_ptr -> nx_ip_interface[i].nxd_interface_ipv6_address_list_head;
183              ipv6_address;
184              ipv6_address = ipv6_address -> nxd_ipv6_address_next)
185         {
186 
187             /* Skip address that is not valid. */
188             if (ipv6_address -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID)
189             {
190                 continue;
191             }
192 
193             if (address_type & IPV6_ADDRESS_LINKLOCAL)
194             {
195 
196                 /* Destination address is link local. */
197                 if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL)
198                 {
199 
200                     /* Found link local address as source. */
201                     break;
202                 }
203             }
204             else if (_nxd_ipv6_find_max_prefix_length(dest_address, ipv6_address -> nxd_ipv6_address,
205                                                       ipv6_address -> nxd_ipv6_address_prefix_length) >=
206                      ipv6_address -> nxd_ipv6_address_prefix_length)
207             {
208 
209                 /* Found a proper outgoing address. */
210                 break;
211             }
212             /* Check for a multicast destination address.*/
213             else if (address_type & IPV6_ADDRESS_MULTICAST)
214             {
215 
216                 /* This indicates a global IP multicast. */
217                 /* So we need to make a best guess at the
218                    address index of the host global address. */
219 
220                 /* Determine(LLA vs Global IP address type from the higher order bytes. */
221                 if ((dest_address[0] & 0x000F0000) == 0x00020000)
222                 {
223 
224                     /* Check for a link local IP address. */
225                     if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL)
226                     {
227 
228                         /* This will do! */
229                         break;
230                     }
231                 }
232                 /* Check for a global IP address. */
233                 else if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_GLOBAL)
234                 {
235 
236                     /* This will do! */
237                     break;
238                 }
239             }
240         }
241 
242         if (ipv6_address)
243         {
244 
245             /* Found a proper address. */
246             *ipv6_addr = ipv6_address;
247             return(NX_SUCCESS);
248         }
249     }
250 
251 #ifndef NX_DISABLE_LOOPBACK_INTERFACE
252     /* Get ipv6 address in the loop back interface. */
253     ipv6_address = ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nxd_interface_ipv6_address_list_head;
254     if (ipv6_address)
255     {
256 
257         /* Check whether the destination is loop back address. */
258         if (CHECK_IPV6_ADDRESSES_SAME(ipv6_address -> nxd_ipv6_address, dest_address))
259         {
260             *ipv6_addr = ipv6_address;
261             return(NX_SUCCESS);
262         }
263     }
264 #endif /* NX_DISABLE_LOOPBACK_INTERFACE */
265 
266     /* Is the destination address gloabl? */
267     if (address_type & IPV6_ADDRESS_GLOBAL)
268     {
269 
270         /* Yes. Check default router. */
271         for (i = 0; i < NX_IPV6_DEFAULT_ROUTER_TABLE_SIZE; i++)
272         {
273 
274             rt_entry = &ip_ptr -> nx_ipv6_default_router_table[i];
275 
276             /* Skip invalid entries. */
277             if (rt_entry -> nx_ipv6_default_router_entry_flag == 0)
278             {
279                 continue;
280             }
281 
282             /* Skip interface which is down. */
283             if (rt_entry -> nx_ipv6_default_router_entry_interface_ptr -> nx_interface_link_up == NX_FALSE)
284             {
285                 continue;
286             }
287 
288             /* Skip not matched interface. */
289             if (if_ptr && (rt_entry -> nx_ipv6_default_router_entry_interface_ptr != if_ptr))
290             {
291                 continue;
292             }
293 
294             /* Get first address from interface. */
295             ipv6_address = rt_entry -> nx_ipv6_default_router_entry_interface_ptr -> nxd_interface_ipv6_address_list_head;
296 
297             while (ipv6_address)
298             {
299 
300                 /* Check for a valid address. */
301                 if (ipv6_address -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID)
302                 {
303                     ipv6_address = ipv6_address -> nxd_ipv6_address_next;
304                 }
305                 /* Check for link-local address. */
306                 else if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL)
307                 {
308                     ipv6_address = ipv6_address -> nxd_ipv6_address_next;
309                 }
310                 else
311                 {
312                     *ipv6_addr = ipv6_address;
313 
314                     /* Found global address as link-local address. */
315                     return(NX_SUCCESS);
316                 }
317             }
318         }
319     }
320 
321     /* No available interface. */
322     return(NX_NO_INTERFACE_ADDRESS);
323 }
324 
325 #endif /* FEATURE_NX_IPV6 */
326 
327