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