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 #ifdef WIN32
12 #define HAVE_REMOTE
13 #define WPCAP
14 #endif
15
16 #include "pcap.h"
17 #include "nx_api.h"
18 #include "tx_thread.h"
19 #ifndef WIN32
20 #include "pthread.h"
21 #endif
22 #ifdef NX_ENABLE_PPPOE
23 #include "nx_pppoe_server.h"
24 #endif
25
26 #ifdef WIN32
27 #pragma comment(lib, "wpcap.lib")
28 #pragma comment(lib, "Packet.lib")
29 #pragma comment(lib, "ws2_32.lib")
30 #endif
31
32 /* Define zero-terminated string containing the source name to open. */
33 /* In windows, the SOURCE NAME looks like this "rpcap://\\Device\\NPF_{4C8Bxxxx-xxxx-xxxx-xxxx-xxxxxxxx8356}" */
34 /* In Linux, the SOURCE NAME looks like this "eth0" */
35 #ifndef NX_PCAP_SOURCE_NAME
36 #define NX_PCAP_SOURCE_NAME "rpcap://\\Device\\NPF_{4C8Bxxxx-xxxx-xxxx-xxxx-xxxxxxxx8356}"
37
38 #endif /* NX_LIBPCAP_SOURCE_NAME */
39
40 /* Define the Link MTU. Note this is not the same as the IP MTU. The Link MTU
41 includes the addition of the Physical Network header (usually Ethernet). This
42 should be larger than the IP instance MTU by the size of the physical header. */
43 #define NX_LINK_MTU 1514
44 #define NX_MAX_PACKET_SIZE 1536
45
46 /* Define Ethernet address format. This is prepended to the incoming IP
47 and ARP/RARP messages. The frame beginning is 14 bytes, but for speed
48 purposes, we are going to assume there are 16 bytes free in front of the
49 prepend pointer and that the prepend pointer is 32-bit aligned.
50
51 Byte Offset Size Meaning
52
53 0 6 Destination Ethernet Address
54 6 6 Source Ethernet Address
55 12 2 Ethernet Frame Type, where:
56
57 0x0800 -> IP Datagram
58 0x0806 -> ARP Request/Reply
59 0x0835 -> RARP request reply
60
61 42 18 Padding on ARP and RARP messages only. */
62
63 #define NX_ETHERNET_IP 0x0800
64 #define NX_ETHERNET_ARP 0x0806
65 #define NX_ETHERNET_RARP 0x8035
66 #define NX_ETHERNET_IPV6 0x86DD
67 #define NX_ETHERNET_PPPOE_DISCOVERY 0x8863
68 #define NX_ETHERNET_PPPOE_SESSION 0x8864
69 #define NX_ETHERNET_SIZE 14
70
71 /* For the pcap ethernet driver, physical addresses are allocated starting
72 at the preset value and then incremented before the next allocation. */
73
74 ULONG nx_pcap_address_msw = 0x0011;
75 ULONG nx_pcap_address_lsw = 0x22334457;
76
77 static const CHAR *nx_pcap_source_name = NX_PCAP_SOURCE_NAME;
78
79 #ifdef WIN32
80 /* Define the Windows thread to call pcap_loop. */
81 static HANDLE nx_pcap_receive_thread;
82 #else
83 /* Define the Linux thread to call pcap_loop. */
84 static pthread_t nx_pcap_receive_thread;
85 #endif
86 static NX_IP *nx_pcap_default_ip;
87 static pcap_t *nx_pcap_fp;
88
89 /* Define the buffer to store data that will be sent by pcap. */
90 static UCHAR nx_pcap_send_buff[NX_MAX_PACKET_SIZE];
91
92
93 /* Define driver prototypes. */
94
95 UINT _nx_pcap_initialize(NX_IP *ip_ptr);
96 UINT _nx_pcap_send_packet(NX_PACKET * packet_ptr);
97 #ifdef WIN32
98 DWORD WINAPI _nx_pcap_receive_thread_entry(LPVOID thread_input);
99 #else
100 void *_nx_pcap_receive_thread_entry(void *arg);
101 #endif
102 VOID _nx_lpcap_packet_receive_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
103 VOID _nx_pcap_network_driver_output(NX_PACKET *packet_ptr);
104 VOID _nx_pcap_network_driver(NX_IP_DRIVER *driver_req_ptr);
105 VOID nx_pcap_cleanup();
106
107 /* Define interface capability. */
108
109 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
110 #define NX_INTERFACE_CAPABILITY ( NX_INTERFACE_CAPABILITY_IPV4_RX_CHECKSUM | \
111 NX_INTERFACE_CAPABILITY_TCP_RX_CHECKSUM | \
112 NX_INTERFACE_CAPABILITY_UDP_RX_CHECKSUM | \
113 NX_INTERFACE_CAPABILITY_ICMPV4_RX_CHECKSUM | \
114 NX_INTERFACE_CAPABILITY_ICMPV6_RX_CHECKSUM )
115 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
116
nx_pcap_set_source_name(const CHAR * source_name)117 VOID nx_pcap_set_source_name(const CHAR *source_name)
118 {
119 nx_pcap_source_name = source_name;
120 }
121
_nx_pcap_send_packet(NX_PACKET * packet_ptr)122 UINT _nx_pcap_send_packet(NX_PACKET * packet_ptr)
123 {
124 ULONG size = 0;
125
126 /* Make sure the data length is less than MTU. */
127 if(packet_ptr -> nx_packet_length > NX_MAX_PACKET_SIZE)
128 return NX_NOT_SUCCESSFUL;
129
130 if(nx_packet_data_retrieve(packet_ptr, nx_pcap_send_buff, &size))
131 return NX_NOT_SUCCESSFUL;
132
133 if(pcap_sendpacket(nx_pcap_fp, nx_pcap_send_buff, size) != 0)
134 return NX_NOT_SUCCESSFUL;
135
136 return NX_SUCCESS;
137 }
138
139
nx_pcap_cleanup()140 void nx_pcap_cleanup()
141 {
142 pcap_close(nx_pcap_fp);
143 }
144
145
_nx_pcap_packet_receive_handler(u_char * param,const struct pcap_pkthdr * header,const u_char * pkt_data)146 VOID _nx_pcap_packet_receive_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
147 {
148
149 NX_PACKET *packet_ptr;
150 UINT status;
151 UINT packet_type;
152
153 #ifndef NX_ENABLE_PCAP_LOCAL_RECEIVE
154 /* Check whether the packet is generated by local. */
155 if((*(pkt_data + 6) == ((nx_pcap_address_msw >> 8) & 0xFF)) &&
156 (*(pkt_data + 7) == (nx_pcap_address_msw & 0xFF)) &&
157 (*(pkt_data + 8) == ((nx_pcap_address_lsw >> 24) & 0xFF)) &&
158 (*(pkt_data + 9) == ((nx_pcap_address_lsw >> 16) & 0xFF)) &&
159 (*(pkt_data + 10) == ((nx_pcap_address_lsw >> 8) & 0xFF)) &&
160 (*(pkt_data + 11) == (nx_pcap_address_lsw & 0xFF)))
161 {
162 return;
163 }
164 #endif /* NX_PCAP_LOCAL_RECEIVE */
165
166 _tx_thread_context_save();
167
168 status = nx_packet_allocate(nx_pcap_default_ip -> nx_ip_default_packet_pool, &packet_ptr, NX_RECEIVE_PACKET, NX_NO_WAIT);
169
170 if(status)
171 {
172 _tx_thread_context_restore();
173 return;
174 }
175
176 /* Make sure IP header is 4-byte aligned. */
177 packet_ptr -> nx_packet_prepend_ptr += 2;
178 packet_ptr -> nx_packet_append_ptr += 2;
179
180 status = nx_packet_data_append(packet_ptr, (VOID*)pkt_data, header -> len,
181 nx_pcap_default_ip -> nx_ip_default_packet_pool, NX_NO_WAIT);
182
183 if(status)
184 {
185 nx_packet_release(packet_ptr);
186 _tx_thread_context_restore();
187 return;
188 }
189
190 /* Pickup the packet header to determine where the packet needs to be sent. */
191 packet_type = (((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+12))) << 8) |
192 ((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+13)));
193
194 /* Route the incoming packet according to its ethernet type. */
195 if((packet_type == NX_ETHERNET_IP) || (packet_type == NX_ETHERNET_IPV6))
196 {
197
198 /* Note: The length reported by some Ethernet hardware includes bytes after the packet
199 as well as the Ethernet header. In some cases, the actual packet length after the
200 Ethernet header should be derived from the length in the IP header (lower 16 bits of
201 the first 32-bit word). */
202
203 /* Clean off the Ethernet header. */
204 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
205
206 /* Adjust the packet length. */
207 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
208
209
210 _nx_ip_packet_deferred_receive(nx_pcap_default_ip, packet_ptr);
211 }
212 else if(packet_type == NX_ETHERNET_ARP)
213 {
214
215 /* Clean off the Ethernet header. */
216 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
217
218 /* Adjust the packet length. */
219 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
220
221 _nx_arp_packet_deferred_receive(nx_pcap_default_ip, packet_ptr);
222
223 }
224 else if(packet_type == NX_ETHERNET_RARP)
225 {
226
227 /* Clean off the Ethernet header. */
228 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
229
230 /* Adjust the packet length. */
231 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
232
233 _nx_rarp_packet_deferred_receive(nx_pcap_default_ip, packet_ptr);
234 }
235 #ifdef NX_ENABLE_PPPOE
236 else if ((packet_type == NX_ETHERNET_PPPOE_DISCOVERY) ||
237 (packet_type == NX_ETHERNET_PPPOE_SESSION))
238 {
239
240 /* Clean off the Ethernet header. */
241 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
242
243 /* Adjust the packet length. */
244 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
245
246 /* Route to the PPPoE receive function. */
247 _nx_pppoe_packet_deferred_receive(packet_ptr);
248 }
249 #endif
250 else
251 {
252
253 /* Invalid ethernet header... release the packet. */
254 nx_packet_release(packet_ptr);
255 }
256 _tx_thread_context_restore();
257 }
258
259 #ifdef WIN32
_nx_pcap_receive_thread_entry(LPVOID thread_input)260 DWORD WINAPI _nx_pcap_receive_thread_entry(LPVOID thread_input)
261 {
262 /* Loop to capture packets. */
263 pcap_loop(nx_pcap_fp, 0, _nx_pcap_packet_receive_handler, NULL);
264 return 0;
265 }
266 #else
_nx_pcap_receive_thread_entry(void * arg)267 void *_nx_pcap_receive_thread_entry(void *arg)
268 {
269
270 /* Loop to capture packets. */
271 pcap_loop(nx_pcap_fp, 0, _nx_pcap_packet_receive_handler, NULL);
272 return((void *)0);
273 }
274 #endif
275
_nx_pcap_initialize(NX_IP * ip_ptr_in)276 UINT _nx_pcap_initialize(NX_IP *ip_ptr_in)
277 {
278 CHAR errbuf[PCAP_ERRBUF_SIZE] = { 0 };
279
280 #ifndef WIN32
281 struct sched_param sp;
282
283 /* Define the thread's priority. */
284 #ifdef TX_LINUX_PRIORITY_ISR
285 sp.sched_priority = TX_LINUX_PRIORITY_ISR;
286 #else
287 sp.sched_priority = 2;
288 #endif
289 #endif
290
291 /* Return if source has been opened. */
292 if(nx_pcap_fp)
293 return 1;
294
295 #ifdef WIN32
296 if((nx_pcap_fp = pcap_open(nx_pcap_source_name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1, NULL, errbuf)) == NULL)
297 {
298 return NX_NOT_CREATED;
299 }
300 #else
301 if((nx_pcap_fp = pcap_create(nx_pcap_source_name, NULL)) == NULL)
302 {
303 return NX_NOT_CREATED;
304 }
305
306 if (pcap_set_immediate_mode(nx_pcap_fp, 1) < 0)
307 {
308 nx_pcap_cleanup();
309 return NX_NOT_CREATED;
310 }
311
312 if (pcap_set_promisc(nx_pcap_fp, 1) < 0)
313 {
314 nx_pcap_cleanup();
315 return NX_NOT_CREATED;
316 }
317
318 if (pcap_set_snaplen(nx_pcap_fp, 65536) < 0)
319 {
320 nx_pcap_cleanup();
321 return NX_NOT_CREATED;
322 }
323
324 if (pcap_activate(nx_pcap_fp) < 0)
325 {
326 nx_pcap_cleanup();
327 return NX_NOT_CREATED;
328 }
329 #endif
330
331 nx_pcap_default_ip = ip_ptr_in;
332
333 #ifdef WIN32
334 nx_pcap_receive_thread = CreateThread(NULL, 0, _nx_pcap_receive_thread_entry, (LPVOID)NULL, CREATE_SUSPENDED, NULL);
335 SetThreadPriority(nx_pcap_receive_thread, THREAD_PRIORITY_BELOW_NORMAL);
336 ResumeThread(nx_pcap_receive_thread);
337 #else
338
339 /* Create a Linux thread to loop for capturing packets */
340 pthread_create(&nx_pcap_receive_thread, NULL, _nx_pcap_receive_thread_entry, NULL);
341
342 /* Set the thread's policy and priority */
343 pthread_setschedparam(nx_pcap_receive_thread, SCHED_FIFO, &sp);
344 #endif
345
346 return NX_SUCCESS;
347 }
348
349
_nx_pcap_network_driver_output(NX_PACKET * packet_ptr)350 VOID _nx_pcap_network_driver_output(NX_PACKET *packet_ptr)
351 {
352 UINT old_threshold = 0;
353
354 /* Disable preemption. */
355 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
356
357 _nx_pcap_send_packet(packet_ptr);
358
359 /* Remove the Ethernet header. In real hardware environments, this is typically
360 done after a transmit complete interrupt. */
361 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
362
363 /* Adjust the packet length. */
364 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
365
366 /* Now that the Ethernet frame has been removed, release the packet. */
367 nx_packet_transmit_release(packet_ptr);
368
369 /* Restore preemption. */
370 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
371 }
372
373
_nx_pcap_network_driver(NX_IP_DRIVER * driver_req_ptr)374 VOID _nx_pcap_network_driver(NX_IP_DRIVER *driver_req_ptr)
375 {
376 NX_IP *ip_ptr;
377 NX_PACKET *packet_ptr;
378 ULONG *ethernet_frame_ptr;
379 NX_INTERFACE *interface_ptr;
380 #ifdef __PRODUCT_NETXDUO__
381 UINT interface_index;
382 #endif
383
384 /* Setup the IP pointer from the driver request. */
385 ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
386
387 /* Default to successful return. */
388 driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
389
390 /* Setup interface pointer. */
391 interface_ptr = driver_req_ptr -> nx_ip_driver_interface;
392
393 #ifdef __PRODUCT_NETXDUO__
394 /* Obtain the index number of the network interface. */
395 interface_index = interface_ptr -> nx_interface_index;
396 #endif
397
398 /* Process according to the driver request type in the IP control
399 block. */
400 switch (driver_req_ptr -> nx_ip_driver_command)
401 {
402
403 case NX_LINK_INTERFACE_ATTACH:
404 {
405 interface_ptr = (NX_INTERFACE*)(driver_req_ptr -> nx_ip_driver_interface);
406 break;
407 }
408
409 case NX_LINK_INITIALIZE:
410 {
411
412 /* Device driver shall initialize the Ethernet Controller here. */
413
414 /* Once the Ethernet controller is initialized, the driver needs to
415 configure the NetX Interface Control block, as outlined below. */
416
417 #ifdef __PRODUCT_NETXDUO__
418 /* The nx_interface_ip_mtu_size should be the MTU for the IP payload.
419 For regular Ethernet, the IP MTU is 1500. */
420 nx_ip_interface_mtu_set(ip_ptr, interface_index, (NX_LINK_MTU - NX_ETHERNET_SIZE));
421
422 /* Set the physical address (MAC address) of this IP instance. */
423 /* For this pcap driver, the MAC address is constructed by
424 incrementing a base lsw value, to simulate multiple nodes hanging on the
425 ethernet. */
426 nx_ip_interface_physical_address_set(ip_ptr, interface_index,
427 nx_pcap_address_msw,
428 nx_pcap_address_lsw,
429 NX_FALSE);
430
431 /* Indicate to the IP software that IP to physical mapping is required. */
432 nx_ip_interface_address_mapping_configure(ip_ptr, interface_index, NX_TRUE);
433 #else
434 interface_ptr -> nx_interface_ip_mtu_size = NX_LINK_MTU;
435 interface_ptr -> nx_interface_physical_address_msw = nx_pcap_address_msw;
436 interface_ptr -> nx_interface_physical_address_lsw = nx_pcap_address_lsw;
437 interface_ptr -> nx_interface_address_mapping_needed = NX_TRUE;
438 #endif
439
440
441 _nx_pcap_initialize(ip_ptr);
442
443 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
444 nx_ip_interface_capability_set(ip_ptr, interface_index, NX_INTERFACE_CAPABILITY);
445 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
446 break;
447 }
448
449 case NX_LINK_ENABLE:
450 {
451
452 /* Process driver link enable. An Ethernet driver shall enable the
453 transmit and reception logic. Once the IP stack issues the
454 LINK_ENABLE command, the stack may start transmitting IP packets. */
455
456
457 /* In the driver, just set the enabled flag. */
458 interface_ptr -> nx_interface_link_up = NX_TRUE;
459
460 break;
461 }
462
463 case NX_LINK_DISABLE:
464 {
465
466 /* Process driver link disable. This command indicates the IP layer
467 is not going to transmit any IP datagrams, nor does it expect any
468 IP datagrams from the interface. Therefore after processing this command,
469 the device driver shall not send any incoming packets to the IP
470 layer. Optionally the device driver may turn off the interface. */
471
472 /* In the pcap driver, just clear the enabled flag. */
473 interface_ptr -> nx_interface_link_up = NX_FALSE;
474
475 break;
476 }
477
478 case NX_LINK_PACKET_SEND:
479 case NX_LINK_PACKET_BROADCAST:
480 case NX_LINK_ARP_SEND:
481 case NX_LINK_ARP_RESPONSE_SEND:
482 case NX_LINK_RARP_SEND:
483 #ifdef NX_ENABLE_PPPOE
484 case NX_LINK_PPPOE_DISCOVERY_SEND:
485 case NX_LINK_PPPOE_SESSION_SEND:
486 #endif
487 {
488
489 /*
490 The IP stack sends down a data packet for transmission.
491 The device driver needs to prepend a MAC header, and fill in the
492 Ethernet frame type (assuming Ethernet protocol for network transmission)
493 based on the type of packet being transmitted.
494
495 The following sequence illustrates this process.
496 */
497
498 /* Place the ethernet frame at the front of the packet. */
499 packet_ptr = driver_req_ptr -> nx_ip_driver_packet;
500
501 /* Adjust the prepend pointer. */
502 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_ETHERNET_SIZE;
503
504 /* Adjust the packet length. */
505 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + NX_ETHERNET_SIZE;
506
507 /* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2
508 bytes to get 32-bit word alignment. */
509 ethernet_frame_ptr = (ULONG *) (packet_ptr -> nx_packet_prepend_ptr - 2);
510
511 /* Build the ethernet frame. */
512 *ethernet_frame_ptr = driver_req_ptr -> nx_ip_driver_physical_address_msw;
513 *(ethernet_frame_ptr+1) = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
514 *(ethernet_frame_ptr+2) = (interface_ptr -> nx_interface_physical_address_msw << 16) |
515 (interface_ptr -> nx_interface_physical_address_lsw >> 16);
516 *(ethernet_frame_ptr+3) = (interface_ptr -> nx_interface_physical_address_lsw << 16);
517
518 if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)
519 *(ethernet_frame_ptr+3) |= NX_ETHERNET_ARP;
520 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND)
521 *(ethernet_frame_ptr+3) |= NX_ETHERNET_ARP;
522 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
523 *(ethernet_frame_ptr+3) |= NX_ETHERNET_RARP;
524 #ifdef NX_ENABLE_PPPOE
525 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_PPPOE_DISCOVERY_SEND)
526 {
527 *(ethernet_frame_ptr + 3) |= NX_ETHERNET_PPPOE_DISCOVERY;
528 }
529 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_PPPOE_SESSION_SEND)
530 {
531 *(ethernet_frame_ptr + 3) |= NX_ETHERNET_PPPOE_SESSION;
532 }
533 #endif
534 #ifdef __PRODUCT_NETXDUO__
535 else if(packet_ptr -> nx_packet_ip_version == 4)
536 *(ethernet_frame_ptr+3) |= NX_ETHERNET_IP;
537 else
538 *(ethernet_frame_ptr+3) |= NX_ETHERNET_IPV6;
539 #else
540 else
541 *(ethernet_frame_ptr+3) |= NX_ETHERNET_IP;
542 #endif
543
544
545
546 /* Endian swapping if NX_LITTLE_ENDIAN is defined. */
547 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
548 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+1));
549 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+2));
550 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+3));
551
552 /* At this point, the packet is a complete Ethernet frame, ready to be transmitted.
553 The driver shall call the actual Ethernet transmit routine and put the packet
554 on the wire.
555
556 In this example, the pcap network transmit routine is called. */
557 _nx_pcap_network_driver_output(packet_ptr);
558 break;
559 }
560
561 case NX_LINK_MULTICAST_JOIN:
562 {
563
564 /* The IP layer issues this command to join a multicast group. Note that
565 multicast operation is required for IPv6.
566
567 On a typically Ethernet controller, the driver computes a hash value based
568 on MAC address, and programs the hash table.
569
570 It is likely the driver also needs to maintain an internal MAC address table.
571 Later if a multicast address is removed, the driver needs
572 to reprogram the hash table based on the remaining multicast MAC addresses. */
573
574 break;
575 }
576
577 case NX_LINK_MULTICAST_LEAVE:
578 {
579
580 /* The IP layer issues this command to remove a multicast MAC address from the
581 receiving list. A device driver shall properly remove the multicast address
582 from the hash table, so the hardware does not receive such traffic. Note that
583 in order to reprogram the hash table, the device driver may have to keep track of
584 current active multicast MAC addresses. */
585
586 /* The following procedure only applies to our pcap network driver, which manages
587 multicast MAC addresses by a simple look up table. */
588
589 break;
590 }
591
592 case NX_LINK_GET_STATUS:
593 {
594
595 /* Return the link status in the supplied return pointer. */
596 *(driver_req_ptr -> nx_ip_driver_return_ptr) = ip_ptr-> nx_ip_interface[0].nx_interface_link_up;
597 break;
598 }
599
600 case NX_LINK_DEFERRED_PROCESSING:
601 {
602
603 /* Driver defined deferred processing. This is typically used to defer interrupt
604 processing to the thread level.
605
606 A typical use case of this command is:
607 On receiving an Ethernet frame, the RX ISR does not process the received frame,
608 but instead records such an event in its internal data structure, and issues
609 a notification to the IP stack (the driver sends the notification to the IP
610 helping thread by calling "_nx_ip_driver_deferred_processing()". When the IP stack
611 gets a notification of a pending driver deferred process, it calls the
612 driver with the NX_LINK_DEFERRED_PROCESSING command. The driver shall complete
613 the pending receive process.
614 */
615
616 /* The pcap driver doesn't require a deferred process so it breaks out of
617 the switch case. */
618
619
620 break;
621 }
622
623 default:
624 {
625
626 /* Invalid driver request. */
627 /* Return the unhandled command status. */
628 driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND;
629 }
630
631 }
632 }
633
634