1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Component                                                        */
17 /**                                                                       */
18 /**   Packet Pool Management (Packet)                                     */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "tx_thread.h"
30 #include "nx_packet.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_packet_allocate                                 PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yuxin Zhou, Microsoft Corporation                                   */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function allocates a packet from the specified packet pool.    */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    pool_ptr                              Pool to allocate packet from  */
50 /*    packet_ptr                            Pointer to place allocated    */
51 /*                                            packet pointer              */
52 /*    packet_type                           Type of packet to allocate    */
53 /*    wait_option                           Suspension option             */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _tx_thread_system_suspend             Suspend thread                */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    Application Code                                                    */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
72 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
73 /*                                            resulting in version 6.1    */
74 /*                                                                        */
75 /**************************************************************************/
_nx_packet_allocate(NX_PACKET_POOL * pool_ptr,NX_PACKET ** packet_ptr,ULONG packet_type,ULONG wait_option)76 UINT  _nx_packet_allocate(NX_PACKET_POOL *pool_ptr,  NX_PACKET **packet_ptr,
77                           ULONG packet_type, 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     /* Make sure the packet_type does not go beyond nx_packet_data_end. */
91     if (pool_ptr -> nx_packet_pool_payload_size < packet_type)
92     {
93         return(NX_INVALID_PARAMETERS);
94     }
95 
96     /* Set the return pointer to NULL initially.  */
97     *packet_ptr =   NX_NULL;
98 
99     /* If trace is enabled, insert this event into the trace buffer.  */
100     NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_ALLOCATE, pool_ptr, 0, packet_type, pool_ptr -> nx_packet_pool_available, NX_TRACE_PACKET_EVENTS, &trace_event, &trace_timestamp);
101 
102     /* Disable interrupts to get a packet from the pool.  */
103     TX_DISABLE
104 
105     /* Determine if there is an available packet.  */
106     if (pool_ptr -> nx_packet_pool_available)
107     {
108 
109         /* Yes, a packet is available.  Decrement the available count.  */
110         pool_ptr -> nx_packet_pool_available--;
111 
112         /* Pickup the current packet pointer.  */
113         work_ptr =  pool_ptr -> nx_packet_pool_available_list;
114 
115         /* Modify the available list to point at the next packet in the pool. */
116         pool_ptr -> nx_packet_pool_available_list =  work_ptr -> nx_packet_queue_next;
117 
118         /* Setup various fields for this packet.  */
119         work_ptr -> nx_packet_queue_next =   NX_NULL;
120 #ifndef NX_DISABLE_PACKET_CHAIN
121         work_ptr -> nx_packet_next =         NX_NULL;
122         work_ptr -> nx_packet_last =         NX_NULL;
123 #endif /* NX_DISABLE_PACKET_CHAIN */
124         work_ptr -> nx_packet_length =       0;
125         work_ptr -> nx_packet_prepend_ptr =  work_ptr -> nx_packet_data_start + packet_type;
126         work_ptr -> nx_packet_append_ptr =   work_ptr -> nx_packet_prepend_ptr;
127         work_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
128 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
129         work_ptr -> nx_packet_interface_capability_flag = 0;
130 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
131         /* Set the TCP queue to the value that indicates it has been allocated.  */
132         /*lint -e{923} suppress cast of ULONG to pointer.  */
133         work_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ALLOCATED;
134 
135 #ifdef FEATURE_NX_IPV6
136 
137         /* Clear the option state. */
138         work_ptr -> nx_packet_option_state = 0;
139 #endif /* FEATURE_NX_IPV6 */
140 
141 #ifdef NX_IPSEC_ENABLE
142 
143         /* Clear the ipsec state. */
144         work_ptr -> nx_packet_ipsec_state = 0;
145         work_ptr -> nx_packet_ipsec_sa_ptr = NX_NULL;
146 #endif /* NX_IPSEC_ENABLE */
147 
148 #ifndef NX_DISABLE_IPV4
149         /* Initialize the IP version field */
150         work_ptr -> nx_packet_ip_version = NX_IP_VERSION_V4;
151 #endif /* !NX_DISABLE_IPV4  */
152 
153         /* Initialize the IP identification flag.  */
154         work_ptr -> nx_packet_identical_copy = NX_FALSE;
155 
156         /* Initialize the IP header length. */
157         work_ptr -> nx_packet_ip_header_length = 0;
158 
159 #ifdef NX_ENABLE_THREAD
160         work_ptr -> nx_packet_type = 0;
161 #endif /* NX_ENABLE_THREAD  */
162 
163         /* Place the new packet pointer in the return destination.  */
164         *packet_ptr =  work_ptr;
165 
166         /* Set status to success.  */
167         status =  NX_SUCCESS;
168 
169         /* Add debug information. */
170         NX_PACKET_DEBUG(__FILE__, __LINE__, work_ptr);
171     }
172     else
173     {
174 
175 #ifndef NX_DISABLE_PACKET_INFO
176         /* Increment the packet pool empty request count.  */
177         pool_ptr -> nx_packet_pool_empty_requests++;
178 #endif
179 
180         /* Determine if the request specifies suspension.  */
181         if (wait_option)
182         {
183 
184             /* Prepare for suspension of this thread.  */
185 
186 #ifndef NX_DISABLE_PACKET_INFO
187             /* Increment the packet pool empty request suspension count.  */
188             pool_ptr -> nx_packet_pool_empty_suspensions++;
189 #endif
190 
191             /* Pickup thread pointer.  */
192             thread_ptr =  _tx_thread_current_ptr;
193 
194             /* Setup cleanup routine pointer.  */
195             thread_ptr -> tx_thread_suspend_cleanup =  _nx_packet_pool_cleanup;
196 
197             /* Setup cleanup information, i.e. this pool control
198                block.  */
199             thread_ptr -> tx_thread_suspend_control_block =  (void *)pool_ptr;
200 
201             /* Save the return packet pointer address as well.  */
202             thread_ptr -> tx_thread_additional_suspend_info =  (void *)packet_ptr;
203 
204             /* Save the packet type (or prepend offset) so this can be added
205                after a new packet becomes available.  */
206             thread_ptr -> tx_thread_suspend_info =  packet_type;
207 
208             /* Setup suspension list.  */
209             if (pool_ptr -> nx_packet_pool_suspension_list)
210             {
211 
212                 /* This list is not NULL, add current thread to the end. */
213                 thread_ptr -> tx_thread_suspended_next =
214                     pool_ptr -> nx_packet_pool_suspension_list;
215                 thread_ptr -> tx_thread_suspended_previous =
216                     (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous;
217                 ((pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next =
218                     thread_ptr;
219                 (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous =   thread_ptr;
220             }
221             else
222             {
223 
224                 /* No other threads are suspended.  Setup the head pointer and
225                    just setup this threads pointers to itself.  */
226                 pool_ptr -> nx_packet_pool_suspension_list =  thread_ptr;
227                 thread_ptr -> tx_thread_suspended_next =            thread_ptr;
228                 thread_ptr -> tx_thread_suspended_previous =        thread_ptr;
229             }
230 
231             /* Increment the suspended thread count.  */
232             pool_ptr -> nx_packet_pool_suspended_count++;
233 
234             /* Set the state to suspended.  */
235             thread_ptr -> tx_thread_state =  TX_TCP_IP;
236 
237             /* Set the suspending flag.  */
238             thread_ptr -> tx_thread_suspending =  TX_TRUE;
239 
240             /* Temporarily disable preemption.  */
241             _tx_thread_preempt_disable++;
242 
243             /* Save the timeout value.  */
244             thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  wait_option;
245 
246             /* Restore interrupts.  */
247             TX_RESTORE
248 
249             /* Call actual thread suspension routine.  */
250             _tx_thread_system_suspend(thread_ptr);
251 
252             /* Update the trace event with the status.  */
253             NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0);
254 
255 #ifdef NX_ENABLE_PACKET_DEBUG_INFO
256             if (thread_ptr -> tx_thread_suspend_status == NX_SUCCESS)
257             {
258 
259                 /* Add debug information. */
260                 NX_PACKET_DEBUG(__FILE__, __LINE__, *packet_ptr);
261             }
262 #endif /* NX_ENABLE_PACKET_DEBUG_INFO */
263 
264             /* Return the completion status.  */
265             return(thread_ptr -> tx_thread_suspend_status);
266         }
267         else
268         {
269 
270             /* Immediate return, return error completion.  */
271             status =  NX_NO_PACKET;
272         }
273     }
274 
275     /* Restore interrupts.  */
276     TX_RESTORE
277 
278     /* Update the trace event with the status.  */
279     NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0);
280 
281     /* Return completion status.  */
282     return(status);
283 }
284 
285