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