:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / net / tcpip / tcpip / routines.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        tcpip/routines.c
5  * PURPOSE:     Common routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 #include <tcpip.h>
11 #include <routines.h>
12 #include <pool.h>
13
14
15 UINT RandomNumber = 0x12345678;
16
17
18 inline NTSTATUS BuildDatagramSendRequest(
19     PDATAGRAM_SEND_REQUEST *SendRequest,
20     PIP_ADDRESS RemoteAddress,
21     USHORT RemotePort,
22     PNDIS_BUFFER Buffer,
23     DWORD BufferSize,
24     DATAGRAM_COMPLETION_ROUTINE Complete,
25     PVOID Context,
26     DATAGRAM_BUILD_ROUTINE Build,
27     ULONG Flags)
28 /*
29  * FUNCTION: Allocates and intializes a datagram send request
30  * ARGUMENTS:
31  *     SendRequest     = Pointer to datagram send request
32  *     RemoteAddress   = Pointer to remote IP address
33  *     RemotePort      = Remote port number
34  *     Buffer          = Pointer to NDIS buffer to send
35  *     BufferSize      = Size of Buffer
36  *     Complete        = Completion routine
37  *     Context         = Pointer to context information
38  *     Build           = Datagram build routine
39  *     Flags           = Protocol specific flags
40  * RETURNS:
41  *     Status of operation
42  */
43 {
44   PDATAGRAM_SEND_REQUEST Request;
45
46   Request = ExAllocatePool(NonPagedPool, sizeof(DATAGRAM_SEND_REQUEST));
47   if (!Request)
48     return STATUS_INSUFFICIENT_RESOURCES;
49
50   InitializeDatagramSendRequest(
51     Request,
52     RemoteAddress,
53     RemotePort,
54     Buffer,
55     BufferSize,
56     Complete,
57     Context,
58     Build,
59     Flags);
60
61   *SendRequest = Request;
62
63   return STATUS_SUCCESS;
64 }
65
66
67 inline NTSTATUS BuildTCPSendRequest(
68     PTCP_SEND_REQUEST *SendRequest,
69     DATAGRAM_COMPLETION_ROUTINE Complete,
70     PVOID Context,
71     PVOID ProtocolContext)
72 /*
73  * FUNCTION: Allocates and intializes a TCP send request
74  * ARGUMENTS:
75  *     SendRequest     = Pointer to TCP send request
76  *     Complete        = Completion routine
77  *     Context         = Pointer to context information
78  *     ProtocolContext = Protocol specific context
79  * RETURNS:
80  *     Status of operation
81  */
82 {
83   PTCP_SEND_REQUEST Request;
84
85   Request = ExAllocatePool(NonPagedPool, sizeof(TCP_SEND_REQUEST));
86   if (!Request)
87     return STATUS_INSUFFICIENT_RESOURCES;
88
89   InitializeTCPSendRequest(
90     Request,
91     Complete,
92     Context,
93     ProtocolContext);
94
95   *SendRequest = Request;
96
97   return STATUS_SUCCESS;
98 }
99
100
101 UINT Random(
102     VOID)
103 /*
104  * FUNCTION: Returns a pseudo random number
105  * RETURNS:
106  *     Pseudo random number
107  */
108 {
109     RandomNumber ^= 0x78563412;
110
111     return RandomNumber;
112 }
113
114
115 __inline INT SkipToOffset(
116     PNDIS_BUFFER Buffer,
117     UINT Offset,
118     PUCHAR *Data,
119     PUINT Size)
120 /*
121  * FUNCTION: Skip Offset bytes into a buffer chain
122  * ARGUMENTS:
123  *     Buffer = Pointer to NDIS buffer
124  *     Offset = Number of bytes to skip
125  *     Data   = Address of a pointer that on return will contain the
126  *              address of the offset in the buffer
127  *     Size   = Address of a pointer that on return will contain the
128  *              size of the destination buffer
129  * RETURNS:
130  *     Offset into buffer, -1 if buffer chain was smaller than Offset bytes
131  * NOTES:
132  *     Buffer may be NULL
133  */
134 {
135     for (;;) {
136
137         if (!Buffer)
138             return -1;
139
140         NdisQueryBuffer(Buffer, Data, Size);
141
142         if (Offset < *Size) {
143             ((ULONG_PTR)*Data) += Offset;
144             *Size              -= Offset;
145             break;
146         }
147
148         Offset -= *Size;
149
150         NdisGetNextBuffer(Buffer, &Buffer);
151     }
152
153     return Offset;
154 }
155
156
157 UINT CopyBufferToBufferChain(
158     PNDIS_BUFFER DstBuffer,
159     UINT DstOffset,
160     PUCHAR SrcData,
161     UINT Length)
162 /*
163  * FUNCTION: Copies data from a buffer to an NDIS buffer chain
164  * ARGUMENTS:
165  *     DstBuffer = Pointer to destination NDIS buffer 
166  *     DstOffset = Destination start offset
167  *     SrcData   = Pointer to source buffer
168  *     Length    = Number of bytes to copy
169  * RETURNS:
170  *     Number of bytes copied to destination buffer
171  * NOTES:
172  *     The number of bytes copied may be limited by the destination
173  *     buffer size
174  */
175 {
176     UINT BytesCopied, BytesToCopy, DstSize;
177     PUCHAR DstData;
178
179     TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcData (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));
180
181     /* Skip DstOffset bytes in the destination buffer chain */
182     if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
183         return 0;
184
185     /* Start copying the data */
186     BytesCopied = 0;
187     for (;;) {
188         BytesToCopy = MIN(DstSize, Length);
189
190         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
191         BytesCopied        += BytesToCopy;
192         (ULONG_PTR)SrcData += BytesToCopy;
193
194         Length -= BytesToCopy;
195         if (Length == 0)
196             break;
197
198         DstSize -= BytesToCopy;
199         if (DstSize == 0) {
200             /* No more bytes in desination buffer. Proceed to
201                the next buffer in the destination buffer chain */
202             NdisGetNextBuffer(DstBuffer, &DstBuffer);
203             if (!DstBuffer)
204                 break;
205
206             NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
207         }
208     }
209
210     return BytesCopied;
211 }
212
213
214 UINT CopyBufferChainToBuffer(
215     PUCHAR DstData,
216     PNDIS_BUFFER SrcBuffer,
217     UINT SrcOffset,
218     UINT Length)
219 /*
220  * FUNCTION: Copies data from an NDIS buffer chain to a buffer
221  * ARGUMENTS:
222  *     DstData   = Pointer to destination buffer
223  *     SrcBuffer = Pointer to source NDIS buffer
224  *     SrcOffset = Source start offset
225  *     Length    = Number of bytes to copy
226  * RETURNS:
227  *     Number of bytes copied to destination buffer
228  * NOTES:
229  *     The number of bytes copied may be limited by the source
230  *     buffer size
231  */
232 {
233     UINT BytesCopied, BytesToCopy, SrcSize;
234     PUCHAR SrcData;
235
236     TI_DbgPrint(DEBUG_BUFFER, ("DstData 0x%X  SrcBuffer 0x%X  SrcOffset 0x%X  Length %d\n",DstData,SrcBuffer, SrcOffset, Length));
237     
238     /* Skip SrcOffset bytes in the source buffer chain */
239     if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
240         return 0;
241
242     /* Start copying the data */
243     BytesCopied = 0;
244     for (;;) {
245         BytesToCopy = MIN(SrcSize, Length);
246
247         TI_DbgPrint(DEBUG_BUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
248
249         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
250         BytesCopied        += BytesToCopy;
251         (ULONG_PTR)DstData += BytesToCopy;
252
253         Length -= BytesToCopy;
254         if (Length == 0)
255             break;
256
257         SrcSize -= BytesToCopy;
258         if (SrcSize == 0) {
259             /* No more bytes in source buffer. Proceed to
260                the next buffer in the source buffer chain */
261             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
262             if (!SrcBuffer)
263                 break;
264
265             NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
266         }
267     }
268
269     return BytesCopied;
270 }
271
272
273 UINT CopyPacketToBuffer(
274     PUCHAR DstData,
275     PNDIS_PACKET SrcPacket,
276     UINT SrcOffset,
277     UINT Length)
278 /*
279  * FUNCTION: Copies data from an NDIS packet to a buffer
280  * ARGUMENTS:
281  *     DstData   = Pointer to destination buffer
282  *     SrcPacket = Pointer to source NDIS packet
283  *     SrcOffset = Source start offset
284  *     Length    = Number of bytes to copy
285  * RETURNS:
286  *     Number of bytes copied to destination buffer
287  * NOTES:
288  *     The number of bytes copied may be limited by the source
289  *     buffer size
290  */
291 {
292     PNDIS_BUFFER FirstBuffer;
293     PVOID Address;
294     UINT FirstLength;
295     UINT TotalLength;
296
297     TI_DbgPrint(DEBUG_BUFFER, ("DstData (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));
298
299     NdisGetFirstBufferFromPacket(SrcPacket,
300                                  &FirstBuffer,
301                                  &Address,
302                                  &FirstLength,
303                                  &TotalLength);
304
305     return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);
306 }
307
308
309 UINT CopyPacketToBufferChain(
310     PNDIS_BUFFER DstBuffer,
311     UINT DstOffset,
312     PNDIS_PACKET SrcPacket,
313     UINT SrcOffset,
314     UINT Length)
315 /*
316  * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain
317  * ARGUMENTS:
318  *     DstBuffer = Pointer to destination NDIS buffer
319  *     DstOffset = Destination start offset
320  *     SrcPacket = Pointer to source NDIS packet
321  *     SrcOffset = Source start offset
322  *     Length    = Number of bytes to copy
323  * RETURNS:
324  *     Number of bytes copied to destination buffer
325  * NOTES:
326  *     The number of bytes copied may be limited by the source and
327  *     destination buffer sizes
328  */
329 {
330     PNDIS_BUFFER SrcBuffer;
331     PUCHAR DstData, SrcData;
332     UINT DstSize, SrcSize;
333     UINT Count, Total;
334
335     TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));
336
337     /* Skip DstOffset bytes in the destination buffer chain */
338     NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
339     if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
340         return 0;
341
342     /* Skip SrcOffset bytes in the source packet */
343     NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, &SrcData, &SrcSize, &Total);
344     if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
345         return 0;
346
347     /* Copy the data */
348     for (Total = 0;;) {
349         /* Find out how many bytes we can copy at one time */
350         if (Length < SrcSize)
351             Count = Length;
352         else
353             Count = SrcSize;
354         if (DstSize < Count)
355             Count = DstSize;
356
357         RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);
358
359         Total  += Count;
360         Length -= Count;
361         if (Length == 0)
362             break;
363
364         DstSize -= Count;
365         if (DstSize == 0) {
366             /* No more bytes in destination buffer. Proceed to
367                the next buffer in the destination buffer chain */
368             NdisGetNextBuffer(DstBuffer, &DstBuffer);
369             if (!DstBuffer)
370                 break;
371
372             NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
373         }
374
375         SrcSize -= Count;
376         if (SrcSize == 0) {
377             /* No more bytes in source buffer. Proceed to
378                the next buffer in the source buffer chain */
379             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
380             if (!SrcBuffer)
381                 break;
382
383             NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
384         }
385     }
386
387     return Total;
388 }
389
390
391 VOID FreeNdisPacket(
392     PNDIS_PACKET Packet)
393 /*
394  * FUNCTION: Frees an NDIS packet
395  * ARGUMENTS:
396  *     Packet = Pointer to NDIS packet to be freed
397  */
398 {
399     PNDIS_BUFFER Buffer, NextBuffer;
400
401     TI_DbgPrint(DEBUG_BUFFER, ("Packet (0x%X)\n", Packet));
402
403     /* Free all the buffers in the packet first */
404     NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
405     for (; Buffer != NULL; Buffer = NextBuffer) {
406         PVOID Data;
407         UINT Length;
408
409         NdisGetNextBuffer(Buffer, &NextBuffer);
410         NdisQueryBuffer(Buffer, &Data, &Length);
411         NdisFreeBuffer(Buffer);
412         ExFreePool(Data);
413     }
414
415     /* Finally free the NDIS packet discriptor */
416     NdisFreePacket(Packet);
417 }
418
419
420 PVOID AdjustPacket(
421     PNDIS_PACKET Packet,
422     UINT Available,
423     UINT Needed)
424 /*
425  * FUNCTION: Adjusts the amount of unused space at the beginning of the packet
426  * ARGUMENTS:
427  *     Packet    = Pointer to packet
428  *     Available = Number of bytes available at start of first buffer
429  *     Needed    = Number of bytes needed for the header
430  * RETURNS:
431  *     Pointer to start of packet
432  */
433 {
434     PNDIS_BUFFER NdisBuffer;
435     INT Adjust;
436
437     TI_DbgPrint(DEBUG_BUFFER, ("Available = %d, Needed = %d.\n", Available, Needed));
438
439     Adjust = Available - Needed;
440
441     NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
442
443     /* If Adjust is zero there is no need to adjust this packet as
444        there is no additional space at start the of first buffer */
445     if (Adjust != 0) {
446         (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust;
447         NdisBuffer->ByteOffset                  += Adjust;
448         NdisBuffer->ByteCount                   -= Adjust;
449     }
450
451     return NdisBuffer->MappedSystemVa;
452 }
453
454
455 UINT ResizePacket(
456     PNDIS_PACKET Packet,
457     UINT Size)
458 /*
459  * FUNCTION: Resizes an NDIS packet
460  * ARGUMENTS:
461  *     Packet = Pointer to packet
462  *     Size   = Number of bytes in first buffer
463  * RETURNS:
464  *     Previous size of first buffer
465  */
466 {
467     PNDIS_BUFFER NdisBuffer;
468     UINT OldSize;
469
470     NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
471
472     OldSize = NdisBuffer->ByteCount;
473
474     if (Size != OldSize)
475         NdisBuffer->ByteCount = Size;
476
477     return OldSize;
478 }
479
480 #ifdef DBG
481
482 VOID DisplayIPPacket(
483     PIP_PACKET IPPacket)
484 {
485     UINT i;
486     PCHAR p;
487     UINT Length;
488     PNDIS_BUFFER Buffer;
489     PNDIS_BUFFER NextBuffer;
490
491     if ((DebugTraceLevel & DEBUG_BUFFER) == 0) {
492         return;
493     }
494
495     if (!IPPacket) {
496         TI_DbgPrint(MIN_TRACE, ("Cannot display null packet.\n"));
497         return;
498     }
499
500           TI_DbgPrint(MIN_TRACE, ("IPPacket is at (0x%X).\n", IPPacket));
501     TI_DbgPrint(MIN_TRACE, ("Header buffer is at (0x%X).\n", IPPacket->Header));
502     TI_DbgPrint(MIN_TRACE, ("Header size is (%d).\n", IPPacket->HeaderSize));
503     TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
504     TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
505     TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
506
507     if (IPPacket->NdisPacket) {
508         NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, &Buffer, NULL);
509         for (; Buffer != NULL; Buffer = NextBuffer) {
510             NdisGetNextBuffer(Buffer, &NextBuffer);
511             NdisQueryBuffer(Buffer, (PVOID)&p, &Length);
512
513             for (i = 0; i < Length; i++) {
514                 if (i % 16 == 0)
515                     DbgPrint("\n");
516                 DbgPrint("%02X ", (p[i]) & 0xFF);
517             }
518             DbgPrint("\n");
519         }
520     } else {
521         p      = IPPacket->Header;
522         Length = IPPacket->ContigSize;
523         for (i = 0; i < Length; i++) {
524             if (i % 16 == 0)
525                 DbgPrint("\n");
526             DbgPrint("%02X ", (p[i]) & 0xFF);
527         }
528         DbgPrint("\n");
529     }
530 }
531 #endif /* DBG */
532
533 /* EOF */