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