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