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