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_packet.h"
31 
32 
33 #ifndef NX_DISABLE_IPV4
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _nx_arp_packet_receive                              PORTABLE C      */
39 /*                                                           6.1.11       */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Yuxin Zhou, Microsoft Corporation                                   */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function processes the reception of both the ARP request and   */
47 /*    the ARP response.  ARP requests are filled in and sent out as ARP   */
48 /*    responses.  ARP responses received are used to update this IP's     */
49 /*    ARP cache and dequeue and send any waiting packet.                  */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    ip_ptr                                Pointer to IP instance        */
54 /*    packet_ptr                            Received ARP packet           */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    None                                                                */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _nx_packet_release                    Release the ARP request       */
63 /*    (nx_ip_arp_allocate)                  ARP entry allocate call       */
64 /*    (nx_ip_arp_gratuitous_response_handler) ARP gratuitous response     */
65 /*    _nx_arp_queue_send                    Send the queued packet        */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    _nx_arp_queue_process                 ARP receive queue processing  */
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 /*  04-25-2022     Yuxin Zhou               Modified comment(s),          */
79 /*                                            fixed compiler errors,      */
80 /*                                            resulting in version 6.1.11 */
81 /*                                                                        */
82 /**************************************************************************/
_nx_arp_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)83 VOID  _nx_arp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
84 {
85 
86 ULONG        *message_ptr;
87 ULONG         sender_physical_msw;
88 ULONG         sender_physical_lsw;
89 ULONG         sender_ip_address;
90 ULONG         target_ip_address;
91 ULONG         message_type;
92 ULONG         index;
93 UCHAR         consumed = NX_FALSE;
94 NX_ARP       *arp_ptr;
95 NX_IP_DRIVER  driver_request;
96 NX_INTERFACE *interface_ptr;
97 
98 
99 #ifndef NX_DISABLE_RX_SIZE_CHECKING
100     /* Determine if the packet length is valid.  */
101     if (packet_ptr -> nx_packet_length < NX_ARP_MESSAGE_SIZE)
102     {
103 
104         /* Invalid ARP message.  Release the packet and return.  */
105 
106 #ifndef NX_DISABLE_ARP_INFO
107         /* Increment the ARP invalid messages count.  */
108         ip_ptr -> nx_ip_arp_invalid_messages++;
109 #endif
110 
111         /* Invalid ARP message.  Just release the packet.  */
112         _nx_packet_release(packet_ptr);
113 
114         /* Return to caller.  */
115         return;
116     }
117 #endif /* NX_DISABLE_RX_SIZE_CHECKING  */
118 
119     /* Setup a pointer to the ARP message.  */
120     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
121     message_ptr =  (ULONG *)packet_ptr -> nx_packet_prepend_ptr;
122 
123     /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
124        swap the endian of the ARP message.  */
125     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1));
126     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2));
127     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3));
128     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4));
129     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5));
130     NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6));
131 
132     /* Pickup the ARP message type.  */
133     message_type =  (ULONG)(*(message_ptr + 1) & 0xFFFF);
134 
135     /* Determine if the ARP message type is valid.  */
136     if ((message_type != NX_ARP_OPTION_REQUEST) && (message_type != NX_ARP_OPTION_RESPONSE))
137     {
138 
139         /* Invalid ARP message.  Release the packet and return.  */
140 
141 #ifndef NX_DISABLE_ARP_INFO
142         /* Increment the ARP invalid messages count.  */
143         ip_ptr -> nx_ip_arp_invalid_messages++;
144 #endif
145 
146         /* Invalid ARP message.  Just release the packet.  */
147         _nx_packet_release(packet_ptr);
148 
149         /* Return to caller.  */
150         return;
151     }
152 
153     /* Pick up the sender's physical address from the message.  */
154     sender_physical_msw =  (*(message_ptr + 2) >> 16);
155     sender_physical_lsw =  (*(message_ptr + 2) << 16) | (*(message_ptr + 3) >> 16);
156     sender_ip_address =    (*(message_ptr + 3) << 16) | (*(message_ptr + 4) >> 16);
157     target_ip_address =    *(message_ptr + 6);
158 
159     /* Does the packet have an interface assigned? */
160     if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr == NX_NULL)
161     {
162 
163         /* No, so default it to the primary interface. */
164         packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &ip_ptr -> nx_ip_interface[0];
165     }
166 
167     /* Pickup the interface information from the incoming packet. */
168     interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
169 
170     /* Determine if it is an IP address conflict when IP address probing.  */
171     if ((interface_ptr -> nx_interface_ip_address == 0) &&
172         (interface_ptr -> nx_interface_ip_probe_address != 0) &&
173         ((sender_ip_address == interface_ptr -> nx_interface_ip_probe_address) ||
174          ((sender_ip_address == 0) && (target_ip_address == interface_ptr -> nx_interface_ip_probe_address))))
175     {
176 
177         /* Make sure the sender physical address is not ours.  */
178         if ((sender_physical_msw != interface_ptr -> nx_interface_physical_address_msw) ||
179             (sender_physical_lsw != interface_ptr -> nx_interface_physical_address_lsw))
180         {
181 
182             /* Determine if there is a a IP address conflict notify handler.  */
183             if (interface_ptr -> nx_interface_ip_conflict_notify_handler)
184             {
185 
186                 /* A IP address conflict is present, call the notification handler.  */
187                 (interface_ptr -> nx_interface_ip_conflict_notify_handler)(ip_ptr, interface_ptr -> nx_interface_index, interface_ptr -> nx_interface_ip_probe_address,
188                                                                            sender_physical_msw, sender_physical_lsw);
189             }
190         }
191 
192         /* Release the packet. */
193         _nx_packet_release(packet_ptr);
194 
195         return;
196     }
197 
198     /* Determine if it is an address conflict packet after set the IP address.  */
199     if ((sender_ip_address != 0) && (sender_ip_address == interface_ptr -> nx_interface_ip_address))
200     {
201 
202         /* Is it sent from other devices. */
203         if ((sender_physical_msw != packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_physical_address_msw) ||
204             (sender_physical_lsw != packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_physical_address_lsw))
205         {
206 
207             /* Yes it is.  */
208             if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_arp_defend_timeout == 0)
209             {
210 
211                 /* Set defend timeout. */
212                 packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_arp_defend_timeout = NX_ARP_DEFEND_INTERVAL;
213 
214                 /* Send the announcement. */
215                 _nx_arp_packet_send(ip_ptr, sender_ip_address, packet_ptr -> nx_packet_address.nx_packet_interface_ptr);
216             }
217 
218             /* Determine if there is a a IP address conflict notify handler.  */
219             if (interface_ptr -> nx_interface_ip_conflict_notify_handler)
220             {
221 
222                 /* A IP address conflict is present, call the notification handler.  */
223                 (interface_ptr -> nx_interface_ip_conflict_notify_handler)(ip_ptr, interface_ptr -> nx_interface_index, interface_ptr -> nx_interface_ip_probe_address,
224                                                                            sender_physical_msw, sender_physical_lsw);
225             }
226 
227             /* This is likely in response to our previous gratuitous ARP from another entity on the
228                network has the same IP address.  */
229 
230             /* Determine if there is a gratuitous ARP response handler.  */
231             if (ip_ptr -> nx_ip_arp_gratuitous_response_handler)
232             {
233 
234                 /* Yes, call the gratuitous ARP response handler. Note that it is responsible
235                    for releasing the packet!  */
236                 (ip_ptr -> nx_ip_arp_gratuitous_response_handler)(ip_ptr, packet_ptr);
237 
238                 return;
239             }
240 
241 #ifdef NX_ARP_DEFEND_BY_REPLY
242 #ifndef NX_DISABLE_ARP_INFO
243             /* Increment the ARP responses sent count.  */
244             ip_ptr -> nx_ip_arp_responses_sent++;
245 #endif
246 
247             /* If trace is enabled, insert this event into the trace buffer.  */
248             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_SEND, ip_ptr, sender_ip_address, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
249 
250             /* Set the ARP message type to ARP response.  */
251             *(message_ptr + 1) =  (*(message_ptr + 1) & 0xFFFF0000) | NX_ARP_OPTION_RESPONSE;
252 
253             /* Now fill in the new source and destination information for the ARP response.  */
254             *(message_ptr + 2) =  (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw << 16) |
255                 (packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw >> 16);
256             *(message_ptr + 3) =  (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw << 16) |
257                 (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address >> 16);
258             *(message_ptr + 4) =  (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address << 16);
259             *(message_ptr + 5) =  (ULONG)0;
260             *(message_ptr + 6) =  (ULONG)0;
261 
262             /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
263                swap the endian of the ARP message.  */
264             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1));
265             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2));
266             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3));
267             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4));
268             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5));
269             NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6));
270 
271             /* Make sure the packet length is set properly.  */
272             packet_ptr -> nx_packet_length =  NX_ARP_MESSAGE_SIZE;
273 
274             /* Setup the append pointer, since the received ARP packet can be padded
275                with unnecessary bytes.  */
276             packet_ptr -> nx_packet_append_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ARP_MESSAGE_SIZE;
277 
278             /* Send the ARP request to the driver.  */
279             driver_request.nx_ip_driver_ptr                  =  ip_ptr;
280             driver_request.nx_ip_driver_command              =  NX_LINK_ARP_RESPONSE_SEND;
281             driver_request.nx_ip_driver_packet               =  packet_ptr;
282             driver_request.nx_ip_driver_physical_address_msw =  0xFFFFUL;
283             driver_request.nx_ip_driver_physical_address_lsw =  0xFFFFFFFFUL;
284             driver_request.nx_ip_driver_interface            =  packet_ptr -> nx_packet_ip_interface;
285 
286             /* If trace is enabled, insert this event into the trace buffer.  */
287             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_RESPONSE_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
288 
289             /* No need to update packet_ptr -> nx_packet_ip_interface.  When responding to an ARP request, use the same interface where the request was received. */
290 
291             (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry)(&driver_request);
292 
293             return;
294 #endif /* NX_ARP_DEFEND_BY_REPLY */
295         }
296 
297         /* Release the conflict packet. */
298         _nx_packet_release(packet_ptr);
299 
300         return;
301     }
302 
303     /* Determine what type of ARP message this is.  Note that ARP requests must
304        also specify this IP instance's IP address.  */
305     if ((message_type == NX_ARP_OPTION_REQUEST) && (target_ip_address == (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)))
306     {
307 
308 #ifndef NX_DISABLE_ARP_INFO
309 
310         /* Increment the ARP requests received count.  */
311         ip_ptr -> nx_ip_arp_requests_received++;
312 
313         /* Increment the ARP responses sent count.  */
314         ip_ptr -> nx_ip_arp_responses_sent++;
315 #endif
316 
317         /* If trace is enabled, insert this event into the trace buffer.  */
318         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE, ip_ptr, sender_ip_address, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
319 
320         /* If trace is enabled, insert this event into the trace buffer.  */
321         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_SEND, ip_ptr, sender_ip_address, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
322 
323         /* Set the ARP message type to ARP response.  */
324         *(message_ptr + 1) =  (*(message_ptr + 1) & 0xFFFF0000) | NX_ARP_OPTION_RESPONSE;
325 
326 
327         /* Now fill in the new source and destination information for the ARP response.  */
328         *(message_ptr + 2) =  (ULONG)(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_physical_address_msw << 16) |
329             (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_physical_address_lsw >> 16);
330         *(message_ptr + 3) =  (ULONG)(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_physical_address_lsw << 16) |
331             (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address >> 16);
332         *(message_ptr + 4) =  (ULONG)(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address << 16) | sender_physical_msw;
333         *(message_ptr + 5) =  (ULONG)sender_physical_lsw;
334         *(message_ptr + 6) =  (ULONG)sender_ip_address;
335 
336         /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
337            swap the endian of the ARP message.  */
338         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1));
339         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2));
340         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3));
341         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4));
342         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5));
343         NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6));
344 
345         /* Make sure the packet length is set properly.  */
346         packet_ptr -> nx_packet_length =  NX_ARP_MESSAGE_SIZE;
347 
348         /* Setup the append pointer, since the received ARP packet can be padded
349            with unnecessary bytes.  */
350         packet_ptr -> nx_packet_append_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ARP_MESSAGE_SIZE;
351 
352         /* Send the ARP request to the driver.  */
353         driver_request.nx_ip_driver_ptr =      ip_ptr;
354         driver_request.nx_ip_driver_command =  NX_LINK_ARP_RESPONSE_SEND;
355         driver_request.nx_ip_driver_packet =   packet_ptr;
356         driver_request.nx_ip_driver_physical_address_msw =  sender_physical_msw;
357         driver_request.nx_ip_driver_physical_address_lsw =  sender_physical_lsw;
358         driver_request.nx_ip_driver_interface            =  packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
359 
360         /* If trace is enabled, insert this event into the trace buffer.  */
361         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_RESPONSE_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
362 
363         /* No need to update interface.  When responding to an ARP request, use the same interface where the request was received. */
364         (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry)(&driver_request);
365 
366         /* Set the consumed as NX_TRUE, do not need to release the packet.  */
367         consumed = NX_TRUE;
368     }
369     else
370     {
371 
372         /* We have a response to a previous ARP request or Gratuitous ARP from another network entity.  */
373 
374 #ifndef NX_DISABLE_ARP_INFO
375 
376         /* Check for the message type to see which counter to increment.  */
377         if (message_type == NX_ARP_OPTION_REQUEST)
378         {
379 
380             /* Increment the ARP requests received count.  */
381             ip_ptr -> nx_ip_arp_requests_received++;
382 
383             /* If trace is enabled, insert this event into the trace buffer.  */
384             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE, ip_ptr, sender_ip_address, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
385         }
386         else
387         {
388 
389             /* Increment the ARP responses received count.  */
390             ip_ptr -> nx_ip_arp_responses_received++;
391 
392             /* If trace is enabled, insert this event into the trace buffer.  */
393             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_RECEIVE, ip_ptr, sender_ip_address, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
394         }
395 #endif /* NX_DISABLE_ARP_INFO */
396     }
397 
398     /* In either case, search the ARP cache to update any entry that matches the sender's IP
399        address.  */
400 
401     /* Now we need to search through the active ARP list for the IP address
402        to see if there is a matching entry.  */
403 
404     /* Calculate the hash index for the sender IP address.  */
405     index =  (UINT)((sender_ip_address + (sender_ip_address >> 8)) & NX_ARP_TABLE_MASK);
406 
407     /* Pickup the first ARP entry.  */
408     arp_ptr = NX_NULL;
409 
410     /* Ignore anything from any ARP packet with a zero sender IP address. */
411     if (sender_ip_address != 0)
412     {
413         /* Calculate the hash index for the sender IP address.  */
414         index =  (UINT)((sender_ip_address + (sender_ip_address >> 8)) & NX_ROUTE_TABLE_MASK);
415 
416         /* Pickup the first ARP entry.  */
417         arp_ptr =  ip_ptr -> nx_ip_arp_table[index];
418     }
419 
420     /* Loop to look for an ARP match.  */
421     while (arp_ptr)
422     {
423 
424         /* Check for an IP match.  */
425         if (arp_ptr -> nx_arp_ip_address == sender_ip_address)
426         {
427 
428 
429 #ifdef NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION
430 
431             /* Determine if there is a ARP collision notify handler.  */
432             if (ip_ptr -> nx_ip_arp_collision_notify_response_handler)
433             {
434 
435                 /* Now check if the machine address is stored in our ARP cache.  */
436                 if ((arp_ptr -> nx_arp_physical_address_msw != 0) || (arp_ptr -> nx_arp_physical_address_lsw != 0))
437                 {
438 
439                     /* Now check if its machine address is different from what is in our ARP cache.  */
440                     if ((arp_ptr -> nx_arp_physical_address_msw != sender_physical_msw) ||
441                         (arp_ptr -> nx_arp_physical_address_lsw != sender_physical_lsw))
442                     {
443 
444                         /* A collision is present with the mapping in our ARP table.  Call the notification handler.
445                            Note: the application must release the packet. */
446                         (ip_ptr -> nx_ip_arp_collision_notify_response_handler)((void *)packet_ptr);
447 
448                         /* We're done.  NetX does not respond or do any further processing.*/
449                         return;
450                     }
451                 }
452             }
453 #endif /* NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION */
454 
455             /* No need to update the static ARP entry. */
456             if (arp_ptr -> nx_arp_route_static)
457             {
458                 break;
459             }
460 
461             /* Save the physical address found in this ARP response.  */
462             arp_ptr -> nx_arp_physical_address_msw =  sender_physical_msw;
463             arp_ptr -> nx_arp_physical_address_lsw =  sender_physical_lsw;
464 
465             /* Set the update rate to the expiration rate since we now have an ARP
466                response.  */
467             arp_ptr -> nx_arp_entry_next_update =  NX_ARP_EXPIRATION_RATE;
468 
469             /* Reset the retry counter for this ARP entry.  */
470             arp_ptr -> nx_arp_retries =  0;
471 
472             /* Set the interface attached to this packet. */
473             arp_ptr -> nx_arp_ip_interface = interface_ptr;
474 
475             /* Call queue send function to send the packet queued up.  */
476             _nx_arp_queue_send(ip_ptr, arp_ptr);
477 
478             /* Yes, we found a match.  Get out of the loop!  */
479             break;
480         }
481 
482         /* Move to the next active ARP entry.  */
483         arp_ptr =  arp_ptr -> nx_arp_active_next;
484 
485         /* Determine if we are at the end of the ARP list.  */
486         if (arp_ptr == ip_ptr -> nx_ip_arp_table[index])
487         {
488 
489             /* Clear the ARP pointer.  */
490             arp_ptr =  NX_NULL;
491             break;
492         }
493     }
494 
495     /* Determine if we have a packet to release. */
496     if (consumed == NX_FALSE)
497     {
498         _nx_packet_release(packet_ptr);
499     }
500 
501 #ifndef NX_DISABLE_ARP_AUTO_ENTRY
502 
503     /* Determine if anything was found.  Ignore ARP messages with a zero IP sender address.   */
504     if ((arp_ptr == NX_NULL) && (sender_ip_address != 0))
505     {
506 
507         /* Calculate the hash index for the sender IP address.  */
508         index =  (UINT)((sender_ip_address + (sender_ip_address >> 8)) & NX_ARP_TABLE_MASK);
509 
510         /* Allocate a new ARP entry in advance of the need to send to the IP
511            address.  */
512         if (((ip_ptr -> nx_ip_arp_allocate)(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_FALSE)) == NX_SUCCESS)
513         {
514 
515             /* Setup a pointer to the new ARP entry.  */
516             arp_ptr =  (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous;
517 
518             /* Setup the IP address and clear the physical mapping.  */
519             arp_ptr -> nx_arp_ip_address =            sender_ip_address;
520             arp_ptr -> nx_arp_physical_address_msw =  sender_physical_msw;
521             arp_ptr -> nx_arp_physical_address_lsw =  sender_physical_lsw;
522             arp_ptr -> nx_arp_entry_next_update =     NX_ARP_EXPIRATION_RATE;
523             arp_ptr -> nx_arp_retries =               0;
524             arp_ptr -> nx_arp_ip_interface         =  interface_ptr;
525         }
526     }
527 #endif /* NX_DISABLE_ARP_AUTO_ENTRY */
528 }
529 #endif /* !NX_DISABLE_IPV4  */
530 
531