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