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 "nx_packet.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_packet_data_append PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function copies the specified data to the end of the specified */
44 /* packet. Additional packets are allocated from the specified pool */
45 /* if needed. */
46 /* */
47 /* INPUT */
48 /* */
49 /* packet_ptr Pointer to packet to append to*/
50 /* data_start Pointer to start of the data */
51 /* data_size Number of bytes to append */
52 /* pool_ptr Pool to allocate packet from */
53 /* wait_option Suspension option */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* status Completion status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _nx_packet_allocate Allocate data packet */
62 /* _nx_packet_release Release data packet */
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), and */
74 /* verified memcpy use cases, */
75 /* resulting in version 6.1 */
76 /* */
77 /**************************************************************************/
_nx_packet_data_append(NX_PACKET * packet_ptr,VOID * data_start,ULONG data_size,NX_PACKET_POOL * pool_ptr,ULONG wait_option)78 UINT _nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size,
79 NX_PACKET_POOL *pool_ptr, ULONG wait_option)
80 {
81
82 #ifndef NX_DISABLE_PACKET_CHAIN
83 UINT status; /* Return status */
84 NX_PACKET *new_list_ptr; /* Head of new list pointer */
85 NX_PACKET *last_packet = NX_NULL; /* Last supplied packet */
86 #endif /* NX_DISABLE_PACKET_CHAIN */
87 ULONG available_bytes; /* Number of available bytes */
88 ULONG copy_size; /* Size for each memory copy */
89 UCHAR *source_ptr; /* Buffer source pointer */
90 NX_PACKET *work_ptr; /* Working packet pointer */
91
92
93 /* If trace is enabled, insert this event into the trace buffer. */
94 NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_DATA_APPEND, packet_ptr, data_start, data_size, pool_ptr, NX_TRACE_PACKET_EVENTS, 0, 0);
95
96 #ifndef NX_DISABLE_PACKET_CHAIN
97 /* Calculate the number of bytes available at the end of the supplied packet. */
98 if (packet_ptr -> nx_packet_last)
99 {
100
101 /* More than one packet. Walk the packet chain starting at the last packet
102 to calculate the remaining bytes. */
103 available_bytes = 0;
104 work_ptr = packet_ptr -> nx_packet_last;
105 do
106 {
107
108 /* Calculate the available bytes in this packet. */
109 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
110 /*lint -e{737} suppress loss of sign, since nx_packet_data_end is assumed to be larger than nx_packet_append_ptr. */
111 available_bytes = available_bytes +
112 (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
113
114 /* Remember the last packet. */
115 last_packet = work_ptr;
116
117 /* Move to the next packet. There typically won't be another packet, but just in
118 case the logic is here for it! */
119 work_ptr = work_ptr -> nx_packet_next;
120 } while (work_ptr);
121 }
122 else
123 #endif /* NX_DISABLE_PACKET_CHAIN */
124 {
125
126 /* Just calculate the number of bytes available in the first packet. */
127 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
128 available_bytes = (ULONG)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr);
129 }
130
131 /* Determine if any new packets are required to satisfy this request. */
132 if (available_bytes < data_size)
133 {
134
135 #ifndef NX_DISABLE_PACKET_CHAIN
136 /* Setup a temporary head pointer. */
137 new_list_ptr = NX_NULL;
138
139 /* Loop to pickup enough packets to complete the append request. */
140 while (available_bytes < data_size)
141 {
142
143 /* Allocate a new packet. */
144 status = _nx_packet_allocate(pool_ptr, &work_ptr, 0, wait_option);
145
146 /* Determine if an error is present. */
147 if (status)
148 {
149
150 /* Yes, an error is present. */
151
152 /* First release any packets that have been allocated so far. */
153 if (new_list_ptr)
154 {
155 _nx_packet_release(new_list_ptr);
156 }
157
158 /* Return the error status to the caller of this service. */
159 return(status);
160 }
161
162 /* Add debug information. */
163 NX_PACKET_DEBUG(__FILE__, __LINE__, work_ptr);
164
165 /* No error is present. Link the new packet to the temporary list being built. */
166 if (new_list_ptr)
167 {
168
169 /* Determine if there is already more than one packet on the list. */
170 if (new_list_ptr -> nx_packet_last)
171 {
172
173 /* Yes, link up the last packet to the new packet and update the
174 last pointer. */
175 /*lint -e{644} suppress variable might not be initialized, since "work_ptr" was initialized in _nx_packet_allocate. */
176 (new_list_ptr -> nx_packet_last) -> nx_packet_next = work_ptr;
177 new_list_ptr -> nx_packet_last = work_ptr;
178 }
179 else
180 {
181
182 /* Second packet allocated. Just setup the last and next in the
183 head pointer. */
184 new_list_ptr -> nx_packet_last = work_ptr;
185 new_list_ptr -> nx_packet_next = work_ptr;
186 }
187 }
188 else
189 {
190
191 /* Just setup the temporary list head. */
192 new_list_ptr = work_ptr;
193 }
194
195 /* Adjust the number of available bytes according to how much space
196 is in the new packet. */
197 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
198 /*lint -e{737} suppress loss of sign, since nx_packet_data_end is assumed to be larger than nx_packet_append_ptr. */
199 /*lint -e{613} suppress possible use of null pointer, since "work_ptr" was set in _nx_packet_allocate. */
200 available_bytes = available_bytes +
201 (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
202 }
203
204 /* At this point, all the necessary packets have been allocated and are present
205 on the temporary list. We need to link this new list to the end of the supplied
206 packet. */
207 if (last_packet)
208 {
209
210 /* Already more than one packet. Add the new packet list to the end. */
211 last_packet -> nx_packet_next = new_list_ptr;
212 }
213 else
214 {
215
216 /* Link the new packet list to the head packet. */
217 packet_ptr -> nx_packet_next = new_list_ptr;
218 }
219
220 /* Clear the last packet that was used to maintain the new list. */
221 /*lint -e{613} suppress possible use of null pointer, since "new_list_ptr" was set in previous loop. */
222 new_list_ptr -> nx_packet_last = NX_NULL;
223 #else
224 NX_PARAMETER_NOT_USED(pool_ptr);
225 NX_PARAMETER_NOT_USED(wait_option);
226
227 return(NX_SIZE_ERROR);
228 #endif /* NX_DISABLE_PACKET_CHAIN */
229 }
230
231 /* Setup the new data length in the packet. */
232 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + data_size;
233
234 /* Now copy the supplied data buffer at the end of the packet. */
235 source_ptr = (UCHAR *)data_start;
236 #ifndef NX_DISABLE_PACKET_CHAIN
237 if (packet_ptr -> nx_packet_last)
238 {
239 work_ptr = packet_ptr -> nx_packet_last;
240 }
241 else
242 {
243 #endif /* NX_DISABLE_PACKET_CHAIN */
244 work_ptr = packet_ptr;
245 #ifndef NX_DISABLE_PACKET_CHAIN
246 }
247 while (data_size)
248 {
249
250 /* Determine the amount of memory to copy. */
251 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
252 if (data_size < (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr))
253 {
254 copy_size = data_size;
255 }
256 else
257 {
258
259 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
260 copy_size = (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
261 }
262 #else
263 copy_size = data_size;
264 #endif /* NX_DISABLE_PACKET_CHAIN */
265
266 /* Copy the data into the current packet buffer. */
267 memcpy(work_ptr -> nx_packet_append_ptr, source_ptr, copy_size); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
268
269 /* Adjust the remaining data size. */
270 data_size = data_size - copy_size;
271
272 /* Update this packets append pointer. */
273 work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_append_ptr + copy_size;
274
275 #ifndef NX_DISABLE_PACKET_CHAIN
276 /* Any more data left to append? */
277 if (data_size)
278 {
279
280 /* Yes, there is more to move. Update the source pointer, move the work pointer
281 to the next packet in the chain and update the last packet pointer. */
282 source_ptr = source_ptr + copy_size;
283 work_ptr = work_ptr -> nx_packet_next;
284 packet_ptr -> nx_packet_last = work_ptr;
285 }
286 }
287 #endif /* NX_DISABLE_PACKET_CHAIN */
288
289 /* Add debug information. */
290 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
291
292 /* Return successful status. */
293 return(NX_SUCCESS);
294 }
295
296