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 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "nx_ip.h"
30 
31 #ifndef NX_DISABLE_IPV4
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_ip_route_find                                   PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*     This function finds an outgoing interface and the next hop address */
45 /*     for a given destination address.  The caller may also set desired  */
46 /*     interface information in the ip_interface_ptr input.  For multicast*/
47 /*     or limited broadcast, this routine looks for the first enabled     */
48 /*     interface (link up) starting with the primary interface if         */
49 /*     a hint was not set by the caller.  For directed broadcast or       */
50 /*     unicast destinations, the hint is ignored and the proper outgoing  */
51 /*     interface is selected.                                             */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    ip_ptr                IN              Pointer to IP instance        */
56 /*    destination_address   IN              Destination address           */
57 /*    ip_interface_ptr      OUT             Interface to use, must point  */
58 /*                                            to valid storage space.     */
59 /*    next_hop_address      OUT             IP address for the next hop,  */
60 /*                                            must point to valid storage */
61 /*                                            space.                      */
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    NX_SUCCESS                            Operation was successful      */
66 /*    NX_IP_ADDRESS_ERROR                   No suitable interface found   */
67 /*                                                                        */
68 /*  CALLS                                                                 */
69 /*                                                                        */
70 /*    None                                                                */
71 /*                                                                        */
72 /*  CALLED BY                                                             */
73 /*                                                                        */
74 /*    _nx_arp_dynamic_entry_set.c           ARP entry set                 */
75 /*    _nx_icmp_ping                         Transmit ICMP echo request    */
76 /*    _nx_ip_packet_send                    IP packet transmit            */
77 /*    _nx_tcp_client_socket_connect         TCP Client socket connection  */
78 /*    _nx_udp_socket_send                   UDP packet send               */
79 /*                                                                        */
80 /*  NOTE:                                                                 */
81 /*                                                                        */
82 /*    None                                                                */
83 /*                                                                        */
84 /*  RELEASE HISTORY                                                       */
85 /*                                                                        */
86 /*    DATE              NAME                      DESCRIPTION             */
87 /*                                                                        */
88 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
89 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
90 /*                                            resulting in version 6.1    */
91 /*                                                                        */
92 /**************************************************************************/
_nx_ip_route_find(NX_IP * ip_ptr,ULONG destination_address,NX_INTERFACE ** ip_interface_ptr,ULONG * next_hop_address)93 ULONG  _nx_ip_route_find(NX_IP *ip_ptr, ULONG destination_address, NX_INTERFACE **ip_interface_ptr, ULONG *next_hop_address)
94 {
95 
96 NX_INTERFACE *interface_ptr;
97 ULONG         i;
98 
99     /* Initialize the next hop address. */
100     *next_hop_address = 0;
101 
102     /* Determine if the destination_address is multicast or directed broadcast. */
103     if (((destination_address & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) ||
104         (destination_address  == NX_IP_LIMITED_BROADCAST))
105     {
106 
107         *next_hop_address = destination_address;
108 
109         /* If the caller did not set the ip_interface value, find a link enabled
110            interface, starting with the primary interface, for transmission.  */
111         if (*ip_interface_ptr == NX_NULL)
112         {
113 
114             /* Find an interface whose link is up. */
115             for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
116             {
117 
118                 if (ip_ptr -> nx_ip_interface[i].nx_interface_link_up)
119                 {
120                     *ip_interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
121                     return(NX_SUCCESS);
122                 }
123             }
124         }
125         /* If the specified interface is up, return success. */
126         else if ((*ip_interface_ptr) -> nx_interface_link_up)
127         {
128             return(NX_SUCCESS);
129         }
130 
131         /* No available interface. */
132         return(NX_IP_ADDRESS_ERROR);
133     }
134 
135     /* Search through the interfaces associated with the IP instance,
136        check if the the destination address is one of the local interface addresses. */
137     for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
138     {
139 
140         /* Use a local variable for convenience. */
141         interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
142 
143         /* Check for a valid interface that maps onto the same network domain as the destination address. */
144         if ((interface_ptr -> nx_interface_valid) &&
145             (interface_ptr -> nx_interface_link_up) &&
146             (interface_ptr -> nx_interface_ip_address == destination_address) &&
147             ((*ip_interface_ptr == NX_NULL) ||
148              (*ip_interface_ptr == interface_ptr)))
149         {
150 
151             /* Yes, use the entry information for interface and next hop. */
152             *ip_interface_ptr = interface_ptr;
153             *next_hop_address = destination_address;
154             return(NX_SUCCESS);
155         }
156     }
157 
158 #ifdef NX_ENABLE_IP_STATIC_ROUTING
159 
160     /* Search through the routing table for a suitable interface. */
161     for (i = 0; i < ip_ptr -> nx_ip_routing_table_entry_count; i++)
162     {
163 
164         /* Get the interface. */
165         interface_ptr = ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface;
166 
167         /* Skip interface that is not up. */
168         if (interface_ptr -> nx_interface_link_up == NX_FALSE)
169         {
170             continue;
171         }
172 
173         /* Does this table entry match the destination table network domain?*/
174         if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_dest_ip ==
175             (destination_address & ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_net_mask))
176         {
177 
178             /* Yes, is next hop address still reachable? */
179             if (interface_ptr -> nx_interface_ip_network !=
180                 (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_next_hop_address &
181                  interface_ptr -> nx_interface_ip_network_mask))
182             {
183                 continue;
184             }
185 
186             /* Use the entry information for interface and next hop. */
187             if (*ip_interface_ptr == NX_NULL)
188             {
189                 *ip_interface_ptr = interface_ptr;
190             }
191             else if (*ip_interface_ptr != interface_ptr)
192             {
193                 continue;
194             }
195 
196             *next_hop_address = ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_next_hop_address;
197 
198             return(NX_SUCCESS);
199         }
200     }
201 
202 #endif /* NX_ENABLE_IP_STATIC_ROUTING */
203 
204     /* Search through the interfaces associated with the IP instance,
205        check if the entry exists. */
206     for (i = 0; i < NX_MAX_IP_INTERFACES; i++)
207     {
208 
209         /* Use a local variable for convenience. */
210         interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
211 
212         /* Check for a valid interface that maps onto the same network domain as the destination address. */
213         if ((interface_ptr -> nx_interface_valid) &&
214             (interface_ptr -> nx_interface_link_up) &&
215             ((interface_ptr -> nx_interface_ip_network_mask & destination_address) == interface_ptr -> nx_interface_ip_network))
216         {
217 
218             /* Yes, use the entry information for interface and next hop. */
219             if (*ip_interface_ptr == NX_NULL)
220             {
221                 *ip_interface_ptr = interface_ptr;
222             }
223             /* Match loopback interface.  */
224             /* Suppress constant value, since "NX_MAX_IP_INTERFACES" can be redefined. */
225 #if (NX_MAX_IP_INTERFACES == (NX_MAX_PHYSICAL_INTERFACES + 1))
226             else if (i == NX_MAX_PHYSICAL_INTERFACES)
227             {
228                 *ip_interface_ptr = interface_ptr;
229             }
230 #endif
231             else if (*ip_interface_ptr != interface_ptr)
232             {
233                 continue;
234             }
235 
236             *next_hop_address = destination_address;
237 
238             return(NX_SUCCESS);
239         }
240     }
241 
242     /* Search the interfaces for IPv4 Link-Local Address according to RFC3927, section2.6.  */
243     /* Determine if destination addrss is link-local address(169.254/16 Hexadecimal:0xA9FE0000).  */
244     if ((destination_address & 0xFFFF0000) == 0xA9FE0000)
245     {
246 
247         /* Yes, check if the interface is set.  */
248         if (*ip_interface_ptr)
249         {
250 
251             /* Determine if the interface is valid.  */
252             if (((*ip_interface_ptr) -> nx_interface_valid) &&
253                 ((*ip_interface_ptr) -> nx_interface_link_up))
254             {
255 
256                 /* Set the next hop address.  */
257                 *next_hop_address = destination_address;
258 
259                 return(NX_SUCCESS);
260             }
261         }
262         else
263         {
264 
265             /* Search through the interfaces associated with the IP instance, set the inteface as first valid interface.  */
266             for (i = 0; i < NX_MAX_IP_INTERFACES; i++)
267             {
268 
269                 /* Check for a valid interface that the address is link-local address.  */
270                 if ((ip_ptr -> nx_ip_interface[i].nx_interface_valid) &&
271                     (ip_ptr -> nx_ip_interface[i].nx_interface_link_up))
272                 {
273 
274                     /* Yes, use the entry information for interface and next hop. */
275                     *ip_interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
276                     *next_hop_address = destination_address;
277 
278                     return(NX_SUCCESS);
279                 }
280             }
281         }
282     }
283 
284     /* Does the IP instance have a gateway? */
285     if ((ip_ptr -> nx_ip_gateway_address) &&
286         (ip_ptr -> nx_ip_gateway_interface) &&
287         (ip_ptr -> nx_ip_gateway_interface -> nx_interface_link_up))
288     {
289 
290         /* Get the interface. */
291         interface_ptr = ip_ptr -> nx_ip_gateway_interface;
292 
293         /* Yes, is gateway address still reachable? */
294         if (interface_ptr -> nx_interface_ip_network !=
295             (ip_ptr -> nx_ip_gateway_address &
296              interface_ptr -> nx_interface_ip_network_mask))
297         {
298             return(NX_IP_ADDRESS_ERROR);
299         }
300 
301         /* Use the gateway as default. */
302         if (*ip_interface_ptr == NX_NULL)
303         {
304             *ip_interface_ptr = interface_ptr;
305         }
306         else if (*ip_interface_ptr != interface_ptr)
307         {
308             return(NX_IP_ADDRESS_ERROR);
309         }
310 
311         *next_hop_address = ip_ptr -> nx_ip_gateway_address;
312 
313         return(NX_SUCCESS);
314     }
315 
316     /* Determine if source addrss is link-local address(169.254/16 Hexadecimal:0xA9FE0000).  */
317     if (*ip_interface_ptr)
318     {
319 
320         /* Determine if the interface is valid and the address of interface is link-local address.  */
321         if (((*ip_interface_ptr) -> nx_interface_valid) &&
322             ((*ip_interface_ptr) -> nx_interface_link_up) &&
323             (((*ip_interface_ptr) -> nx_interface_ip_address & 0xFFFF0000) == 0xA9FE0000))
324         {
325 
326             /* Set the next hop address.  */
327             *next_hop_address = destination_address;
328 
329             return(NX_SUCCESS);
330         }
331     }
332     else
333     {
334 
335         /* Search through the interfaces associated with the IP instance,
336            check if interface is valid and the address of interface is link-local address. */
337         for (i = 0; i < NX_MAX_IP_INTERFACES; i++)
338         {
339 
340             /* Use a local variable for convenience. */
341             interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
342 
343             /* Check for a valid interface that the address is link-local address.  */
344             if ((interface_ptr -> nx_interface_valid) &&
345                 (interface_ptr -> nx_interface_link_up) &&
346                 ((interface_ptr -> nx_interface_ip_address & 0xFFFF0000) == 0xA9FE0000))
347             {
348 
349                 /* Yes, use the entry information for interface and next hop. */
350                 *ip_interface_ptr = interface_ptr;
351                 *next_hop_address = destination_address;
352 
353                 return(NX_SUCCESS);
354             }
355         }
356     }
357 
358     /* Cannot find a proper way to transmit this packet.
359        Return the error status. */
360     return(NX_IP_ADDRESS_ERROR);
361 }
362 #endif /* NX_DISABLE_IPV4 */
363 
364