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 /** Address Resolution Protocol (ARP) */
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_arp.h"
29 #include "nx_ip.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_arp_dynamic_entry_set PORTABLE C */
36 /* 6.1.6 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function allocates an ARP dynamic entry for the application */
44 /* and assigns the specified IP to hardware mapping. If the specified */
45 /* hardware address is zero, an actual ARP request will be sent out. */
46 /* */
47 /* INPUT */
48 /* */
49 /* ip_ptr IP instance pointer */
50 /* ip_address IP Address to bind to */
51 /* physical_msw Physical address MSW */
52 /* physical_lsw Physical address LSW */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _nx_ip_route_find Find suitable outgoing */
61 /* interface */
62 /* _nx_arp_entry_allocate Allocate an ARP entry */
63 /* _nx_arp_packet_send Send ARP request */
64 /* _nx_arp_queue_send Send the queued packet */
65 /* tx_mutex_get Obtain protection mutex */
66 /* tx_mutex_put Release protection mutex */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* Application Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
77 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* 04-02-2021 Yuxin Zhou Modified comment(s), corrected*/
80 /* the returned status, */
81 /* resulting in version 6.1.6 */
82 /* */
83 /**************************************************************************/
_nx_arp_dynamic_entry_set(NX_IP * ip_ptr,ULONG ip_address,ULONG physical_msw,ULONG physical_lsw)84 UINT _nx_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address,
85 ULONG physical_msw, ULONG physical_lsw)
86 {
87
88 #ifndef NX_DISABLE_IPV4
89 NX_ARP *arp_ptr;
90 NX_ARP *search_ptr;
91 NX_ARP *arp_list_head;
92 UINT index;
93 UINT status;
94 NX_INTERFACE *nx_interface = NX_NULL;
95 ULONG next_hop_address;
96
97 /* If trace is enabled, insert this event into the trace buffer. */
98 NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_DYNAMIC_ENTRY_SET, ip_ptr, ip_address, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, 0, 0);
99
100 /* Initialize next_hop_address to zero. */
101 next_hop_address = 0;
102
103 /* Make sure the destination address is directly accessible. */
104 if (_nx_ip_route_find(ip_ptr, ip_address, &nx_interface, &next_hop_address) != NX_SUCCESS)
105 {
106
107 return(NX_IP_ADDRESS_ERROR);
108 }
109
110 /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized by _nx_ip_route_find. */
111 if (next_hop_address != ip_address)
112 {
113
114 return(NX_IP_ADDRESS_ERROR);
115 }
116
117 /* Obtain protection on this IP instance for access into the ARP dynamic
118 list. */
119 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
120
121 /* Calculate the hash index for the specified IP address. */
122 index = (UINT)((ip_address + (ip_address >> 8)) & NX_ARP_TABLE_MASK);
123
124 /* Pickup the head pointer of the ARP entries for this IP instance. */
125 arp_list_head = ip_ptr -> nx_ip_arp_table[index];
126
127 /* Search the ARP list for the same IP address. */
128 search_ptr = arp_list_head;
129 arp_ptr = NX_NULL;
130 while (search_ptr)
131 {
132
133 /* Determine if there is a duplicate IP address. */
134 if (search_ptr -> nx_arp_ip_address == ip_address)
135 {
136
137 /* Yes, the IP address matches, setup the ARP entry pointer. */
138 arp_ptr = search_ptr;
139
140 /* Get out of the loop. */
141 break;
142 }
143
144 /* Move to the next entry in the active list. */
145 search_ptr = search_ptr -> nx_arp_active_next;
146
147 /* Determine if the search pointer is back at the head of
148 the list. */
149 if (search_ptr == arp_list_head)
150 {
151
152 /* End of the ARP list, end the search. */
153 break;
154 }
155 }
156
157 /* Determine if an ARP entry is found. */
158 if (arp_ptr)
159 {
160
161 /* Determine if this is a static entry. */
162 if (arp_ptr -> nx_arp_route_static == NX_TRUE)
163 {
164
165 /* Release the mutex. */
166 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
167
168 /* Return the error status. */
169 return(NX_DUPLICATED_ENTRY);
170 }
171 }
172 else
173 {
174
175 /* No matching IP address in the ARP cache and a new dynamic entry needs to be allocated. */
176
177 /* Allocate a dynamic ARP entry. */
178 status = _nx_arp_entry_allocate(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_FALSE);
179
180 /* Determine if an error occurred. */
181 if (status != NX_SUCCESS)
182 {
183
184 /* Release the mutex. */
185 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
186
187 /* Return the error status. */
188 return(status);
189 }
190
191 /* Otherwise, setup a pointer to the new ARP entry. The newly allocated
192 ARP entry was allocated at the end of the ARP list so it should be
193 referenced using the previous pointer from the list head. */
194 arp_ptr = (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous;
195 }
196
197 /* Setup the IP address and clear the physical mapping. */
198 arp_ptr -> nx_arp_ip_address = ip_address;
199 arp_ptr -> nx_arp_physical_address_msw = physical_msw;
200 arp_ptr -> nx_arp_physical_address_lsw = physical_lsw;
201 arp_ptr -> nx_arp_retries = 0;
202
203 /*lint -e{644} suppress variable might not be initialized, since "nx_interface" was initialized in _nx_ip_route_find. */
204 arp_ptr -> nx_arp_ip_interface = nx_interface;
205
206 /* Determine if a physical address was supplied. */
207 if ((physical_msw | physical_lsw) == 0)
208 {
209
210 /* Since there isn't physical mapping, change the update rate
211 for possible ARP retries. */
212 arp_ptr -> nx_arp_entry_next_update = NX_ARP_UPDATE_RATE;
213
214 /* The physical address was not specified so send an
215 ARP request for the selected IP address. */
216 /*lint -e{668} suppress possibly passing a null pointer, since nx_interface is set in _nx_ip_route_find. */
217 _nx_arp_packet_send(ip_ptr, ip_address, nx_interface);
218 }
219 else
220 {
221
222 /* Update the next update time. */
223 arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE;
224
225 /* Call queue send function to send the packet queued up. */
226 _nx_arp_queue_send(ip_ptr, arp_ptr);
227 }
228
229 /* Release the protection on the ARP list. */
230 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
231
232 /* Return status to the caller. */
233 return(NX_SUCCESS);
234 #else /* NX_DISABLE_IPV4 */
235 NX_PARAMETER_NOT_USED(ip_ptr);
236 NX_PARAMETER_NOT_USED(ip_address);
237 NX_PARAMETER_NOT_USED(physical_msw);
238 NX_PARAMETER_NOT_USED(physical_lsw);
239
240 return(NX_NOT_SUPPORTED);
241 #endif /* !NX_DISABLE_IPV4 */
242 }
243
244