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 Link Layer */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19 #define NX_SOURCE_CODE
20
21 #include "nx_link.h"
22 #include "nx_ip.h"
23 #include "nx_arp.h"
24 #include "nx_rarp.h"
25 #include "nx_packet.h"
26
27 #ifdef NX_ENABLE_VLAN
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* nx_link_vlan_set PORTABLE C */
33 /* 6.4.0 */
34 /* AUTHOR */
35 /* */
36 /* Tiejun Zhou, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function sets VLAN tag to interface. VLAN tag is comprised the */
41 /* PCP and VLAN ID, encoded in host byte order. See example below. */
42 /* VLAN tag: 0x0002 */
43 /* PCP: 0x00 */
44 /* VLAN ID: 0x02 */
45 /* When the priority of a packet is set either to packet directly or */
46 /* through the socket, the PCP from VLAN tag is override. */
47 /* */
48 /* INPUT */
49 /* */
50 /* ip_ptr IP instance pointer */
51 /* interface_index IP Interface Index */
52 /* vlan_tag VLAN tag to set */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* tx_mutex_get Get protection mutex */
61 /* tx_mutex_put Put protection mutex */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
72 /* */
73 /**************************************************************************/
nx_link_vlan_set(NX_IP * ip_ptr,UINT interface_index,UINT vlan_tag)74 UINT nx_link_vlan_set(NX_IP *ip_ptr, UINT interface_index, UINT vlan_tag)
75 {
76
77 /* Check for invalid input pointers. */
78 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID))
79 {
80 return(NX_PTR_ERROR);
81 }
82
83 /* Check for valid interface ID */
84 if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
85 {
86 return(NX_INVALID_INTERFACE);
87 }
88
89 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
90
91 ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_tag = (USHORT)(vlan_tag & 0xFFFF);
92 ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_valid = NX_TRUE;
93 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
94
95 return(NX_SUCCESS);
96 }
97
98
99 /**************************************************************************/
100 /* */
101 /* FUNCTION RELEASE */
102 /* */
103 /* nx_link_vlan_get PORTABLE C */
104 /* 6.4.0 */
105 /* AUTHOR */
106 /* */
107 /* Tiejun Zhou, Microsoft Corporation */
108 /* */
109 /* DESCRIPTION */
110 /* */
111 /* This function gets VLAN tag from interface. VLAN tag is comprised */
112 /* the PCP and VLAN ID, encoded in host byte order. See example below. */
113 /* VLAN tag: 0x0002 */
114 /* PCP: 0x00 */
115 /* VLAN ID: 0x02 */
116 /* */
117 /* INPUT */
118 /* */
119 /* ip_ptr IP instance pointer */
120 /* interface_index IP Interface Index */
121 /* vlan_tag Return VLAN tag */
122 /* */
123 /* OUTPUT */
124 /* */
125 /* status Completion status */
126 /* */
127 /* CALLS */
128 /* */
129 /* tx_mutex_get Get protection mutex */
130 /* tx_mutex_put Put protection mutex */
131 /* */
132 /* CALLED BY */
133 /* */
134 /* Application Code */
135 /* */
136 /* RELEASE HISTORY */
137 /* */
138 /* DATE NAME DESCRIPTION */
139 /* */
140 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
141 /* */
142 /**************************************************************************/
nx_link_vlan_get(NX_IP * ip_ptr,UINT interface_index,USHORT * vlan_tag)143 UINT nx_link_vlan_get(NX_IP *ip_ptr, UINT interface_index, USHORT *vlan_tag)
144 {
145
146 /* Check for invalid input pointers. */
147 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (vlan_tag == NX_NULL))
148 {
149 return(NX_PTR_ERROR);
150 }
151
152 /* Check for valid interface ID */
153 if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
154 {
155 return(NX_INVALID_INTERFACE);
156 }
157
158 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
159
160 if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_valid)
161 {
162 *vlan_tag = ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_tag;
163 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
164
165 return(NX_SUCCESS);
166 }
167 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
168
169 return(NX_NOT_FOUND);
170 }
171
172
173 /**************************************************************************/
174 /* */
175 /* FUNCTION RELEASE */
176 /* */
177 /* nx_link_vlan_clear PORTABLE C */
178 /* 6.4.0 */
179 /* AUTHOR */
180 /* */
181 /* Tiejun Zhou, Microsoft Corporation */
182 /* */
183 /* DESCRIPTION */
184 /* */
185 /* This function clears VLAN tag from interface. */
186 /* */
187 /* INPUT */
188 /* */
189 /* ip_ptr IP instance pointer */
190 /* interface_index IP Interface Index */
191 /* */
192 /* OUTPUT */
193 /* */
194 /* status Completion status */
195 /* */
196 /* CALLS */
197 /* */
198 /* tx_mutex_get Get protection mutex */
199 /* tx_mutex_put Put protection mutex */
200 /* */
201 /* CALLED BY */
202 /* */
203 /* Application Code */
204 /* */
205 /* RELEASE HISTORY */
206 /* */
207 /* DATE NAME DESCRIPTION */
208 /* */
209 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
210 /* */
211 /**************************************************************************/
nx_link_vlan_clear(NX_IP * ip_ptr,UINT interface_index)212 UINT nx_link_vlan_clear(NX_IP *ip_ptr, UINT interface_index)
213 {
214
215 /* Check for invalid input pointers. */
216 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID))
217 {
218 return(NX_PTR_ERROR);
219 }
220
221 /* Check for valid interface ID */
222 if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
223 {
224 return(NX_INVALID_INTERFACE);
225 }
226
227 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
228
229 ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_tag = 0;
230 ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_valid = NX_FALSE;
231 ip_ptr -> nx_ip_interface[interface_index].nx_interface_parent_ptr = NX_NULL;
232 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
233
234 return(NX_SUCCESS);
235 }
236
237
238 /**************************************************************************/
239 /* */
240 /* FUNCTION RELEASE */
241 /* */
242 /* nx_link_multicast_join PORTABLE C */
243 /* 6.4.0 */
244 /* AUTHOR */
245 /* */
246 /* Tiejun Zhou, Microsoft Corporation */
247 /* */
248 /* DESCRIPTION */
249 /* */
250 /* This function handles the request to join the specified multicast */
251 /* group on a specified network device. */
252 /* */
253 /* INPUT */
254 /* */
255 /* ip_ptr IP instance pointer */
256 /* interface_index Index to the interface */
257 /* physical_address_msw Physical address MSW */
258 /* physical_address_lsw Physical address LSW */
259 /* */
260 /* OUTPUT */
261 /* */
262 /* status Completion status */
263 /* */
264 /* CALLS */
265 /* */
266 /* tx_mutex_get Get protection mutex */
267 /* tx_mutex_put Put protection mutex */
268 /* */
269 /* CALLED BY */
270 /* */
271 /* Application Code */
272 /* */
273 /* RELEASE HISTORY */
274 /* */
275 /* DATE NAME DESCRIPTION */
276 /* */
277 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
278 /* */
279 /**************************************************************************/
nx_link_multicast_join(NX_IP * ip_ptr,UINT interface_index,ULONG physical_address_msw,ULONG physical_address_lsw)280 UINT nx_link_multicast_join(NX_IP *ip_ptr, UINT interface_index,
281 ULONG physical_address_msw, ULONG physical_address_lsw)
282 {
283 NX_IP_DRIVER driver_request;
284
285
286 /* Check for invalid input pointers. */
287 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID))
288 {
289 return(NX_PTR_ERROR);
290 }
291
292 /* Check for interface being valid. */
293 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
294 {
295 return(NX_INVALID_INTERFACE);
296 }
297
298 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
299
300 /* Build driver command to join multicast. */
301 driver_request.nx_ip_driver_ptr = ip_ptr;
302 driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_JOIN;
303 driver_request.nx_ip_driver_physical_address_msw = physical_address_msw;
304 driver_request.nx_ip_driver_physical_address_lsw = physical_address_lsw;
305 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]);
306
307 /* Send out link packet. */
308 (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request);
309 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
310
311 return(driver_request.nx_ip_driver_status);
312 }
313
314
315 /**************************************************************************/
316 /* */
317 /* FUNCTION RELEASE */
318 /* */
319 /* nx_link_multicast_leave PORTABLE C */
320 /* 6.4.0 */
321 /* AUTHOR */
322 /* */
323 /* Tiejun Zhou, Microsoft Corporation */
324 /* */
325 /* DESCRIPTION */
326 /* */
327 /* This function handles the request to leave the specified multicast */
328 /* group on a specified network device. */
329 /* */
330 /* */
331 /* INPUT */
332 /* */
333 /* ip_ptr IP instance pointer */
334 /* interface_index Index to the interface */
335 /* physical_address_msw Physical address MSW */
336 /* physical_address_lsw Physical address LSW */
337 /* */
338 /* OUTPUT */
339 /* */
340 /* status Completion status */
341 /* */
342 /* CALLS */
343 /* */
344 /* tx_mutex_get Get protection mutex */
345 /* tx_mutex_put Put protection mutex */
346 /* */
347 /* CALLED BY */
348 /* */
349 /* Application Code */
350 /* */
351 /* RELEASE HISTORY */
352 /* */
353 /* DATE NAME DESCRIPTION */
354 /* */
355 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
356 /* */
357 /**************************************************************************/
nx_link_multicast_leave(NX_IP * ip_ptr,UINT interface_index,ULONG physical_address_msw,ULONG physical_address_lsw)358 UINT nx_link_multicast_leave(NX_IP *ip_ptr, UINT interface_index,
359 ULONG physical_address_msw, ULONG physical_address_lsw)
360 {
361 NX_IP_DRIVER driver_request;
362
363
364 /* Check for invalid input pointers. */
365 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID))
366 {
367 return(NX_PTR_ERROR);
368 }
369
370 /* Check for interface being valid. */
371 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
372 {
373 return(NX_INVALID_INTERFACE);
374 }
375
376 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
377
378 /* Build driver command to leave multicast. */
379 driver_request.nx_ip_driver_ptr = ip_ptr;
380 driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_LEAVE;
381 driver_request.nx_ip_driver_physical_address_msw = physical_address_msw;
382 driver_request.nx_ip_driver_physical_address_lsw = physical_address_lsw;
383 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]);
384
385 /* Send out link packet. */
386 (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request);
387 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
388
389 return(driver_request.nx_ip_driver_status);
390 }
391
392
393 /**************************************************************************/
394 /* */
395 /* FUNCTION RELEASE */
396 /* */
397 /* nx_link_ethernet_packet_send PORTABLE C */
398 /* 6.4.0 */
399 /* AUTHOR */
400 /* */
401 /* Tiejun Zhou, Microsoft Corporation */
402 /* */
403 /* DESCRIPTION */
404 /* */
405 /* This function sends out a link packet with layer 3 header already */
406 /* constructed or raw packet. Ethernet header will be added in this */
407 /* function. */
408 /* */
409 /* INPUT */
410 /* */
411 /* ip_ptr IP instance pointer */
412 /* interface_index Index to the interface */
413 /* packet_ptr Packet to send */
414 /* physical_address_msw Physical address MSW */
415 /* physical_address_lsw Physical address LSW */
416 /* packet_type Packet type of link layer */
417 /* */
418 /* OUTPUT */
419 /* */
420 /* status Completion status */
421 /* */
422 /* CALLS */
423 /* */
424 /* tx_mutex_get Get protection mutex */
425 /* tx_mutex_put Put protection mutex */
426 /* nx_link_ethernet_header_add Add Ethernet header */
427 /* nx_link_raw_packet_send Send link layer raw packet */
428 /* _nx_packet_transmit_release Release transmit packet */
429 /* */
430 /* CALLED BY */
431 /* */
432 /* Application Code */
433 /* */
434 /* RELEASE HISTORY */
435 /* */
436 /* DATE NAME DESCRIPTION */
437 /* */
438 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
439 /* */
440 /**************************************************************************/
nx_link_ethernet_packet_send(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr,ULONG physical_address_msw,ULONG physical_address_lsw,UINT packet_type)441 UINT nx_link_ethernet_packet_send(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr,
442 ULONG physical_address_msw, ULONG physical_address_lsw, UINT packet_type)
443 {
444 UINT status;
445
446
447 /* Check for invalid input pointers. */
448 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL))
449 {
450 return(NX_PTR_ERROR);
451 }
452
453 /* Check for interface being valid. */
454 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
455 {
456 return(NX_INVALID_INTERFACE);
457 }
458
459 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
460
461 /* Add Ethernet header. */
462 status = nx_link_ethernet_header_add(ip_ptr, interface_index, packet_ptr,
463 physical_address_msw, physical_address_lsw,
464 packet_type);
465 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
466
467 /* Check return status. */
468 if (status)
469 {
470
471 /* Release the packet. */
472 _nx_packet_transmit_release(packet_ptr);
473 return(status);
474 }
475
476 /* Send out the packet. */
477 return(nx_link_raw_packet_send(ip_ptr, interface_index, packet_ptr));
478 }
479
480
481 /**************************************************************************/
482 /* */
483 /* FUNCTION RELEASE */
484 /* */
485 /* nx_link_raw_packet_send PORTABLE C */
486 /* 6.4.0 */
487 /* AUTHOR */
488 /* */
489 /* Tiejun Zhou, Microsoft Corporation */
490 /* */
491 /* DESCRIPTION */
492 /* */
493 /* This function sends out a link packet with layer 2 header already */
494 /* constructed or raw packet. */
495 /* */
496 /* INPUT */
497 /* */
498 /* ip_ptr IP instance pointer */
499 /* interface_index Index to the interface */
500 /* packet_ptr Packet to send */
501 /* */
502 /* OUTPUT */
503 /* */
504 /* status Completion status */
505 /* */
506 /* CALLS */
507 /* */
508 /* tx_mutex_get Get protection mutex */
509 /* tx_mutex_put Put protection mutex */
510 /* */
511 /* CALLED BY */
512 /* */
513 /* Application Code */
514 /* */
515 /* RELEASE HISTORY */
516 /* */
517 /* DATE NAME DESCRIPTION */
518 /* */
519 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
520 /* */
521 /**************************************************************************/
nx_link_raw_packet_send(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr)522 UINT nx_link_raw_packet_send(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr)
523 {
524 NX_IP_DRIVER driver_request;
525
526
527 /* Check for invalid input pointers. */
528 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL))
529 {
530 return(NX_PTR_ERROR);
531 }
532
533 /* Check for interface being valid. */
534 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
535 {
536 return(NX_INVALID_INTERFACE);
537 }
538
539 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
540
541 /* Build driver command to send out raw packet. */
542 driver_request.nx_ip_driver_ptr = ip_ptr;
543 driver_request.nx_ip_driver_command = NX_LINK_RAW_PACKET_SEND;
544 driver_request.nx_ip_driver_packet = packet_ptr;
545 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]);
546
547 /* Send out link packet. */
548 (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request);
549 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
550
551 return(driver_request.nx_ip_driver_status);
552 }
553
554
555 /**************************************************************************/
556 /* */
557 /* FUNCTION RELEASE */
558 /* */
559 /* nx_link_packet_receive_callback_add PORTABLE C */
560 /* 6.4.0 */
561 /* AUTHOR */
562 /* */
563 /* Tiejun Zhou, Microsoft Corporation */
564 /* */
565 /* DESCRIPTION */
566 /* */
567 /* This function adds a receive callback function to specified */
568 /* interface. Multiple callbacks callback functions can be added */
569 /* to each interface. They will be invoked one by one until the packet */
570 /* is consumed. Only packet matching registered packet_type will be */
571 /* passed to callback function. NX_LINK_PACKET_TYPE_ALL can be used */
572 /* to handle all types except TCP/IP ones. */
573 /* */
574 /* Note, only unknown packet type is passed to callback functions. */
575 /* TCP/IP packet will be received by internal function directly. */
576 /* */
577 /* INPUT */
578 /* */
579 /* ip_ptr IP instance pointer */
580 /* interface_index Index to the interface */
581 /* queue_ptr Pointer to queue instance */
582 /* packet_type Packet type to be handled */
583 /* callback_ptr Pointer to callback function */
584 /* context Pointer to context */
585 /* */
586 /* OUTPUT */
587 /* */
588 /* status Completion status */
589 /* */
590 /* CALLS */
591 /* */
592 /* tx_mutex_get Get protection mutex */
593 /* tx_mutex_put Put protection mutex */
594 /* */
595 /* CALLED BY */
596 /* */
597 /* Application Code */
598 /* */
599 /* RELEASE HISTORY */
600 /* */
601 /* DATE NAME DESCRIPTION */
602 /* */
603 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
604 /* */
605 /**************************************************************************/
nx_link_packet_receive_callback_add(NX_IP * ip_ptr,UINT interface_index,NX_LINK_RECEIVE_QUEUE * queue_ptr,UINT packet_type,nx_link_packet_receive_callback * callback_ptr,VOID * context)606 UINT nx_link_packet_receive_callback_add(NX_IP *ip_ptr, UINT interface_index, NX_LINK_RECEIVE_QUEUE *queue_ptr,
607 UINT packet_type, nx_link_packet_receive_callback *callback_ptr, VOID *context)
608 {
609 NX_INTERFACE *interface_ptr;
610
611 /* Check for invalid input pointers. */
612 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
613 (queue_ptr == NX_NULL) || (callback_ptr == NX_NULL))
614 {
615 return(NX_PTR_ERROR);
616 }
617
618 /* Check for interface being valid. */
619 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
620 {
621 return(NX_INVALID_INTERFACE);
622 }
623
624 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
625 interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]);
626
627 /* Initialize receive queue. */
628 queue_ptr -> packet_type = (USHORT)(packet_type & 0xFFFF);
629 queue_ptr -> context = context;
630 queue_ptr -> callback = callback_ptr;
631
632 /* Add receive queue to interface. */
633 if (interface_ptr -> nx_interface_link_receive_queue_head)
634 {
635
636 /* Add to the tail. */
637 queue_ptr -> previous_ptr = interface_ptr -> nx_interface_link_receive_queue_head -> previous_ptr;
638 interface_ptr -> nx_interface_link_receive_queue_head -> previous_ptr -> next_ptr = queue_ptr;
639 }
640 else
641 {
642
643 /* Queue is empty. Add to the head. */
644 queue_ptr -> previous_ptr = queue_ptr;
645 interface_ptr -> nx_interface_link_receive_queue_head = queue_ptr;
646 }
647 queue_ptr -> next_ptr = interface_ptr -> nx_interface_link_receive_queue_head;
648 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
649
650 return(NX_SUCCESS);
651 }
652
653
654 /**************************************************************************/
655 /* */
656 /* FUNCTION RELEASE */
657 /* */
658 /* nx_link_packet_receive_callback_remove PORTABLE C */
659 /* 6.4.0 */
660 /* AUTHOR */
661 /* */
662 /* Tiejun Zhou, Microsoft Corporation */
663 /* */
664 /* DESCRIPTION */
665 /* */
666 /* This function removes a receive callback function to specified */
667 /* interface. */
668 /* */
669 /* INPUT */
670 /* */
671 /* ip_ptr IP instance pointer */
672 /* interface_index Index to the interface */
673 /* queue_ptr Pointer to queue instance */
674 /* */
675 /* OUTPUT */
676 /* */
677 /* status Completion status */
678 /* */
679 /* CALLS */
680 /* */
681 /* tx_mutex_get Get protection mutex */
682 /* tx_mutex_put Put protection mutex */
683 /* */
684 /* CALLED BY */
685 /* */
686 /* Application Code */
687 /* */
688 /* RELEASE HISTORY */
689 /* */
690 /* DATE NAME DESCRIPTION */
691 /* */
692 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
693 /* */
694 /**************************************************************************/
nx_link_packet_receive_callback_remove(NX_IP * ip_ptr,UINT interface_index,NX_LINK_RECEIVE_QUEUE * queue_ptr)695 UINT nx_link_packet_receive_callback_remove(NX_IP *ip_ptr, UINT interface_index, NX_LINK_RECEIVE_QUEUE *queue_ptr)
696 {
697 NX_INTERFACE *interface_ptr;
698
699 /* Check for invalid input pointers. */
700 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (queue_ptr == NX_NULL))
701 {
702 return(NX_PTR_ERROR);
703 }
704
705 /* Check for interface being valid. */
706 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
707 {
708 return(NX_INVALID_INTERFACE);
709 }
710
711 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
712 interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]);
713
714 if (queue_ptr -> next_ptr == queue_ptr)
715 {
716
717 /* This is the only entry in the queue. */
718 interface_ptr -> nx_interface_link_receive_queue_head = NX_NULL;
719 }
720 else
721 {
722
723 /* Queue is not empty. */
724 queue_ptr -> previous_ptr -> next_ptr = queue_ptr -> next_ptr;
725 queue_ptr -> next_ptr -> previous_ptr = queue_ptr -> previous_ptr;
726
727 if (interface_ptr -> nx_interface_link_receive_queue_head == queue_ptr)
728 {
729
730 /* Remove from the head. */
731 interface_ptr -> nx_interface_link_receive_queue_head = queue_ptr -> next_ptr;
732 }
733 }
734 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
735
736 return(NX_SUCCESS);
737 }
738
739
740 /**************************************************************************/
741 /* */
742 /* FUNCTION RELEASE */
743 /* */
744 /* nx_link_ethernet_header_parse PORTABLE C */
745 /* 6.4.0 */
746 /* AUTHOR */
747 /* */
748 /* Tiejun Zhou, Microsoft Corporation */
749 /* */
750 /* DESCRIPTION */
751 /* */
752 /* This function parses Ethernet packet and return each file of header.*/
753 /* */
754 /* INPUT */
755 /* */
756 /* packet_ptr Packet to parse header */
757 /* destination_msb Destination address MSW */
758 /* destination_lsb Destination address LSW */
759 /* source_msb Source address MSW */
760 /* source_lsb Source address LSW */
761 /* ether_type Ethernet type */
762 /* vlan_tag VLAN tag */
763 /* vlan_tag_valid Contain VLAN tag or not */
764 /* header_size Size of Ethernet header */
765 /* */
766 /* OUTPUT */
767 /* */
768 /* status Completion status */
769 /* */
770 /* CALLS */
771 /* */
772 /* None */
773 /* */
774 /* CALLED BY */
775 /* */
776 /* Application Code */
777 /* nx_link_ethernet_packet_received Process received packet */
778 /* */
779 /* RELEASE HISTORY */
780 /* */
781 /* DATE NAME DESCRIPTION */
782 /* */
783 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
784 /* */
785 /**************************************************************************/
nx_link_ethernet_header_parse(NX_PACKET * packet_ptr,ULONG * destination_msb,ULONG * destination_lsb,ULONG * source_msb,ULONG * source_lsb,USHORT * ether_type,USHORT * vlan_tag,UCHAR * vlan_tag_valid,UINT * header_size)786 UINT nx_link_ethernet_header_parse(NX_PACKET *packet_ptr, ULONG *destination_msb, ULONG *destination_lsb,
787 ULONG *source_msb, ULONG *source_lsb, USHORT *ether_type, USHORT *vlan_tag,
788 UCHAR *vlan_tag_valid, UINT *header_size)
789 {
790 UCHAR *data_ptr = packet_ptr -> nx_packet_prepend_ptr;
791
792 /* Get destination address. */
793 if (destination_msb && destination_lsb)
794 {
795 *destination_msb = (ULONG)((data_ptr[0] << 8) | data_ptr[1]);
796 *destination_lsb = (ULONG)((data_ptr[2] << 24) | (data_ptr[3] << 16) | (data_ptr[4] << 8) | data_ptr[5]);
797 }
798
799 /* Get source address. */
800 if (source_msb && source_lsb)
801 {
802 *source_msb = (ULONG)((data_ptr[6] << 8) | data_ptr[7]);
803 *source_lsb = (ULONG)((data_ptr[8] << 24) | (data_ptr[9] << 16) | (data_ptr[10] << 8) | data_ptr[11]);
804 }
805
806 /* Check VLAN tag. */
807 if (((data_ptr[12] << 8) | data_ptr[13]) == NX_LINK_ETHERNET_TPID)
808 {
809
810 /* VLAN tag is present. */
811 if (vlan_tag)
812 {
813
814 /* Get VLAN tag. */
815 *vlan_tag = (USHORT)((data_ptr[14] << 8) | data_ptr[15]);
816 }
817
818 if (vlan_tag_valid)
819 {
820 *vlan_tag_valid = NX_TRUE;
821 }
822
823 /* Get ethernet type. */
824 if (ether_type)
825 {
826 *ether_type = (USHORT)((data_ptr[16] << 8) | data_ptr[17]);
827 }
828
829 if (header_size)
830 {
831 *header_size = NX_LINK_ETHERNET_HEADER_SIZE + NX_LINK_VLAN_HEADER_SIZE;
832 }
833 }
834 else
835 {
836 if (vlan_tag)
837 {
838
839 /* Reset VLAN tag. */
840 *vlan_tag = 0;
841 }
842
843 if (vlan_tag_valid)
844 {
845 *vlan_tag_valid = NX_FALSE;
846 }
847
848 /* Get ethernet type. */
849 if (ether_type)
850 {
851 *ether_type = (USHORT)((data_ptr[12] << 8) | data_ptr[13]);
852 }
853
854 if (header_size)
855 {
856 *header_size = NX_LINK_ETHERNET_HEADER_SIZE;
857 }
858 }
859 return(NX_SUCCESS);
860 }
861
862
863 /**************************************************************************/
864 /* */
865 /* FUNCTION RELEASE */
866 /* */
867 /* nx_link_ethernet_header_add PORTABLE C */
868 /* 6.4.0 */
869 /* AUTHOR */
870 /* */
871 /* Tiejun Zhou, Microsoft Corporation */
872 /* */
873 /* DESCRIPTION */
874 /* */
875 /* This function adds Ethernet header to packet. If VLAN tag is valid */
876 /* in current interface, it will be added to Ethernet header. */
877 /* */
878 /* INPUT */
879 /* */
880 /* ip_ptr IP instance pointer */
881 /* interface_index Index to the interface */
882 /* packet_ptr Packet to send */
883 /* physical_address_msw Physical address MSW */
884 /* physical_address_lsw Physical address LSW */
885 /* packet_type Packet type of link layer */
886 /* */
887 /* OUTPUT */
888 /* */
889 /* status Completion status */
890 /* */
891 /* CALLS */
892 /* */
893 /* None */
894 /* */
895 /* CALLED BY */
896 /* */
897 /* nx_link_ethernet_packet_send Send Ethernet packet */
898 /* */
899 /* RELEASE HISTORY */
900 /* */
901 /* DATE NAME DESCRIPTION */
902 /* */
903 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
904 /* */
905 /**************************************************************************/
nx_link_ethernet_header_add(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr,ULONG physical_address_msw,ULONG physical_address_lsw,UINT packet_type)906 UINT nx_link_ethernet_header_add(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr,
907 ULONG physical_address_msw, ULONG physical_address_lsw, UINT packet_type)
908 {
909 ULONG header_length;
910 ULONG *ethernet_frame_ptr;
911 NX_INTERFACE *interface_ptr;
912 USHORT vlan_tag;
913
914 interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]);
915
916 /* Calculate the header length. */
917 if (interface_ptr -> nx_interface_vlan_valid)
918 {
919 header_length = NX_LINK_ETHERNET_HEADER_SIZE + NX_LINK_VLAN_HEADER_SIZE;
920 }
921 else
922 {
923 header_length = NX_LINK_ETHERNET_HEADER_SIZE;
924 }
925
926 /* Check available space in packet. */
927 if ((ULONG)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < header_length)
928 {
929
930 /* Not enough space in packet. */
931 return(NX_PACKET_OFFSET_ERROR);
932 }
933
934 /* Adjust packet pointer and length. */
935 packet_ptr -> nx_packet_prepend_ptr -= header_length;
936 packet_ptr -> nx_packet_length += header_length;
937
938 /* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2
939 bytes to get 32-bit word alignment. */
940 ethernet_frame_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - 2);
941
942 /* Build the ethernet frame. */
943 *ethernet_frame_ptr = physical_address_msw;
944 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
945 *(++ethernet_frame_ptr) = physical_address_lsw;
946 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
947 *(++ethernet_frame_ptr) = (interface_ptr -> nx_interface_physical_address_msw << 16) |
948 (interface_ptr -> nx_interface_physical_address_lsw >> 16);
949 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
950 *(++ethernet_frame_ptr) = (interface_ptr -> nx_interface_physical_address_lsw << 16);
951 if (interface_ptr -> nx_interface_vlan_valid)
952 {
953 /* Build VLAN tag. */
954 *(ethernet_frame_ptr) |= NX_LINK_ETHERNET_TPID;
955 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
956
957 if (packet_ptr -> nx_packet_vlan_priority != NX_VLAN_PRIORITY_INVALID)
958 {
959 vlan_tag = (USHORT)((interface_ptr -> nx_interface_vlan_tag & (~NX_LINK_VLAN_PCP_MASK)) |
960 ((packet_ptr -> nx_packet_vlan_priority << NX_LINK_VLAN_PCP_SHIFT) & NX_LINK_VLAN_PCP_MASK));
961 }
962 else
963 {
964 vlan_tag = interface_ptr -> nx_interface_vlan_tag;
965 }
966
967 *(++ethernet_frame_ptr) = (ULONG)(vlan_tag << 16);
968 }
969 *(ethernet_frame_ptr) |= (USHORT)(packet_type & 0xFFFF);
970 NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
971
972 return(NX_SUCCESS);
973 }
974
975
976 /**************************************************************************/
977 /* */
978 /* FUNCTION RELEASE */
979 /* */
980 /* nx_link_packet_transmitted PORTABLE C */
981 /* 6.4.0 */
982 /* AUTHOR */
983 /* */
984 /* Tiejun Zhou, Microsoft Corporation */
985 /* */
986 /* DESCRIPTION */
987 /* */
988 /* This function handles event when a packet is transmitted from */
989 /* network driver. Packet will be released. */
990 /* */
991 /* INPUT */
992 /* */
993 /* ip_ptr IP instance pointer */
994 /* interface_index Index to the interface */
995 /* packet_ptr Pointer to packet */
996 /* time_ptr Timestamp of packet */
997 /* transmitted (not used) */
998 /* */
999 /* OUTPUT */
1000 /* */
1001 /* status Completion status */
1002 /* */
1003 /* CALLS */
1004 /* */
1005 /* tx_mutex_get Get protection mutex */
1006 /* tx_mutex_put Put protection mutex */
1007 /* _nx_packet_transmit_release Release transmit packet */
1008 /* */
1009 /* CALLED BY */
1010 /* */
1011 /* Network driver */
1012 /* */
1013 /* RELEASE HISTORY */
1014 /* */
1015 /* DATE NAME DESCRIPTION */
1016 /* */
1017 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1018 /* */
1019 /**************************************************************************/
nx_link_packet_transmitted(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr,NX_LINK_TIME * time_ptr)1020 VOID nx_link_packet_transmitted(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr, NX_LINK_TIME *time_ptr)
1021 {
1022 ULONG header_length;
1023
1024 NX_PARAMETER_NOT_USED(time_ptr);
1025
1026 /* Check for invalid input pointers. */
1027 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL))
1028 {
1029 return;
1030 }
1031
1032 /* Check for interface being valid. */
1033 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
1034 {
1035 return;
1036 }
1037
1038 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
1039
1040 /* Calculate the header length. */
1041 if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_vlan_valid)
1042 {
1043 header_length = NX_LINK_ETHERNET_HEADER_SIZE + NX_LINK_VLAN_HEADER_SIZE;
1044 }
1045 else
1046 {
1047 header_length = NX_LINK_ETHERNET_HEADER_SIZE;
1048 }
1049 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1050
1051 /* Remove the Ethernet header. */
1052 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_length;
1053
1054 /* Adjust the packet length. */
1055 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_length;
1056
1057 /* Release the packet. */
1058 _nx_packet_transmit_release(packet_ptr);
1059 }
1060
1061
1062 /**************************************************************************/
1063 /* */
1064 /* FUNCTION RELEASE */
1065 /* */
1066 /* nx_link_ethernet_packet_received PORTABLE C */
1067 /* 6.4.0 */
1068 /* AUTHOR */
1069 /* */
1070 /* Tiejun Zhou, Microsoft Corporation */
1071 /* */
1072 /* DESCRIPTION */
1073 /* */
1074 /* This function handles event when an Ethernet packet is received */
1075 /* from network driver. The packet will be dispatch to VLAN interface */
1076 /* when VLAN tag is found. For registered raw packet type, the packet */
1077 /* will be passed to callback functions for further processing. */
1078 /* */
1079 /* INPUT */
1080 /* */
1081 /* ip_ptr IP instance pointer */
1082 /* interface_index Index to the interface */
1083 /* packet_ptr Pointer to packet */
1084 /* time_ptr Timestamp of packet received */
1085 /* */
1086 /* OUTPUT */
1087 /* */
1088 /* status Completion status */
1089 /* */
1090 /* CALLS */
1091 /* */
1092 /* _nx_packet_release Release packet */
1093 /* nx_link_ethernet_header_parse Parse Ethernet header */
1094 /* _nx_ip_packet_deferred_receive IP packet receive */
1095 /* _nx_arp_packet_deferred_receive ARP packet receive */
1096 /* _nx_rarp_packet_deferred_receive RARP packet receive */
1097 /* */
1098 /* CALLED BY */
1099 /* */
1100 /* Network driver */
1101 /* */
1102 /* RELEASE HISTORY */
1103 /* */
1104 /* DATE NAME DESCRIPTION */
1105 /* */
1106 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1107 /* */
1108 /**************************************************************************/
nx_link_ethernet_packet_received(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr,NX_LINK_TIME * time_ptr)1109 VOID nx_link_ethernet_packet_received(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr,
1110 NX_LINK_TIME *time_ptr)
1111 {
1112 USHORT packet_type;
1113 UINT header_size;
1114 USHORT vlan_tag;
1115 UCHAR vlan_tag_valid;
1116 ULONG physical_address_msw;
1117 ULONG physical_address_lsw;
1118 UINT i;
1119 NX_INTERFACE *interface_ptr;
1120 NX_LINK_RECEIVE_QUEUE *queue_ptr;
1121
1122 /* Check for invalid input pointers. */
1123 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL))
1124 {
1125 _nx_packet_release(packet_ptr);
1126 return;
1127 }
1128
1129 /* Check for interface being valid. */
1130 if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)
1131 {
1132 _nx_packet_release(packet_ptr);
1133 return;
1134 }
1135
1136 interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]);
1137 queue_ptr = interface_ptr -> nx_interface_link_receive_queue_head;
1138
1139 /* Get packet type and header size. */
1140 nx_link_ethernet_header_parse(packet_ptr, &physical_address_msw, &physical_address_lsw,
1141 NULL, NULL, &packet_type, &vlan_tag, &vlan_tag_valid, &header_size);
1142
1143 /* Match VLAN ID. */
1144 if (vlan_tag_valid == NX_FALSE)
1145 {
1146
1147 /* No VLAN tag for incoming packet. */
1148 if (interface_ptr -> nx_interface_vlan_valid)
1149 {
1150
1151 /* Current interface is tagged. */
1152 /* Try to redirect packet to parent interface. */
1153 if ((interface_ptr -> nx_interface_parent_ptr) &&
1154 (interface_ptr -> nx_interface_parent_ptr -> nx_interface_vlan_valid == NX_FALSE))
1155 {
1156
1157 /* This packet is actually for parent interface. */
1158 interface_ptr = interface_ptr -> nx_interface_parent_ptr;
1159 interface_index = interface_ptr -> nx_interface_index;
1160 }
1161 else
1162 {
1163
1164 /* Drop the packet. */
1165 _nx_packet_release(packet_ptr);
1166
1167 return;
1168 }
1169 }
1170 }
1171 else
1172 {
1173
1174 /* VLAN tag is found in incoming packet. */
1175 /* Match VLAN ID on current interface first. */
1176 if (interface_ptr -> nx_interface_vlan_valid)
1177 {
1178 if ((vlan_tag & NX_LINK_VLAN_ID_MASK) != (interface_ptr -> nx_interface_vlan_tag & NX_LINK_VLAN_ID_MASK))
1179 {
1180
1181 /* Drop the packet. */
1182 _nx_packet_release(packet_ptr);
1183
1184 return;
1185 }
1186 }
1187 else
1188 {
1189
1190 /* This packet may be received from child VLAN interface. */
1191 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
1192 {
1193 if (ip_ptr -> nx_ip_interface[i].nx_interface_parent_ptr != interface_ptr)
1194 {
1195
1196 /* This is not one of current child interface. */
1197 continue;
1198 }
1199
1200 if ((vlan_tag & NX_LINK_VLAN_ID_MASK) ==
1201 (ip_ptr -> nx_ip_interface[i].nx_interface_vlan_tag & NX_LINK_VLAN_ID_MASK))
1202 {
1203
1204 /* This packet is actually for current child interface. */
1205 interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
1206 interface_index = i;
1207 break;
1208 }
1209 }
1210
1211 if (i == NX_MAX_PHYSICAL_INTERFACES)
1212 {
1213
1214 /* Drop the packet. */
1215 _nx_packet_release(packet_ptr);
1216
1217 return;
1218 }
1219 }
1220 }
1221
1222 /* Setup interface pointer. */
1223 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr;
1224
1225 /* Route the incoming packet according to its ethernet type. */
1226 /* The RAM driver accepts both IPv4 and IPv6 frames. */
1227 if ((packet_type == NX_LINK_ETHERNET_IP) || (packet_type == NX_LINK_ETHERNET_IPV6))
1228 {
1229
1230 /* Store the PTP timestamp at the start of the packet (replacing Ethernet header)
1231 in case of PTP over UDP. */
1232 if (time_ptr)
1233 {
1234 ((ULONG *)packet_ptr -> nx_packet_data_start)[0] = time_ptr -> nano_second;
1235 ((ULONG *)packet_ptr -> nx_packet_data_start)[1] = time_ptr -> second_low;
1236 ((ULONG *)packet_ptr -> nx_packet_data_start)[2] = time_ptr -> second_high;
1237 }
1238
1239 /* Note: The length reported by some Ethernet hardware includes bytes after the packet
1240 as well as the Ethernet header. In some cases, the actual packet length after the
1241 Ethernet header should be derived from the length in the IP header (lower 16 bits of
1242 the first 32-bit word). */
1243
1244 /* Clean off the Ethernet header. */
1245 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_size;
1246
1247 /* Adjust the packet length. */
1248 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_size;
1249
1250 /* Route to the ip receive function. */
1251 _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
1252 }
1253 #ifndef NX_DISABLE_IPV4
1254 else if (packet_type == NX_LINK_ETHERNET_ARP)
1255 {
1256
1257 /* Clean off the Ethernet header. */
1258 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_size;
1259
1260 /* Adjust the packet length. */
1261 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_size;
1262
1263 /* Route to the ARP receive function. */
1264 _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
1265 }
1266 else if (packet_type == NX_LINK_ETHERNET_RARP)
1267 {
1268
1269 /* Clean off the Ethernet header. */
1270 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_size;
1271
1272 /* Adjust the packet length. */
1273 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_size;
1274
1275 /* Route to the RARP receive function. */
1276 _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
1277 }
1278 #endif /* !NX_DISABLE_IPV4 */
1279 else
1280 {
1281
1282 /* Store the PTP timestamp at the start of the packet (replacing Ethernet header)
1283 in case of PTP over ETH. */
1284 if ((packet_type == NX_LINK_ETHERNET_PTP) && (time_ptr != NX_NULL))
1285 {
1286 ((ULONG *)packet_ptr -> nx_packet_data_start)[0] = time_ptr -> nano_second;
1287 ((ULONG *)packet_ptr -> nx_packet_data_start)[1] = time_ptr -> second_low;
1288 ((ULONG *)packet_ptr -> nx_packet_data_start)[2] = time_ptr -> second_high;
1289 }
1290
1291 queue_ptr = interface_ptr -> nx_interface_link_receive_queue_head;
1292 while (queue_ptr)
1293 {
1294
1295 /* Match packet type. */
1296 if ((queue_ptr -> packet_type == packet_type) || (queue_ptr -> packet_type == NX_LINK_PACKET_TYPE_ALL))
1297 {
1298
1299 /* Call the packet receive handler. */
1300 if (queue_ptr -> callback(ip_ptr, interface_index, packet_ptr,
1301 physical_address_msw, physical_address_lsw,
1302 packet_type, header_size, queue_ptr -> context, time_ptr) == NX_SUCCESS)
1303 {
1304
1305 /* Packet was consumed. */
1306 return;
1307 }
1308 }
1309
1310 /* Move to the next queue. */
1311 queue_ptr = queue_ptr -> next_ptr;
1312 if (queue_ptr == interface_ptr -> nx_interface_link_receive_queue_head)
1313 {
1314
1315 /* We have reached the end of the queue. */
1316 break;
1317 }
1318 }
1319
1320 /* Invalid ethernet header... release the packet. */
1321 _nx_packet_release(packet_ptr);
1322 }
1323 }
1324
1325
1326 /**************************************************************************/
1327 /* */
1328 /* FUNCTION RELEASE */
1329 /* */
1330 /* nx_link_vlan_interface_create PORTABLE C */
1331 /* 6.4.0 */
1332 /* AUTHOR */
1333 /* */
1334 /* Tiejun Zhou, Microsoft Corporation */
1335 /* */
1336 /* DESCRIPTION */
1337 /* */
1338 /* This function creates a VLAN interface and bind to parent */
1339 /* interface. Any packet received from parent interface will be */
1340 /* dispatched to right interface according to the match of VLAN ID. */
1341 /* VLAN tag is comprised the PCP and VLAN ID, encoded in host byte */
1342 /* order. See example below. */
1343 /* VLAN tag: 0x0002 */
1344 /* PCP: 0x00 */
1345 /* VLAN ID: 0x02 */
1346 /* When the priority of a packet is set either to packet directly or */
1347 /* through the socket, the PCP from VLAN tag is override. */
1348 /* */
1349 /* INPUT */
1350 /* */
1351 /* ip_ptr IP instance pointer */
1352 /* interface_name Interface name */
1353 /* ip_address IPv4 address */
1354 /* network_mask IPv4 network mask */
1355 /* vlan_tag VLAN tag to set */
1356 /* parent_interface_index Index of parent interface */
1357 /* interface_index_ptr Index of created interface */
1358 /* */
1359 /* OUTPUT */
1360 /* */
1361 /* status Completion status */
1362 /* */
1363 /* CALLS */
1364 /* */
1365 /* tx_mutex_get Get protection mutex */
1366 /* tx_mutex_put Put protection mutex */
1367 /* */
1368 /* CALLED BY */
1369 /* */
1370 /* Application Code */
1371 /* */
1372 /* RELEASE HISTORY */
1373 /* */
1374 /* DATE NAME DESCRIPTION */
1375 /* */
1376 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1377 /* */
1378 /**************************************************************************/
nx_link_vlan_interface_create(NX_IP * ip_ptr,CHAR * interface_name,ULONG ip_address,ULONG network_mask,UINT vlan_tag,UINT parent_interface_index,UINT * interface_index_ptr)1379 UINT nx_link_vlan_interface_create(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask,
1380 UINT vlan_tag, UINT parent_interface_index, UINT *interface_index_ptr)
1381 {
1382 UINT i;
1383 NX_INTERFACE *interface_ptr = NX_NULL;
1384
1385 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
1386 #ifdef NX_DISABLE_IPV4
1387 NX_PARAMETER_NOT_USED(ip_address);
1388 NX_PARAMETER_NOT_USED(network_mask);
1389 #else
1390 /* Perform duplicate address detection. */
1391 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
1392 {
1393 if ((ip_ptr -> nx_ip_interface[i].nx_interface_ip_address == ip_address) &&
1394 (ip_address != 0))
1395 {
1396
1397 /* The IPv4 address already exists. */
1398 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1399 return(NX_DUPLICATED_ENTRY);
1400 }
1401
1402 if ((ip_ptr -> nx_ip_interface[i].nx_interface_vlan_tag & NX_LINK_VLAN_ID_MASK) ==
1403 (vlan_tag & NX_LINK_VLAN_ID_MASK))
1404 {
1405
1406 /* The VLAN already exists, only one PCP for one VLAN ID is supported */
1407 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1408 return(NX_DUPLICATED_ENTRY);
1409 }
1410 }
1411 #endif /* !NX_DISABLE_IPV4 */
1412
1413 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
1414 {
1415
1416 interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
1417
1418 if (!(interface_ptr -> nx_interface_valid))
1419 {
1420
1421 /* Find a valid entry. */
1422 break;
1423 }
1424 }
1425
1426 if (i == NX_MAX_PHYSICAL_INTERFACES)
1427 {
1428
1429 /* No more free entry. return. */
1430 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1431 return(NX_NO_MORE_ENTRIES);
1432 }
1433
1434 if (parent_interface_index >= NX_MAX_PHYSICAL_INTERFACES)
1435 {
1436 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1437 return(NX_INVALID_PARAMETERS);
1438 }
1439
1440 /* Inherit the driver properties from parent interface */
1441 memcpy(interface_ptr, &(ip_ptr -> nx_ip_interface[parent_interface_index]), /* Use case of memcpy is verified. */
1442 sizeof(NX_INTERFACE));
1443
1444 interface_ptr -> nx_interface_parent_ptr = &(ip_ptr -> nx_ip_interface[parent_interface_index]);
1445
1446 *interface_index_ptr = i;
1447
1448 interface_ptr -> nx_interface_index = (UCHAR)i;
1449
1450 /* Mark the entry as valid. */
1451 interface_ptr -> nx_interface_valid = NX_TRUE;
1452
1453 /* Fill in the interface information. */
1454 #ifndef NX_DISABLE_IPV4
1455 interface_ptr -> nx_interface_ip_address = ip_address;
1456 interface_ptr -> nx_interface_ip_network_mask = network_mask;
1457 interface_ptr -> nx_interface_ip_network = ip_address & network_mask;
1458 #endif /* !NX_DISABLE_IPV4 */
1459 interface_ptr -> nx_interface_name = interface_name;
1460 interface_ptr -> nx_interface_vlan_tag = (USHORT)(vlan_tag & 0xFFFF);
1461 interface_ptr -> nx_interface_vlan_valid = NX_TRUE;
1462 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1463
1464 return(NX_SUCCESS);
1465 }
1466
1467
1468 /**************************************************************************/
1469 /* */
1470 /* FUNCTION RELEASE */
1471 /* */
1472 /* nx_link_driver_request_preprocess PORTABLE C */
1473 /* 6.4.0 */
1474 /* AUTHOR */
1475 /* */
1476 /* Tiejun Zhou, Microsoft Corporation */
1477 /* */
1478 /* DESCRIPTION */
1479 /* */
1480 /* This function handles generic driver request. When the packet is */
1481 /* sent through VLAN interface, parent interface will be returned. */
1482 /* */
1483 /* INPUT */
1484 /* */
1485 /* driver_request Pointer to driver request */
1486 /* actual_interface Pointer to actual interface */
1487 /* */
1488 /* OUTPUT */
1489 /* */
1490 /* status Completion status */
1491 /* */
1492 /* CALLS */
1493 /* */
1494 /* _nx_packet_transmit_release Release transmit packet */
1495 /* [nx_interface_link_header_add] Add link layer header */
1496 /* */
1497 /* CALLED BY */
1498 /* */
1499 /* TCP/IP layer */
1500 /* */
1501 /* RELEASE HISTORY */
1502 /* */
1503 /* DATE NAME DESCRIPTION */
1504 /* */
1505 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1506 /* */
1507 /**************************************************************************/
nx_link_driver_request_preprocess(NX_IP_DRIVER * driver_request,NX_INTERFACE ** actual_interface)1508 UINT nx_link_driver_request_preprocess(NX_IP_DRIVER *driver_request, NX_INTERFACE **actual_interface)
1509 {
1510
1511 /* Set actual interface to the one from driver request by default. */
1512 *actual_interface = driver_request -> nx_ip_driver_interface;
1513
1514 if (driver_request -> nx_ip_driver_interface == NX_NULL)
1515 {
1516
1517 /* Unsupported driver request. Let caller handle it. */
1518 return(NX_SUCCESS);
1519 }
1520
1521 if (driver_request -> nx_ip_driver_interface -> nx_interface_parent_ptr == NX_NULL)
1522 {
1523
1524 /* This is a driver request from parent interface. Nothing to do in this function. */
1525 return(NX_SUCCESS);
1526 }
1527
1528 /* This driver request is for VLAN interface. */
1529 *actual_interface = driver_request -> nx_ip_driver_interface -> nx_interface_parent_ptr;
1530
1531 switch (driver_request -> nx_ip_driver_command)
1532 {
1533 case NX_LINK_ARP_SEND: /* fallthrough */
1534 case NX_LINK_ARP_RESPONSE_SEND: /* fallthrough */
1535 case NX_LINK_PACKET_BROADCAST: /* fallthrough */
1536 case NX_LINK_RARP_SEND: /* fallthrough */
1537 case NX_LINK_PACKET_SEND: /* fallthrough */
1538 #ifdef NX_ENABLE_PPPOE
1539 case NX_LINK_PPPOE_DISCOVERY_SEND: /* fallthrough */
1540 case NX_LINK_PPPOE_SESSION_SEND: /* fallthrough */
1541 #endif
1542 case NX_LINK_RAW_PACKET_SEND: /* fallthrough */
1543 case NX_LINK_GET_STATUS: /* fallthrough */
1544 case NX_LINK_GET_SPEED: /* fallthrough */
1545 case NX_LINK_GET_DUPLEX_TYPE: /* fallthrough */
1546 case NX_LINK_GET_ERROR_COUNT: /* fallthrough */
1547 case NX_LINK_GET_RX_COUNT: /* fallthrough */
1548 case NX_LINK_GET_TX_COUNT: /* fallthrough */
1549 case NX_LINK_GET_ALLOC_ERRORS: /* fallthrough */
1550 case NX_INTERFACE_CAPABILITY_GET: /* fallthrough */
1551 case NX_LINK_FACTORY_ADDRESS_GET: /* fallthrough */
1552 case NX_LINK_GET_INTERFACE_TYPE: /* fallthrough */
1553 case NX_LINK_USER_COMMAND:
1554 break;
1555
1556 case NX_LINK_INTERFACE_ATTACH: /* fallthrough */
1557 case NX_LINK_INTERFACE_DETACH: /* fallthrough */
1558 case NX_LINK_INITIALIZE: /* fallthrough */
1559 /* As parent interface is set, the link interface is already initialized */
1560 case NX_LINK_UNINITIALIZE: /* fallthrough */
1561 case NX_LINK_MULTICAST_JOIN: /* fallthrough */
1562 case NX_LINK_MULTICAST_LEAVE:
1563 driver_request -> nx_ip_driver_status = NX_SUCCESS;
1564 return(NX_CONTINUE);
1565
1566 case NX_LINK_ENABLE: /* fallthrough */
1567 case NX_LINK_DISABLE: /* fallthrough */
1568 /* The link status of virtual interface should be same with its parent physical interface */
1569 case NX_LINK_SET_PHYSICAL_ADDRESS: /* fallthrough */
1570 /* Set mac address is not supported for virtual interface */
1571 case NX_LINK_RX_ENABLE: /* fallthrough */
1572 case NX_LINK_RX_DISABLE: /* fallthrough */
1573 /* Directly control RX in driver is not supported for virtual interface */
1574 case NX_LINK_DEFERRED_PROCESSING: /* fallthrough */
1575 case NX_INTERFACE_CAPABILITY_SET: /* fallthrough */
1576 case NX_LINK_6LOWPAN_COMMAND: /* fallthrough */
1577 default:
1578
1579 /* For virtual interface, no need to send the commands to driver layer */
1580 driver_request -> nx_ip_driver_status = NX_UNHANDLED_COMMAND;
1581 return(NX_CONTINUE);
1582 }
1583
1584 return(NX_SUCCESS);
1585 }
1586
1587
1588 /**************************************************************************/
1589 /* */
1590 /* FUNCTION RELEASE */
1591 /* */
1592 /* nx_link_vlan_interface_status_change PORTABLE C */
1593 /* 6.4.0 */
1594 /* AUTHOR */
1595 /* */
1596 /* Tiejun Zhou, Microsoft Corporation */
1597 /* */
1598 /* DESCRIPTION */
1599 /* */
1600 /* This function dispatched link status change event from parent */
1601 /* interface to VLAN interfaces. */
1602 /* */
1603 /* INPUT */
1604 /* */
1605 /* ip_ptr Pointer to IP control block */
1606 /* interface_index Index to the interface */
1607 /* */
1608 /* OUTPUT */
1609 /* */
1610 /* status Completion status */
1611 /* */
1612 /* CALLS */
1613 /* */
1614 /* tx_mutex_get Obtain protection mutex */
1615 /* tx_mutex_put Release protection mutex */
1616 /* [nx_ip_link_status_change_callback] User provided callback */
1617 /* */
1618 /* CALLED BY */
1619 /* */
1620 /* _nx_ip_deferred_link_status_process Process link status event */
1621 /* */
1622 /* RELEASE HISTORY */
1623 /* */
1624 /* DATE NAME DESCRIPTION */
1625 /* */
1626 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1627 /* */
1628 /**************************************************************************/
nx_link_vlan_interface_status_change(NX_IP * ip_ptr,UINT interface_index)1629 void nx_link_vlan_interface_status_change(NX_IP *ip_ptr, UINT interface_index)
1630 {
1631 UINT i;
1632 NX_INTERFACE *nx_interface = NX_NULL;
1633
1634 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
1635 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
1636 {
1637 nx_interface = &(ip_ptr -> nx_ip_interface[i]);
1638
1639 if ((nx_interface -> nx_interface_valid) &&
1640 (nx_interface -> nx_interface_parent_ptr != NX_NULL) &&
1641 (nx_interface -> nx_interface_parent_ptr -> nx_interface_index == interface_index))
1642 {
1643 nx_interface -> nx_interface_link_up = nx_interface -> nx_interface_parent_ptr -> nx_interface_link_up;
1644
1645 /* Reset the flag. */
1646 nx_interface -> nx_interface_link_status_change = NX_FALSE;
1647
1648 /* Invoke the callback function. */
1649 /*lint -e{644} suppress variable might not be initialized, since "link_up" was initialized in nx_interface_link_driver_entry. */
1650 ip_ptr -> nx_ip_link_status_change_callback(ip_ptr, i, nx_interface -> nx_interface_link_up);
1651 }
1652 }
1653 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1654 }
1655 #endif /* NX_ENABLE_VLAN */
1656