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