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