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