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