1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Internet Protocol (IP)                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "tx_thread.h"
29 #include "nx_ip.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_ip_raw_packet_receive                           PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function retrieves the first packet from the received raw      */
45 /*    packet list and returns it to the caller.  If no packet is present  */
46 /*    the routine may optionally suspend waiting on the list for a        */
47 /*    packet.                                                             */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    ip_ptr                                IP control block pointer      */
52 /*    packet_ptr                            Pointer to return allocated   */
53 /*                                            packet                      */
54 /*    wait_option                           Suspension option             */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    status                                Completion status             */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _tx_thread_system_suspend             Suspend thread                */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
73 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*                                                                        */
76 /**************************************************************************/
_nx_ip_raw_packet_receive(NX_IP * ip_ptr,NX_PACKET ** packet_ptr,ULONG wait_option)77 UINT  _nx_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, ULONG wait_option)
78 {
79 TX_INTERRUPT_SAVE_AREA
80 
81 UINT                   status;      /* Return status           */
82 TX_THREAD             *thread_ptr;  /* Working thread pointer  */
83 NX_PACKET             *work_ptr;    /* Working packet pointer  */
84 
85 #ifdef TX_ENABLE_EVENT_TRACE
86 TX_TRACE_BUFFER_ENTRY *trace_event;
87 ULONG                  trace_timestamp;
88 #endif
89 
90 
91     /* If trace is enabled, insert this event into the trace buffer.  */
92     NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_RECEIVE, ip_ptr, 0, wait_option, 0, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp);
93 
94     /* Disable interrupts to get a packet from the pool.  */
95     TX_DISABLE
96 
97     /* Determine if there is an available packet.  */
98     if (ip_ptr -> nx_ip_raw_received_packet_count)
99     {
100 
101         /* Yes, a packet is available.  Decrement the raw packet receive count.  */
102         ip_ptr -> nx_ip_raw_received_packet_count--;
103 
104         /* Pickup the first raw packet pointer.  */
105         work_ptr =  ip_ptr -> nx_ip_raw_received_packet_head;
106 
107         /* Modify the available list to point at the next packet in the pool. */
108         ip_ptr -> nx_ip_raw_received_packet_head =  work_ptr -> nx_packet_queue_next;
109 
110         /* Determine if the tail pointer points to the same packet.  */
111         if (ip_ptr -> nx_ip_raw_received_packet_tail == work_ptr)
112         {
113 
114             /* Yes, just set tail pointer to NULL since we must be at the end of the queue.  */
115             ip_ptr -> nx_ip_raw_received_packet_tail =  NX_NULL;
116         }
117 
118         /* Place the raw packet pointer in the return destination.  */
119         *packet_ptr =  work_ptr;
120 
121         /* Update the trace event with the status.  */
122         NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_RAW_PACKET_RECEIVE, 0, *packet_ptr, 0, 0);
123 
124         /* Set status to success.  */
125         status =  NX_SUCCESS;
126     }
127     else
128     {
129 
130         /* Determine if the request specifies suspension.  */
131         if (wait_option)
132         {
133 
134             /* Prepare for suspension of this thread.  */
135 
136             /* Pickup thread pointer.  */
137             thread_ptr =  _tx_thread_current_ptr;
138 
139             /* Setup cleanup routine pointer.  */
140             thread_ptr -> tx_thread_suspend_cleanup =  _nx_ip_raw_packet_cleanup;
141 
142             /* Setup cleanup information, i.e. this IP control
143                block.  */
144             thread_ptr -> tx_thread_suspend_control_block =  (void *)ip_ptr;
145 
146             /* Save the return packet pointer address as well.  */
147             thread_ptr -> tx_thread_additional_suspend_info =  (void *)packet_ptr;
148 
149             /* Setup suspension list.  */
150             if (ip_ptr -> nx_ip_raw_packet_suspension_list)
151             {
152 
153                 /* This list is not NULL, add current thread to the end. */
154                 thread_ptr -> tx_thread_suspended_next =
155                     ip_ptr -> nx_ip_raw_packet_suspension_list;
156                 thread_ptr -> tx_thread_suspended_previous =
157                     (ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous;
158                 ((ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr;
159                 (ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous =   thread_ptr;
160             }
161             else
162             {
163 
164                 /* No other threads are suspended.  Setup the head pointer and
165                    just setup this threads pointers to itself.  */
166                 ip_ptr -> nx_ip_raw_packet_suspension_list =    thread_ptr;
167                 thread_ptr -> tx_thread_suspended_next =        thread_ptr;
168                 thread_ptr -> tx_thread_suspended_previous =    thread_ptr;
169             }
170 
171             /* Increment the suspended thread count.  */
172             ip_ptr -> nx_ip_raw_packet_suspended_count++;
173 
174             /* Set the state to suspended.  */
175             thread_ptr -> tx_thread_state =  TX_TCP_IP;
176 
177             /* Set the suspending flag.  */
178             thread_ptr -> tx_thread_suspending =  TX_TRUE;
179 
180             /* Temporarily disable preemption.  */
181             _tx_thread_preempt_disable++;
182 
183             /* Save the timeout value.  */
184             thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  wait_option;
185 
186             /* Restore interrupts.  */
187             TX_RESTORE
188 
189             /* Call actual thread suspension routine.  */
190             _tx_thread_system_suspend(thread_ptr);
191 
192             /* Update the trace event with the status.  */
193             NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_RAW_PACKET_RECEIVE, 0, *packet_ptr, 0, 0);
194 
195             /* Return the completion status.  */
196             return(thread_ptr -> tx_thread_suspend_status);
197         }
198         else
199         {
200 
201             /* Immediate return, return error completion.  */
202             status =  NX_NO_PACKET;
203         }
204     }
205 
206     /* Restore interrupts.  */
207     TX_RESTORE
208 
209     /* Return completion status.  */
210     return(status);
211 }
212 
213