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