Merge aicom-network-branch (without NDIS changes for now)
[reactos.git] / reactos / drivers / network / tcpip / tcpip / buffer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/buffer.c
5 * PURPOSE: Miscellaneous operations on NDIS_BUFFERs and packets.
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 __inline INT SkipToOffset(
14 PNDIS_BUFFER Buffer,
15 UINT Offset,
16 PCHAR *Data,
17 PUINT Size)
18 /*
19 * FUNCTION: Skip Offset bytes into a buffer chain
20 * ARGUMENTS:
21 * Buffer = Pointer to NDIS buffer
22 * Offset = Number of bytes to skip
23 * Data = Address of a pointer that on return will contain the
24 * address of the offset in the buffer
25 * Size = Address of a pointer that on return will contain the
26 * size of the destination buffer
27 * RETURNS:
28 * Offset into buffer, -1 if buffer chain was smaller than Offset bytes
29 * NOTES:
30 * Buffer may be NULL
31 */
32 {
33 for (;;) {
34
35 if (!Buffer)
36 return -1;
37
38 NdisQueryBuffer(Buffer, (PVOID)Data, Size);
39
40 if (Offset < *Size) {
41 *Data = (PCHAR)((ULONG_PTR) *Data + Offset);
42 *Size -= Offset;
43 break;
44 }
45
46 Offset -= *Size;
47
48 NdisGetNextBuffer(Buffer, &Buffer);
49 }
50
51 return Offset;
52 }
53
54
55 UINT CopyBufferToBufferChain(
56 PNDIS_BUFFER DstBuffer,
57 UINT DstOffset,
58 PCHAR SrcData,
59 UINT Length)
60 /*
61 * FUNCTION: Copies data from a buffer to an NDIS buffer chain
62 * ARGUMENTS:
63 * DstBuffer = Pointer to destination NDIS buffer
64 * DstOffset = Destination start offset
65 * SrcData = Pointer to source buffer
66 * Length = Number of bytes to copy
67 * RETURNS:
68 * Number of bytes copied to destination buffer
69 * NOTES:
70 * The number of bytes copied may be limited by the destination
71 * buffer size
72 */
73 {
74 UINT BytesCopied, BytesToCopy, DstSize;
75 PCHAR DstData;
76
77 TI_DbgPrint(DEBUG_PBUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcData (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));
78
79 /* Skip DstOffset bytes in the destination buffer chain */
80 if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
81 return 0;
82
83 /* Start copying the data */
84 BytesCopied = 0;
85 for (;;) {
86 BytesToCopy = MIN(DstSize, Length);
87
88 RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
89 BytesCopied += BytesToCopy;
90 SrcData = (PCHAR)((ULONG_PTR)SrcData + BytesToCopy);
91
92 Length -= BytesToCopy;
93 if (Length == 0)
94 break;
95
96 DstSize -= BytesToCopy;
97 if (DstSize == 0) {
98 /* No more bytes in desination buffer. Proceed to
99 the next buffer in the destination buffer chain */
100 NdisGetNextBuffer(DstBuffer, &DstBuffer);
101 if (!DstBuffer)
102 break;
103
104 NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
105 }
106 }
107
108 return BytesCopied;
109 }
110
111
112 UINT CopyBufferChainToBuffer(
113 PCHAR DstData,
114 PNDIS_BUFFER SrcBuffer,
115 UINT SrcOffset,
116 UINT Length)
117 /*
118 * FUNCTION: Copies data from an NDIS buffer chain to a buffer
119 * ARGUMENTS:
120 * DstData = Pointer to destination buffer
121 * SrcBuffer = Pointer to source NDIS buffer
122 * SrcOffset = Source start offset
123 * Length = Number of bytes to copy
124 * RETURNS:
125 * Number of bytes copied to destination buffer
126 * NOTES:
127 * The number of bytes copied may be limited by the source
128 * buffer size
129 */
130 {
131 UINT BytesCopied, BytesToCopy, SrcSize;
132 PCHAR SrcData;
133
134 TI_DbgPrint(DEBUG_PBUFFER, ("DstData 0x%X SrcBuffer 0x%X SrcOffset 0x%X Length %d\n",DstData,SrcBuffer, SrcOffset, Length));
135
136 /* Skip SrcOffset bytes in the source buffer chain */
137 if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
138 return 0;
139
140 /* Start copying the data */
141 BytesCopied = 0;
142 for (;;) {
143 BytesToCopy = MIN(SrcSize, Length);
144
145 TI_DbgPrint(DEBUG_PBUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
146
147 RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
148 BytesCopied += BytesToCopy;
149 DstData = (PCHAR)((ULONG_PTR)DstData + BytesToCopy);
150
151 Length -= BytesToCopy;
152 if (Length == 0)
153 break;
154
155 SrcSize -= BytesToCopy;
156 if (SrcSize == 0) {
157 /* No more bytes in source buffer. Proceed to
158 the next buffer in the source buffer chain */
159 NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
160 if (!SrcBuffer)
161 break;
162
163 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
164 }
165 }
166
167 return BytesCopied;
168 }
169
170
171 UINT CopyPacketToBuffer(
172 PCHAR DstData,
173 PNDIS_PACKET SrcPacket,
174 UINT SrcOffset,
175 UINT Length)
176 /*
177 * FUNCTION: Copies data from an NDIS packet to a buffer
178 * ARGUMENTS:
179 * DstData = Pointer to destination buffer
180 * SrcPacket = Pointer to source NDIS packet
181 * SrcOffset = Source start offset
182 * Length = Number of bytes to copy
183 * RETURNS:
184 * Number of bytes copied to destination buffer
185 * NOTES:
186 * The number of bytes copied may be limited by the source
187 * buffer size
188 */
189 {
190 PNDIS_BUFFER FirstBuffer;
191 PVOID Address;
192 UINT FirstLength;
193 UINT TotalLength;
194
195 TI_DbgPrint(DEBUG_PBUFFER, ("DstData (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));
196
197 NdisGetFirstBufferFromPacket(SrcPacket,
198 &FirstBuffer,
199 &Address,
200 &FirstLength,
201 &TotalLength);
202
203 return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);
204 }
205
206
207 UINT CopyPacketToBufferChain(
208 PNDIS_BUFFER DstBuffer,
209 UINT DstOffset,
210 PNDIS_PACKET SrcPacket,
211 UINT SrcOffset,
212 UINT Length)
213 /*
214 * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain
215 * ARGUMENTS:
216 * DstBuffer = Pointer to destination NDIS buffer
217 * DstOffset = Destination start offset
218 * SrcPacket = Pointer to source NDIS packet
219 * SrcOffset = Source start offset
220 * Length = Number of bytes to copy
221 * RETURNS:
222 * Number of bytes copied to destination buffer
223 * NOTES:
224 * The number of bytes copied may be limited by the source and
225 * destination buffer sizes
226 */
227 {
228 PNDIS_BUFFER SrcBuffer;
229 PCHAR DstData, SrcData;
230 UINT DstSize, SrcSize;
231 UINT Count, Total;
232
233 TI_DbgPrint(DEBUG_PBUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));
234
235 /* Skip DstOffset bytes in the destination buffer chain */
236 NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
237 if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
238 return 0;
239
240 /* Skip SrcOffset bytes in the source packet */
241 NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, (PVOID)&SrcData, &SrcSize, &Total);
242 if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
243 return 0;
244
245 /* Copy the data */
246 for (Total = 0;;) {
247 /* Find out how many bytes we can copy at one time */
248 if (Length < SrcSize)
249 Count = Length;
250 else
251 Count = SrcSize;
252 if (DstSize < Count)
253 Count = DstSize;
254
255 RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);
256
257 Total += Count;
258 Length -= Count;
259 if (Length == 0)
260 break;
261
262 DstSize -= Count;
263 if (DstSize == 0) {
264 /* No more bytes in destination buffer. Proceed to
265 the next buffer in the destination buffer chain */
266 NdisGetNextBuffer(DstBuffer, &DstBuffer);
267 if (!DstBuffer)
268 break;
269
270 NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
271 }
272
273 SrcSize -= Count;
274 if (SrcSize == 0) {
275 /* No more bytes in source buffer. Proceed to
276 the next buffer in the source buffer chain */
277 NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
278 if (!SrcBuffer)
279 break;
280
281 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
282 }
283 }
284
285 return Total;
286 }
287
288
289 UINT ResizePacket(
290 PNDIS_PACKET Packet,
291 UINT Size)
292 /*
293 * FUNCTION: Resizes an NDIS packet
294 * ARGUMENTS:
295 * Packet = Pointer to packet
296 * Size = Number of bytes in first buffer
297 * RETURNS:
298 * Previous size of first buffer
299 */
300 {
301 PNDIS_BUFFER NdisBuffer;
302 UINT OldSize;
303
304 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
305
306 OldSize = NdisBuffer->ByteCount;
307
308 if (Size != OldSize)
309 NdisBuffer->ByteCount = Size;
310
311 return OldSize;
312 }
313
314 NDIS_STATUS PrependPacket( PNDIS_PACKET Packet, PCHAR Data, UINT Length,
315 BOOLEAN Copy ) {
316 PNDIS_BUFFER Buffer;
317 NDIS_STATUS Status;
318 PCHAR NewBuf;
319
320 if( Copy ) {
321 NewBuf = ExAllocatePoolWithTag( NonPagedPool, Length, PACKET_BUFFER_TAG );
322 if( !NewBuf ) return NDIS_STATUS_RESOURCES;
323 RtlCopyMemory( NewBuf, Data, Length );
324 } else NewBuf = Data;
325
326 NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewBuf, Length );
327 if( Status != NDIS_STATUS_SUCCESS ) {
328 if (Copy) ExFreePoolWithTag(NewBuf, PACKET_BUFFER_TAG);
329 return Status;
330 }
331
332 NdisChainBufferAtFront( Packet, Buffer );
333
334 return STATUS_SUCCESS;
335 }
336
337 void GetDataPtr( PNDIS_PACKET Packet,
338 UINT Offset,
339 PCHAR *DataOut,
340 PUINT Size ) {
341 PNDIS_BUFFER Buffer;
342
343 NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
344 if( !Buffer ) return;
345 SkipToOffset( Buffer, Offset, DataOut, Size );
346 }
347
348 NDIS_STATUS AllocatePacketWithBuffer( PNDIS_PACKET *NdisPacket,
349 PCHAR Data, UINT Len ) {
350 PNDIS_PACKET Packet;
351 PNDIS_BUFFER Buffer;
352 NDIS_STATUS Status;
353 PCHAR NewData;
354
355 NewData = ExAllocatePoolWithTag( NonPagedPool, Len, PACKET_BUFFER_TAG );
356 if( !NewData ) return NDIS_STATUS_RESOURCES;
357
358 if( Data ) RtlCopyMemory(NewData, Data, Len);
359
360 NdisAllocatePacket( &Status, &Packet, GlobalPacketPool );
361 if( Status != NDIS_STATUS_SUCCESS ) {
362 ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG );
363 return Status;
364 }
365
366 NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len );
367 if( Status != NDIS_STATUS_SUCCESS ) {
368 ExFreePoolWithTag( NewData, PACKET_BUFFER_TAG );
369 FreeNdisPacket( Packet );
370 return Status;
371 }
372
373 NdisChainBufferAtFront( Packet, Buffer );
374 *NdisPacket = Packet;
375
376 return NDIS_STATUS_SUCCESS;
377 }
378
379
380 VOID FreeNdisPacket
381 ( PNDIS_PACKET Packet )
382 /*
383 * FUNCTION: Frees an NDIS packet
384 * ARGUMENTS:
385 * Packet = Pointer to NDIS packet to be freed
386 */
387 {
388 PNDIS_BUFFER Buffer, NextBuffer;
389
390 TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet));
391
392 /* Free all the buffers in the packet first */
393 NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
394 for (; Buffer != NULL; Buffer = NextBuffer) {
395 PVOID Data;
396 UINT Length;
397
398 NdisGetNextBuffer(Buffer, &NextBuffer);
399 NdisQueryBuffer(Buffer, &Data, &Length);
400 TI_DbgPrint(DEBUG_PBUFFER, ("Freeing ndis buffer (0x%X)\n", Buffer));
401 NdisFreeBuffer(Buffer);
402 TI_DbgPrint(DEBUG_PBUFFER, ("Freeing exal buffer (0x%X)\n", Data));
403 ExFreePoolWithTag(Data, PACKET_BUFFER_TAG);
404 }
405
406 /* Finally free the NDIS packet discriptor */
407 NdisFreePacket(Packet);
408 }