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