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