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