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 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _nx_arp_static_entry_create PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* Yuxin Zhou, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function dynamically allocates an ARP entry for the application*/
45 /* to make a static IP to hardware mapping. */
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_queue_send Send the queued packet */
64 /* tx_mutex_get Obtain protection mutex */
65 /* tx_mutex_put Release protection mutex */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* Application Code */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
76 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* */
79 /**************************************************************************/
_nx_arp_static_entry_create(NX_IP * ip_ptr,ULONG ip_address,ULONG physical_msw,ULONG physical_lsw)80 UINT _nx_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address,
81 ULONG physical_msw, ULONG physical_lsw)
82 {
83
84 #ifndef NX_DISABLE_IPV4
85 TX_INTERRUPT_SAVE_AREA
86 NX_ARP *arp_ptr;
87 NX_ARP *search_ptr;
88 NX_ARP *arp_list_head;
89 UINT index;
90 UINT status;
91 NX_INTERFACE *nx_interface = NX_NULL;
92 ULONG next_hop_address;
93
94 /* If trace is enabled, insert this event into the trace buffer. */
95 NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_STATIC_ENTRY_CREATE, ip_ptr, ip_address, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, 0, 0);
96
97 /* Make sure the destination address is directly accessible. */
98 if (_nx_ip_route_find(ip_ptr, ip_address, &nx_interface, &next_hop_address) != NX_SUCCESS)
99 {
100
101 return(NX_IP_ADDRESS_ERROR);
102 }
103
104 /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
105 if (next_hop_address != ip_address)
106 {
107
108 return(NX_IP_ADDRESS_ERROR);
109 }
110
111 /* Obtain protection on this IP instance for access into the ARP dynamic
112 list. */
113 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
114
115 /* Calculate the hash index for the specified IP address. */
116 index = (UINT)((ip_address + (ip_address >> 8)) & NX_ARP_TABLE_MASK);
117
118 /* Pickup the head pointer of the ARP entries for this IP instance. */
119 arp_list_head = ip_ptr -> nx_ip_arp_table[index];
120
121 /* Search the ARP list for the same IP address. */
122 search_ptr = arp_list_head;
123 arp_ptr = NX_NULL;
124 while (search_ptr)
125 {
126
127 /* Determine if there is a duplicate IP address. */
128 if (search_ptr -> nx_arp_ip_address == ip_address)
129 {
130
131 /* Yes, the IP address matches, setup the ARP entry pointer. */
132 arp_ptr = search_ptr;
133
134 /* Get out of the loop. */
135 break;
136 }
137
138 /* Move to the next entry in the active list. */
139 search_ptr = search_ptr -> nx_arp_active_next;
140
141 /* Determine if the search pointer is back at the head of
142 the list. */
143 if (search_ptr == arp_list_head)
144 {
145
146 /* End of the ARP list, end the search. */
147 break;
148 }
149 }
150
151 /* Determine if we find an ARP entry. */
152 if (arp_ptr)
153 {
154
155 /* Determine if this is a static entry. */
156 if (arp_ptr -> nx_arp_route_static == NX_FALSE)
157 {
158
159 /* Disable interrupts temporarily. */
160 TX_DISABLE
161
162 /* Remove this entry from the ARP dynamic list. */
163
164 /* Determine if this is the only ARP entry on the dynamic list. */
165 if (arp_ptr == arp_ptr -> nx_arp_pool_next)
166 {
167
168 /* Remove the sole entry from the dynamic list head. */
169 ip_ptr -> nx_ip_arp_dynamic_list = NX_NULL;
170 }
171 else
172 {
173
174 /* Remove the entry from a list of more than one entry. */
175
176 /* Update the links of the adjacent ARP dynamic pool entries. */
177 (arp_ptr -> nx_arp_pool_next) -> nx_arp_pool_previous = arp_ptr -> nx_arp_pool_previous;
178 (arp_ptr -> nx_arp_pool_previous) -> nx_arp_pool_next = arp_ptr -> nx_arp_pool_next;
179
180 /* Update the list head pointer. */
181 if (ip_ptr -> nx_ip_arp_dynamic_list == arp_ptr)
182 {
183 ip_ptr -> nx_ip_arp_dynamic_list = arp_ptr -> nx_arp_pool_next;
184 }
185 }
186
187 /* Decrement the number of active dynamic entries. */
188 ip_ptr -> nx_ip_arp_dynamic_active_count--;
189
190 /* Add the entry to the ARP static list. */
191
192 /* Determine if the ARP static list is empty. */
193 if (ip_ptr -> nx_ip_arp_static_list == NX_NULL)
194 {
195
196 /* Just place this single ARP entry on the list. */
197 arp_ptr -> nx_arp_pool_next = arp_ptr;
198 arp_ptr -> nx_arp_pool_previous = arp_ptr;
199 ip_ptr -> nx_ip_arp_static_list = arp_ptr;
200 }
201 else
202 {
203
204 /* Add to the end of the ARP static list. */
205 arp_ptr -> nx_arp_pool_next = ip_ptr -> nx_ip_arp_static_list;
206 arp_ptr -> nx_arp_pool_previous = (ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous;
207 ((ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous) -> nx_arp_pool_next = arp_ptr;
208 (ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous = arp_ptr;
209 }
210
211 /* Restore interrupts. */
212 TX_RESTORE
213
214 #ifndef NX_DISABLE_ARP_INFO
215 /* Increment the ARP static entry count. */
216 ip_ptr -> nx_ip_arp_static_entries++;
217 #endif
218 }
219 }
220 /* Determine if we didn't find an ARP entry and need to allocate a new
221 static entry. */
222 else
223 {
224
225 /* No matching IP address in the ARP cache. */
226
227 /* Allocate a static ARP entry. */
228 status = _nx_arp_entry_allocate(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_TRUE);
229
230 /* Determine if an error occurred. */
231 if (status != NX_SUCCESS)
232 {
233
234 /* Release the mutex. */
235 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
236
237 /* Return the error status. */
238 return(status);
239 }
240
241 /* Otherwise, setup a pointer to the new ARP entry. The newly allocated
242 ARP entry was allocated at the end of the ARP list so it should be
243 referenced using the previous pointer from the list head. */
244 arp_ptr = (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous;
245 }
246
247 /* Indicate the entry does not need updating. */
248 arp_ptr -> nx_arp_entry_next_update = 0;
249
250 /* Place the important information in the ARP structure. */
251 arp_ptr -> nx_arp_route_static = NX_TRUE;
252 arp_ptr -> nx_arp_ip_address = ip_address;
253 arp_ptr -> nx_arp_physical_address_msw = physical_msw;
254 arp_ptr -> nx_arp_physical_address_lsw = physical_lsw;
255
256 /*lint -e{644} suppress variable might not be initialized, since "nx_interface" was initialized in _nx_ip_route_find. */
257 arp_ptr -> nx_arp_ip_interface = nx_interface;
258
259 /* Call queue send function to send the packet queued up, if the original entry is dynamic entry. */
260 _nx_arp_queue_send(ip_ptr, arp_ptr);
261
262 /* Release the protection on the ARP list. */
263 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
264
265 /* Return status to the caller. */
266 return(NX_SUCCESS);
267 #else /* NX_DISABLE_IPV4 */
268 NX_PARAMETER_NOT_USED(ip_ptr);
269 NX_PARAMETER_NOT_USED(ip_address);
270 NX_PARAMETER_NOT_USED(physical_msw);
271 NX_PARAMETER_NOT_USED(physical_lsw);
272
273 return(NX_NOT_SUPPORTED);
274 #endif /* !NX_DISABLE_IPV4 */
275 }
276
277