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