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