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