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 /** RAM Network (RAM) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 /* Include necessary system files. */
23
24 #include "nx_api.h"
25 #include "nx_ram_network_driver_test_1500.h"
26 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
27 #define NX_DROP_ERROR_CHECKSUM
28 #include "nx_ip.h"
29 #include "nx_tcp.h"
30 #include "nx_udp.h"
31 #include "nx_icmp.h"
32 #include "nx_igmp.h"
33 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
34
35
36 #ifdef NX_BSD_RAW_PPPOE_SUPPORT
37 #include "nxd_bsd.h"
38 #endif /* NX_BSD_RAW_PPPOE_SUPPORT */
39
40 #if defined(__PRODUCT_NETXDUO__) && defined(NX_ENABLE_VLAN)
41 #include "nx_link.h"
42 #endif
43
44 #ifdef NX_PCAP_ENABLE
45 #ifdef linux
46 #include "sys/time.h"
47 #else
48 #include "winsock.h"
49 #endif
50 FILE *nx_network_driver_pcap_fp = NX_NULL;
51 #endif /* NX_PCAP_ENABLE */
52
53 #ifdef NX_PPP_PPPOE_ENABLE
54 #include "nx_pppoe_client.h"
55 #include "nx_pppoe_server.h"
56
57 extern NX_PPPOE_CLIENT *_nx_pppoe_client_created_ptr;
58 extern NX_PPPOE_SERVER *_nx_pppoe_server_created_ptr;
59 #endif
60
61 ULONG fragment_order_test = 0;
62 ULONG packet_gather = 0;
63 ULONG packet_drop = 0;
64 NX_PACKET *packet_save[4] = {0, 0, 0, 0};
65 NX_PACKET_POOL *driver_pool = NX_NULL;
66 CHAR driver_data_buffer[3014];
67 ULONG driver_data_length;
68
69 /* Define Ethernet address format. This is prepended to the incoming IP
70 and ARP/RARP messages. The frame beginning is 14 bytes, but for speed
71 purposes, we are going to assume there are 16 bytes free in front of the
72 prepend pointer and that the prepend pointer is 32-bit aligned.
73
74 Byte Offset Size Meaning
75
76 0 6 Destination Ethernet Address
77 6 6 Source Ethernet Address
78 12 2 Ethernet Frame Type, where:
79
80 0x0800 -> IP Datagram
81 0x0806 -> ARP Request/Reply
82 0x0835 -> RARP request reply
83
84 42 18 Padding on ARP and RARP messages only. */
85
86 #define NX_ETHERNET_IP 0x0800
87 #define NX_ETHERNET_ARP 0x0806
88 #define NX_ETHERNET_RARP 0x8035
89 #define NX_ETHERNET_IPV6 0x86DD
90 #ifdef NX_PPP_PPPOE_ENABLE
91 #define NX_ETHERNET_PPPOE_DISCOVERY 0x8863
92 #define NX_ETHERNET_PPPOE_SESSION 0x8864
93 #endif
94 #define NX_ETHERNET_SIZE 14
95
96 #define NX_LINK_MTU 1514
97
98 /* For the simulated ethernet driver, physical addresses are allocated starting
99 at the preset value and then incremented before the next allocation. */
100
101 ULONG simulated_address_msw = 0x0011;
102 ULONG simulated_address_lsw = 0x22334456;
103
104 #define NX_MAX_RAM_INTERFACES 8
105 #define NX_RAM_DRIVER_MAX_MCAST_ADDRESSES 8
106
107 typedef struct MAC_ADDRESS_STRUCT
108 {
109 ULONG nx_mac_address_msw;
110 ULONG nx_mac_address_lsw;
111
112 } MAC_ADDRESS;
113
114
115 /* Define an application-specific data structure that holds internal
116 data (such as the state information) of a device driver.
117
118 The example below applies to the simulated RAM driver.
119 User shall replace its content with information related to
120 the actual driver being used. */
121 typedef struct _nx_ram_network_driver_instance_type
122 {
123 UINT nx_ram_network_driver_in_use;
124 UINT nx_ram_network_driver_id;
125 NX_INTERFACE *nx_ram_driver_interface_ptr;
126 NX_IP *nx_ram_driver_ip_ptr;
127 MAC_ADDRESS nx_ram_driver_mac_address;
128 MAC_ADDRESS nx_ram_driver_mcast_address[NX_RAM_DRIVER_MAX_MCAST_ADDRESSES];
129
130 } _nx_ram_network_driver_instance_type;
131
132 /* In this example, there are four instances of the simulated RAM driver.
133 Therefore an array of four driver instances are created to keep track of
134 the interface information of each driver. */
135 static _nx_ram_network_driver_instance_type nx_ram_driver[NX_MAX_RAM_INTERFACES];
136
137
138 /* Define driver prototypes. */
139
140 VOID _nx_ram_network_driver_internal(NX_IP_DRIVER *driver_req_ptr, UINT mtu_size);
_nx_ram_network_driver_3000(NX_IP_DRIVER * driver_req_ptr)141 VOID _nx_ram_network_driver_3000(NX_IP_DRIVER *driver_req_ptr)
142 {
143 _nx_ram_network_driver_internal(driver_req_ptr, 3000);
144 }
_nx_ram_network_driver_1500(NX_IP_DRIVER * driver_req_ptr)145 VOID _nx_ram_network_driver_1500(NX_IP_DRIVER *driver_req_ptr)
146 {
147 _nx_ram_network_driver_internal(driver_req_ptr, 1500);
148 }
_nx_ram_network_driver_1024(NX_IP_DRIVER * driver_req_ptr)149 VOID _nx_ram_network_driver_1024(NX_IP_DRIVER *driver_req_ptr)
150 {
151 _nx_ram_network_driver_internal(driver_req_ptr, 1024);
152 }
_nx_ram_network_driver_512(NX_IP_DRIVER * driver_req_ptr)153 VOID _nx_ram_network_driver_512(NX_IP_DRIVER *driver_req_ptr)
154 {
155 _nx_ram_network_driver_internal(driver_req_ptr, 512);
156 }
_nx_ram_network_driver_256(NX_IP_DRIVER * driver_req_ptr)157 VOID _nx_ram_network_driver_256(NX_IP_DRIVER *driver_req_ptr)
158 {
159 _nx_ram_network_driver_internal(driver_req_ptr, 256);
160 }
161
162 UINT (*packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
163 UINT (*advanced_packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
164
165 VOID _nx_ram_network_driver_output(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id);
166 VOID _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id);
167 VOID _nx_ram_network_driver_reset();
168
169 TX_TIMER nx_driver_timers[NX_MAX_TIMER];
170 NX_IP_DRIVER nx_driver_requests[NX_MAX_TIMER];
171 UCHAR nx_driver_timer_used[NX_MAX_TIMER];
172
173
174 #ifndef NX_INTERFACE_CAPABILITY
175 #define NX_INTERFACE_CAPABILITY ( NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_IGMP_TX_CHECKSUM )
176 #endif
177
178 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
179 UINT _nx_ram_network_driver_calculate_checksum(NX_INTERFACE *interface_ptr, NX_PACKET *packet_ptr, UCHAR is_check);
180 #endif
181
182 #ifdef NX_PCAP_ENABLE
183 UINT write_pcap_file(NX_PACKET *packet_ptr);
184 #endif /* NX_PCAP_ENABLE */
185
186
187 /**************************************************************************/
188 /* */
189 /* FUNCTION RELEASE */
190 /* */
191 /* _nx_ram_network_driver_set_pool PORTABLE C */
192 /* 6.4.0 */
193 /* AUTHOR */
194 /* */
195 /* Wenhui Xie, Microsoft Corporation */
196 /* */
197 /* DESCRIPTION */
198 /* */
199 /* This function sets the virtual network driver pool. */
200 /* */
201 /* INPUT */
202 /* */
203 /* pool_ptr Pool used by driver */
204 /* */
205 /* OUTPUT */
206 /* */
207 /* None */
208 /* */
209 /* CALLS */
210 /* */
211 /* None */
212 /* */
213 /* CALLED BY */
214 /* */
215 /* Application */
216 /* */
217 /* RELEASE HISTORY */
218 /* */
219 /* DATE NAME DESCRIPTION */
220 /* */
221 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
222 /* */
223 /**************************************************************************/
_nx_ram_network_driver_set_pool(NX_PACKET_POOL * pool_ptr)224 UINT _nx_ram_network_driver_set_pool(NX_PACKET_POOL *pool_ptr)
225 {
226 driver_pool = pool_ptr;
227 return NX_SUCCESS;
228 }
229
230
231 /**************************************************************************/
232 /* */
233 /* FUNCTION RELEASE */
234 /* */
235 /* _nx_ram_network_driver_reset PORTABLE C */
236 /* 6.4.0 */
237 /* AUTHOR */
238 /* */
239 /* Wenhui Xie, Microsoft Corporation */
240 /* */
241 /* DESCRIPTION */
242 /* */
243 /* This function resets the virtual network driver. */
244 /* */
245 /* INPUT */
246 /* */
247 /* None */
248 /* */
249 /* OUTPUT */
250 /* */
251 /* None */
252 /* */
253 /* CALLS */
254 /* */
255 /* None */
256 /* */
257 /* CALLED BY */
258 /* */
259 /* Application */
260 /* */
261 /* RELEASE HISTORY */
262 /* */
263 /* DATE NAME DESCRIPTION */
264 /* */
265 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
266 /* */
267 /**************************************************************************/
_nx_ram_network_driver_reset(void)268 void _nx_ram_network_driver_reset(void)
269 {
270 simulated_address_msw = 0x0011;
271 simulated_address_lsw = 0x22334456;
272
273 fragment_order_test = 0;
274 packet_gather = 0;
275 packet_drop = 0;
276 packet_save[0] = 0;
277 packet_save[1] = 0;
278 packet_save[2] = 0;
279 packet_save[3] = 0;
280
281 memset(&nx_ram_driver[0], 0 ,sizeof(_nx_ram_network_driver_instance_type) * (NX_MAX_RAM_INTERFACES));
282 memset(&nx_driver_timers[0], 0, sizeof(TX_TIMER) * (NX_MAX_TIMER));
283 memset(&nx_driver_requests[0], 0, sizeof(NX_IP_DRIVER) * (NX_MAX_TIMER));
284 memset(&nx_driver_timer_used[0], 0, sizeof(UCHAR) * (NX_MAX_TIMER));
285
286 driver_pool = NX_NULL;
287 }
288
289 /**************************************************************************/
290 /* */
291 /* FUNCTION RELEASE */
292 /* */
293 /* _nx_ram_network_driver_delay_entry PORTABLE C */
294 /* 6.4.0 */
295 /* AUTHOR */
296 /* */
297 /* Wenhui Xie, Microsoft Corporation */
298 /* */
299 /* DESCRIPTION */
300 /* */
301 /* This function sends out delayed packet. */
302 /* */
303 /* INPUT */
304 /* */
305 /* index index of driver request */
306 /* */
307 /* OUTPUT */
308 /* */
309 /* None */
310 /* */
311 /* CALLS */
312 /* */
313 /* _nx_ram_network_driver_output Send physical packet out */
314 /* */
315 /* CALLED BY */
316 /* */
317 /* */
318 /* RELEASE HISTORY */
319 /* */
320 /* DATE NAME DESCRIPTION */
321 /* */
322 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
323 /* */
324 /**************************************************************************/
_nx_ram_network_driver_delay_entry(ULONG timer_input)325 VOID _nx_ram_network_driver_delay_entry(ULONG timer_input)
326 {
327 TX_INTERRUPT_SAVE_AREA
328 UINT index;
329 UINT interface_instance_id;
330 NX_IP_DRIVER *driver_req;
331
332 index = (timer_input & 0xFFFF0000) >> 16;
333 interface_instance_id = timer_input & 0x0000FFFF;
334
335 driver_req = &nx_driver_requests[index];
336
337 /* Send out delayed packet. */
338 _nx_ram_network_driver_output(driver_req -> nx_ip_driver_ptr, driver_req -> nx_ip_driver_packet, interface_instance_id);
339
340 /* Deactivate timer. */
341 tx_timer_deactivate(&nx_driver_timers[index]);
342
343 TX_DISABLE
344
345 /* Clean the used flag. */
346 nx_driver_timer_used[index] = NX_RAMDRIVER_TIMER_DIRTY;
347
348 TX_RESTORE
349 }
350
351 /**************************************************************************/
352 /* */
353 /* FUNCTION RELEASE */
354 /* */
355 /* _nx_ram_network_driver_timer_clean PORTABLE C */
356 /* 6.4.0 */
357 /* AUTHOR */
358 /* */
359 /* Wenhui Xie, Microsoft Corporation */
360 /* */
361 /* DESCRIPTION */
362 /* */
363 /* This function cleans timers used by driver. */
364 /* */
365 /* INPUT */
366 /* */
367 /* */
368 /* OUTPUT */
369 /* */
370 /* None */
371 /* */
372 /* CALLS */
373 /* */
374 /* */
375 /* CALLED BY */
376 /* */
377 /* */
378 /* RELEASE HISTORY */
379 /* */
380 /* DATE NAME DESCRIPTION */
381 /* */
382 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
383 /* */
384 /**************************************************************************/
_nx_ram_network_driver_timer_clean(VOID)385 VOID _nx_ram_network_driver_timer_clean(VOID)
386 {
387 UINT timer_index;
388
389 for(timer_index = 0; timer_index < NX_MAX_TIMER; timer_index++)
390 {
391 if(nx_driver_timer_used[timer_index] != NX_RAMDRIVER_TIMER_UNUSED)
392 {
393 tx_timer_deactivate(&nx_driver_timers[timer_index]);
394 tx_timer_delete(&nx_driver_timers[timer_index]);
395 }
396
397 nx_driver_timer_used[timer_index] = NX_RAMDRIVER_TIMER_UNUSED;
398 }
399 }
400
401 /**************************************************************************/
402 /* */
403 /* FUNCTION RELEASE */
404 /* */
405 /* _nx_ram_network_driver_internal PORTABLE C */
406 /* 6.4.0 */
407 /* AUTHOR */
408 /* */
409 /* Wenhui Xie, Microsoft Corporation */
410 /* */
411 /* DESCRIPTION */
412 /* */
413 /* This function acts as a virtual network for testing the NetX source */
414 /* and driver concepts. */
415 /* */
416 /* Note, This function has callback functions for test cases. */
417 /* */
418 /* INPUT */
419 /* */
420 /* driver_req__ptr Pointer to NX_IP_DRIVER */
421 /* mtu_size LINK MTU size */
422 /* */
423 /* OUTPUT */
424 /* */
425 /* None */
426 /* */
427 /* CALLS */
428 /* */
429 /* */
430 /* CALLED BY */
431 /* */
432 /* NetX IP processing */
433 /* */
434 /* RELEASE HISTORY */
435 /* */
436 /* DATE NAME DESCRIPTION */
437 /* */
438 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
439 /* */
440 /**************************************************************************/
_nx_ram_network_driver_internal(NX_IP_DRIVER * driver_req_ptr,UINT mtu_size)441 VOID _nx_ram_network_driver_internal(NX_IP_DRIVER *driver_req_ptr, UINT mtu_size)
442 {
443
444 TX_INTERRUPT_SAVE_AREA
445 NX_IP *ip_ptr;
446 NX_PACKET *packet_ptr;
447 #ifndef NX_ENABLE_VLAN
448 ULONG *ethernet_frame_ptr;
449 #endif
450 NX_INTERFACE *interface_ptr;
451 #ifdef __PRODUCT_NETXDUO__
452 UINT interface_index;
453 #endif
454 UINT i;
455 NX_PACKET *dup_packet_ptr = NX_NULL;
456 UINT timer_index;
457 UINT op = 0, delay = 0;
458 UINT status;
459 ULONG timer_input;
460 NX_PACKET_POOL *pool_ptr;
461 UINT old_threshold = 0;
462 USHORT ether_type;
463
464 /* Setup the IP pointer from the driver request. */
465 ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
466
467 /* Set driver pool. */
468 if (driver_pool)
469 pool_ptr = driver_pool;
470 else
471 pool_ptr = ip_ptr -> nx_ip_default_packet_pool;
472
473 /* Default to successful return. */
474 driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
475
476 #ifdef NX_ENABLE_VLAN
477 /* Let link layer to preprocess the driver request and return actual interface. */
478 if (nx_link_driver_request_preprocess(driver_req_ptr, &interface_ptr) != NX_SUCCESS)
479 {
480 return;
481 }
482 #else
483 /* Setup interface pointer. */
484 interface_ptr = driver_req_ptr -> nx_ip_driver_interface;
485 #endif
486
487 #ifdef __PRODUCT_NETXDUO__
488 /* Obtain the index number of the network interface. */
489 interface_index = interface_ptr -> nx_interface_index;
490 #endif
491
492 /* Find out the driver interface if the driver command is not ATTACH. */
493 if(driver_req_ptr -> nx_ip_driver_command != NX_LINK_INTERFACE_ATTACH)
494 {
495 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
496 {
497 if(nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
498 continue;
499
500 if(nx_ram_driver[i].nx_ram_driver_ip_ptr != ip_ptr)
501 continue;
502
503 if(nx_ram_driver[i].nx_ram_driver_interface_ptr != interface_ptr)
504 continue;
505
506 break;
507 }
508
509 if(i == NX_MAX_RAM_INTERFACES)
510 {
511 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
512 return;
513 }
514 }
515
516 /* Process according to the driver request type in the IP control block. */
517 switch (driver_req_ptr -> nx_ip_driver_command)
518 {
519
520 case NX_LINK_INTERFACE_ATTACH:
521 {
522
523 /* Disable preemption. */
524 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
525
526 /* Find an available driver instance to attach the interface. */
527 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
528 {
529 if(nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
530 break;
531 }
532 /* An available entry is found. */
533 if(i < NX_MAX_RAM_INTERFACES)
534 {
535 /* Set the IN USE flag.*/
536 nx_ram_driver[i].nx_ram_network_driver_in_use = 1;
537
538 nx_ram_driver[i].nx_ram_network_driver_id = i;
539
540 /* Record the interface attached to the IP instance. */
541 nx_ram_driver[i].nx_ram_driver_interface_ptr = interface_ptr;
542
543 /* Record the IP instance. */
544 nx_ram_driver[i].nx_ram_driver_ip_ptr = ip_ptr;
545
546 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = simulated_address_msw;
547 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = simulated_address_lsw + i;
548 }
549 else
550 {
551 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
552 }
553
554 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
555 interface_ptr -> nx_interface_capability_flag = NX_INTERFACE_CAPABILITY;
556 #endif
557
558 /* Restore preemption. */
559 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
560
561 break;
562 }
563
564 #ifdef __PRODUCT_NETXDUO__
565 case NX_LINK_UNINITIALIZE:
566 case NX_LINK_INTERFACE_DETACH :
567 {
568
569 /* Zero out the driver instance. */
570 memset(&(nx_ram_driver[i]), 0 , sizeof(_nx_ram_network_driver_instance_type));
571
572 break;
573 }
574 #endif
575 case NX_LINK_INITIALIZE:
576 {
577
578 /* Device driver shall initialize the Ethernet Controller here. */
579
580 packet_process_callback = NX_NULL;
581 advanced_packet_process_callback = NX_NULL;
582
583 #ifdef __PRODUCT_NETXDUO__
584 /* Once the Ethernet controller is initialized, the driver needs to
585 configure the NetX Interface Control block, as outlined below. */
586
587 /* The nx_interface_ip_mtu_size should be the MTU for the IP payload.
588 For regular Ethernet, the IP MTU is 1500. */
589 nx_ip_interface_mtu_set(ip_ptr, interface_index, mtu_size);
590
591 /* Set the physical address (MAC address) of this IP instance. */
592 /* For this simulated RAM driver, the MAC address is constructed by
593 incrementing a base lsw value, to simulate multiple nodes hanging on the
594 ethernet. */
595 nx_ip_interface_physical_address_set(ip_ptr, interface_index,
596 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw,
597 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw, NX_FALSE);
598
599 /* Indicate to the IP software that IP to physical mapping is required. */
600 nx_ip_interface_address_mapping_configure(ip_ptr, interface_index, NX_TRUE);
601 #else
602
603 interface_ptr -> nx_interface_ip_mtu_size = mtu_size;
604
605 /* Set the physical address (MAC address) of this IP instance. */
606 /* For this simulated RAM driver, the MAC address is constructed by
607 incrementing a base lsw value, to simulate multiple nodes hanging on the
608 ethernet. */
609
610 interface_ptr -> nx_interface_physical_address_msw = nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw;
611 interface_ptr -> nx_interface_physical_address_lsw = nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw;
612
613 /* Indicate to the IP software that IP to physical mapping is required. */
614 interface_ptr -> nx_interface_address_mapping_needed = NX_TRUE;
615 #endif
616
617 break;
618 }
619
620 case NX_LINK_ENABLE:
621 {
622
623 /* Process driver link enable. An Ethernet driver shall enable the
624 transmit and reception logic. Once the IP stack issues the
625 LINK_ENABLE command, the stack may start transmitting IP packets. */
626
627 /* In the RAM driver, just set the enabled flag. */
628 interface_ptr -> nx_interface_link_up = NX_TRUE;
629
630 break;
631 }
632
633 case NX_LINK_DISABLE:
634 {
635
636 /* Process driver link disable. This command indicates the IP layer
637 is not going to transmit any IP datagrams, nor does it expect any
638 IP datagrams from the interface. Therefore after processing this command,
639 the device driver shall not send any incoming packets to the IP
640 layer. Optionally the device driver may turn off the interface. */
641
642 /* In the RAM driver, just clear the enabled flag. */
643 interface_ptr -> nx_interface_link_up = NX_FALSE;
644
645 break;
646 }
647
648 case NX_LINK_PACKET_SEND:
649 case NX_LINK_PACKET_BROADCAST:
650 case NX_LINK_ARP_SEND:
651 case NX_LINK_ARP_RESPONSE_SEND:
652 case NX_LINK_RARP_SEND:
653 {
654
655 /* The IP stack sends down a data packet for transmission.
656 The device driver needs to prepend a MAC header, and fill in the
657 Ethernet frame type (assuming Ethernet protocol for network transmission)
658 based on the type of packet being transmitted.
659
660 The following sequence illustrates this process. */
661
662
663 /* Place the ethernet frame at the front of the packet. */
664 packet_ptr = driver_req_ptr -> nx_ip_driver_packet;
665
666 if (interface_ptr -> nx_interface_link_up == NX_FALSE)
667 {
668
669 /* Link is down. Drop the packet. */
670 nx_packet_transmit_release(packet_ptr);
671 return;
672 }
673
674 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
675 if(((driver_req_ptr -> nx_ip_driver_command) == NX_LINK_PACKET_BROADCAST) ||
676 ((driver_req_ptr -> nx_ip_driver_command) == NX_LINK_PACKET_SEND))
677 _nx_ram_network_driver_calculate_checksum(nx_ram_driver[i].nx_ram_driver_interface_ptr, packet_ptr, NX_FALSE);
678 #endif
679
680 /* Advanced function entry for calling. */
681 if(advanced_packet_process_callback != NX_NULL)
682 {
683 status = advanced_packet_process_callback(ip_ptr, packet_ptr, &op, &delay);
684
685 if(!status)
686 return;
687
688 /* Advanced process. */
689 switch(op)
690 {
691 case NX_RAMDRIVER_OP_DROP:
692 {
693
694 /* Drop the packet. */
695 nx_packet_transmit_release(packet_ptr);
696 return;
697 }break;
698
699 case NX_RAMDRIVER_OP_DELAY:
700 {
701 TX_DISABLE
702
703 /* Find an unused timer. */
704 for(timer_index = 0; timer_index < NX_MAX_TIMER; timer_index++)
705 {
706 if(nx_driver_timer_used[timer_index] != NX_RAMDRIVER_TIMER_USED)
707 {
708 if(nx_driver_timer_used[timer_index] == NX_RAMDRIVER_TIMER_DIRTY)
709 tx_timer_delete(&nx_driver_timers[timer_index]);
710
711 nx_driver_timer_used[timer_index] = NX_RAMDRIVER_TIMER_USED;
712 break;
713 }
714 }
715 TX_RESTORE
716
717 if(timer_index < NX_MAX_TIMER)
718 {
719 memcpy(&nx_driver_requests[timer_index], driver_req_ptr, sizeof(NX_IP_DRIVER));
720
721 timer_input = (timer_index << 16) | i;
722
723 tx_timer_create(&nx_driver_timers[timer_index], "Driver timer",
724 _nx_ram_network_driver_delay_entry,
725 (ULONG)timer_input,
726 delay, delay, TX_NO_ACTIVATE);
727 }
728 else
729 {
730
731 /* No available timer, just send bypass. */
732 op = NX_RAMDRIVER_OP_BYPASS;
733 }
734 }break;
735
736 case NX_RAMDRIVER_OP_DUPLICATE:
737 {
738
739 /* Set the dup_packet_ptr. */
740 dup_packet_ptr = packet_ptr;
741 }break;
742
743 case NX_RAMDRIVER_OP_BYPASS:
744 default:
745 break;
746 }
747 }
748
749 /*A function entry for calling*/
750 if(packet_process_callback != NX_NULL)
751 {
752
753 status = packet_process_callback(ip_ptr, packet_ptr);
754 if(!status)
755 return;
756 }
757
758 /* Get Ethernet type. */
759 if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)
760 {
761 ether_type = NX_ETHERNET_ARP;
762 }
763 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND)
764 {
765 ether_type = NX_ETHERNET_ARP;
766 }
767 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
768 {
769 ether_type = NX_ETHERNET_RARP;
770 }
771 #ifdef __PRODUCT_NETXDUO__
772 else if (packet_ptr -> nx_packet_ip_version == 6)
773 {
774 ether_type = NX_ETHERNET_IPV6;
775 }
776 #endif
777 else
778 {
779 ether_type = NX_ETHERNET_IP;
780 }
781
782 #ifdef NX_ENABLE_VLAN
783 /* Add Ethernet header. */
784 if (nx_link_ethernet_header_add(ip_ptr,
785 driver_req_ptr -> nx_ip_driver_interface -> nx_interface_index, packet_ptr,
786 driver_req_ptr -> nx_ip_driver_physical_address_msw,
787 driver_req_ptr -> nx_ip_driver_physical_address_lsw,
788 (UINT)ether_type))
789 {
790
791 /* Release the packet. */
792 nx_packet_transmit_release(packet_ptr);
793 break;
794 }
795 #else
796 /* Adjust the prepend pointer. */
797 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_ETHERNET_SIZE;
798
799 /* Adjust the packet length. */
800 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + NX_ETHERNET_SIZE;
801
802 /* If the physical header won't fit, return an error. */
803 if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start)
804 {
805
806 /* Remove the Ethernet header. */
807 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
808
809 /* Adjust the packet length. */
810 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
811
812 /* Drop the packet. */
813 nx_packet_transmit_release(packet_ptr);
814
815 return;
816 }
817
818 /* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2
819 bytes to get 32-bit word alignment. */
820 ethernet_frame_ptr = (ULONG *) (packet_ptr -> nx_packet_prepend_ptr - 2);
821
822 /* Build the ethernet frame. */
823 *ethernet_frame_ptr = driver_req_ptr -> nx_ip_driver_physical_address_msw;
824 *(ethernet_frame_ptr+1) = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
825 *(ethernet_frame_ptr+2) = (interface_ptr -> nx_interface_physical_address_msw << 16) |
826 (interface_ptr -> nx_interface_physical_address_lsw >> 16);
827 *(ethernet_frame_ptr+3) = (interface_ptr -> nx_interface_physical_address_lsw << 16);
828
829 if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)
830 *(ethernet_frame_ptr+3) |= NX_ETHERNET_ARP;
831 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND)
832 *(ethernet_frame_ptr+3) |= NX_ETHERNET_ARP;
833 else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
834 *(ethernet_frame_ptr+3) |= NX_ETHERNET_RARP;
835 #ifdef FEATURE_NX_IPV6
836 else if(packet_ptr -> nx_packet_ip_version == 6)
837 *(ethernet_frame_ptr+3) |= NX_ETHERNET_IPV6;
838 #endif
839 else
840 *(ethernet_frame_ptr+3) |= NX_ETHERNET_IP;
841
842
843 /* Endian swapping if NX_LITTLE_ENDIAN is defined. */
844 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
845 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+1));
846 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+2));
847 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr+3));
848 #endif /* NX_ENABLE_VLAN */
849
850 /* At this point, the packet is a complete Ethernet frame, ready to be transmitted.
851 The driver shall call the actual Ethernet transmit routine and put the packet
852 on the wire.
853
854 In this example, the simulated RAM network transmit routine is called. */
855
856 /* Check whether we need to duplicate the packet. */
857 if(dup_packet_ptr != NX_NULL)
858 nx_packet_copy(packet_ptr, &dup_packet_ptr, pool_ptr, NX_NO_WAIT);
859 if(op != NX_RAMDRIVER_OP_DELAY)
860 _nx_ram_network_driver_output(ip_ptr, packet_ptr, i);
861 else
862 tx_timer_activate(&nx_driver_timers[timer_index]);
863
864 /* Send the duplicate packet. */
865 if(dup_packet_ptr != NX_NULL)
866 _nx_ram_network_driver_output(ip_ptr, dup_packet_ptr, i);
867
868 break;
869 }
870 #ifdef NX_ENABLE_VLAN
871 case NX_LINK_RAW_PACKET_SEND:
872 {
873
874 /* Send raw packet out directly. */
875 _nx_ram_network_driver_output(ip_ptr, driver_req_ptr -> nx_ip_driver_packet, i);
876 break;
877 }
878 #endif /* NX_ENABLE_VLAN */
879 case NX_LINK_MULTICAST_JOIN:
880 {
881 UINT mcast_index;
882
883 /* The IP layer issues this command to join a multicast group. Note that
884 multicast operation is required for IPv6.
885
886 On a typically Ethernet controller, the driver computes a hash value based
887 on MAC address, and programs the hash table.
888
889 It is likely the driver also needs to maintain an internal MAC address table.
890 Later if a multicast address is removed, the driver needs
891 to reprogram the hash table based on the remaining multicast MAC addresses. */
892
893
894 /* The following procedure only applies to our simulated RAM network driver, which manages
895 multicast MAC addresses by a simple look up table. */
896 for(mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
897 {
898 if(nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw == 0 &&
899 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == 0 )
900 {
901 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
902 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
903 break;
904 }
905 }
906 if(mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
907 driver_req_ptr -> nx_ip_driver_status = NX_NO_MORE_ENTRIES;
908
909 break;
910 }
911
912 case NX_LINK_MULTICAST_LEAVE:
913 {
914
915 UINT mcast_index;
916
917 /* The IP layer issues this command to remove a multicast MAC address from the
918 receiving list. A device driver shall properly remove the multicast address
919 from the hash table, so the hardware does not receive such traffic. Note that
920 in order to reprogram the hash table, the device driver may have to keep track of
921 current active multicast MAC addresses. */
922
923 /* The following procedure only applies to our simulated RAM network driver, which manages
924 multicast MAC addresses by a simple look up table. */
925 for(mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
926 {
927 if(nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw == driver_req_ptr -> nx_ip_driver_physical_address_msw &&
928 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == driver_req_ptr -> nx_ip_driver_physical_address_lsw)
929 {
930 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = 0;
931 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = 0;
932 break;
933 }
934 }
935 if(mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
936 driver_req_ptr -> nx_ip_driver_status = NX_ENTRY_NOT_FOUND;
937
938 break;
939 }
940
941 case NX_LINK_GET_STATUS:
942 {
943
944 /* Return the link status in the supplied return pointer. */
945 *(driver_req_ptr -> nx_ip_driver_return_ptr) = interface_ptr -> nx_interface_link_up;
946 break;
947 }
948
949 case NX_LINK_DEFERRED_PROCESSING:
950 {
951
952 /* Driver defined deferred processing. This is typically used to defer interrupt
953 processing to the thread level.
954
955 A typical use case of this command is:
956 On receiving an Ethernet frame, the RX ISR does not process the received frame,
957 but instead records such an event in its internal data structure, and issues
958 a notification to the IP stack (the driver sends the notification to the IP
959 helping thread by calling "_nx_ip_driver_deferred_processing()". When the IP stack
960 gets a notification of a pending driver deferred process, it calls the
961 driver with the NX_LINK_DEFERRED_PROCESSING command. The driver shall complete
962 the pending receive process.
963 */
964
965 /* The simulated RAM driver doesn't require a deferred process so it breaks out of
966 the switch case. */
967
968
969 break;
970 }
971
972 #ifdef __PRODUCT_NETXDUO__
973 case NX_LINK_SET_PHYSICAL_ADDRESS:
974 {
975
976 /* Find an driver instance to attach the interface. */
977 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
978 {
979 if(nx_ram_driver[i].nx_ram_driver_interface_ptr == interface_ptr)
980 break;
981 }
982
983 /* An available entry is found. */
984 if(i < NX_MAX_RAM_INTERFACES)
985 {
986
987 /* Set the physical address. */
988 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
989 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
990 }
991 else
992 {
993 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
994 }
995
996 break;
997 }
998 #endif
999
1000 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1001 case NX_INTERFACE_CAPABILITY_GET:
1002 {
1003 interface_ptr -> nx_interface_capability_flag = NX_INTERFACE_CAPABILITY;
1004 break;
1005 }
1006
1007 case NX_INTERFACE_CAPABILITY_SET:
1008 {
1009 break;
1010 }
1011
1012 #endif
1013 #ifdef NX_BSD_RAW_PPPOE_SUPPORT
1014 case NX_LINK_PACKET_PPPOE_SESS_SEND:
1015 case NX_LINK_PACKET_PPPOE_DISC_SEND:
1016
1017 /* Place the ethernet frame at the front of the packet. */
1018 packet_ptr = driver_req_ptr -> nx_ip_driver_packet;
1019
1020 _nx_ram_network_driver_output(ip_ptr, packet_ptr, i);
1021 break;
1022
1023 #endif /* NX_BSD_RAW_PPPOE_SUPPORT */
1024 default:
1025 {
1026
1027 /* Invalid driver request. */
1028
1029 /* Return the unhandled command status. */
1030 driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND;
1031 }
1032 }
1033 }
1034
1035 /**************************************************************************/
1036 /* */
1037 /* FUNCTION RELEASE */
1038 /* */
1039 /* _nx_ram_network_driver PORTABLE C */
1040 /* 6.4.0 */
1041 /* AUTHOR */
1042 /* */
1043 /* Wenhui Xie, Microsoft Corporation */
1044 /* */
1045 /* DESCRIPTION */
1046 /* */
1047 /* This function acts as a virtual network for testing the NetX source */
1048 /* and driver concepts. */
1049 /* */
1050 /* INPUT */
1051 /* */
1052 /* driver_req__ptr Pointer to NX_IP_DRIVER */
1053 /* */
1054 /* OUTPUT */
1055 /* */
1056 /* None */
1057 /* */
1058 /* CALLS */
1059 /* */
1060 /* */
1061 /* CALLED BY */
1062 /* */
1063 /* NetX IP processing */
1064 /* */
1065 /* RELEASE HISTORY */
1066 /* */
1067 /* DATE NAME DESCRIPTION */
1068 /* */
1069 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
1070 /* */
1071 /**************************************************************************/
_nx_ram_network_driver(NX_IP_DRIVER * driver_req_ptr)1072 VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr)
1073 {
1074
1075 NX_IP *ip_ptr;
1076 NX_PACKET *packet_ptr;
1077 #ifndef NX_ENABLE_VLAN
1078 ULONG *ethernet_frame_ptr;
1079 #endif /* NX_ENABLE_VLAN */
1080 NX_INTERFACE *interface_ptr;
1081 #ifdef __PRODUCT_NETXDUO__
1082 UINT interface_index;
1083 #endif
1084 UINT i;
1085 UINT mtu_size = 128;
1086 UINT old_threshold = 0;
1087 USHORT ether_type;
1088
1089 /* Setup the IP pointer from the driver request. */
1090 ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
1091
1092 /* Default to successful return. */
1093 driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
1094
1095 #ifdef NX_ENABLE_VLAN
1096 /* Let link layer to preprocess the driver request and return actual interface. */
1097 if (nx_link_driver_request_preprocess(driver_req_ptr, &interface_ptr) != NX_SUCCESS)
1098 {
1099 return;
1100 }
1101 #else
1102 /* Setup interface pointer. */
1103 interface_ptr = driver_req_ptr -> nx_ip_driver_interface;
1104 #endif
1105
1106 #ifdef __PRODUCT_NETXDUO__
1107 /* Obtain the index number of the network interface. */
1108 interface_index = interface_ptr -> nx_interface_index;
1109 #endif
1110
1111 /* Find out the driver interface if the driver command is not ATTACH. */
1112 if(driver_req_ptr -> nx_ip_driver_command != NX_LINK_INTERFACE_ATTACH)
1113 {
1114 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
1115 {
1116 if(nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
1117 continue;
1118
1119 if(nx_ram_driver[i].nx_ram_driver_ip_ptr != ip_ptr)
1120 continue;
1121
1122 if(nx_ram_driver[i].nx_ram_driver_interface_ptr != interface_ptr)
1123 continue;
1124
1125 break;
1126 }
1127
1128 if(i == NX_MAX_RAM_INTERFACES)
1129 {
1130 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
1131 return;
1132 }
1133 }
1134
1135 /* Process according to the driver request type in the IP control block. */
1136 switch (driver_req_ptr -> nx_ip_driver_command)
1137 {
1138 case NX_LINK_INTERFACE_ATTACH:
1139 {
1140
1141 /* Disable preemption. */
1142 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
1143
1144 /* Find an available driver instance to attach the interface. */
1145 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
1146 {
1147 if(nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
1148 break;
1149 }
1150 /* An available entry is found. */
1151 if(i < NX_MAX_RAM_INTERFACES)
1152 {
1153 /* Set the IN USE flag.*/
1154 nx_ram_driver[i].nx_ram_network_driver_in_use = 1;
1155
1156 nx_ram_driver[i].nx_ram_network_driver_id = i;
1157
1158 /* Record the interface attached to the IP instance. */
1159 nx_ram_driver[i].nx_ram_driver_interface_ptr = interface_ptr;
1160
1161 /* Record the IP instance. */
1162 nx_ram_driver[i].nx_ram_driver_ip_ptr = ip_ptr;
1163 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = simulated_address_msw;
1164 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = simulated_address_lsw + i;
1165 }
1166 else
1167 {
1168 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
1169 }
1170
1171 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1172 interface_ptr -> nx_interface_capability_flag = NX_INTERFACE_CAPABILITY;
1173 #endif
1174
1175 /* Restore preemption. */
1176 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1177
1178 break;
1179 }
1180 #ifdef __PRODUCT_NETXDUO__
1181 case NX_LINK_INTERFACE_DETACH :
1182 {
1183 /* Zero out the driver instance. */
1184 memset(&(nx_ram_driver[i]), 0 , sizeof(_nx_ram_network_driver_instance_type));
1185 break;
1186 }
1187 #endif
1188 case NX_LINK_INITIALIZE:
1189 {
1190 /* Device driver shall initialize the Ethernet Controller here. */
1191
1192 packet_process_callback = NX_NULL;
1193 advanced_packet_process_callback = NX_NULL;
1194
1195 #ifdef __PRODUCT_NETXDUO__
1196 /* Once the Ethernet controller is initialized, the driver needs to
1197 configure the NetX Interface Control block, as outlined below. */
1198
1199 /* The nx_interface_ip_mtu_size should be the MTU for the IP payload.
1200 For regular Ethernet, the IP MTU is 1500. */
1201 nx_ip_interface_mtu_set(ip_ptr, interface_index, mtu_size);
1202
1203 /* Set the physical address (MAC address) of this IP instance. */
1204 /* For this simulated RAM driver, the MAC address is constructed by
1205 incrementing a base lsw value, to simulate multiple nodes hanging on the
1206 ethernet. */
1207 nx_ip_interface_physical_address_set(ip_ptr, interface_index,
1208 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw,
1209 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw, NX_FALSE);
1210
1211 /* Indicate to the IP software that IP to physical mapping is required. */
1212 nx_ip_interface_address_mapping_configure(ip_ptr, interface_index, NX_TRUE);
1213 #else
1214
1215 interface_ptr -> nx_interface_ip_mtu_size = mtu_size;
1216
1217 /* Set the physical address (MAC address) of this IP instance. */
1218 /* For this simulated RAM driver, the MAC address is constructed by
1219 incrementing a base lsw value, to simulate multiple nodes hanging on the
1220 ethernet. */
1221
1222 interface_ptr -> nx_interface_physical_address_msw = nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw;
1223 interface_ptr -> nx_interface_physical_address_lsw = nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw;
1224
1225 /* Indicate to the IP software that IP to physical mapping is required. */
1226 interface_ptr -> nx_interface_address_mapping_needed = NX_TRUE;
1227
1228 #endif
1229
1230 break;
1231 }
1232
1233 case NX_LINK_ENABLE:
1234 {
1235
1236 /* Process driver link enable. An Ethernet driver shall enable the
1237 transmit and reception logic. Once the IP stack issues the
1238 LINK_ENABLE command, the stack may start transmitting IP packets. */
1239
1240 /* In the RAM driver, just set the enabled flag. */
1241 interface_ptr -> nx_interface_link_up = NX_TRUE;
1242
1243 break;
1244 }
1245
1246 case NX_LINK_DISABLE:
1247 {
1248
1249 /* Process driver link disable. This command indicates the IP layer
1250 is not going to transmit any IP datagrams, nor does it expect any
1251 IP datagrams from the interface. Therefore after processing this command,
1252 the device driver shall not send any incoming packets to the IP
1253 layer. Optionally the device driver may turn off the interface. */
1254
1255 /* In the RAM driver, just clear the enabled flag. */
1256 interface_ptr -> nx_interface_link_up = NX_FALSE;
1257
1258 break;
1259 }
1260
1261 case NX_LINK_PACKET_SEND:
1262 case NX_LINK_PACKET_BROADCAST:
1263 case NX_LINK_ARP_SEND:
1264 case NX_LINK_ARP_RESPONSE_SEND:
1265 case NX_LINK_RARP_SEND:
1266 #ifdef NX_PPP_PPPOE_ENABLE
1267 case NX_LINK_PPPOE_DISCOVERY_SEND:
1268 case NX_LINK_PPPOE_SESSION_SEND:
1269 #endif
1270 {
1271 /* Process driver send packet. */
1272
1273 /* Place the ethernet frame at the front of the packet. */
1274 packet_ptr = driver_req_ptr -> nx_ip_driver_packet;
1275
1276 if (interface_ptr -> nx_interface_link_up == NX_FALSE)
1277 {
1278
1279 /* Link is down. Drop the packet. */
1280 nx_packet_transmit_release(packet_ptr);
1281 return;
1282 }
1283
1284 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1285 if(((driver_req_ptr -> nx_ip_driver_command) == NX_LINK_PACKET_BROADCAST) ||
1286 ((driver_req_ptr -> nx_ip_driver_command) == NX_LINK_PACKET_SEND))
1287 _nx_ram_network_driver_calculate_checksum(nx_ram_driver[i].nx_ram_driver_interface_ptr, packet_ptr, NX_FALSE);
1288 #endif
1289
1290 /* Get Ethernet type. */
1291 if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)
1292 {
1293 ether_type = NX_ETHERNET_ARP;
1294 }
1295 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND)
1296 {
1297 ether_type = NX_ETHERNET_ARP;
1298 }
1299 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
1300 {
1301 ether_type = NX_ETHERNET_RARP;
1302 }
1303 #ifdef NX_PPP_PPPOE_ENABLE
1304 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_PPPOE_DISCOVERY_SEND)
1305 {
1306 ether_type = NX_ETHERNET_PPPOE_DISCOVERY;
1307 }
1308 else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_PPPOE_SESSION_SEND)
1309 {
1310 ether_type = NX_ETHERNET_PPPOE_SESSION;
1311 }
1312 #endif
1313 #if defined(__PRODUCT_NETXDUO__)
1314 else if (packet_ptr -> nx_packet_ip_version == 6)
1315 {
1316 ether_type = NX_ETHERNET_IPV6;
1317 }
1318 #endif
1319 else
1320 {
1321 ether_type = NX_ETHERNET_IP;
1322 }
1323
1324 #ifdef NX_ENABLE_VLAN
1325 /* Add Ethernet header. */
1326 if (nx_link_ethernet_header_add(ip_ptr,
1327 driver_req_ptr -> nx_ip_driver_interface -> nx_interface_index, packet_ptr,
1328 driver_req_ptr -> nx_ip_driver_physical_address_msw,
1329 driver_req_ptr -> nx_ip_driver_physical_address_lsw,
1330 (UINT)ether_type))
1331 {
1332
1333 /* Release the packet. */
1334 nx_packet_transmit_release(packet_ptr);
1335 break;
1336 }
1337 #else
1338 /* Adjust the prepend pointer. */
1339 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_ETHERNET_SIZE;
1340
1341 /* Adjust the packet length. */
1342 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + NX_ETHERNET_SIZE;
1343
1344 /* If the physical header won't fit, return an error. */
1345 if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start)
1346 {
1347
1348 /* Remove the Ethernet header. */
1349 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1350
1351 /* Adjust the packet length. */
1352 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1353
1354 /* Drop the packet. */
1355 nx_packet_transmit_release(packet_ptr);
1356
1357 return;
1358 }
1359
1360 /* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2
1361 bytes to get 32-bit word alignment. */
1362 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
1363 ethernet_frame_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - 2);
1364
1365 /* Build the ethernet frame. */
1366 *ethernet_frame_ptr = driver_req_ptr -> nx_ip_driver_physical_address_msw;
1367 *(ethernet_frame_ptr + 1) = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
1368 *(ethernet_frame_ptr + 2) = (interface_ptr -> nx_interface_physical_address_msw << 16) |
1369 (interface_ptr -> nx_interface_physical_address_lsw >> 16);
1370 *(ethernet_frame_ptr + 3) = (interface_ptr -> nx_interface_physical_address_lsw << 16) | ether_type;
1371
1372 /* Endian swapping if NX_LITTLE_ENDIAN is defined. */
1373 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
1374 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1));
1375 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2));
1376 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3));
1377 #endif /* NX_ENABLE_VLAN */
1378
1379 /* At this point, the packet is a complete Ethernet frame, ready to be transmitted.
1380 The driver shall call the actual Ethernet transmit routine and put the packet
1381 on the wire.
1382
1383 In this example, the simulated RAM network transmit routine is called. */
1384
1385 _nx_ram_network_driver_output(ip_ptr, packet_ptr, i );
1386
1387 break;
1388 }
1389
1390
1391 #ifdef NX_ENABLE_VLAN
1392 case NX_LINK_RAW_PACKET_SEND:
1393 {
1394
1395 /* Send raw packet out directly. */
1396 _nx_ram_network_driver_output(ip_ptr, driver_req_ptr -> nx_ip_driver_packet, i);
1397 break;
1398 }
1399 #endif /* NX_ENABLE_VLAN */
1400
1401 case NX_LINK_MULTICAST_JOIN:
1402 {
1403 UINT mcast_index;
1404
1405 /* The IP layer issues this command to join a multicast group. Note that
1406 multicast operation is required for IPv6.
1407
1408 On a typically Ethernet controller, the driver computes a hash value based
1409 on MAC address, and programs the hash table.
1410
1411 It is likely the driver also needs to maintain an internal MAC address table.
1412 Later if a multicast address is removed, the driver needs
1413 to reprogram the hash table based on the remaining multicast MAC addresses. */
1414
1415
1416 /* The following procedure only applies to our simulated RAM network driver, which manages
1417 multicast MAC addresses by a simple look up table. */
1418 for(mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
1419 {
1420 if(nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw == 0 &&
1421 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == 0 )
1422 {
1423 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
1424 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
1425 break;
1426 }
1427 }
1428 if(mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
1429 driver_req_ptr -> nx_ip_driver_status = NX_NO_MORE_ENTRIES;
1430
1431 break;
1432 }
1433
1434 case NX_LINK_MULTICAST_LEAVE:
1435 {
1436
1437 UINT mcast_index;
1438
1439 /* The IP layer issues this command to remove a multicast MAC address from the
1440 receiving list. A device driver shall properly remove the multicast address
1441 from the hash table, so the hardware does not receive such traffic. Note that
1442 in order to reprogram the hash table, the device driver may have to keep track of
1443 current active multicast MAC addresses. */
1444
1445 /* The following procedure only applies to our simulated RAM network driver, which manages
1446 multicast MAC addresses by a simple look up table. */
1447 for(mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
1448 {
1449 if(nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw == driver_req_ptr -> nx_ip_driver_physical_address_msw &&
1450 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == driver_req_ptr -> nx_ip_driver_physical_address_lsw)
1451 {
1452 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = 0;
1453 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = 0;
1454 break;
1455 }
1456 }
1457 if(mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
1458 driver_req_ptr -> nx_ip_driver_status = NX_ENTRY_NOT_FOUND;
1459
1460 break;
1461 }
1462
1463 case NX_LINK_GET_STATUS:
1464 {
1465
1466 /* Return the link status in the supplied return pointer. */
1467 *(driver_req_ptr -> nx_ip_driver_return_ptr) = ip_ptr-> nx_ip_interface[0].nx_interface_link_up;
1468 break;
1469 }
1470
1471 case NX_LINK_DEFERRED_PROCESSING:
1472 {
1473
1474 /* Driver defined deferred processing. This is typically used to defer interrupt
1475 processing to the thread level.
1476
1477 A typical use case of this command is:
1478 On receiving an Ethernet frame, the RX ISR does not process the received frame,
1479 but instead records such an event in its internal data structure, and issues
1480 a notification to the IP stack (the driver sends the notification to the IP
1481 helping thread by calling "_nx_ip_driver_deferred_processing()". When the IP stack
1482 gets a notification of a pending driver deferred process, it calls the
1483 driver with the NX_LINK_DEFERRED_PROCESSING command. The driver shall complete
1484 the pending receive process. */
1485
1486 /* The simulated RAM driver doesn't require a deferred process so it breaks out of
1487 the switch case. */
1488
1489 break;
1490 }
1491
1492 #ifdef __PRODUCT_NETXDUO__
1493 case NX_LINK_SET_PHYSICAL_ADDRESS:
1494 {
1495
1496 /* Find an driver instance to attach the interface. */
1497 for(i = 0; i < NX_MAX_RAM_INTERFACES;i++)
1498 {
1499 if(nx_ram_driver[i].nx_ram_driver_interface_ptr == interface_ptr)
1500 break;
1501 }
1502
1503 /* An available entry is found. */
1504 if(i < NX_MAX_RAM_INTERFACES)
1505 {
1506
1507 /* Set the physical address. */
1508 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
1509 nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
1510 }
1511 else
1512 {
1513 driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE;
1514 }
1515
1516 break;
1517 }
1518 #endif
1519
1520 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1521 case NX_INTERFACE_CAPABILITY_GET:
1522 {
1523 interface_ptr -> nx_interface_capability_flag = NX_INTERFACE_CAPABILITY;
1524 break;
1525 }
1526
1527 case NX_INTERFACE_CAPABILITY_SET:
1528 {
1529 break;
1530 }
1531
1532 #endif
1533 default:
1534 {
1535
1536 /* Invalid driver request. */
1537
1538 /* Return the unhandled command status. */
1539 driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND;
1540 }
1541 }
1542 }
1543
1544 /**************************************************************************/
1545 /* */
1546 /* FUNCTION RELEASE */
1547 /* */
1548 /* _nx_ram_network_driver_output PORTABLE C */
1549 /* 6.4.0 */
1550 /* AUTHOR */
1551 /* */
1552 /* Wenhui Xie, Microsoft Corporation */
1553 /* */
1554 /* DESCRIPTION */
1555 /* */
1556 /* This function simply sends the packet to the IP instance on the */
1557 /* created IP list that matches the physical destination specified in */
1558 /* the Ethernet packet. In a real hardware setting, this routine */
1559 /* would simply put the packet out on the wire. */
1560 /* */
1561 /* INPUT */
1562 /* */
1563 /* ip_ptr Pointer to IP protocol block */
1564 /* packet_ptr Packet pointer */
1565 /* */
1566 /* OUTPUT */
1567 /* */
1568 /* None */
1569 /* */
1570 /* CALLS */
1571 /* */
1572 /* nx_packet_copy Copy a packet */
1573 /* nx_packet_transmit_release Release a packet */
1574 /* _nx_ram_network_driver_receive RAM driver receive processing */
1575 /* */
1576 /* CALLED BY */
1577 /* */
1578 /* NetX IP processing */
1579 /* */
1580 /* RELEASE HISTORY */
1581 /* */
1582 /* DATE NAME DESCRIPTION */
1583 /* */
1584 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
1585 /* */
1586 /**************************************************************************/
_nx_ram_network_driver_output(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT interface_instance_id)1587 VOID _nx_ram_network_driver_output(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id)
1588 {
1589 NX_IP *dest_ip;
1590 NX_PACKET *packet_copy;
1591 ULONG destination_address_msw;
1592 ULONG destination_address_lsw;
1593 UINT old_threshold = 0;
1594 UINT i;
1595 UINT mcast_index;
1596 NX_PACKET_POOL *pool_ptr;
1597
1598 #ifdef NX_DEBUG_PACKET
1599 UCHAR *ptr;
1600 UINT j;
1601
1602 ptr = packet_ptr -> nx_packet_prepend_ptr;
1603 printf("Ethernet Packet: ");
1604 for (j = 0; j < 6; j++)
1605 printf("%02X", *ptr++);
1606 printf(" ");
1607 for (j = 0; j < 6; j++)
1608 printf("%02X", *ptr++);
1609 printf(" %02X", *ptr++);
1610 printf("%02X ", *ptr++);
1611
1612 i = 0;
1613 for (j = 0; j < (packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE); j++)
1614 {
1615 printf("%02X", *ptr++);
1616 i++;
1617 if (i > 3)
1618 {
1619 i = 0;
1620 printf(" ");
1621 }
1622 }
1623 printf("\n");
1624 #endif
1625
1626 /* Pickup the destination IP address from the packet_ptr. */
1627 destination_address_msw = (ULONG) *(packet_ptr -> nx_packet_prepend_ptr);
1628 destination_address_msw = (destination_address_msw << 8) | (ULONG) *(packet_ptr -> nx_packet_prepend_ptr+1);
1629 destination_address_lsw = (ULONG) *(packet_ptr -> nx_packet_prepend_ptr+2);
1630 destination_address_lsw = (destination_address_lsw << 8) | (ULONG) *(packet_ptr -> nx_packet_prepend_ptr+3);
1631 destination_address_lsw = (destination_address_lsw << 8) | (ULONG) *(packet_ptr -> nx_packet_prepend_ptr+4);
1632 destination_address_lsw = (destination_address_lsw << 8) | (ULONG) *(packet_ptr -> nx_packet_prepend_ptr+5);
1633
1634 /* Disable preemption. */
1635 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
1636
1637 /* Retrieve data from packet. */
1638 nx_packet_data_retrieve(packet_ptr, driver_data_buffer, &driver_data_length);
1639
1640 #ifdef NX_PCAP_ENABLE
1641 /* Write packet data into pcap file. */
1642 write_pcap_file(packet_ptr);
1643 #endif
1644
1645 /* Loop through all instances of created IPs to see who gets the packet. */
1646 for(i = 0; i < NX_MAX_RAM_INTERFACES; i++)
1647 {
1648
1649 /* Skip the interface from which the packet was sent. */
1650 if(i == interface_instance_id)
1651 continue;
1652
1653 /* Skip the instance that has not been initialized. */
1654 if(nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
1655 continue;
1656
1657 dest_ip = nx_ram_driver[i].nx_ram_driver_ip_ptr;
1658
1659 /* If the destination MAC address is broadcast or the destination matches the interface MAC,
1660 accept the packet. */
1661 if(((destination_address_msw == ((ULONG) 0x0000FFFF)) && (destination_address_lsw == ((ULONG) 0xFFFFFFFF))) || /* Broadcast match */
1662 ((destination_address_msw == nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw) &&
1663 (destination_address_lsw == nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw)) ||
1664 (destination_address_msw == ((ULONG)0x00003333)) || /* Ethernet multicast address, RFC2464, Section7, Page 5 2. */
1665 ((destination_address_msw == 0) && (destination_address_lsw == 0)))
1666 {
1667
1668 /* Set the packet pool. */
1669 if (driver_pool)
1670 pool_ptr = driver_pool;
1671 else
1672 pool_ptr = dest_ip -> nx_ip_default_packet_pool;
1673
1674 /* Allocate packet. */
1675 if (nx_packet_allocate(pool_ptr, &packet_copy, NX_RECEIVE_PACKET, NX_NO_WAIT))
1676 {
1677
1678 /* Remove the Ethernet header. */
1679 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1680
1681 /* Adjust the packet length. */
1682 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1683
1684 /* Error, no point in continuing, just release the packet. */
1685 nx_packet_transmit_release(packet_ptr);
1686
1687 /* Restore preemption. */
1688 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1689 return;
1690 }
1691
1692 /* Skip two bytes. */
1693 packet_copy -> nx_packet_prepend_ptr += 2;
1694 packet_copy -> nx_packet_append_ptr += 2;
1695
1696 /* Make a copy of packet for the forwarding. */
1697 if (nx_packet_data_append(packet_copy, driver_data_buffer, driver_data_length, pool_ptr, NX_NO_WAIT))
1698 {
1699 #ifdef NX_ENABLE_VLAN
1700 /* Error, no point in continuing, just release the packet. */
1701 nx_link_packet_transmitted(nx_ram_driver[interface_instance_id].nx_ram_driver_ip_ptr,
1702 nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
1703 packet_ptr, NX_NULL);
1704 #else
1705 /* Remove the Ethernet header. */
1706 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1707
1708 /* Adjust the packet length. */
1709 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1710
1711 /* Error, no point in continuing, just release the packet. */
1712 nx_packet_transmit_release(packet_ptr);
1713
1714 /* Release the packet. */
1715 nx_packet_release(packet_copy);
1716
1717 /* Restore preemption. */
1718 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1719 #endif /* NX_ENABLE_VLAN */
1720 return;
1721 }
1722
1723 #ifdef __PRODUCT_NETXDUO__
1724 /* Copy packet version. */
1725 packet_copy -> nx_packet_ip_version = packet_ptr -> nx_packet_ip_version;
1726 #endif /* __PRODUCT_NETXDUO__ */
1727
1728 _nx_ram_network_driver_receive(dest_ip, packet_copy, i);
1729 }
1730 else
1731 {
1732 for(mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
1733 {
1734
1735 if(destination_address_msw == nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw &&
1736 destination_address_lsw == nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw)
1737 {
1738
1739 /* Set the packet pool. */
1740 if (driver_pool)
1741 pool_ptr = driver_pool;
1742 else
1743 pool_ptr = dest_ip -> nx_ip_default_packet_pool;
1744
1745 /* Allocate packet. */
1746 if (nx_packet_allocate(pool_ptr, &packet_copy, NX_RECEIVE_PACKET, NX_NO_WAIT))
1747 {
1748
1749 /* Remove the Ethernet header. */
1750 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1751
1752 /* Adjust the packet length. */
1753 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1754
1755 /* Error, no point in continuing, just release the packet. */
1756 nx_packet_transmit_release(packet_ptr);
1757
1758 /* Restore preemption. */
1759 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1760 return;
1761 }
1762
1763 /* Skip two bytes. */
1764 packet_copy -> nx_packet_prepend_ptr += 2;
1765 packet_copy -> nx_packet_append_ptr += 2;
1766
1767 /* Make a copy of packet for the forwarding. */
1768 if (nx_packet_data_append(packet_copy, driver_data_buffer, driver_data_length, pool_ptr, NX_NO_WAIT))
1769 {
1770
1771 /* Remove the Ethernet header. */
1772 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1773
1774 /* Adjust the packet length. */
1775 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1776
1777 /* Error, no point in continuing, just release the packet. */
1778 nx_packet_transmit_release(packet_ptr);
1779
1780 /* Restore preemption. */
1781 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1782 return;
1783 }
1784
1785 _nx_ram_network_driver_receive(dest_ip, packet_copy, i);
1786
1787
1788 }
1789
1790
1791 }
1792 }
1793 }
1794
1795 #ifdef NX_ENABLE_VLAN
1796 /* Release the packet. */
1797 nx_link_packet_transmitted(nx_ram_driver[interface_instance_id].nx_ram_driver_ip_ptr,
1798 nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
1799 packet_ptr, NX_NULL);
1800 #else
1801 /* Remove the Ethernet header. In real hardware environments, this is typically
1802 done after a transmit complete interrupt. */
1803 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1804
1805 /* Adjust the packet length. */
1806 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1807
1808 /* Now that the Ethernet frame has been removed, release the packet. */
1809 nx_packet_transmit_release(packet_ptr);
1810 #endif
1811 /* Restore preemption. */
1812 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
1813 }
1814
1815 /**************************************************************************/
1816 /* */
1817 /* FUNCTION RELEASE */
1818 /* */
1819 /* _nx_ram_network_driver_receive PORTABLE C */
1820 /* 6.4.0 */
1821 /* AUTHOR */
1822 /* */
1823 /* Wenhui Xie, Microsoft Corporation */
1824 /* */
1825 /* DESCRIPTION */
1826 /* */
1827 /* This function processing incoming packets. In the RAM network */
1828 /* driver, the incoming packets are coming from the RAM driver output */
1829 /* routine. In real hardware settings, this routine would be called */
1830 /* from the receive packet ISR. */
1831 /* */
1832 /* INPUT */
1833 /* */
1834 /* ip_ptr Pointer to IP protocol block */
1835 /* packet_ptr Packet pointer */
1836 /* interface_instance_id The interface ID the packet is*/
1837 /* destined for */
1838 /* */
1839 /* OUTPUT */
1840 /* */
1841 /* None */
1842 /* */
1843 /* CALLS */
1844 /* */
1845 /* _nx_ip_packet_receive IP receive packet processing */
1846 /* _nx_ip_packet_deferred_receive IP deferred receive packet */
1847 /* processing */
1848 /* _nx_arp_packet_deferred_receive ARP receive processing */
1849 /* _nx_rarp_packet_deferred_receive RARP receive processing */
1850 /* nx_packet_release Packet release */
1851 /* */
1852 /* CALLED BY */
1853 /* */
1854 /* NetX IP processing */
1855 /* */
1856 /* RELEASE HISTORY */
1857 /* */
1858 /* DATE NAME DESCRIPTION */
1859 /* */
1860 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
1861 /* */
1862 /**************************************************************************/
_nx_ram_network_driver_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT interface_instance_id)1863 VOID _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id)
1864 {
1865 #ifdef NX_ENABLE_VLAN
1866 nx_link_ethernet_packet_received(ip_ptr,
1867 nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
1868 packet_ptr, NX_NULL);
1869 #else
1870 UINT packet_type;
1871
1872 /* Pickup the packet header to determine where the packet needs to be
1873 sent. */
1874 packet_type = (((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+12))) << 8) |
1875 ((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+13)));
1876
1877 /* Setup interface pointer. */
1878 packet_ptr -> nx_packet_ip_interface = nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr;
1879
1880 /* Route the incoming packet according to its ethernet type. */
1881 /* The RAM driver accepts both IPv4 and IPv6 frames. */
1882 if ((packet_type == NX_ETHERNET_IP) || (packet_type == NX_ETHERNET_IPV6))
1883 {
1884
1885 /* Note: The length reported by some Ethernet hardware includes bytes after the packet
1886 as well as the Ethernet header. In some cases, the actual packet length after the
1887 Ethernet header should be derived from the length in the IP header (lower 16 bits of
1888 the first 32-bit word). */
1889
1890 /* Clean off the Ethernet header. */
1891 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1892
1893 /* Adjust the packet length. */
1894 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1895
1896
1897 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1898 if(_nx_ram_network_driver_calculate_checksum(packet_ptr -> nx_packet_ip_interface, packet_ptr, NX_TRUE))
1899 {
1900 #ifdef NX_DROP_ERROR_CHECKSUM
1901 nx_packet_release(packet_ptr);
1902 return;
1903 #endif /* NX_DROP_ERROR_CHECKSUM */
1904 }
1905 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1906
1907 /* Route to the ip receive function. */
1908
1909 #ifdef NX_DIRECT_ISR_CALL
1910 _nx_ip_packet_receive(ip_ptr, packet_ptr);
1911 #else
1912 _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
1913 #endif
1914 }
1915 #ifndef NX_DISABLE_IPV4
1916 else if (packet_type == NX_ETHERNET_ARP)
1917 {
1918
1919 /* Clean off the Ethernet header. */
1920 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1921
1922 /* Adjust the packet length. */
1923 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1924
1925 /* Route to the ARP receive function. */
1926 _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
1927
1928 }
1929 else if (packet_type == NX_ETHERNET_RARP)
1930 {
1931
1932 /* Clean off the Ethernet header. */
1933 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1934
1935 /* Adjust the packet length. */
1936 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1937
1938 /* Route to the RARP receive function. */
1939 _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
1940 }
1941 #ifdef NX_PPP_PPPOE_ENABLE
1942 else if ((packet_type == NX_ETHERNET_PPPOE_DISCOVERY) ||
1943 (packet_type == NX_ETHERNET_PPPOE_SESSION))
1944 {
1945
1946 /* Clean off the Ethernet header. */
1947 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
1948
1949 /* Adjust the packet length. */
1950 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
1951
1952 if (_nx_pppoe_client_created_ptr -> nx_pppoe_interface_ptr == nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr)
1953 {
1954 /* Route to the PPPoE client receive function. */
1955 _nx_pppoe_client_packet_deferred_receive(packet_ptr);
1956 }
1957 else if (_nx_pppoe_server_created_ptr -> nx_pppoe_interface_ptr == nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr)
1958 {
1959 /* Route to the PPPoE server receive function. */
1960 _nx_pppoe_server_packet_deferred_receive(packet_ptr);
1961 }
1962 }
1963 #endif
1964 #endif
1965
1966 #ifdef NX_BSD_RAW_PPPOE_SUPPORT
1967 else if((packet_type == ETHERTYPE_PPPOE_DISC) || (packet_type == ETHERTYPE_PPPOE_SESS))
1968 {
1969 _nx_bsd_pppoe_packet_received(packet_ptr, packet_type, interface_instance_id);
1970
1971 }
1972 #endif /* NX_BSD_RAW_PPPOE_SUPPORT */
1973
1974 else
1975 {
1976 /* Invalid ethernet header... release the packet. */
1977 nx_packet_release(packet_ptr);
1978 }
1979 #endif /* NX_ENABLE_VLAN */
1980 }
1981
1982
1983 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1984 /**************************************************************************/
1985 /* */
1986 /* FUNCTION RELEASE */
1987 /* */
1988 /* _nx_ram_network_driver_calculate_checksum PORTABLE C */
1989 /* 6.4.0 */
1990 /* AUTHOR */
1991 /* */
1992 /* Wenhui Xie, Microsoft Corporation */
1993 /* */
1994 /* DESCRIPTION */
1995 /* */
1996 /* This function calculates or verifys checksum for headers. */
1997 /* */
1998 /* INPUT */
1999 /* */
2000 /* interface_ptr Pointer to interface */
2001 /* packet_ptr Packet pointer */
2002 /* is_check Check or verify */
2003 /* */
2004 /* OUTPUT */
2005 /* */
2006 /* status Completion status */
2007 /* */
2008 /* CALLS */
2009 /* */
2010 /* _nx_ip_checksum_compute */
2011 /* */
2012 /* CALLED BY */
2013 /* */
2014 /* _nx_ram_network_driver_internal */
2015 /* _nx_ram_network_driver */
2016 /* */
2017 /* RELEASE HISTORY */
2018 /* */
2019 /* DATE NAME DESCRIPTION */
2020 /* */
2021 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
2022 /* */
2023 /**************************************************************************/
_nx_ram_network_driver_calculate_checksum(NX_INTERFACE * interface_ptr,NX_PACKET * packet_ptr,UCHAR is_check)2024 UINT _nx_ram_network_driver_calculate_checksum(NX_INTERFACE *interface_ptr, NX_PACKET *packet_ptr, UCHAR is_check)
2025 {
2026 ULONG next_protocol = 0;
2027 UCHAR *org_prepend_ptr;
2028 USHORT checksum;
2029 ULONG val;
2030 UCHAR is_done = NX_FALSE;
2031 UCHAR is_fragmented = NX_FALSE;
2032 ULONG ip_src_addr[4];
2033 ULONG ip_dst_addr[4];
2034 ULONG data_length;
2035 NX_TCP_HEADER *tcp_header_ptr;
2036 NX_UDP_HEADER *udp_header_ptr;
2037 #ifndef NX_DISABLE_IPV4
2038 ULONG ip_header_length;
2039 NX_IPV4_HEADER *ip_header_ptr;
2040 NX_ICMP_HEADER *icmpv4_header_ptr;
2041 NX_IGMP_HEADER *igmp_header_ptr;
2042 #endif /* NX_DISABLE_IPV4 */
2043 #ifdef FEATURE_NX_IPV6
2044 NX_ICMPV6_HEADER *icmpv6_header_ptr;
2045 NX_IPV6_HEADER *ipv6_header_ptr;
2046 #endif
2047
2048 /* Get IP version. */
2049 #ifndef NX_DISABLE_IPV4
2050 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
2051 {
2052 next_protocol = NX_PROTOCOL_IPV4;
2053 }
2054 #endif /* NX_DISABLE_IPV4 */
2055 #ifdef FEATURE_NX_IPV6
2056 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
2057 {
2058 next_protocol = NX_PROTOCOL_IPV6;
2059 }
2060 #endif
2061 if (next_protocol == 0)
2062 return NX_INVALID_PACKET;
2063
2064 /* Store original prepend_ptr. */
2065 org_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr;
2066
2067 /* Loop to process headers. */
2068 while(!is_done)
2069 {
2070 switch(next_protocol)
2071 {
2072 #ifndef NX_DISABLE_IPV4
2073 case NX_PROTOCOL_IPV4:
2074 {
2075
2076 /* It's assumed that the IP link driver has positioned the top pointer in the
2077 packet to the start of the IP address... so that's where we will start. */
2078 ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
2079
2080 /* Pick up the first word in the IP header. */
2081 val = ip_header_ptr -> nx_ip_header_word_0;
2082
2083 /* Convert to host byte order. */
2084 NX_CHANGE_ULONG_ENDIAN(val);
2085
2086 /* Obtain IP header length. */
2087 ip_header_length = (val & NX_IP_LENGTH_MASK) >> 24;
2088
2089 /* Check if IPv4 checksum is enabled. */
2090 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_RX_CHECKSUM)) ||
2091 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)))
2092 {
2093
2094 /* Check fragmentation. */
2095 if(is_fragmented)
2096 {
2097
2098 /* Not support fragmentation. Restore origianl prepend_ptr. */
2099 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2100 return NX_SUCCESS;
2101 }
2102
2103 checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
2104 /* length is the size of IP header, including options */
2105 ip_header_length << 2,
2106 /* IPv4 header checksum doesn't care src/dest addresses */
2107 NULL, NULL);
2108
2109 if(is_check)
2110 {
2111 checksum = ~checksum & NX_LOWER_16_MASK;
2112
2113 /* Check the checksum. */
2114 if (checksum)
2115 {
2116
2117 /* Checksum error. Restore origianl prepend_ptr. */
2118 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2119 return NX_INVALID_PACKET;
2120 }
2121 }
2122 else
2123 {
2124 val = (ULONG)(~checksum);
2125 val = val & NX_LOWER_16_MASK;
2126
2127 /* Convert to network byte order. */
2128 NX_CHANGE_ULONG_ENDIAN(val);
2129
2130 /* Now store the checksum in the IP header. */
2131 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val;
2132 }
2133 }
2134
2135 /* Check if FRAGMENT flag is set. */
2136 val = ip_header_ptr -> nx_ip_header_word_1;
2137 NX_CHANGE_ULONG_ENDIAN(val);
2138 if(val & NX_IP_FRAGMENT_MASK)
2139 {
2140
2141 /* Fragmented packet not supported. Restore origianl prepend_ptr. */
2142 is_fragmented = NX_TRUE;
2143 }
2144
2145 /* Get src and dst addresses. */
2146 ip_src_addr[0] = ip_header_ptr -> nx_ip_header_source_ip;
2147 ip_dst_addr[0] = ip_header_ptr -> nx_ip_header_destination_ip;
2148 NX_CHANGE_ULONG_ENDIAN(ip_src_addr[0]);
2149 NX_CHANGE_ULONG_ENDIAN(ip_dst_addr[0]);
2150
2151 /* Get next protocol. */
2152 next_protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 8) & 0xFF;
2153
2154 /* Remove IPv4 header. */
2155 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + (ip_header_length << 2);
2156 data_length = packet_ptr -> nx_packet_length - (ip_header_length << 2);
2157 break;
2158 }
2159 #endif /* NX_DISABLE_IPV4 */
2160
2161 case NX_PROTOCOL_TCP:
2162 {
2163
2164 /* Check if TCP checksum is enabled. */
2165 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_RX_CHECKSUM)) ||
2166 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)))
2167 {
2168
2169 /* Check fragmentation. */
2170 if(is_fragmented)
2171 {
2172 /* When receiving a fragmented packet, do nothing, deliver it to NetX. */
2173 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2174 return NX_SUCCESS;
2175 }
2176
2177 /* Calculate the TCP checksum without protection. */
2178 checksum = _nx_ip_checksum_compute(packet_ptr, NX_PROTOCOL_TCP,
2179 data_length,
2180 ip_src_addr, ip_dst_addr);
2181
2182 if(is_check)
2183 {
2184 checksum = ~checksum & NX_LOWER_16_MASK;
2185
2186 /* Check the checksum. */
2187 if (checksum)
2188 {
2189
2190 /* Checksum error. Restore origianl prepend_ptr. */
2191 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2192 return NX_INVALID_PACKET;
2193 }
2194 }
2195 else
2196 {
2197
2198 /* Pickup the pointer to the head of the TCP packet. */
2199 tcp_header_ptr = (NX_TCP_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
2200
2201 checksum = ~checksum & NX_LOWER_16_MASK;
2202
2203 /* Move the checksum into header. */
2204 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2205 tcp_header_ptr -> nx_tcp_header_word_4 |= (checksum << NX_SHIFT_BY_16);
2206 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2207 }
2208 }
2209
2210 /* No necessary to process next protocol. */
2211 is_done = NX_TRUE;
2212 break;
2213 }
2214
2215 case NX_PROTOCOL_UDP:
2216 {
2217
2218 /* Check if UDP checksum is enabled. */
2219 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_RX_CHECKSUM)) ||
2220 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)))
2221 {
2222
2223 /* Check fragmentation. */
2224 if(is_fragmented)
2225 {
2226 /* When receiving a fragmented packet, do nothing, deliver it to NetX. */
2227 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2228 return NX_SUCCESS;
2229 }
2230
2231 /* Calculate the UDP checksum without protection. */
2232 checksum = _nx_ip_checksum_compute(packet_ptr, NX_PROTOCOL_UDP,
2233 data_length,
2234 ip_src_addr, ip_dst_addr);
2235
2236 if(is_check)
2237 {
2238
2239 /* Pickup the pointer to the head of the UDP packet. */
2240 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
2241
2242 /* Move the checksum into header. */
2243 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2244 if(((udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK) == 0) &&
2245 (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4))
2246 checksum = 0;
2247 else
2248 checksum = ~checksum & NX_LOWER_16_MASK;
2249 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2250
2251 /* Check the checksum. */
2252 if (checksum)
2253 {
2254
2255 /* Checksum error. Restore origianl prepend_ptr. */
2256 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2257 return NX_INVALID_PACKET;
2258 }
2259 }
2260 else
2261 {
2262
2263 /* Pickup the pointer to the head of the UDP packet. */
2264 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
2265
2266 /* Move the checksum into header. */
2267 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2268 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | (~checksum & NX_LOWER_16_MASK);
2269 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2270 }
2271 }
2272
2273 /* No necessary to process next protocol. */
2274 is_done = NX_TRUE;
2275 break;
2276 }
2277
2278 #ifndef NX_DISABLE_IPV4
2279 case NX_PROTOCOL_ICMP:
2280 {
2281
2282 /* Check if ICMPv4 checksum is enabled. */
2283 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_RX_CHECKSUM)) ||
2284 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)))
2285 {
2286
2287 /* Check fragmentation. */
2288 if(is_fragmented)
2289 {
2290
2291 /* Not support fragmentation. Restore origianl prepend_ptr. */
2292 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2293 return NX_SUCCESS;
2294 }
2295
2296 /* Calculate the ICMPv4 checksum without protection. */
2297 checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_ICMP,
2298 data_length,
2299 /* ICMPV4 header checksum doesn't care src/dest addresses */
2300 NULL, NULL);
2301
2302 if(is_check)
2303 {
2304 checksum = ~checksum & NX_LOWER_16_MASK;
2305
2306 /* Check the checksum. */
2307 if (checksum)
2308 {
2309
2310 /* Checksum error. Restore origianl prepend_ptr. */
2311 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2312 return NX_INVALID_PACKET;
2313 }
2314 }
2315 else
2316 {
2317
2318 /* Pickup the pointer to the head of the ICMPv4 packet. */
2319 icmpv4_header_ptr = (NX_ICMP_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
2320
2321 /* Move the checksum into header. */
2322 NX_CHANGE_ULONG_ENDIAN(icmpv4_header_ptr -> nx_icmp_header_word_0);
2323 icmpv4_header_ptr -> nx_icmp_header_word_0 = icmpv4_header_ptr -> nx_icmp_header_word_0 | (~checksum & NX_LOWER_16_MASK);
2324 NX_CHANGE_ULONG_ENDIAN(icmpv4_header_ptr -> nx_icmp_header_word_0);
2325 }
2326 }
2327
2328 /* No necessary to process next protocol. */
2329 is_done = NX_TRUE;
2330 break;
2331 }
2332
2333 case NX_PROTOCOL_IGMP:
2334 {
2335
2336 /* Check if IGMP checksum is enabled. */
2337 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IGMP_RX_CHECKSUM)) ||
2338 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IGMP_TX_CHECKSUM)))
2339 {
2340
2341 /* Check fragmentation. */
2342 if(is_fragmented)
2343 {
2344
2345 /* Not support fragmentation. Restore origianl prepend_ptr. */
2346 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2347 return NX_SUCCESS;
2348 }
2349
2350 /* Pickup the pointer to the head of the IGMP packet. */
2351 igmp_header_ptr = (NX_IGMP_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
2352
2353 /* Change the endian. */
2354 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_0);
2355 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_1);
2356
2357 /* Calculate the checksum. */
2358 val = igmp_header_ptr -> nx_igmp_header_word_0;
2359 checksum = (val >> NX_SHIFT_BY_16);
2360 checksum += (val & NX_LOWER_16_MASK);
2361 val = igmp_header_ptr -> nx_igmp_header_word_1;
2362 checksum += (val >> NX_SHIFT_BY_16);
2363 checksum += (val & NX_LOWER_16_MASK);
2364
2365 /* Add in the carry bits into the checksum. */
2366 checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
2367
2368 /* Do it again in case previous operation generates an overflow. */
2369 checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
2370
2371 if(is_check)
2372 {
2373
2374 /* Change the endian. */
2375 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_0);
2376 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_1);
2377
2378 /* Check the checksum. */
2379 if ((~checksum) & 0xFFFF)
2380 {
2381
2382 /* Checksum error. Restore origianl prepend_ptr. */
2383 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2384 return NX_INVALID_PACKET;
2385 }
2386 }
2387 else
2388 {
2389
2390 /* Place the checksum into the first header word. */
2391 igmp_header_ptr -> nx_igmp_header_word_0 = igmp_header_ptr -> nx_igmp_header_word_0 | (~checksum & NX_LOWER_16_MASK);
2392
2393 /* Change the endian. */
2394 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_0);
2395 NX_CHANGE_ULONG_ENDIAN(igmp_header_ptr -> nx_igmp_header_word_1);
2396 }
2397
2398 /* No necessary to process next protocol. */
2399 is_done = NX_TRUE;
2400 break;
2401 }
2402
2403 /* No necessary to process next protocol. */
2404 is_done = NX_TRUE;
2405 break;
2406 }
2407 #endif /* NX_DISABLE_IPV4 */
2408
2409 #ifdef FEATURE_NX_IPV6
2410 case NX_PROTOCOL_ICMPV6:
2411 {
2412
2413 /* Check if ICMPv6 checksum is enabled. */
2414 if(((is_check) && (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV6_RX_CHECKSUM)) ||
2415 ((!is_check) && (packet_ptr -> nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM)))
2416 {
2417
2418 /* Check fragmentation. */
2419 if(is_fragmented)
2420 {
2421
2422 /* Not support fragmentation. Restore origianl prepend_ptr. */
2423 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2424 return NX_SUCCESS;
2425 }
2426
2427 /* Calculate the ICMPv6 checksum without protection. */
2428 checksum = _nx_ip_checksum_compute(packet_ptr, NX_PROTOCOL_ICMPV6,
2429 data_length,
2430 ip_src_addr, ip_dst_addr);
2431
2432 if(is_check)
2433 {
2434 checksum = ~checksum & NX_LOWER_16_MASK;
2435
2436 /* Check the checksum. */
2437 if (checksum)
2438 {
2439
2440 /* Checksum error. Restore origianl prepend_ptr. */
2441 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2442 return NX_INVALID_PACKET;
2443 }
2444 }
2445 else
2446 {
2447
2448 /* Pickup the pointer to the head of the ICMPv6 packet. */
2449 icmpv6_header_ptr = (NX_ICMPV6_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
2450
2451 checksum = ~checksum;
2452
2453 /* Move the checksum into header. */
2454 NX_CHANGE_USHORT_ENDIAN(checksum);
2455 icmpv6_header_ptr -> nx_icmpv6_header_checksum = checksum;
2456 }
2457 }
2458
2459 /* No necessary to process next protocol. */
2460 is_done = NX_TRUE;
2461 break;
2462 }
2463
2464 case NX_PROTOCOL_IPV6:
2465 {
2466
2467 /* Check fragmentation. */
2468 if(is_fragmented)
2469 {
2470
2471 /* Not support fragmentation. Restore origianl prepend_ptr. */
2472 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2473 return NX_SUCCESS;
2474 }
2475
2476 /* Points to the base of IPv6 header. */
2477 ipv6_header_ptr = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_prepend_ptr;
2478
2479 /* Get src and dst addresses. */
2480 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_source_ip, ip_src_addr);
2481 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_destination_ip, ip_dst_addr);
2482 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_src_addr);
2483 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_dst_addr);
2484
2485 /* Get next protocol. */
2486 next_protocol = (ipv6_header_ptr -> nx_ip_header_word_1 >> 16) & 0xFF;
2487
2488 /* Remove IPv6 header. */
2489 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV6_HEADER);
2490 data_length = packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER);
2491 break;
2492 }
2493
2494 case NX_PROTOCOL_NEXT_HEADER_FRAGMENT:
2495 is_fragmented = NX_TRUE;
2496 case NX_PROTOCOL_NEXT_HEADER_HOP_BY_HOP:
2497 case NX_PROTOCOL_NEXT_HEADER_DESTINATION:
2498 case NX_PROTOCOL_NEXT_HEADER_ROUTING:
2499 {
2500 next_protocol = (ULONG)(*packet_ptr -> nx_packet_prepend_ptr);
2501 data_length -= (ULONG)(*(packet_ptr -> nx_packet_prepend_ptr + 1));
2502 packet_ptr -> nx_packet_prepend_ptr += (ULONG)(*(packet_ptr -> nx_packet_prepend_ptr + 1));
2503 break;
2504 }
2505 #endif
2506
2507 default:
2508 /* Unsupported protocol. */
2509 is_done = NX_TRUE;
2510 break;
2511 }
2512 }
2513
2514
2515 /* Restore origianl prepend_ptr. */
2516 packet_ptr -> nx_packet_prepend_ptr = org_prepend_ptr;
2517 return NX_SUCCESS;
2518 }
2519 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2520
2521
2522 #ifdef NX_PCAP_ENABLE
2523 /**************************************************************************/
2524 /* */
2525 /* FUNCTION RELEASE */
2526 /* */
2527 /* get_time_of_day PORTABLE C */
2528 /* 6.4.0 */
2529 /* AUTHOR */
2530 /* */
2531 /* Wenhui Xie, Microsoft Corporation */
2532 /* */
2533 /* DESCRIPTION */
2534 /* */
2535 /* This function gets sec and usec from January 1, 1970 */
2536 /* */
2537 /* INPUT */
2538 /* */
2539 /* tv Pointer to TIME_VAL structure */
2540 /* */
2541 /* OUTPUT */
2542 /* */
2543 /* None */
2544 /* */
2545 /* CALLS */
2546 /* */
2547 /* */
2548 /* CALLED BY */
2549 /* */
2550 /* write_pcap_file */
2551 /* */
2552 /* RELEASE HISTORY */
2553 /* */
2554 /* DATE NAME DESCRIPTION */
2555 /* */
2556 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
2557 /* */
2558 /**************************************************************************/
get_time_of_day(NX_TIME_VALUE * time_value)2559 VOID get_time_of_day(NX_TIME_VALUE *time_value)
2560 {
2561 #ifdef linux
2562
2563 /* Get the system time. */
2564 gettimeofday(tv);
2565 #else
2566 SYSTEMTIME systemtime;
2567 FILETIME filetime;
2568 ULONG64 time;
2569
2570 /* Get the system time. */
2571 GetSystemTime(&systemtime);
2572
2573 /* Get the file time. */
2574 SystemTimeToFileTime(&systemtime, &filetime);
2575
2576 /* Set the time as ULONG64. */
2577 time = ((ULONG64)filetime.dwLowDateTime);
2578 time += (((ULONG64)filetime.dwHighDateTime) << 32);
2579
2580 /* Set the time as from January 1, 1970. */
2581 time_value -> tv_sec = (LONG)((time - ((UINT64)116444736000000000ULL)) / 10000000L);
2582 time_value -> tv_usec = (LONG)(systemtime.wMilliseconds * 1000);
2583 #endif
2584 }
2585
2586 /**************************************************************************/
2587 /* */
2588 /* FUNCTION RELEASE */
2589 /* */
2590 /* create_pcap_file PORTABLE C */
2591 /* 6.4.0 */
2592 /* AUTHOR */
2593 /* */
2594 /* Wenhui Xie, Microsoft Corporation */
2595 /* */
2596 /* DESCRIPTION */
2597 /* */
2598 /* This function creates libpcap file global header based on libpcap */
2599 /* file format and writes it to the file. */
2600 /* */
2601 /* INPUT */
2602 /* */
2603 /* file_name String of file name */
2604 /* */
2605 /* OUTPUT */
2606 /* */
2607 /* NX_PCAP_FILE_OK Successful file open status */
2608 /* NX_PCAP_FILE_ERROR Failed file open status */
2609 /* */
2610 /* CALLS */
2611 /* */
2612 /* */
2613 /* CALLED BY */
2614 /* */
2615 /* Application Code */
2616 /* */
2617 /* RELEASE HISTORY */
2618 /* */
2619 /* DATE NAME DESCRIPTION */
2620 /* */
2621 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
2622 /* */
2623 /**************************************************************************/
create_pcap_file(CHAR * file_name)2624 UINT create_pcap_file(CHAR *file_name)
2625 {
2626 NX_PCAP_FILE_HEADER pcap_file_header;
2627
2628 /* Set the pcap file header value. */
2629 pcap_file_header.magic_number = 0xa1b2c3d4;
2630 pcap_file_header.version_major = 2;
2631 pcap_file_header.version_minor = 4;
2632 pcap_file_header.this_zone = -28800;
2633 pcap_file_header.sig_figs = 0;
2634 pcap_file_header.snapshot_length = 0x0000ffff;
2635 pcap_file_header.link_type = 1;
2636
2637 /* Open the pcap file. */
2638 nx_network_driver_pcap_fp = fopen(file_name, "wb+");
2639
2640 /* Check if open the pcap file. */
2641 if (nx_network_driver_pcap_fp == NX_NULL)
2642 return (NX_PCAP_FILE_ERROR);
2643
2644 /* Write the pcap file header. */
2645 fwrite(&pcap_file_header, sizeof(pcap_file_header), 1, nx_network_driver_pcap_fp);
2646
2647 /* Return. */
2648 return (NX_PCAP_FILE_OK);
2649 }
2650
2651 /**************************************************************************/
2652 /* */
2653 /* FUNCTION RELEASE */
2654 /* */
2655 /* write_pcap_file PORTABLE C */
2656 /* 6.4.0 */
2657 /* AUTHOR */
2658 /* */
2659 /* Wenhui Xie, Microsoft Corporation */
2660 /* */
2661 /* DESCRIPTION */
2662 /* */
2663 /* This function creates libpcap file packet header based on libpcap */
2664 /* file format, receives packet data, and writes them to the file. */
2665 /* */
2666 /* INPUT */
2667 /* */
2668 /* packet_ptr Pointer to the source packet */
2669 /* */
2670 /* OUTPUT */
2671 /* */
2672 /* NX_PCAP_FILE_OK Successful file open status */
2673 /* NX_PCAP_FILE_ERROR Failed file open status */
2674 /* */
2675 /* CALLS */
2676 /* */
2677 /* */
2678 /* CALLED BY */
2679 /* */
2680 /* _nx_ram_network_driver_output */
2681 /* */
2682 /* RELEASE HISTORY */
2683 /* */
2684 /* DATE NAME DESCRIPTION */
2685 /* */
2686 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
2687 /* */
2688 /**************************************************************************/
write_pcap_file(NX_PACKET * packet_ptr)2689 UINT write_pcap_file(NX_PACKET *packet_ptr)
2690 {
2691 NX_PCAP_PACKET_HEADER pcap_packet_header;
2692 NX_TIME_VALUE time_value;
2693 CHAR data_buffer[3014];
2694 ULONG data_length;
2695
2696 /* Get the system time. */
2697 get_time_of_day(&time_value);
2698
2699 /* Retrieve data from packet. */
2700 nx_packet_data_retrieve(packet_ptr, data_buffer, &data_length);
2701
2702 /* Set the time. */
2703 pcap_packet_header.time_stamp_second = time_value.tv_sec;
2704 pcap_packet_header.time_stamp_microseconds = time_value.tv_usec;
2705 pcap_packet_header.capture_length = data_length;
2706 pcap_packet_header.actual_length = data_length;
2707
2708 /* Check if open the pcap file. */
2709 if (nx_network_driver_pcap_fp == NX_NULL)
2710 return (NX_PCAP_FILE_ERROR);
2711
2712 /* Write the pcap packet header. */
2713 fwrite(&pcap_packet_header, sizeof(pcap_packet_header), 1, nx_network_driver_pcap_fp);
2714
2715 /* Write the packet data. */
2716 fwrite(data_buffer, data_length, 1, nx_network_driver_pcap_fp);
2717
2718 /* Flush the file data. */
2719 fflush(nx_network_driver_pcap_fp);
2720
2721 /* Return. */
2722 return (NX_PCAP_FILE_OK);
2723 }
2724
2725 /**************************************************************************/
2726 /* */
2727 /* FUNCTION RELEASE */
2728 /* */
2729 /* close_pcap_file PORTABLE C */
2730 /* 6.4.0 */
2731 /* AUTHOR */
2732 /* */
2733 /* Wenhui Xie, Microsoft Corporation */
2734 /* */
2735 /* DESCRIPTION */
2736 /* */
2737 /* This function closes the libpcap file opened */
2738 /* */
2739 /* INPUT */
2740 /* */
2741 /* None */
2742 /* */
2743 /* OUTPUT */
2744 /* None */
2745 /* */
2746 /* CALLS */
2747 /* */
2748 /* */
2749 /* CALLED BY */
2750 /* */
2751 /* Application Code */
2752 /* */
2753 /* RELEASE HISTORY */
2754 /* */
2755 /* DATE NAME DESCRIPTION */
2756 /* */
2757 /* 12-31-2023 Wenhui Xie Initial Version 6.4.0 */
2758 /* */
2759 /**************************************************************************/
close_pcap_file()2760 VOID close_pcap_file()
2761 {
2762
2763 /* Check if the pcap file pointer. */
2764 if (nx_network_driver_pcap_fp != NX_NULL)
2765 {
2766
2767 /* Close the file. */
2768 fclose(nx_network_driver_pcap_fp);
2769
2770 /* Set the pcap file pointer to NX_NULL. */
2771 nx_network_driver_pcap_fp = NX_NULL;
2772 }
2773 }
2774 #endif /* NX_PCAP_ENABLE */
2775
2776 #ifdef NX_BSD_RAW_SUPPORT
2777 /* Stub function used by BSD raw socket. */
_nx_driver_hardware_packet_send(NX_PACKET * packet_ptr)2778 UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
2779 {
2780
2781 if (!(packet_ptr -> nx_packet_ip_interface -> nx_interface_valid))
2782 return(NX_PTR_ERROR);
2783 return(NX_SUCCESS);
2784 }
2785
2786 /* Callback function pointer when packet is received. */
2787 VOID (*_nx_driver_hardware_packet_received_callback)(NX_PACKET *packet_ptr, UCHAR *consumed);
2788 #endif /* NX_BSD_RAW_SUPPORT */
2789