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