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 /**   Packet Pool Management (Packet)                                     */
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_packet.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_packet_release                                  PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function releases the packet chain back to the appropriate     */
45 /*    packet pools.                                                       */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    packet_ptr                            Pointer of packet to release  */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    status                                Completion status             */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _tx_thread_system_resume              Resume suspended thread       */
58 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    Application Code                                                    */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
68 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
69 /*                                            resulting in version 6.1    */
70 /*                                                                        */
71 /**************************************************************************/
_nx_packet_release(NX_PACKET * packet_ptr)72 UINT  _nx_packet_release(NX_PACKET *packet_ptr)
73 {
74 
75 TX_INTERRUPT_SAVE_AREA
76 
77 NX_PACKET_POOL *pool_ptr;       /* Pool pointer            */
78 TX_THREAD      *thread_ptr;     /* Working thread pointer  */
79 #ifndef NX_DISABLE_PACKET_CHAIN
80 NX_PACKET      *next_packet;    /* Working block pointer   */
81 #endif /* NX_DISABLE_PACKET_CHAIN */
82 
83 
84     /* If trace is enabled, insert this event into the trace buffer.  */
85     NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_RELEASE, packet_ptr, packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next, (packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_available, 0, NX_TRACE_PACKET_EVENTS, 0, 0);
86 
87 #ifndef NX_DISABLE_PACKET_CHAIN
88     /* Loop to free all packets chained together, not assuming they are
89        from the same pool.  */
90     while (packet_ptr)
91     {
92 #endif /* NX_DISABLE_PACKET_CHAIN */
93 
94         /* Check to see if the packet is releasable.  */
95         /*lint -e{923} suppress cast of ULONG to pointer.  */
96         if (packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))
97         {
98 
99 #ifndef NX_DISABLE_PACKET_INFO
100             /* Pickup the pool pointer.  */
101             pool_ptr =  packet_ptr -> nx_packet_pool_owner;
102 
103             /* Check for a good pool pointer...  error must be the packet!  */
104             if ((pool_ptr) && (pool_ptr -> nx_packet_pool_id == NX_PACKET_POOL_ID))
105             {
106 
107                 /* Increment the packet pool invalid release error count.  */
108                 pool_ptr -> nx_packet_pool_invalid_releases++;
109             }
110 #endif
111 
112             /* Return an error indicating the packet could not be released.  */
113             return(NX_PTR_ERROR);
114         }
115         /* End of packet check.  */
116 
117 #ifndef NX_DISABLE_PACKET_CHAIN
118         /* Pickup the next packet. */
119         next_packet =  packet_ptr -> nx_packet_next;
120 #endif /* NX_DISABLE_PACKET_CHAIN */
121 
122         /* Add debug information. */
123         NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
124 
125         /* Disable interrupts to put this packet back in the packet pool.  */
126         TX_DISABLE
127 
128         /* Pickup the pool pointer.  */
129         pool_ptr =  packet_ptr -> nx_packet_pool_owner;
130 
131         /* Determine if there are any threads suspended on the block pool.  */
132         thread_ptr =  pool_ptr -> nx_packet_pool_suspension_list;
133         if (thread_ptr)
134         {
135 
136             /* Remove the suspended thread from the list.  */
137 
138             /* See if this is the only suspended thread on the list.  */
139             if (thread_ptr == thread_ptr -> tx_thread_suspended_next)
140             {
141 
142                 /* Yes, the only suspended thread.  */
143 
144                 /* Update the head pointer.  */
145                 pool_ptr -> nx_packet_pool_suspension_list =  NX_NULL;
146             }
147             else
148             {
149 
150                 /* At least one more thread is on the same expiration list.  */
151 
152                 /* Update the list head pointer.  */
153                 pool_ptr -> nx_packet_pool_suspension_list =  thread_ptr -> tx_thread_suspended_next;
154 
155                 /* Update the links of the adjacent threads.  */
156                 (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous =
157                     thread_ptr -> tx_thread_suspended_previous;
158                 (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next =
159                     thread_ptr -> tx_thread_suspended_next;
160             }
161 
162             /* Decrement the suspension count.  */
163             pool_ptr -> nx_packet_pool_suspended_count--;
164 
165             /* Prepare for resumption of the first thread.  */
166 
167             /* Clear cleanup routine to avoid timeout.  */
168             thread_ptr -> tx_thread_suspend_cleanup =  TX_NULL;
169 
170             /* Temporarily disable preemption.  */
171             _tx_thread_preempt_disable++;
172 
173             /* Restore interrupts.  */
174             TX_RESTORE
175 
176             /* Adjust this packet to look just like a new packet.  */
177             packet_ptr -> nx_packet_queue_next  =  NX_NULL;
178 #ifndef NX_DISABLE_PACKET_CHAIN
179             packet_ptr -> nx_packet_next        =  NX_NULL;
180             packet_ptr -> nx_packet_last        =  NX_NULL;
181 #endif /* NX_DISABLE_PACKET_CHAIN */
182             packet_ptr -> nx_packet_length      =  0;
183             packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_data_start + (thread_ptr -> tx_thread_suspend_info);
184             packet_ptr -> nx_packet_append_ptr  =  packet_ptr -> nx_packet_prepend_ptr;
185             packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
186 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
187             packet_ptr -> nx_packet_interface_capability_flag = 0;
188 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
189             /* Set the TCP queue to the value that indicates it has been allocated.  */
190             /*lint -e{923} suppress cast of ULONG to pointer.  */
191             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ALLOCATED;
192 
193 #ifdef FEATURE_NX_IPV6
194 
195             /* Clear the option state. */
196             packet_ptr -> nx_packet_option_state = 0;
197 #endif /* FEATURE_NX_IPV6 */
198 
199 #ifdef NX_IPSEC_ENABLE
200 
201             /* Clear the ipsec state. */
202             packet_ptr -> nx_packet_ipsec_state = 0;
203 #endif /* NX_IPSEC_ENABLE */
204 
205             /* Clear the IP version.  */
206             packet_ptr -> nx_packet_ip_version  =  0;
207 
208             /* Clear the IP identification flag.  */
209             packet_ptr -> nx_packet_identical_copy = NX_FALSE;
210 
211             /* Initialize the IP header length. */
212             packet_ptr -> nx_packet_ip_header_length = 0;
213 
214             /* Return this block pointer to the suspended thread waiting for
215                a block.  */
216             *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) =  packet_ptr;
217 
218             /* Put return status into the thread control block.  */
219             thread_ptr -> tx_thread_suspend_status =  NX_SUCCESS;
220 
221             /* Resume thread.  */
222             _tx_thread_system_resume(thread_ptr);
223         }
224         else
225         {
226 
227             /* No thread is suspended for a memory block.  */
228 
229             /* Mark the packet as free.  */
230             /*lint -e{923} suppress cast of ULONG to pointer.  */
231             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_FREE;
232 
233             /* Put the packet back in the available list.  */
234             packet_ptr -> nx_packet_queue_next =  pool_ptr -> nx_packet_pool_available_list;
235 
236             /* Adjust the head pointer.  */
237             pool_ptr -> nx_packet_pool_available_list =  packet_ptr;
238 
239             /* Increment the count of available blocks.  */
240             pool_ptr -> nx_packet_pool_available++;
241 
242             /* Restore interrupts.  */
243             TX_RESTORE
244         }
245 
246 #ifndef NX_DISABLE_PACKET_CHAIN
247         /* Move to the next packet in the list.  */
248         packet_ptr =  next_packet;
249     }
250 #endif /* NX_DISABLE_PACKET_CHAIN */
251 
252     /* Return completion status.  */
253     return(NX_SUCCESS);
254 }
255 
256