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