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