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