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 
23 /* Include necessary system files.  */
24 
25 #include "nx_api.h"
26 #include "nx_link.h"
27 
28 
29 /* Define the Link MTU. Note this is not the same as the IP MTU.  The Link MTU
30    includes the addition of the Physical Network header (usually Ethernet). This
31    should be larger than the IP instance MTU by the size of the physical header. */
32 #define NX_LINK_MTU      1514
33 
34 
35 /* Define Ethernet address format.  This is prepended to the incoming IP
36    and ARP/RARP messages.  The frame beginning is 14 bytes, but for speed
37    purposes, we are going to assume there are 16 bytes free in front of the
38    prepend pointer and that the prepend pointer is 32-bit aligned.
39 
40     Byte Offset     Size            Meaning
41 
42         0           6           Destination Ethernet Address
43         6           6           Source Ethernet Address
44         12          2           Ethernet Frame Type, where:
45 
46                                         0x0800 -> IP Datagram
47                                         0x0806 -> ARP Request/Reply
48                                         0x0835 -> RARP request reply
49 
50         42          18          Padding on ARP and RARP messages only.  */
51 
52 #define NX_ETHERNET_IP   0x0800
53 #define NX_ETHERNET_ARP  0x0806
54 #define NX_ETHERNET_RARP 0x8035
55 #define NX_ETHERNET_IPV6 0x86DD
56 #define NX_ETHERNET_SIZE 14
57 
58 /* For the simulated ethernet driver, physical addresses are allocated starting
59    at the preset value and then incremented before the next allocation.  */
60 
61 ULONG   simulated_address_msw =  0x0011;
62 ULONG   simulated_address_lsw =  0x22334456;
63 
64 
65 /* Define driver prototypes.  */
66 
67 VOID    _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
68 void    _nx_ram_network_driver_output(NX_PACKET *packet_ptr, UINT interface_instance_id);
69 void    _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id);
70 
71 #define NX_MAX_RAM_INTERFACES             4
72 #define NX_RAM_DRIVER_MAX_MCAST_ADDRESSES 3
73 typedef struct MAC_ADDRESS_STRUCT
74 {
75     ULONG nx_mac_address_msw;
76     ULONG nx_mac_address_lsw;
77 } MAC_ADDRESS;
78 
79 
80 /* Define an application-specific data structure that holds internal
81    data (such as the state information) of a device driver.
82 
83    The example below applies to the simulated RAM driver.
84    User shall replace its content with information related to
85    the actual driver being used. */
86 typedef struct _nx_ram_network_driver_instance_type
87 {
88     UINT          nx_ram_network_driver_in_use;
89 
90     UINT          nx_ram_network_driver_id;
91 
92     NX_INTERFACE *nx_ram_driver_interface_ptr;
93 
94     NX_IP        *nx_ram_driver_ip_ptr;
95 
96     MAC_ADDRESS   nx_ram_driver_mac_address;
97 
98     MAC_ADDRESS   nx_ram_driver_mcast_address[NX_RAM_DRIVER_MAX_MCAST_ADDRESSES];
99 } _nx_ram_network_driver_instance_type;
100 
101 
102 /* In this example, there are four instances of the simulated RAM driver.
103    Therefore an array of four driver instances are created to keep track of
104    the interface information of each driver. */
105 static _nx_ram_network_driver_instance_type nx_ram_driver[NX_MAX_RAM_INTERFACES];
106 
107 
108 /**************************************************************************/
109 /*                                                                        */
110 /*  FUNCTION                                               RELEASE        */
111 /*                                                                        */
112 /*    _nx_ram_network_driver                              PORTABLE C      */
113 /*                                                           6.4.0        */
114 /*  AUTHOR                                                                */
115 /*                                                                        */
116 /*    Yuxin Zhou, Microsoft Corporation                                   */
117 /*                                                                        */
118 /*  DESCRIPTION                                                           */
119 /*                                                                        */
120 /*    This function acts as a virtual network for testing the NetX source */
121 /*    and driver concepts.   User application may use this routine as     */
122 /*    a template for the actual network driver.  Note that this driver    */
123 /*    simulates Ethernet operation.  Some of the parameters don't apply   */
124 /*    for non-Ethernet interfaces.                                        */
125 /*                                                                        */
126 /*  INPUT                                                                 */
127 /*                                                                        */
128 /*    ip_ptr                                Pointer to IP protocol block  */
129 /*                                                                        */
130 /*  OUTPUT                                                                */
131 /*                                                                        */
132 /*    None                                                                */
133 /*                                                                        */
134 /*  CALLS                                                                 */
135 /*                                                                        */
136 /*    _nx_ram_network_driver_output         Send physical packet out      */
137 /*                                                                        */
138 /*  CALLED BY                                                             */
139 /*                                                                        */
140 /*    NetX IP processing                                                  */
141 /*                                                                        */
142 /*  RELEASE HISTORY                                                       */
143 /*                                                                        */
144 /*    DATE              NAME                      DESCRIPTION             */
145 /*                                                                        */
146 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
147 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
148 /*                                            resulting in version 6.1    */
149 /*  10-15-2021     Yuxin Zhou               Modified comment(s), and      */
150 /*                                            added sample of returning   */
151 /*                                            link's interface type,      */
152 /*                                            resulting in version 6.1.9  */
153 /*  12-31-2023     Yajun Xia                Modified comment(s),          */
154 /*                                            supported VLAN and generic  */
155 /*                                            link layer,                 */
156 /*                                            resulting in version 6.4.0  */
157 /*                                                                        */
158 /**************************************************************************/
_nx_ram_network_driver(NX_IP_DRIVER * driver_req_ptr)159 VOID  _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr)
160 {
161 UINT          i = 0;
162 NX_IP        *ip_ptr;
163 NX_PACKET    *packet_ptr;
164 NX_INTERFACE *interface_ptr;
165 UINT          interface_index;
166 USHORT        ether_type;
167 #ifndef NX_ENABLE_VLAN
168 ULONG        *ethernet_frame_ptr;
169 #endif /* NX_ENABLE_VLAN */
170 
171     /* Setup the IP pointer from the driver request.  */
172     ip_ptr =  driver_req_ptr -> nx_ip_driver_ptr;
173 
174     /* Default to successful return.  */
175     driver_req_ptr -> nx_ip_driver_status =  NX_SUCCESS;
176 
177 #ifdef NX_ENABLE_VLAN
178     /* Let link layer to preprocess the driver request and return actual interface.  */
179     if (nx_link_driver_request_preprocess(driver_req_ptr, &interface_ptr) != NX_SUCCESS)
180     {
181         return;
182     }
183 #else
184     /* Setup interface pointer.  */
185     interface_ptr = driver_req_ptr -> nx_ip_driver_interface;
186 #endif /* NX_ENABLE_VLAN */
187 
188     /* Obtain the index number of the network interface. */
189     interface_index = interface_ptr -> nx_interface_index;
190 
191     /* Find out the driver interface if the driver command is not ATTACH. */
192     if (driver_req_ptr -> nx_ip_driver_command != NX_LINK_INTERFACE_ATTACH)
193     {
194         for (i = 0; i < NX_MAX_RAM_INTERFACES; i++)
195         {
196             if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
197             {
198                 continue;
199             }
200 
201             if (nx_ram_driver[i].nx_ram_driver_ip_ptr != ip_ptr)
202             {
203                 continue;
204             }
205 
206             if (nx_ram_driver[i].nx_ram_driver_interface_ptr == interface_ptr)
207             {
208                 break;
209             }
210         }
211 
212         if (i == NX_MAX_RAM_INTERFACES)
213         {
214             driver_req_ptr -> nx_ip_driver_status =  NX_INVALID_INTERFACE;
215             return;
216         }
217     }
218 
219 
220     /* Process according to the driver request type in the IP control
221        block.  */
222     switch (driver_req_ptr -> nx_ip_driver_command)
223     {
224 
225     case NX_LINK_INTERFACE_ATTACH:
226     {
227 
228         /* Find an available driver instance to attach the interface. */
229         for (i = 0; i < NX_MAX_RAM_INTERFACES; i++)
230         {
231             if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
232             {
233                 break;
234             }
235         }
236         /* An available entry is found. */
237         if (i < NX_MAX_RAM_INTERFACES)
238         {
239             /* Set the IN USE flag.*/
240             nx_ram_driver[i].nx_ram_network_driver_in_use  = 1;
241 
242             nx_ram_driver[i].nx_ram_network_driver_id = i;
243 
244             /* Record the interface attached to the IP instance. */
245             nx_ram_driver[i].nx_ram_driver_interface_ptr = interface_ptr;
246 
247             /* Record the IP instance. */
248             nx_ram_driver[i].nx_ram_driver_ip_ptr = ip_ptr;
249 
250             nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = simulated_address_msw;
251             nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = simulated_address_lsw + i;
252         }
253         else
254         {
255             driver_req_ptr -> nx_ip_driver_status =  NX_INVALID_INTERFACE;
256         }
257 
258         break;
259     }
260 
261     case NX_LINK_INTERFACE_DETACH:
262     {
263 
264         /* Zero out the driver instance. */
265         memset(&(nx_ram_driver[i]), 0, sizeof(_nx_ram_network_driver_instance_type));
266 
267         break;
268     }
269 
270     case NX_LINK_INITIALIZE:
271     {
272 
273         /* Device driver shall initialize the Ethernet Controller here. */
274 
275 #ifdef NX_DEBUG
276         printf("NetX RAM Driver Initialization - %s\n", ip_ptr -> nx_ip_name);
277         printf("  IP Address =%08X\n", ip_ptr -> nx_ip_address);
278 #endif
279 
280         /* Once the Ethernet controller is initialized, the driver needs to
281            configure the NetX Interface Control block, as outlined below. */
282 
283         /* The nx_interface_ip_mtu_size should be the MTU for the IP payload.
284            For regular Ethernet, the IP MTU is 1500. */
285         nx_ip_interface_mtu_set(ip_ptr, interface_index, (NX_LINK_MTU - NX_ETHERNET_SIZE));
286 
287         /* Set the physical address (MAC address) of this IP instance.  */
288         /* For this simulated RAM driver, the MAC address is constructed by
289            incrementing a base lsw value, to simulate multiple nodes on the
290            ethernet.  */
291         nx_ip_interface_physical_address_set(ip_ptr, interface_index,
292                                              nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw,
293                                              nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw, NX_FALSE);
294 
295         /* Indicate to the IP software that IP to physical mapping is required.  */
296         nx_ip_interface_address_mapping_configure(ip_ptr, interface_index, NX_TRUE);
297 
298         break;
299     }
300 
301     case NX_LINK_UNINITIALIZE:
302     {
303 
304         /* Zero out the driver instance. */
305         memset(&(nx_ram_driver[i]), 0, sizeof(_nx_ram_network_driver_instance_type));
306 
307         break;
308     }
309 
310     case NX_LINK_ENABLE:
311     {
312 
313         /* Process driver link enable.  An Ethernet driver shall enable the
314            transmit and reception logic.  Once the IP stack issues the
315            LINK_ENABLE command, the stack may start transmitting IP packets. */
316 
317 
318         /* In the RAM driver, just set the enabled flag.  */
319         interface_ptr -> nx_interface_link_up =  NX_TRUE;
320 
321 #ifdef NX_DEBUG
322         printf("NetX RAM Driver Link Enabled - %s\n", ip_ptr -> nx_ip_name);
323 #endif
324         break;
325     }
326 
327     case NX_LINK_DISABLE:
328     {
329 
330         /* Process driver link disable.  This command indicates the IP layer
331            is not going to transmit any IP datagrams, nor does it expect any
332            IP datagrams from the interface.  Therefore after processing this command,
333            the device driver shall not send any incoming packets to the IP
334            layer.  Optionally the device driver may turn off the interface. */
335 
336         /* In the RAM driver, just clear the enabled flag.  */
337         interface_ptr -> nx_interface_link_up =  NX_FALSE;
338 
339 #ifdef NX_DEBUG
340         printf("NetX RAM Driver Link Disabled - %s\n", ip_ptr -> nx_ip_name);
341 #endif
342         break;
343     }
344 
345     case NX_LINK_PACKET_SEND:
346     case NX_LINK_PACKET_BROADCAST:
347     case NX_LINK_ARP_SEND:
348     case NX_LINK_ARP_RESPONSE_SEND:
349     case NX_LINK_RARP_SEND:
350     {
351 
352         /*
353            The IP stack sends down a data packet for transmission.
354            The device driver needs to prepend a MAC header, and fill in the
355            Ethernet frame type (assuming Ethernet protocol for network transmission)
356            based on the type of packet being transmitted.
357 
358            The following sequence illustrates this process.
359          */
360 
361 
362         /* Place the ethernet frame at the front of the packet.  */
363         packet_ptr =  driver_req_ptr -> nx_ip_driver_packet;
364 
365         /* Get Ethernet type.  */
366         if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)
367         {
368             ether_type = NX_ETHERNET_ARP;
369         }
370         else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND)
371         {
372             ether_type = NX_ETHERNET_ARP;
373         }
374         else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
375         {
376             ether_type = NX_ETHERNET_RARP;
377         }
378         else if (packet_ptr -> nx_packet_ip_version == 4)
379         {
380             ether_type = NX_ETHERNET_IP;
381         }
382         else
383         {
384             ether_type = NX_ETHERNET_IPV6;
385         }
386 
387 #ifdef NX_ENABLE_VLAN
388         /* Add Ethernet header.  */
389         if (nx_link_ethernet_header_add(ip_ptr,
390                                         driver_req_ptr -> nx_ip_driver_interface -> nx_interface_index, packet_ptr,
391                                         driver_req_ptr -> nx_ip_driver_physical_address_msw,
392                                         driver_req_ptr -> nx_ip_driver_physical_address_lsw,
393                                         (UINT)ether_type))
394         {
395 
396             /* Release the packet.  */
397             nx_packet_transmit_release(packet_ptr);
398             break;
399         }
400 #else
401 
402         /* Adjust the prepend pointer.  */
403         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr - NX_ETHERNET_SIZE;
404 
405         /* Adjust the packet length.  */
406         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length + NX_ETHERNET_SIZE;
407 
408         /* Setup the ethernet frame pointer to build the ethernet frame.  Backup another 2
409            bytes to get 32-bit word alignment.  */
410         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
411         ethernet_frame_ptr =  (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - 2);
412 
413         /* Build the ethernet frame.  */
414         *ethernet_frame_ptr     =  driver_req_ptr -> nx_ip_driver_physical_address_msw;
415         *(ethernet_frame_ptr + 1) =  driver_req_ptr -> nx_ip_driver_physical_address_lsw;
416         *(ethernet_frame_ptr + 2) =  (interface_ptr -> nx_interface_physical_address_msw << 16) |
417             (interface_ptr -> nx_interface_physical_address_lsw >> 16);
418         *(ethernet_frame_ptr + 3) =  (interface_ptr -> nx_interface_physical_address_lsw << 16) | ether_type;
419 
420         /* Endian swapping if NX_LITTLE_ENDIAN is defined.  */
421         NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
422         NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1));
423         NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2));
424         NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3));
425 #endif /* NX_ENABLE_VLAN */
426 
427 #ifdef NX_DEBUG_PACKET
428         printf("NetX RAM Driver Packet Send - %s\n", ip_ptr -> nx_ip_name);
429 #endif
430 
431         /* At this point, the packet is a complete Ethernet frame, ready to be transmitted.
432            The driver shall call the actual Ethernet transmit routine and put the packet
433            on the wire.
434 
435            In this example, the simulated RAM network transmit routine is called. */
436         _nx_ram_network_driver_output(packet_ptr, i);
437         break;
438     }
439 
440 #ifdef NX_ENABLE_VLAN
441     case NX_LINK_RAW_PACKET_SEND:
442     {
443 
444         /* Send raw packet out directly.  */
445         _nx_ram_network_driver_output(driver_req_ptr -> nx_ip_driver_packet, i);
446         break;
447     }
448 #endif /* NX_ENABLE_VLAN */
449 
450     case NX_LINK_MULTICAST_JOIN:
451     {
452     UINT mcast_index;
453 
454         /* The IP layer issues this command to join a multicast group.  Note that
455            multicast operation is required for IPv6.
456 
457            On a typically Ethernet controller, the driver computes a hash value based
458            on MAC address, and programs the hash table.
459 
460            It is likely the driver also needs to maintain an internal MAC address table.
461            Later if a multicast address is removed, the driver needs
462            to reprogram the hash table based on the remaining multicast MAC addresses. */
463 
464 
465         /* The following procedure only applies to our simulated RAM network driver, which manages
466            multicast MAC addresses by a simple look up table. */
467         for (mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
468         {
469             if (nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw == 0 &&
470                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == 0)
471             {
472                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
473                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
474                 break;
475             }
476         }
477         if (mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
478         {
479             driver_req_ptr -> nx_ip_driver_status =  NX_NO_MORE_ENTRIES;
480         }
481 
482         break;
483     }
484 
485 
486     case NX_LINK_MULTICAST_LEAVE:
487     {
488 
489     UINT mcast_index;
490 
491         /* The IP layer issues this command to remove a multicast MAC address from the
492            receiving list.  A device driver shall properly remove the multicast address
493            from the hash table, so the hardware does not receive such traffic.  Note that
494            in order to reprogram the hash table, the device driver may have to keep track of
495            current active multicast MAC addresses. */
496 
497         /* The following procedure only applies to our simulated RAM network driver, which manages
498            multicast MAC addresses by a simple look up table. */
499         for (mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
500         {
501             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 &&
502                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw == driver_req_ptr -> nx_ip_driver_physical_address_lsw)
503             {
504                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw = 0;
505                 nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw = 0;
506                 break;
507             }
508         }
509         if (mcast_index == NX_RAM_DRIVER_MAX_MCAST_ADDRESSES)
510         {
511             driver_req_ptr -> nx_ip_driver_status =  NX_ENTRY_NOT_FOUND;
512         }
513 
514         break;
515     }
516 
517     case NX_LINK_GET_STATUS:
518     {
519 
520         /* Return the link status in the supplied return pointer.  */
521         *(driver_req_ptr -> nx_ip_driver_return_ptr) =  ip_ptr -> nx_ip_interface[0].nx_interface_link_up;
522         break;
523     }
524 
525     case NX_LINK_GET_SPEED:
526     {
527 
528         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
529         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
530         break;
531     }
532 
533     case NX_LINK_GET_DUPLEX_TYPE:
534     {
535 
536         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
537         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
538         break;
539     }
540 
541     case NX_LINK_GET_ERROR_COUNT:
542     {
543 
544         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
545         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
546         break;
547     }
548 
549     case NX_LINK_GET_RX_COUNT:
550     {
551 
552         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
553         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
554         break;
555     }
556 
557     case NX_LINK_GET_TX_COUNT:
558     {
559 
560         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
561         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
562         break;
563     }
564 
565     case NX_LINK_GET_ALLOC_ERRORS:
566     {
567 
568         /* Return the link's line speed in the supplied return pointer. Unsupported feature.  */
569         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
570         break;
571     }
572 
573     case NX_LINK_GET_INTERFACE_TYPE:
574     {
575 
576         /* Return the link's interface type in the supplied return pointer. Unsupported feature.  */
577         *(driver_req_ptr -> nx_ip_driver_return_ptr) = NX_INTERFACE_TYPE_UNKNOWN;
578         break;
579     }
580 
581     case NX_LINK_DEFERRED_PROCESSING:
582     {
583 
584         /* Driver defined deferred processing. This is typically used to defer interrupt
585            processing to the thread level.
586 
587            A typical use case of this command is:
588            On receiving an Ethernet frame, the RX ISR does not process the received frame,
589            but instead records such an event in its internal data structure, and issues
590            a notification to the IP stack (the driver sends the notification to the IP
591            helping thread by calling "_nx_ip_driver_deferred_processing()".  When the IP stack
592            gets a notification of a pending driver deferred process, it calls the
593            driver with the NX_LINK_DEFERRED_PROCESSING command.  The driver shall complete
594            the pending receive process.
595          */
596 
597         /* The simulated RAM driver doesn't require a deferred process so it breaks out of
598            the switch case. */
599 
600 
601         break;
602     }
603 
604     case NX_LINK_SET_PHYSICAL_ADDRESS:
605     {
606 
607         /* Find an driver instance to attach the interface. */
608         for (i = 0; i < NX_MAX_RAM_INTERFACES; i++)
609         {
610             if (nx_ram_driver[i].nx_ram_driver_interface_ptr == interface_ptr)
611             {
612                 break;
613             }
614         }
615 
616         /* An available entry is found. */
617         if (i < NX_MAX_RAM_INTERFACES)
618         {
619 
620             /* Set the physical address.  */
621             nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw = driver_req_ptr -> nx_ip_driver_physical_address_msw;
622             nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
623         }
624         else
625         {
626             driver_req_ptr -> nx_ip_driver_status =  NX_INVALID_INTERFACE;
627         }
628 
629         break;
630     }
631 
632 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
633     case NX_INTERFACE_CAPABILITY_GET:
634     {
635 
636         /* Return the capability of the Ethernet controller speed in the supplied return pointer. Unsupported feature.  */
637         *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0;
638         break;
639     }
640 
641     case NX_INTERFACE_CAPABILITY_SET:
642     {
643 
644         /* Set the capability of the Ethernet controller. Unsupported feature.  */
645         break;
646     }
647 #endif /* NX_ENABLE_INTERFACE_CAPABILITY  */
648 
649     default:
650 
651         /* Invalid driver request.  */
652 
653         /* Return the unhandled command status.  */
654         driver_req_ptr -> nx_ip_driver_status =  NX_UNHANDLED_COMMAND;
655 
656 #ifdef NX_DEBUG
657         printf("NetX RAM Driver Received invalid request - %s\n", ip_ptr -> nx_ip_name);
658 #endif
659         break;
660     }
661 }
662 
663 
664 /**************************************************************************/
665 /*                                                                        */
666 /*  FUNCTION                                               RELEASE        */
667 /*                                                                        */
668 /*    _nx_ram_network_driver_output                       PORTABLE C      */
669 /*                                                           6.4.0        */
670 /*  AUTHOR                                                                */
671 /*                                                                        */
672 /*    Yuxin Zhou, Microsoft Corporation                                   */
673 /*                                                                        */
674 /*  DESCRIPTION                                                           */
675 /*                                                                        */
676 /*    This function simply sends the packet to the IP instance on the     */
677 /*    created IP list that matches the physical destination specified in  */
678 /*    the Ethernet packet.  In a real hardware setting, this routine      */
679 /*    would simply put the packet out on the wire.                        */
680 /*                                                                        */
681 /*  INPUT                                                                 */
682 /*                                                                        */
683 /*    packet_ptr                            Packet pointer                */
684 /*    interface_instance_id                 ID of driver instance         */
685 /*                                                                        */
686 /*  OUTPUT                                                                */
687 /*                                                                        */
688 /*    None                                                                */
689 /*                                                                        */
690 /*  CALLS                                                                 */
691 /*                                                                        */
692 /*    nx_packet_copy                        Copy a packet                 */
693 /*    nx_packet_transmit_release            Release a packet              */
694 /*    _nx_ram_network_driver_receive        RAM driver receive processing */
695 /*                                                                        */
696 /*  CALLED BY                                                             */
697 /*                                                                        */
698 /*    NetX IP processing                                                  */
699 /*                                                                        */
700 /*  RELEASE HISTORY                                                       */
701 /*                                                                        */
702 /*    DATE              NAME                      DESCRIPTION             */
703 /*                                                                        */
704 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
705 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
706 /*                                            resulting in version 6.1    */
707 /*  12-31-2023     Yajun Xia                Modified comment(s),          */
708 /*                                            supported VLAN and generic  */
709 /*                                            link layer,                 */
710 /*                                            resulting in version 6.4.0  */
711 /*                                                                        */
712 /**************************************************************************/
_nx_ram_network_driver_output(NX_PACKET * packet_ptr,UINT interface_instance_id)713 void  _nx_ram_network_driver_output(NX_PACKET *packet_ptr, UINT interface_instance_id)
714 {
715 
716 NX_IP     *next_ip;
717 NX_PACKET *packet_copy;
718 ULONG      destination_address_msw;
719 ULONG      destination_address_lsw;
720 UINT       old_threshold = 0;
721 UINT       i;
722 UINT       mcast_index;
723 
724 #ifdef NX_DEBUG_PACKET
725 UCHAR *ptr;
726 UINT   j;
727 
728     ptr =  packet_ptr -> nx_packet_prepend_ptr;
729     printf("Ethernet Packet: ");
730     for (j = 0; j < 6; j++)
731     {
732         printf("%02X", *ptr++);
733     }
734     printf(" ");
735     for (j = 0; j < 6; j++)
736     {
737         printf("%02X", *ptr++);
738     }
739     printf(" %02X", *ptr++);
740     printf("%02X ", *ptr++);
741 
742     i = 0;
743     for (j = 0; j < (packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE); j++)
744     {
745         printf("%02X", *ptr++);
746         i++;
747         if (i > 3)
748         {
749             i = 0;
750             printf(" ");
751         }
752     }
753     printf("\n");
754 
755 
756 #endif
757 
758     /* Pickup the destination IP address from the packet_ptr.  */
759     destination_address_msw =  (ULONG)*(packet_ptr -> nx_packet_prepend_ptr);
760     destination_address_msw =  (destination_address_msw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 1);
761     destination_address_lsw =  (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 2);
762     destination_address_lsw =  (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 3);
763     destination_address_lsw =  (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 4);
764     destination_address_lsw =  (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 5);
765 
766 
767     /* Disable preemption.  */
768     tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
769 
770     for (i = 0; i < NX_MAX_RAM_INTERFACES; i++)
771     {
772 
773         /* Skip the interface from which the packet was sent. */
774         if (i == interface_instance_id)
775         {
776             continue;
777         }
778 
779         /* Skip the instance that has not been initialized. */
780         if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0)
781         {
782             continue;
783         }
784 
785         /* Set the next IP instance.  */
786         next_ip = nx_ram_driver[i].nx_ram_driver_ip_ptr;
787 
788         /* If the destination MAC address is broadcast or the destination matches the interface MAC,
789            accept the packet. */
790         if (((destination_address_msw == ((ULONG)0x0000FFFF)) && (destination_address_lsw == ((ULONG)0xFFFFFFFF))) ||   /* Broadcast match */
791             ((destination_address_msw == nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_msw) &&
792              (destination_address_lsw == nx_ram_driver[i].nx_ram_driver_mac_address.nx_mac_address_lsw)) ||
793             (destination_address_msw == ((ULONG)0x00003333)) ||
794             ((destination_address_msw == 0) && (destination_address_lsw == 0)))
795         {
796 
797             /* Make a copy of packet for the forwarding.  */
798             if (nx_packet_copy(packet_ptr, &packet_copy, next_ip -> nx_ip_default_packet_pool, NX_NO_WAIT))
799             {
800 #ifdef NX_ENABLE_VLAN
801                 /* Error, no point in continuing, just release the packet.  */
802                 nx_link_packet_transmitted(nx_ram_driver[interface_instance_id].nx_ram_driver_ip_ptr,
803                                            nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
804                                            packet_ptr, NX_NULL);
805 #else
806 
807                 /* Remove the Ethernet header.  */
808                 packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
809 
810                 /* Adjust the packet length.  */
811                 packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
812 
813                 /* Error, no point in continuing, just release the packet.  */
814                 nx_packet_transmit_release(packet_ptr);
815 #endif /* NX_ENABLE_VLAN */
816                 return;
817             }
818 
819             /*lint -e{644} suppress variable might not be initialized, since "packet_copy" was initialized in nx_packet_copy. */
820             _nx_ram_network_driver_receive(next_ip, packet_copy, i);
821         }
822         else
823         {
824             for (mcast_index = 0; mcast_index < NX_RAM_DRIVER_MAX_MCAST_ADDRESSES; mcast_index++)
825             {
826 
827                 if (destination_address_msw == nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_msw &&
828                     destination_address_lsw == nx_ram_driver[i].nx_ram_driver_mcast_address[mcast_index].nx_mac_address_lsw)
829                 {
830 
831                     /* Make a copy of packet for the forwarding.  */
832                     if (nx_packet_copy(packet_ptr, &packet_copy, next_ip -> nx_ip_default_packet_pool, NX_NO_WAIT))
833                     {
834 
835                         /* Remove the Ethernet header.  */
836                         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
837 
838                         /* Adjust the packet length.  */
839                         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
840 
841                         /* Error, no point in continuing, just release the packet.  */
842                         nx_packet_transmit_release(packet_ptr);
843                         return;
844                     }
845 
846                     _nx_ram_network_driver_receive(next_ip, packet_copy, i);
847                 }
848             }
849         }
850     }
851 
852 #ifdef NX_ENABLE_VLAN
853     /* Release the packet.  */
854     nx_link_packet_transmitted(nx_ram_driver[interface_instance_id].nx_ram_driver_ip_ptr,
855                                 nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
856                                 packet_ptr, NX_NULL);
857 #else
858     /* Remove the Ethernet header.  In real hardware environments, this is typically
859        done after a transmit complete interrupt.  */
860     packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
861 
862     /* Adjust the packet length.  */
863     packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
864 
865     /* Now that the Ethernet frame has been removed, release the packet.  */
866     nx_packet_transmit_release(packet_ptr);
867 #endif /* NX_ENABLE_VLAN */
868 
869     /* Restore preemption.  */
870     /*lint -e{644} suppress variable might not be initialized, since "old_threshold" was initialized in previous tx_thread_preemption_change. */
871     tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
872 }
873 
874 
875 /**************************************************************************/
876 /*                                                                        */
877 /*  FUNCTION                                               RELEASE        */
878 /*                                                                        */
879 /*    _nx_ram_network_driver_receive                      PORTABLE C      */
880 /*                                                           6.4.0        */
881 /*  AUTHOR                                                                */
882 /*                                                                        */
883 /*    Yuxin Zhou, Microsoft Corporation                                   */
884 /*                                                                        */
885 /*  DESCRIPTION                                                           */
886 /*                                                                        */
887 /*    This function processing incoming packets.  In the RAM network      */
888 /*    driver, the incoming packets are coming from the RAM driver output  */
889 /*    routine.  In real hardware settings, this routine would be called   */
890 /*    from the receive packet ISR.                                        */
891 /*                                                                        */
892 /*  INPUT                                                                 */
893 /*                                                                        */
894 /*    ip_ptr                                Pointer to IP protocol block  */
895 /*    packet_ptr                            Packet pointer                */
896 /*    interface_instance_id                 The interface ID the packet is*/
897 /*                                            destined for                */
898 /*                                                                        */
899 /*  OUTPUT                                                                */
900 /*                                                                        */
901 /*    None                                                                */
902 /*                                                                        */
903 /*  CALLS                                                                 */
904 /*                                                                        */
905 /*    _nx_ip_packet_receive                 IP receive packet processing  */
906 /*    _nx_ip_packet_deferred_receive        IP deferred receive packet    */
907 /*                                            processing                  */
908 /*    _nx_arp_packet_deferred_receive       ARP receive processing        */
909 /*    _nx_rarp_packet_deferred_receive      RARP receive processing       */
910 /*    nx_packet_release                     Packet release                */
911 /*                                                                        */
912 /*  CALLED BY                                                             */
913 /*                                                                        */
914 /*    NetX IP processing                                                  */
915 /*                                                                        */
916 /*  RELEASE HISTORY                                                       */
917 /*                                                                        */
918 /*    DATE              NAME                      DESCRIPTION             */
919 /*                                                                        */
920 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
921 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
922 /*                                            resulting in version 6.1    */
923 /*  12-31-2023     Yajun Xia                Modified comment(s),          */
924 /*                                            supported VLAN and generic  */
925 /*                                            link layer,                 */
926 /*                                            resulting in version 6.4.0  */
927 /*                                                                        */
928 /**************************************************************************/
_nx_ram_network_driver_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT interface_instance_id)929 void  _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT interface_instance_id)
930 {
931 #ifdef NX_ENABLE_VLAN
932     nx_link_ethernet_packet_received(ip_ptr,
933                                      nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr -> nx_interface_index,
934                                      packet_ptr, NX_NULL);
935 #else
936 UINT packet_type;
937 
938     /* Pickup the packet header to determine where the packet needs to be
939        sent.  */
940     packet_type =  (((UINT)(*(packet_ptr -> nx_packet_prepend_ptr + 12))) << 8) |
941         ((UINT)(*(packet_ptr -> nx_packet_prepend_ptr + 13)));
942 
943 
944     /* Setup interface pointer.  */
945     packet_ptr -> nx_packet_address.nx_packet_interface_ptr = nx_ram_driver[interface_instance_id].nx_ram_driver_interface_ptr;
946 
947 
948     /* Route the incoming packet according to its ethernet type.  */
949     /* The RAM driver accepts both IPv4 and IPv6 frames. */
950     if ((packet_type == NX_ETHERNET_IP) || (packet_type == NX_ETHERNET_IPV6))
951     {
952 
953         /* Note:  The length reported by some Ethernet hardware includes bytes after the packet
954            as well as the Ethernet header.  In some cases, the actual packet length after the
955            Ethernet header should be derived from the length in the IP header (lower 16 bits of
956            the first 32-bit word).  */
957 
958         /* Clean off the Ethernet header.  */
959         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
960 
961         /* Adjust the packet length.  */
962         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
963 
964         /* Route to the ip receive function.  */
965 #ifdef NX_DEBUG_PACKET
966         printf("NetX RAM Driver IP Packet Receive - %s\n", ip_ptr -> nx_ip_name);
967 #endif
968 
969 #ifdef NX_DIRECT_ISR_CALL
970         _nx_ip_packet_receive(ip_ptr, packet_ptr);
971 #else
972         _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
973 #endif
974     }
975 #ifndef NX_DISABLE_IPV4
976     else if (packet_type == NX_ETHERNET_ARP)
977     {
978 
979         /* Clean off the Ethernet header.  */
980         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
981 
982         /* Adjust the packet length.  */
983         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
984 
985         /* Route to the ARP receive function.  */
986 #ifdef NX_DEBUG
987         printf("NetX RAM Driver ARP Receive - %s\n", ip_ptr -> nx_ip_name);
988 #endif
989         _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
990     }
991     else if (packet_type == NX_ETHERNET_RARP)
992     {
993 
994         /* Clean off the Ethernet header.  */
995         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
996 
997         /* Adjust the packet length.  */
998         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE;
999 
1000         /* Route to the RARP receive function.  */
1001 #ifdef NX_DEBUG
1002         printf("NetX RAM Driver RARP Receive - %s\n", ip_ptr -> nx_ip_name);
1003 #endif
1004         _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
1005     }
1006 #endif /* !NX_DISABLE_IPV4  */
1007     else
1008     {
1009 
1010         /* Invalid ethernet header... release the packet.  */
1011         nx_packet_release(packet_ptr);
1012     }
1013 #endif /* NX_ENABLE_VLAN */
1014 }
1015 
1016