Whamcloud - gitweb
293b63069f44a798975204f9cc6b4ec4d3219fd7
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-tcpip.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 #define DEBUG_SUBSYSTEM S_LNET
36
37 #include <libcfs/libcfs.h>
38 #include <lnet/lnet.h>
39
40 #define TDILND_MODULE_NAME L"tdilnd"
41
42 ks_tdi_data_t ks_data;
43
44 VOID
45 KsDumpPrint(PCHAR buffer, ULONG length)
46 {
47     ULONG i;
48     for (i=0; i < length; i++) {
49         if (((i+1) % 31) == 0)
50             printk("\n");
51         printk("%2.2x ", (UCHAR)buffer[i]);
52     }
53     printk("\n");
54 }
55
56 PVOID
57 KsMapMdlBuffer (PMDL    Mdl);
58
59 VOID
60 KsDumpMdlChain(PMDL Mdl, ULONG length)
61 {
62     PMDL mdl = Mdl;
63     PCHAR buffer = NULL;
64     ULONG len = 0;
65     int i = 0;
66
67     while (mdl) {
68         printk("mdl %d:\n", i);
69         buffer = KsMapMdlBuffer(mdl);
70         KsDumpPrint(buffer, mdl->ByteCount);
71         len += mdl->ByteCount;
72         mdl = mdl->Next;
73     }
74     ASSERT(len == length);
75 }
76
77 /*
78  * KsLockUserBuffer
79  *   Allocate MDL for the buffer and lock the pages into
80  *   nonpaged pool
81  *
82  * Arguments:
83  *   UserBuffer:  the user buffer to be locked
84  *   Length:      length in bytes of the buffer
85  *   Operation:   read or write access
86  *   pMdl:        the result of the created mdl
87  *
88  * Return Value:
89  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
90  *                 or other error code)
91  *
92  * NOTES:
93  *   N/A
94  */
95
96 NTSTATUS
97 KsLockUserBuffer (
98     IN PVOID            UserBuffer,
99     IN BOOLEAN          bPaged,
100     IN ULONG            Length,
101     IN LOCK_OPERATION   Operation,
102     OUT PMDL *          pMdl
103     )
104 {
105     NTSTATUS    Status;
106     PMDL        Mdl = NULL;
107
108     LASSERT(UserBuffer != NULL);
109
110     *pMdl = NULL;
111
112     Mdl = IoAllocateMdl(
113                 UserBuffer,
114                 Length,
115                 FALSE,
116                 FALSE,
117                 NULL
118                 );
119
120     if (Mdl == NULL) {
121
122         Status = STATUS_INSUFFICIENT_RESOURCES;
123
124     } else {
125
126         __try {
127
128             if (bPaged) {
129                 MmProbeAndLockPages(
130                     Mdl,
131                     KernelMode,
132                     Operation
133                     );
134             } else {
135                 MmBuildMdlForNonPagedPool(
136                     Mdl
137                     );
138             }
139
140             Status = STATUS_SUCCESS;
141
142             *pMdl = Mdl;
143
144         } __except (EXCEPTION_EXECUTE_HANDLER) {
145
146             IoFreeMdl(Mdl);
147
148             Mdl = NULL;
149
150             cfs_enter_debugger();
151
152             Status = STATUS_INVALID_USER_BUFFER;
153         }
154     }
155
156     return Status;
157 }
158
159 /*
160  * KsMapMdlBuffer
161  *   Map the mdl into a buffer in kernel space
162  *
163  * Arguments:
164  *   Mdl:  the mdl to be mapped
165  *
166  * Return Value:
167  *   PVOID: the buffer mapped or NULL in failure
168  *
169  * NOTES:
170  *   N/A
171  */
172
173 PVOID
174 KsMapMdlBuffer (PMDL    Mdl)
175 {
176     LASSERT(Mdl != NULL);
177
178     return MmGetSystemAddressForMdlSafe(
179                 Mdl,
180                 NormalPagePriority
181                 );
182 }
183
184
185 /*
186  * KsReleaseMdl
187  *   Unlock all the pages in the mdl
188  *
189  * Arguments:
190  *   Mdl:  memory description list to be released
191  *
192  * Return Value:
193  *   N/A
194  *
195  * NOTES:
196  *   N/A
197  */
198
199 VOID
200 KsReleaseMdl (IN PMDL   Mdl,
201               IN int    Paged )
202 {
203     LASSERT(Mdl != NULL);
204
205     while (Mdl) {
206
207         PMDL    Next;
208
209         Next = Mdl->Next;
210
211         if (Paged) {
212             MmUnlockPages(Mdl);
213         }
214
215         IoFreeMdl(Mdl);
216
217         Mdl = Next;
218     }
219 }
220
221 /*
222  * KsQueryMdlsSize
223  *   Query the whole size of a MDL (may be chained)
224  *
225  * Arguments:
226  *   Mdl:  the Mdl to be queried
227  *
228  * Return Value:
229  *   ULONG: the total size of the mdl
230  *
231  * NOTES:
232  *   N/A
233  */
234
235 ULONG
236 KsQueryMdlsSize (PMDL Mdl)
237 {
238     PMDL    Next = Mdl;
239     ULONG   Length = 0;
240
241
242     //
243     // Walking the MDL Chain ...
244     //
245
246     while (Next) {
247         Length += MmGetMdlByteCount(Next);
248         Next = Next->Next;
249     }
250
251     return (Length);
252 }
253
254 /*
255  * KsCopyMdlToBuffer
256  *   Copy payload from  Mdl to buffer
257  *
258  * Arguments:
259  *   SourceMdl: the source mdl
260  *   SourceOffset: start offset of the source
261  *   DestinationBuffer: the dst buffer
262  *   DestinationOffset: the offset where data are to be copied.
263  *   BytesTobecopied: the expteced bytes to be copied
264  *
265  * Return Value:
266  *   Length of data copied from MDL to user buffer
267  *
268  * NOTES:
269  *   N/A
270  */
271
272 ULONG
273 KsCopyMdlToBuffer(
274     IN PMDL     SourceMdl,
275     IN ULONG    SourceOffset,
276     IN PVOID    DestinationBuffer,
277     IN ULONG    DestinationOffset,
278     IN ULONG    BytesTobeCopied
279     )
280 {
281     PUCHAR      SourceBuffer = NULL;
282     PUCHAR      TargetBuffer = DestinationBuffer;
283     ULONG       BytesCopied = 0;
284
285     if (MmGetMdlByteCount(SourceMdl) <= SourceOffset) {
286         return 0;
287     }
288
289     BytesCopied = MmGetMdlByteCount(SourceMdl) - SourceOffset;
290     if (BytesCopied > BytesTobeCopied) {
291         BytesCopied = BytesTobeCopied;
292     }
293
294     SourceBuffer = (PUCHAR)KsMapMdlBuffer(SourceMdl);
295
296     RtlMoveMemory(TargetBuffer + DestinationOffset,
297                   SourceBuffer + SourceOffset, BytesCopied);
298
299    return BytesCopied;
300 }
301
302 /*
303  * KsInitializeKsTsdu
304  *   Initialize the Tsdu buffer header
305  *
306  * Arguments:
307  *   KsTsdu: the Tsdu to be initialized
308  *   Length: the total length of the Tsdu
309  *
310  * Return Value:
311  *   VOID
312  *
313  * NOTES:
314  *   N/A
315  */
316
317 VOID
318 KsInitializeKsTsdu(
319     PKS_TSDU    KsTsdu,
320     ULONG       Length
321     )
322 {
323     KsTsdu->Magic = KS_TSDU_MAGIC;
324     KsTsdu->TotalLength = Length;
325     KsTsdu->StartOffset = KsTsdu->LastOffset =
326     KS_QWORD_ALIGN(sizeof(KS_TSDU));
327 }
328
329 /*
330  * KsAllocateKsTsdu
331  *   Reuse a Tsdu from the freelist or allocate a new Tsdu
332  *   from the LookAsideList table or the NonPagedPool
333  *
334  * Arguments:
335  *   N/A
336  *
337  * Return Value:
338  *   PKS_Tsdu: the new Tsdu or NULL if it fails
339  *
340  * Notes:
341  *   N/A
342  */
343
344 PKS_TSDU
345 KsAllocateKsTsdu()
346 {
347     PKS_TSDU    KsTsdu = NULL;
348
349         spin_lock(&(ks_data.ksnd_tsdu_lock));
350
351     if (!cfs_list_empty (&(ks_data.ksnd_freetsdus))) {
352
353         LASSERT(ks_data.ksnd_nfreetsdus > 0);
354
355         KsTsdu = cfs_list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
356         cfs_list_del(&(KsTsdu->Link));
357         ks_data.ksnd_nfreetsdus--;
358
359     } else {
360
361         KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
362                         ks_data.ksnd_tsdu_slab, 0);
363     }
364
365         spin_unlock(&(ks_data.ksnd_tsdu_lock));
366
367     if (NULL != KsTsdu) {
368         RtlZeroMemory(KsTsdu, ks_data.ksnd_tsdu_size);
369         KsInitializeKsTsdu(KsTsdu, (ULONG)ks_data.ksnd_tsdu_size);
370     }
371
372     return (KsTsdu);
373 }
374
375 /*
376  * KsFreeKsTsdu
377  *   Release a Tsdu: uninitialize then free it.
378  *
379  * Arguments:
380  *   KsTsdu: Tsdu to be freed.
381  *
382  * Return Value:
383  *   N/A
384  *
385  * Notes:
386  *   N/A
387  */
388
389 VOID
390 KsFreeKsTsdu(
391     PKS_TSDU  KsTsdu
392     )
393 {
394     cfs_mem_cache_free(
395             ks_data.ksnd_tsdu_slab,
396             KsTsdu );
397 }
398
399 /*
400  * KsPutKsTsdu
401  *   Move the Tsdu to the free tsdu list in ks_data.
402  *
403  * Arguments:
404  *   KsTsdu: Tsdu to be moved.
405  *
406  * Return Value:
407  *   N/A
408  *
409  * Notes:
410  *   N/A
411  */
412
413 VOID
414 KsPutKsTsdu(
415     PKS_TSDU  KsTsdu
416     )
417 {
418         spin_lock(&(ks_data.ksnd_tsdu_lock));
419         if (ks_data.ksnd_nfreetsdus > 128) {
420                 KsFreeKsTsdu(KsTsdu);
421         } else {
422                 cfs_list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
423                 ks_data.ksnd_nfreetsdus++;
424         }
425         spin_unlock(&(ks_data.ksnd_tsdu_lock));
426 }
427
428 /* with tconn lock acquired */
429 ks_mdl_t *
430 KsLockTsdus(
431     ks_tconn_t *    tconn,
432     PKS_TSDUMGR     TsduMgr,
433     PULONG          Flags,
434     PULONG          Length
435     )
436 {
437  
438     ks_mdl_t *      mdl = NULL;
439     ks_mdl_t *      tail = NULL;
440
441     PKS_TSDU        KsTsdu;
442     PKS_TSDU_DAT    KsTsduDat;
443     PKS_TSDU_BUF    KsTsduBuf;
444     PKS_TSDU_MDL    KsTsduMdl;
445
446     *Length  = 0;
447
448     cfs_list_for_each_entry_typed(KsTsdu,
449             &TsduMgr->TsduList,KS_TSDU, Link) {
450
451         ULONG   start = 0;
452
453         LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
454         start = KsTsdu->StartOffset;
455
456         while (start < KsTsdu->LastOffset) {
457
458             ks_mdl_t *  iov = NULL;
459
460             KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
461             KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
462             KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
463             LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
464                     KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
465                     KsTsduMdl->TsduType == TSDU_TYPE_MDL);
466
467             if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
468
469                 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->TotalLength);
470                 if (KsTsduDat->Mdl) {
471                     iov = KsTsduDat->Mdl;
472                 } else {
473                     KsLockUserBuffer(
474                         &KsTsduDat->Data[KsTsduDat->StartOffset],
475                         FALSE,
476                         KsTsduDat->DataLength,
477                         IoReadAccess,
478                         &iov );
479                     KsTsduDat->Mdl = iov;
480                 }
481 /*
482                 printk("KsLockTsdus: %u\n", KsTsduDat->DataLength);
483                 KsDumpPrint(
484                         &KsTsduDat->Data[KsTsduDat->StartOffset],
485                         KsTsduDat->DataLength);
486 */                        
487                 *Length += KsTsduDat->DataLength;
488                 start += KsTsduDat->TotalLength;
489
490             } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
491
492                 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
493                 if (KsTsduBuf->Mdl) {
494                     iov = KsTsduBuf->Mdl;
495                 } else {
496                     KsLockUserBuffer(
497                         (PUCHAR)KsTsduBuf->UserBuffer + 
498                                  KsTsduBuf->StartOffset,
499                         FALSE,
500                         KsTsduBuf->DataLength,
501                         IoReadAccess,
502                         &iov );
503                     KsTsduBuf->Mdl = iov;
504                 }
505
506                 *Length += KsTsduBuf->DataLength;
507                 start += sizeof(KS_TSDU_BUF);
508
509             } else {
510
511                 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
512                 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
513                 iov = KsTsduMdl->Mdl; 
514                 *Length += KsTsduMdl->DataLength;
515                 start += sizeof(KS_TSDU_MDL);
516             }
517
518             if (!iov) {
519                 cfs_enter_debugger();
520                 goto cleanup;
521             }
522
523             if (tail) {
524                 tail->Next = iov;
525             } else {
526                 mdl = iov;
527             }
528             tail = iov;
529             tail->Next = NULL;
530 /*
531             printk("KsLockTsdus: mdl %d\n", tail->ByteCount);
532             KsDumpMdlChain(tail, tail->ByteCount);
533 */
534         }
535     }
536 #if 0
537     if (Flags) {
538         *Flags = TsduFlags;
539     }
540 #endif
541     return mdl;
542
543 cleanup:
544     
545     *Length = 0;
546     return NULL;
547 }
548
549 ks_mdl_t *
550 KsSplitMdl(
551     IN ks_mdl_t *   master,
552     IN ULONG        offset,
553     IN ULONG        length
554     )
555 {
556     ks_mdl_t *  mdl = NULL;
557     char *      ptr = NULL;
558
559     /* calculate the start virtual address */
560     ptr = (char *)KsMapMdlBuffer(master) + offset;
561
562     /* allocate new mdl for new memory range */
563     mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
564
565     if (!mdl) {
566         return NULL;
567     }
568             
569     /* initialize the mdl */
570     IoBuildPartialMdl(master, mdl, (PVOID)ptr, length);
571
572     return mdl;
573 }
574
575 /* with tconn lock acquired */
576 VOID
577 KsReleaseTsdus(
578     ks_tconn_t *        tconn,
579     PKS_TSDUMGR         TsduMgr,
580     ULONG               length
581     )
582 {
583     PKS_TSDU        KsTsdu;
584     PKS_TSDU_DAT    KsTsduDat;
585     PKS_TSDU_BUF    KsTsduBuf;
586     PKS_TSDU_MDL    KsTsduMdl;
587 #if DBG    
588     ULONG           total = TsduMgr->TotalBytes;
589     ULONG           size = length;
590 #endif
591
592     LASSERT(TsduMgr->TotalBytes >= length);
593
594     while (!cfs_list_empty(&TsduMgr->TsduList)) {
595
596         ULONG   start = 0;
597
598         KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
599         LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
600         start = KsTsdu->StartOffset;
601
602         while (length > 0 && start < KsTsdu->LastOffset) {
603
604             ULONG           size = 0;
605             ks_mdl_t *      mdl = NULL;
606
607             KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
608             KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
609             KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
610             LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
611                     KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
612                     KsTsduMdl->TsduType == TSDU_TYPE_MDL);
613
614             if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
615
616                 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->DataLength);
617                 if (length >= KsTsduDat->DataLength) {
618                     /* whole tsdu is sent out */
619                     size = KsTsduDat->DataLength;
620                     start += KsTsduDat->TotalLength;
621                 } else {
622                     size = length;
623                     KsTsduDat->StartOffset += size;
624                 }
625
626                 if (KsTsduDat->Mdl) {
627                     mdl = KsTsduDat->Mdl;
628                     KsTsduDat->Mdl = NULL;
629                 }
630
631                 KsTsduDat->DataLength -= size;
632
633             } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
634
635                 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
636                 if (length >= KsTsduBuf->DataLength) {
637                     /* whole tsdu is sent out */
638                     size = KsTsduBuf->DataLength;
639                     start += sizeof(KS_TSDU_BUF);
640                     LASSERT(KsTsduBuf->UserBuffer);
641                     ExFreePool(KsTsduBuf->UserBuffer);
642                     KsTsduBuf->UserBuffer = NULL;
643                 } else {
644                     KsTsduBuf->StartOffset += length;
645                     size = length;
646                 }
647
648                 if (KsTsduBuf->Mdl) {
649                     mdl = KsTsduBuf->Mdl;
650                     KsTsduBuf->Mdl = NULL;
651                 }
652
653                 KsTsduBuf->DataLength -= size;
654                 
655             } else {
656
657                 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
658                 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
659                 mdl = KsTsduMdl->Mdl;
660                 if (length >= KsTsduMdl->DataLength) {
661                     /* whole mdl is sent out */
662                     size = KsTsduMdl->DataLength;
663                     start += sizeof(KS_TSDU_MDL);
664                     KsTsduMdl->Mdl = NULL;
665                 } else {
666                     /* now split the remained data out */
667                     ks_mdl_t * mdl1 = KsSplitMdl(mdl, length,
668                                   KsTsduMdl->DataLength - length);
669                     if (NULL == mdl1) {
670                         mdl->ByteOffset += length;
671                         mdl = NULL;
672                     } else {
673                         KsTsduMdl->Mdl = mdl1;
674                     }
675                     size = length;
676                     KsTsduMdl->StartOffset += size;
677                 }
678
679                 KsTsduMdl->DataLength -= size;
680             }
681
682             length -= size;
683             TsduMgr->TotalBytes -= size;
684
685             if (mdl) {
686                 mdl->Next = NULL;
687                 KsReleaseMdl(mdl, FALSE);
688             }
689
690             KsTsdu->StartOffset = start;
691         }
692
693         if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
694
695             /* remove KsTsdu from list */
696             cfs_list_del(&KsTsdu->Link);
697             TsduMgr->NumOfTsdu--;
698             KsPutKsTsdu(KsTsdu);
699         }
700
701         if (length == 0) {
702             break;
703         }
704     }
705
706     LASSERT(length == 0);
707 #if DBG
708     LASSERT(total - size == TsduMgr->TotalBytes);
709     KsPrint((4, "KsReleaseTsdus: TsduMgr=%p Remained=%xh (%xh)\n",
710                 TsduMgr, TsduMgr->TotalBytes, size ));
711 #endif
712 }
713
714 PKS_TSDUMGR
715 KsQueryTsduMgr(
716     ks_tconn_t *    tconn,
717     BOOLEAN         expedited,
718     BOOLEAN         sending
719     )
720 {
721
722     PKS_CHAIN           KsChain;
723     PKS_TSDUMGR         TsduMgr;
724
725     /* get the latest Tsdu buffer form TsduMgr list.
726        just set NULL if the list is empty. */
727
728     if (sending) {
729         if (tconn->kstc_type == kstt_sender) {
730             KsChain = &(tconn->sender.kstc_send);
731         } else {
732             LASSERT(tconn->kstc_type == kstt_child);
733             KsChain = &(tconn->child.kstc_send);
734         }
735     } else {
736         if (tconn->kstc_type == kstt_sender) {
737             KsChain = &(tconn->sender.kstc_recv);
738         } else {
739             LASSERT(tconn->kstc_type == kstt_child);
740             KsChain = &(tconn->child.kstc_recv);
741         }
742     }
743
744     if (expedited) {
745         TsduMgr = &(KsChain->Expedited);
746     } else {
747         TsduMgr = &(KsChain->Normal);
748     }
749
750     return TsduMgr;
751 }
752
753 PKS_TSDU
754 KsGetTsdu(PKS_TSDUMGR TsduMgr, ULONG Length)
755 {
756     PKS_TSDU KsTsdu = NULL;
757
758     /* retrieve the latest Tsdu buffer form TsduMgr
759        list if the list is not empty. */
760
761     if (cfs_list_empty(&(TsduMgr->TsduList))) {
762
763         LASSERT(TsduMgr->NumOfTsdu == 0);
764         KsTsdu = NULL;
765
766     } else {
767
768         LASSERT(TsduMgr->NumOfTsdu > 0);
769         KsTsdu = cfs_list_entry(TsduMgr->TsduList.prev, KS_TSDU, Link);
770
771         /* if this Tsdu does not contain enough space, we need
772            allocate a new Tsdu queue. */
773
774         if (KsTsdu->LastOffset + Length > KsTsdu->TotalLength) {
775             KsTsdu = NULL;
776         }
777     }
778
779     /* allocate a new Tsdu in case we are not statisfied. */
780     if (NULL == KsTsdu) {
781         KsTsdu = KsAllocateKsTsdu();
782         if (NULL != KsTsdu) {
783             cfs_list_add_tail(&(KsTsdu->Link), &(TsduMgr->TsduList));
784             TsduMgr->NumOfTsdu++;
785         }
786     }
787
788     return KsTsdu;
789 }
790
791 ULONG
792 KsWriteTsduDat(
793     PKS_TSDUMGR TsduMgr,
794     PCHAR       buffer,
795     ULONG       length,
796     ULONG       flags
797     )
798 {
799     PKS_TSDU            KsTsdu;
800     PKS_TSDU_DAT        KsTsduDat;
801     PKS_TSDU_BUF        KsTsduBuf;
802
803     BOOLEAN             bNewBuff = FALSE;
804     PCHAR               Buffer = NULL;
805
806 /*
807     printk("KsWriteTsduDat: %u\n", length);
808     KsDumpPrint(buffer, length);
809 */
810     /* if the Tsdu is even larger than the biggest Tsdu, we have
811        to allocate new buffer and use TSDU_TYPE_BUF to store it */
812
813     if ( KS_TSDU_STRU_SIZE(length) > ks_data.ksnd_tsdu_size -
814          KS_QWORD_ALIGN(sizeof(KS_TSDU))) {
815         bNewBuff = TRUE;
816     }
817
818     /* allocating the buffer for TSDU_TYPE_BUF */
819     if (bNewBuff) {
820         Buffer = ExAllocatePool(NonPagedPool, length);
821         if (NULL == Buffer) {
822             /* there's no enough memory for us. We just try to
823                receive maximum bytes with a new Tsdu */
824             bNewBuff = FALSE;
825             length = ks_data.ksnd_tsdu_size - KS_TSDU_STRU_SIZE(0) - 
826                      KS_QWORD_ALIGN(sizeof(KS_TSDU));
827         }
828     }
829
830     /* get empty Tsdu from TsduMgr */
831     KsTsdu = KsGetTsdu(TsduMgr, bNewBuff ? sizeof(KS_TSDU_BUF) :
832                                 KS_TSDU_STRU_SIZE(length) );
833
834     /* allocate a new Tsdu in case we are not statisfied. */
835     if (NULL == KsTsdu) {
836         goto errorout;
837     }
838
839     KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
840     KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
841
842     if (bNewBuff) {
843
844         /* setup up the KS_TSDU_BUF record */
845         KsTsduBuf->TsduType     = TSDU_TYPE_BUF;
846         KsTsduBuf->TsduFlags    = 0;
847         KsTsduBuf->StartOffset  = 0;
848         KsTsduBuf->UserBuffer   = Buffer;
849         KsTsduBuf->DataLength   = length;
850         KsTsduBuf->Mdl          = NULL;
851         if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
852             KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
853         }
854
855         KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
856
857     } else {
858
859         /* setup the KS_TSDU_DATA to contain all the messages */
860
861         KsTsduDat->TsduType     =  TSDU_TYPE_DAT;
862         KsTsduDat->TsduFlags    = 0;
863
864         if ( KsTsdu->TotalLength - KsTsdu->LastOffset < 
865             KS_TSDU_STRU_SIZE(length) ) {
866             length = KsTsdu->TotalLength - KsTsdu->LastOffset -
867                      FIELD_OFFSET(KS_TSDU_DAT, Data);
868         }
869         KsTsduDat->DataLength   =  length;
870         KsTsduDat->TotalLength  =  KS_TSDU_STRU_SIZE(length);
871         KsTsduDat->StartOffset  = 0;
872         KsTsduDat->Mdl = NULL;
873         if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
874             KsTsduDat->TsduFlags |= KS_TSDU_COMM_PARTIAL;
875         }
876
877         Buffer = &KsTsduDat->Data[0];
878         KsTsdu->LastOffset += KsTsduDat->TotalLength;
879     }
880
881     RtlMoveMemory(Buffer, buffer, length);
882     TsduMgr->TotalBytes += length;
883
884     KsPrint((4, "KsWriteTsduDat: TsduMgr=%p bytes in queue:%xh (%xh)\n",
885                 TsduMgr, TsduMgr->TotalBytes, length));
886     return length;
887
888 errorout:
889
890     return 0;
891 }
892
893 ULONG
894 KsWriteTsduBuf(
895     PKS_TSDUMGR TsduMgr,
896     PCHAR       buffer,
897     ULONG       length,
898     ULONG       flags
899     )
900 {
901     PKS_TSDU            KsTsdu;
902     PKS_TSDU_BUF        KsTsduBuf;
903
904     /* get empty Tsdu from TsduMgr */
905     KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_BUF));
906
907     /* allocate a new Tsdu in case we are not statisfied. */
908     if (NULL == KsTsdu) {
909         goto errorout;
910     }
911
912     /* setup up the KS_TSDU_BUF record */
913     KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
914     KsTsduBuf->TsduType     = TSDU_TYPE_BUF;
915     KsTsduBuf->TsduFlags    = 0;
916     KsTsduBuf->StartOffset  = 0;
917     KsTsduBuf->UserBuffer   = buffer;
918     KsTsduBuf->DataLength   = length;
919     KsTsduBuf->Mdl          = NULL;
920     KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
921     if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
922         KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
923     }
924
925     TsduMgr->TotalBytes  +=  length;
926     KsPrint((4, "KsWriteTsduBuf: TsduMgr=%p bytes in queue:%xh (%xh)\n",
927                 TsduMgr, TsduMgr->TotalBytes, length));
928
929     return length;
930
931 errorout:
932     return 0;
933 }
934
935 ULONG
936 KsWriteTsduMdl(
937     PKS_TSDUMGR     TsduMgr,
938     ks_mdl_t *      mdl, 
939     PVOID           desc,
940     ULONG           offset,
941     ULONG           length,
942     ULONG           flags
943     )
944 {
945     PKS_TSDU            KsTsdu;
946     PKS_TSDU_MDL        KsTsduMdl;
947
948     /* get empty Tsdu from TsduMgr */
949     KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_MDL));
950
951     /* allocate a new Tsdu in case we are not statisfied. */
952     if (NULL == KsTsdu) {
953         goto errorout;
954     }
955
956     /* setup up the KS_TSDU_MDL record */
957     KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
958     KsTsduMdl->TsduType     = TSDU_TYPE_MDL;
959     KsTsduMdl->TsduFlags    = 0;
960     KsTsduMdl->StartOffset  = 0;
961     KsTsduMdl->BaseOffset   = offset;
962     KsTsduMdl->DataLength   = length;
963     KsTsduMdl->Mdl          = mdl;
964     KsTsduMdl->Descriptor   = desc;
965     KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
966     if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
967         KsTsduMdl->TsduFlags |= KS_TSDU_COMM_PARTIAL;
968     }
969
970     TsduMgr->TotalBytes  +=  length;
971     KsPrint((4, "KsWriteTsduMdl: TsduMgr=%p bytes in queue:%xh (%xh)\n",
972                 TsduMgr, TsduMgr->TotalBytes, length));
973
974     return length;
975
976 errorout:
977     return 0;
978 }
979
980 ULONG
981 KsReadTsdu (
982     PKS_TSDUMGR     TsduMgr,
983     PCHAR           buffer,
984     ULONG           length,
985     ULONG           flags
986     )
987 {
988     PKS_TSDU        KsTsdu;
989     PKS_TSDU_DAT    KsTsduDat;
990     PKS_TSDU_BUF    KsTsduBuf;
991     PKS_TSDU_MDL    KsTsduMdl;
992
993     PUCHAR          Buffer;
994     ULONG           BytesRecved = 0;
995 #if DBG
996     ULONG           TotalBytes = TsduMgr->TotalBytes;
997 #endif    
998
999     KsPrint((4, "KsReadTsdu: TsduMgr=%p request=%xh total=%xh\n",
1000                 TsduMgr, length, TsduMgr->TotalBytes ));
1001 NextTsdu:
1002
1003     if (TsduMgr->TotalBytes == 0) {
1004
1005         /* It's a notification event. We need reset it to
1006            un-signaled state in case there no any tsdus. */
1007
1008         KeResetEvent(&(TsduMgr->Event));
1009
1010     } else {
1011
1012         KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1013         LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1014
1015         /* remove the KsTsdu from TsduMgr list to release the lock */
1016         cfs_list_del(&(KsTsdu->Link));
1017         TsduMgr->NumOfTsdu--;
1018
1019         while (length > BytesRecved) {
1020
1021             ULONG BytesToCopy = 0;
1022             ULONG StartOffset = 0;
1023             ULONG BytesCopied = 0;
1024
1025             if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1026                 /* KsTsdu is empty now, we need free it ... */
1027                 KsPutKsTsdu(KsTsdu);
1028                 KsTsdu = NULL;
1029                 break;
1030             }
1031
1032             KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1033             KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1034             KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1035
1036             if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
1037                  TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
1038
1039                 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1040
1041                     /* Data Tsdu Unit ... */
1042                     Buffer = &KsTsduDat->Data[0];
1043                     StartOffset = KsTsduDat->StartOffset;
1044                     if (KsTsduDat->DataLength - KsTsduDat->StartOffset > length - BytesRecved) {
1045                         /* Recvmsg requst could be statisfied ... */
1046                         BytesToCopy = length - BytesRecved;
1047                     } else {
1048                         BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
1049                     }
1050
1051                 } else {
1052
1053                     /* Buffer Tsdu Unit */
1054                     ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1055                     Buffer = KsTsduBuf->UserBuffer;
1056                     StartOffset = KsTsduBuf->StartOffset;
1057
1058                     if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > length - BytesRecved) {
1059                         /* Recvmsg requst could be statisfied ... */
1060                         BytesToCopy = length - BytesRecved;
1061                     } else {
1062                         BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
1063                     }
1064                 }
1065
1066                 if (BytesToCopy > 0) {
1067                     RtlMoveMemory(buffer + BytesRecved, Buffer + StartOffset, BytesToCopy);
1068                 }
1069                 BytesCopied = BytesToCopy;
1070                 BytesRecved += BytesCopied;
1071                 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1072                 TsduMgr->TotalBytes -= BytesCopied;
1073                 KsPrint((4, "KsReadTsdu: TsduMgr=%p copied=%xh recved=%xh\n",
1074                             TsduMgr, BytesCopied, BytesRecved ));
1075
1076                 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1077
1078                     KsTsduDat->StartOffset += BytesCopied;
1079                     if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
1080                         if (KsTsduDat->Mdl) {
1081                             KsTsduDat->Mdl->Next = NULL;
1082                             KsReleaseMdl(KsTsduDat->Mdl, FALSE);
1083                         }
1084                         KsTsdu->StartOffset += KsTsduDat->TotalLength;
1085                     }
1086
1087                 } else {
1088
1089                     ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1090                     KsTsduBuf->StartOffset += BytesCopied;
1091                     if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
1092                         KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1093                         /* now we need release the buf to system pool */
1094                         if (KsTsduBuf->Mdl) {
1095                             KsTsduBuf->Mdl->Next = NULL;
1096                             KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1097                         }
1098                         ExFreePool(KsTsduBuf->UserBuffer);
1099                     }
1100                 }
1101
1102             } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1103
1104                 /* MDL Tsdu Unit ... */
1105                 if (KsTsduMdl->DataLength > length - BytesRecved) {
1106                     /* Recvmsg requst could be statisfied ... */
1107                     BytesToCopy = length - BytesRecved;
1108                 } else {
1109                     BytesToCopy = KsTsduMdl->DataLength;
1110                 }
1111
1112                 BytesCopied = 
1113                     KsCopyMdlToBuffer(
1114                             KsTsduMdl->Mdl,
1115                             KsTsduMdl->StartOffset + 
1116                             KsTsduMdl->BaseOffset,
1117                             buffer,
1118                             BytesRecved,
1119                             BytesToCopy
1120                             );
1121                 KsPrint((4, "KsReadTsdu: TsduMgr=%p mdl=%p dec=%p copied=%xh "
1122                             "recved=%xh\n",
1123                             TsduMgr, KsTsduMdl->Mdl, KsTsduMdl->Descriptor,
1124                             BytesCopied, BytesRecved + BytesCopied));
1125                 if (BytesCopied == 0) {
1126                     cfs_enter_debugger();
1127                     break;
1128                 }
1129
1130                 KsTsduMdl->StartOffset += BytesCopied;
1131                 KsTsduMdl->DataLength  -= BytesCopied;
1132                 BytesRecved += BytesCopied;
1133                 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1134                 TsduMgr->TotalBytes -= BytesCopied;
1135
1136                 if (0 == KsTsduMdl->DataLength) {
1137
1138                     /* Call TdiReturnChainedReceives to release the Tsdu memory */
1139                     LASSERT(KsTsduMdl->Descriptor != NULL);
1140                     if (KsTsduMdl->Descriptor) {
1141                         TdiReturnChainedReceives(
1142                             &(KsTsduMdl->Descriptor),
1143                             1 );
1144                     }
1145
1146                     KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1147                 }
1148
1149             } else {
1150                 KsPrint((1, "KsReadTsdu: unknown tsdu slot: slot = %x type = %x Start= %x Length=%x\n",
1151                         KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength));
1152                 KsPrint((1, "            Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x\n",
1153                         KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength));
1154                 cfs_enter_debugger();
1155             }
1156         }
1157
1158         /* we need attach the KsTsdu to the list header */
1159         if (KsTsdu) {
1160             if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1161                 KsPutKsTsdu(KsTsdu);
1162                 KsTsdu = NULL;
1163             } else {
1164                 TsduMgr->NumOfTsdu++;
1165                 cfs_list_add(&(KsTsdu->Link), &(TsduMgr->TsduList));
1166             }
1167         }
1168         
1169         if (length > BytesRecved) {
1170             goto NextTsdu;
1171         }
1172     }
1173
1174 #if DBG
1175     LASSERT(TotalBytes == TsduMgr->TotalBytes + BytesRecved);
1176 #endif
1177     KsPrint((4, "KsReadTsdu: TsduMgr=%p recved=%xh (%xh) remained=%xh\n",
1178                 TsduMgr, BytesRecved, length, TsduMgr->TotalBytes ));
1179
1180     return BytesRecved;
1181 }
1182
1183
1184 ULONG
1185 KsTdiSendFlags(int SockFlags)
1186 {
1187     ULONG   TdiFlags = 0;
1188
1189     if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1190         cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
1191     }
1192
1193     if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1194         cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
1195     }
1196
1197     if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1198         cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1199     }
1200
1201     return TdiFlags;
1202 }
1203
1204 ULONG
1205 KsTdiRecvFlags(int SockFlags)
1206 {
1207     ULONG   TdiFlags = 0;
1208
1209     if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1210         cfs_set_flag(TdiFlags, TDI_RECEIVE_EXPEDITED);
1211     }
1212
1213     if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1214         cfs_set_flag(TdiFlags, TDI_RECEIVE_PARTIAL);
1215     }
1216
1217     if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1218         cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1219     }
1220
1221     return TdiFlags;
1222 }
1223
1224 int
1225 KsWriteTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1226 {
1227     int rc = 0;
1228
1229     if (TsduMgr->TotalBytes <= TDINAL_MAX_TSDU_QUEUE_SIZE) {
1230         rc = KsWriteTsduDat(TsduMgr, buffer, length, flags);
1231     }
1232
1233     if (rc > 0) {
1234         return rc;
1235     }
1236
1237    return -EAGAIN;
1238 }
1239
1240 int
1241 KsReadTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1242 {
1243     int rc = KsReadTsdu(TsduMgr, buffer, length, flags);
1244
1245     if (rc > 0) {
1246         return rc;
1247     }
1248
1249     return -EAGAIN;
1250 }
1251
1252 /*
1253  * KsInitializeKsTsduMgr
1254  *   Initialize the management structure of
1255  *   Tsdu buffers
1256  *
1257  * Arguments:
1258  *   TsduMgr: the TsduMgr to be initialized
1259  *
1260  * Return Value:
1261  *   VOID
1262  *
1263  * NOTES:
1264  *   N/A
1265  */
1266
1267 VOID
1268 KsInitializeKsTsduMgr(
1269     PKS_TSDUMGR     TsduMgr
1270     )
1271 {
1272     KeInitializeEvent(
1273             &(TsduMgr->Event),
1274             NotificationEvent,
1275             FALSE
1276             );
1277
1278     CFS_INIT_LIST_HEAD(
1279             &(TsduMgr->TsduList)
1280             );
1281
1282     TsduMgr->NumOfTsdu  = 0;
1283     TsduMgr->TotalBytes = 0;
1284
1285         spin_lock_init(&TsduMgr->Lock);
1286 }
1287
1288
1289 /*
1290  * KsInitializeKsChain
1291  *   Initialize the China structure for receiving
1292  *   or transmitting
1293  *
1294  * Arguments:
1295  *   KsChain: the KsChain to be initialized
1296  *
1297  * Return Value:
1298  *   VOID
1299  *
1300  * NOTES:
1301  *   N/A
1302  */
1303
1304 VOID
1305 KsInitializeKsChain(
1306     PKS_CHAIN       KsChain
1307     )
1308 {
1309     KsInitializeKsTsduMgr(&(KsChain->Normal));
1310     KsInitializeKsTsduMgr(&(KsChain->Expedited));
1311     KsChain->Expedited.OOB = TRUE;
1312 }
1313
1314
1315 /*
1316  * KsCleanupTsduMgr
1317  *   Clean up all the Tsdus in the TsduMgr list
1318  *
1319  * Arguments:
1320  *   TsduMgr: the Tsdu list manager
1321  *
1322  * Return Value:
1323  *   NTSTATUS:  nt status code
1324  *
1325  * NOTES:
1326  *   N/A
1327  */
1328
1329 NTSTATUS
1330 KsCleanupTsduMgr(
1331     PKS_TSDUMGR     TsduMgr
1332     )
1333 {
1334     PKS_TSDU        KsTsdu;
1335     PKS_TSDU_DAT    KsTsduDat;
1336     PKS_TSDU_BUF    KsTsduBuf;
1337     PKS_TSDU_MDL    KsTsduMdl;
1338
1339     LASSERT(NULL != TsduMgr);
1340
1341     KsRemoveTdiEngine(TsduMgr);
1342     KeSetEvent(&(TsduMgr->Event), 0, FALSE);
1343
1344     while (!cfs_list_empty(&TsduMgr->TsduList)) {
1345
1346         KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1347         LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1348
1349         if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
1350
1351             //
1352             // KsTsdu is empty now, we need free it ...
1353             //
1354
1355             cfs_list_del(&(KsTsdu->Link));
1356             TsduMgr->NumOfTsdu--;
1357
1358             KsFreeKsTsdu(KsTsdu);
1359
1360         } else {
1361
1362             KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1363             KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1364             KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1365
1366             if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1367
1368                 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1369
1370             } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
1371
1372                 ASSERT(KsTsduBuf->UserBuffer != NULL);
1373
1374                 if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
1375                     if (KsTsduBuf->Mdl) {
1376                         KsTsduBuf->Mdl->Next = NULL;
1377                         KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1378                     }
1379                     ExFreePool(KsTsduBuf->UserBuffer);
1380                 } else {
1381                     cfs_enter_debugger();
1382                 }
1383
1384                 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1385
1386             } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1387
1388                 //
1389                 // MDL Tsdu Unit ...
1390                 //
1391                 if (KsTsduMdl->Descriptor) {
1392                     TdiReturnChainedReceives(
1393                         &(KsTsduMdl->Descriptor),
1394                         1 );
1395                 } else if (KsTsduMdl->Mdl) {
1396                     KsTsduMdl->Mdl->Next = NULL;
1397                     KsReleaseMdl(KsTsduMdl->Mdl, FALSE);
1398                 }
1399
1400                 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1401             }
1402         }
1403     }
1404
1405     return STATUS_SUCCESS;
1406 }
1407
1408
1409 /*
1410  * KsCleanupKsChain
1411  *   Clean up the TsduMgrs of the KsChain
1412  *
1413  * Arguments:
1414  *   KsChain: the chain managing TsduMgr
1415  *
1416  * Return Value:
1417  *   NTSTATUS:  nt status code
1418  *
1419  * NOTES:
1420  *   N/A
1421  */
1422
1423 NTSTATUS
1424 KsCleanupKsChain(
1425     PKS_CHAIN   KsChain
1426     )
1427 {
1428     NTSTATUS    Status;
1429
1430     LASSERT(NULL != KsChain);
1431
1432     Status = KsCleanupTsduMgr(
1433                 &(KsChain->Normal)
1434                 );
1435
1436     if (!NT_SUCCESS(Status)) {
1437         cfs_enter_debugger();
1438         goto errorout;
1439     }
1440
1441     Status = KsCleanupTsduMgr(
1442                 &(KsChain->Expedited)
1443                 );
1444
1445     if (!NT_SUCCESS(Status)) {
1446         cfs_enter_debugger();
1447         goto errorout;
1448     }
1449
1450 errorout:
1451
1452     return Status;
1453 }
1454
1455
1456 /*
1457  * KsCleanupTsdu
1458  *   Clean up all the Tsdus of a tdi connected object
1459  *
1460  * Arguments:
1461  *   tconn: the tdi connection which is connected already.
1462  *
1463  * Return Value:
1464  *   Nt status code
1465  *
1466  * NOTES:
1467  *   N/A
1468  */
1469
1470 NTSTATUS
1471 KsCleanupTsdu(
1472     ks_tconn_t * tconn
1473     )
1474 {
1475     NTSTATUS        Status = STATUS_SUCCESS;
1476
1477
1478     if (tconn->kstc_type != kstt_sender &&
1479         tconn->kstc_type != kstt_child ) {
1480
1481         goto errorout;
1482     }
1483
1484     if (tconn->kstc_type == kstt_sender) {
1485
1486         Status = KsCleanupKsChain(
1487                     &(tconn->sender.kstc_recv)
1488                     );
1489
1490         if (!NT_SUCCESS(Status)) {
1491             cfs_enter_debugger();
1492             goto errorout;
1493         }
1494
1495         Status = KsCleanupKsChain(
1496                     &(tconn->sender.kstc_send)
1497                     );
1498
1499         if (!NT_SUCCESS(Status)) {
1500             cfs_enter_debugger();
1501             goto errorout;
1502         }
1503
1504     } else {
1505
1506         Status = KsCleanupKsChain(
1507                     &(tconn->child.kstc_recv)
1508                     );
1509
1510         if (!NT_SUCCESS(Status)) {
1511             cfs_enter_debugger();
1512             goto errorout;
1513         }
1514
1515         Status = KsCleanupKsChain(
1516                     &(tconn->child.kstc_send)
1517                     );
1518
1519         if (!NT_SUCCESS(Status)) {
1520             cfs_enter_debugger();
1521             goto errorout;
1522         }
1523
1524     }
1525
1526 errorout:
1527
1528     return (Status);
1529 }
1530
1531 NTSTATUS
1532 KsIrpCompletionRoutine(
1533     IN PDEVICE_OBJECT    DeviceObject,
1534     IN PIRP              Irp,
1535     IN PVOID             Context
1536     )
1537 {
1538     if (NULL != Context) {
1539         KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
1540     }
1541
1542     return STATUS_MORE_PROCESSING_REQUIRED;
1543
1544     UNREFERENCED_PARAMETER(DeviceObject);
1545     UNREFERENCED_PARAMETER(Irp);
1546 }
1547
1548
1549 /*
1550  * KsBuildTdiIrp
1551  *   Allocate a new IRP and initialize it to be issued to tdi
1552  *
1553  * Arguments:
1554  *   DeviceObject:  device object created by the underlying
1555  *                  TDI transport driver
1556  *
1557  * Return Value:
1558  *   PRIP:   the allocated Irp in success or NULL in failure.
1559  *
1560  * NOTES:
1561  *   N/A
1562  */
1563
1564 PIRP
1565 KsBuildTdiIrp(
1566     IN PDEVICE_OBJECT    DeviceObject
1567     )
1568 {
1569     PIRP                Irp;
1570     PIO_STACK_LOCATION  IrpSp;
1571
1572     //
1573     // Allocating the IRP ...
1574     //
1575
1576     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1577
1578     if (NULL != Irp) {
1579
1580         //
1581         // Getting the Next Stack Location ...
1582         //
1583
1584         IrpSp = IoGetNextIrpStackLocation(Irp);
1585
1586         //
1587         // Initializing Irp ...
1588         //
1589
1590         IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1591         IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
1592     }
1593
1594     return Irp;
1595 }
1596
1597 /*
1598  * KsSubmitTdiIrp
1599  *   Issue the Irp to the underlying tdi driver
1600  *
1601  * Arguments:
1602  *   DeviceObject:  the device object created by TDI driver
1603  *   Irp:           the I/O request packet to be processed
1604  *   bSynchronous:  synchronous or not. If true, we need wait
1605  *                  until the process is finished.
1606  *   Information:   returned info
1607  *
1608  * Return Value:
1609  *   NTSTATUS:      kernel status code
1610  *
1611  * NOTES:
1612  *   N/A
1613  */
1614
1615 NTSTATUS
1616 KsSubmitTdiIrp(
1617     IN PDEVICE_OBJECT   DeviceObject,
1618     IN PIRP             Irp,
1619     IN BOOLEAN          bSynchronous,
1620     OUT PULONG          Information
1621     )
1622 {
1623     NTSTATUS            Status;
1624     KEVENT              Event;
1625
1626     if (bSynchronous) {
1627
1628         KeInitializeEvent(
1629             &Event,
1630             SynchronizationEvent,
1631             FALSE
1632             );
1633
1634
1635         IoSetCompletionRoutine(
1636             Irp,
1637             KsIrpCompletionRoutine,
1638             &Event,
1639             TRUE,
1640             TRUE,
1641             TRUE
1642             );
1643     }
1644
1645     Status = IoCallDriver(DeviceObject, Irp);
1646
1647     if (bSynchronous) {
1648
1649         if (STATUS_PENDING == Status) {
1650
1651             Status = KeWaitForSingleObject(
1652                         &Event,
1653                         Executive,
1654                         KernelMode,
1655                         FALSE,
1656                         NULL
1657                         );
1658         }
1659
1660         Status = Irp->IoStatus.Status;
1661
1662         if (Information) {
1663             *Information = (ULONG)(Irp->IoStatus.Information);
1664         }
1665
1666         IoFreeIrp(Irp);
1667     }
1668
1669     if (!NT_SUCCESS(Status)) {
1670
1671         KsPrint((1, "KsSubmitTdiIrp: Error when submitting the Irp: "
1672                     "Status = %xh (%s)\n", Status, KsNtStatusToString(Status)));
1673     }
1674
1675     return (Status);
1676 }
1677
1678
1679
1680 /*
1681  * KsOpenControl
1682  *   Open the Control Channel Object ...
1683  *
1684  * Arguments:
1685  *   DeviceName:   the device name to be opened
1686  *   Handle:       opened handle in success case
1687  *   FileObject:   the fileobject of the device
1688  *
1689  * Return Value:
1690  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
1691  *                 or other error code)
1692  *
1693  * Notes:
1694  *   N/A
1695  */
1696
1697 NTSTATUS
1698 KsOpenControl(
1699     IN PUNICODE_STRING      DeviceName,
1700     OUT HANDLE *            Handle,
1701     OUT PFILE_OBJECT *      FileObject
1702    )
1703 {
1704     NTSTATUS          Status = STATUS_SUCCESS;
1705
1706     OBJECT_ATTRIBUTES ObjectAttributes;
1707     IO_STATUS_BLOCK   IoStatus;
1708
1709
1710     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1711
1712     //
1713     // Initializing ...
1714     //
1715
1716     InitializeObjectAttributes(
1717         &ObjectAttributes,
1718         DeviceName,
1719         OBJ_CASE_INSENSITIVE |
1720         OBJ_KERNEL_HANDLE,
1721         NULL,
1722         NULL
1723         );
1724
1725     LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL );
1726
1727     //
1728     // Creating the Transport Address Object ...
1729     //
1730
1731     Status = ZwCreateFile(
1732                 Handle,
1733                 FILE_READ_DATA | FILE_WRITE_DATA,
1734                 &ObjectAttributes,
1735                 &IoStatus,
1736                 0,
1737                 FILE_ATTRIBUTE_NORMAL,
1738                 FILE_SHARE_READ | FILE_SHARE_WRITE,
1739                 FILE_OPEN,
1740                 0,
1741                 NULL,
1742                 0
1743                 );
1744
1745
1746     if (NT_SUCCESS(Status)) {
1747
1748         //
1749         // Now Obtaining the FileObject of the Transport Address ...
1750         //
1751
1752         Status = ObReferenceObjectByHandle(
1753                     *Handle,
1754                     FILE_ANY_ACCESS,
1755                     NULL,
1756                     KernelMode,
1757                     FileObject,
1758                     NULL
1759                     );
1760
1761         if (!NT_SUCCESS(Status)) {
1762
1763             cfs_enter_debugger();
1764             ZwClose(*Handle);
1765         }
1766
1767     } else {
1768
1769         cfs_enter_debugger();
1770     }
1771
1772     return (Status);
1773 }
1774
1775
1776 /*
1777  * KsCloseControl
1778  *   Release the Control Channel Handle and FileObject
1779  *
1780  * Arguments:
1781  *   Handle:       the channel handle to be released
1782  *   FileObject:   the fileobject to be released
1783  *
1784  * Return Value:
1785  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
1786  *                 or other error code)
1787  *
1788  * Notes:
1789  *   N/A
1790  */
1791
1792 NTSTATUS
1793 KsCloseControl(
1794     IN HANDLE             Handle,
1795     IN PFILE_OBJECT       FileObject
1796    )
1797 {
1798     NTSTATUS  Status = STATUS_SUCCESS;
1799
1800     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1801
1802     if (FileObject) {
1803
1804         ObDereferenceObject(FileObject);
1805     }
1806
1807     if (Handle) {
1808
1809         Status = ZwClose(Handle);
1810     }
1811
1812     ASSERT(NT_SUCCESS(Status));
1813
1814     return (Status);
1815 }
1816
1817
1818 /*
1819  * KsOpenAddress
1820  *   Open the tdi address object
1821  *
1822  * Arguments:
1823  *   DeviceName:   device name of the address object
1824  *   pAddress:     tdi address of the address object
1825  *   AddressLength: length in bytes of the tdi address
1826  *   Handle:       the newly opened handle
1827  *   FileObject:   the newly opened fileobject
1828  *
1829  * Return Value:
1830  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
1831  *                 or other error code)
1832  *
1833  * Notes:
1834  *   N/A
1835  */
1836
1837 NTSTATUS
1838 KsOpenAddress(
1839     IN PUNICODE_STRING      DeviceName,
1840     IN PTRANSPORT_ADDRESS   pAddress,
1841     IN ULONG                AddressLength,
1842     OUT HANDLE *            Handle,
1843     OUT PFILE_OBJECT *      FileObject
1844    )
1845 {
1846     NTSTATUS          Status = STATUS_SUCCESS;
1847
1848     PFILE_FULL_EA_INFORMATION Ea = NULL;
1849     ULONG             EaLength;
1850     UCHAR             EaBuffer[EA_MAX_LENGTH];
1851
1852     OBJECT_ATTRIBUTES ObjectAttributes;
1853     IO_STATUS_BLOCK   IoStatus;
1854
1855     //
1856     // Building EA for the Address Object to be Opened ...
1857     //
1858
1859     Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1860     Ea->NextEntryOffset = 0;
1861     Ea->Flags = 0;
1862     Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
1863     Ea->EaValueLength = (USHORT)AddressLength;
1864     RtlCopyMemory(
1865         &(Ea->EaName),
1866         TdiTransportAddress,
1867         Ea->EaNameLength + 1
1868         );
1869     RtlMoveMemory(
1870         &(Ea->EaName[Ea->EaNameLength + 1]),
1871         pAddress,
1872         AddressLength
1873         );
1874     EaLength =  sizeof(FILE_FULL_EA_INFORMATION) +
1875                 Ea->EaNameLength + AddressLength;
1876
1877     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1878
1879
1880     //
1881     // Initializing ...
1882     //
1883
1884     InitializeObjectAttributes(
1885         &ObjectAttributes,
1886         DeviceName,
1887         OBJ_CASE_INSENSITIVE |
1888         OBJ_KERNEL_HANDLE,
1889         NULL,
1890         NULL
1891         );
1892
1893     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1894
1895     //
1896     // Creating the Transport Address Object ...
1897     //
1898
1899     Status = ZwCreateFile(
1900                 Handle,
1901                 FILE_READ_DATA | FILE_WRITE_DATA,
1902                 &ObjectAttributes,
1903                 &IoStatus,
1904                 0,
1905                 FILE_ATTRIBUTE_NORMAL,
1906                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
1907                 FILE_OPEN,
1908                 0,
1909                 Ea,
1910                 EaLength
1911                 );
1912
1913
1914     if (NT_SUCCESS(Status)) {
1915
1916         //
1917         // Now Obtaining the FileObject of the Transport Address ...
1918         //
1919
1920         Status = ObReferenceObjectByHandle(
1921                     *Handle,
1922                     FILE_ANY_ACCESS,
1923                     NULL,
1924                     KernelMode,
1925                     FileObject,
1926                     NULL
1927                     );
1928
1929         if (!NT_SUCCESS(Status)) {
1930
1931             cfs_enter_debugger();
1932             ZwClose(*Handle);
1933         }
1934
1935     } else {
1936
1937         cfs_enter_debugger();
1938     }
1939
1940     return (Status);
1941 }
1942
1943 /*
1944  * KsCloseAddress
1945  *   Release the Hanlde and FileObject of an opened tdi
1946  *   address object
1947  *
1948  * Arguments:
1949  *   Handle:       the handle to be released
1950  *   FileObject:   the fileobject to be released
1951  *
1952  * Return Value:
1953  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
1954  *                 or other error code)
1955  *
1956  * Notes:
1957  *   N/A
1958  */
1959
1960 NTSTATUS
1961 KsCloseAddress(
1962     IN HANDLE             Handle,
1963     IN PFILE_OBJECT       FileObject
1964 )
1965 {
1966     NTSTATUS  Status = STATUS_SUCCESS;
1967
1968     if (FileObject) {
1969
1970         ObDereferenceObject(FileObject);
1971     }
1972
1973     if (Handle) {
1974
1975         Status = ZwClose(Handle);
1976     }
1977
1978     ASSERT(NT_SUCCESS(Status));
1979
1980     return (Status);
1981 }
1982
1983
1984 /*
1985  * KsOpenConnection
1986  *   Open a tdi connection object
1987  *
1988  * Arguments:
1989  *   DeviceName:   device name of the connection object
1990  *   ConnectionContext: the connection context
1991  *   Handle:       the newly opened handle
1992  *   FileObject:   the newly opened fileobject
1993  *
1994  * Return Value:
1995  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
1996  *                 or other error code)
1997  *
1998  * Notes:
1999  *   N/A
2000  */
2001
2002 NTSTATUS
2003 KsOpenConnection(
2004     IN PUNICODE_STRING      DeviceName,
2005     IN CONNECTION_CONTEXT   ConnectionContext,
2006     OUT HANDLE *            Handle,
2007     OUT PFILE_OBJECT *      FileObject
2008    )
2009 {
2010     NTSTATUS            Status = STATUS_SUCCESS;
2011
2012     PFILE_FULL_EA_INFORMATION Ea = NULL;
2013     ULONG               EaLength;
2014     UCHAR               EaBuffer[EA_MAX_LENGTH];
2015
2016     OBJECT_ATTRIBUTES   ObjectAttributes;
2017     IO_STATUS_BLOCK     IoStatus;
2018
2019     //
2020     // Building EA for the Address Object to be Opened ...
2021     //
2022
2023     Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
2024     Ea->NextEntryOffset = 0;
2025     Ea->Flags = 0;
2026     Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
2027     Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
2028     RtlCopyMemory(
2029         &(Ea->EaName),
2030         TdiConnectionContext,
2031         Ea->EaNameLength + 1
2032         );
2033     RtlMoveMemory(
2034         &(Ea->EaName[Ea->EaNameLength + 1]),
2035         &ConnectionContext,
2036         sizeof(CONNECTION_CONTEXT)
2037         );
2038     EaLength =  sizeof(FILE_FULL_EA_INFORMATION) - 1 +
2039                                 Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
2040
2041     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2042
2043
2044     //
2045     // Initializing ...
2046     //
2047
2048     InitializeObjectAttributes(
2049         &ObjectAttributes,
2050         DeviceName,
2051         OBJ_CASE_INSENSITIVE |
2052         OBJ_KERNEL_HANDLE,
2053         NULL,
2054         NULL
2055         );
2056
2057     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2058
2059     //
2060     // Creating the Connection Object ...
2061     //
2062
2063     Status = ZwCreateFile(
2064                 Handle,
2065                 FILE_READ_DATA | FILE_WRITE_DATA,
2066                 &ObjectAttributes,
2067                 &IoStatus,
2068                 NULL,
2069                 FILE_ATTRIBUTE_NORMAL,
2070                 FILE_SHARE_READ | FILE_SHARE_WRITE,
2071                 FILE_OPEN,
2072                 0,
2073                 Ea,
2074                 EaLength
2075                 );
2076
2077
2078     if (NT_SUCCESS(Status)) {
2079
2080         //
2081         // Now Obtaining the FileObject of the Transport Address ...
2082         //
2083
2084         Status = ObReferenceObjectByHandle(
2085                     *Handle,
2086                     FILE_ANY_ACCESS,
2087                     NULL,
2088                     KernelMode,
2089                     FileObject,
2090                     NULL
2091                     );
2092
2093         if (!NT_SUCCESS(Status)) {
2094
2095             cfs_enter_debugger();
2096             ZwClose(*Handle);
2097         }
2098
2099     } else {
2100
2101         cfs_enter_debugger();
2102     }
2103
2104     return (Status);
2105 }
2106
2107 /*
2108  * KsCloseConnection
2109  *   Release the Hanlde and FileObject of an opened tdi
2110  *   connection object
2111  *
2112  * Arguments:
2113  *   Handle:       the handle to be released
2114  *   FileObject:   the fileobject to be released
2115  *
2116  * Return Value:
2117  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2118  *                 or other error code)
2119  *
2120  * Notes:
2121  *   N/A
2122  */
2123
2124 NTSTATUS
2125 KsCloseConnection(
2126     IN HANDLE             Handle,
2127     IN PFILE_OBJECT       FileObject
2128     )
2129 {
2130     NTSTATUS  Status = STATUS_SUCCESS;
2131
2132     if (FileObject) {
2133
2134         ObDereferenceObject(FileObject);
2135     }
2136
2137     if (Handle) {
2138
2139         Status = ZwClose(Handle);
2140     }
2141
2142     ASSERT(NT_SUCCESS(Status));
2143
2144     return (Status);
2145 }
2146
2147
2148 /*
2149  * KsAssociateAddress
2150  *   Associate an address object with a connection object
2151  *
2152  * Arguments:
2153  *   AddressHandle:  the handle of the address object
2154  *   ConnectionObject:  the FileObject of the connection
2155  *
2156  * Return Value:
2157  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2158  *                 or other error code)
2159  *
2160  * Notes:
2161  *   N/A
2162  */
2163
2164 NTSTATUS
2165 KsAssociateAddress(
2166     IN HANDLE           AddressHandle,
2167     IN PFILE_OBJECT     ConnectionObject
2168     )
2169 {
2170     NTSTATUS            Status;
2171     PDEVICE_OBJECT      DeviceObject;
2172     PIRP                Irp;
2173
2174     //
2175     // Getting the DeviceObject from Connection FileObject
2176     //
2177
2178     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2179
2180     //
2181     // Building Tdi Internal Irp ...
2182     //
2183
2184     Irp = KsBuildTdiIrp(DeviceObject);
2185
2186     if (NULL == Irp) {
2187
2188         Status = STATUS_INSUFFICIENT_RESOURCES;
2189
2190     } else {
2191
2192         //
2193         // Assocating the Address Object with the Connection Object
2194         //
2195
2196         TdiBuildAssociateAddress(
2197             Irp,
2198             DeviceObject,
2199             ConnectionObject,
2200             NULL,
2201             NULL,
2202             AddressHandle
2203             );
2204
2205         //
2206         // Calling the Transprot Driver with the Prepared Irp
2207         //
2208
2209         Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2210     }
2211
2212     return (Status);
2213 }
2214
2215
2216 /*
2217  * KsDisassociateAddress
2218  *   Disassociate the connection object (the relationship will
2219  *   the corresponding address object will be dismissed. )
2220  *
2221  * Arguments:
2222  *   ConnectionObject:  the FileObject of the connection
2223  *
2224  * Return Value:
2225  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2226  *                 or other error code)
2227  *
2228  * Notes:
2229  *   N/A
2230  */
2231
2232 NTSTATUS
2233 KsDisassociateAddress(
2234     IN PFILE_OBJECT     ConnectionObject
2235     )
2236 {
2237     NTSTATUS            Status;
2238     PDEVICE_OBJECT      DeviceObject;
2239     PIRP                   Irp;
2240
2241     //
2242     // Getting the DeviceObject from Connection FileObject
2243     //
2244
2245     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2246
2247     //
2248     // Building Tdi Internal Irp ...
2249     //
2250
2251     Irp = KsBuildTdiIrp(DeviceObject);
2252
2253     if (NULL == Irp) {
2254
2255         Status = STATUS_INSUFFICIENT_RESOURCES;
2256
2257     } else {
2258
2259         //
2260         // Disassocating the Address Object with the Connection Object
2261         //
2262
2263         TdiBuildDisassociateAddress(
2264             Irp,
2265             DeviceObject,
2266             ConnectionObject,
2267             NULL,
2268             NULL
2269             );
2270
2271         //
2272         // Calling the Transprot Driver with the Prepared Irp
2273         //
2274
2275         Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2276     }
2277
2278     return (Status);
2279 }
2280
2281
2282 /*
2283
2284 //
2285 // Connection Control Event Callbacks
2286 //
2287
2288 TDI_EVENT_CONNECT
2289 TDI_EVENT_DISCONNECT
2290 TDI_EVENT_ERROR
2291
2292 //
2293 // Tcp Event Callbacks
2294 //
2295
2296 TDI_EVENT_RECEIVE
2297 TDI_EVENT_RECEIVE_EXPEDITED
2298 TDI_EVENT_CHAINED_RECEIVE
2299 TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
2300
2301 //
2302 // Udp Event Callbacks
2303 //
2304
2305 TDI_EVENT_RECEIVE_DATAGRAM
2306 TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
2307
2308 */
2309
2310
2311 /*
2312  * KsSetEventHandlers
2313  *   Set the tdi event callbacks with an address object
2314  *
2315  * Arguments:
2316  *   AddressObject: the FileObject of the address object
2317  *   EventContext:  the parameter for the callbacks
2318  *   Handlers:      the handlers indictor array
2319  *
2320  * Return Value:
2321  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2322  *                 or other error code)
2323  *
2324  * NOTES:
2325  *   N/A
2326  */
2327
2328 NTSTATUS
2329 KsSetEventHandlers(
2330     IN PFILE_OBJECT                         AddressObject,  // Address File Object
2331     IN PVOID                                EventContext,   // Context for Handlers
2332     IN PKS_EVENT_HANDLERS                   Handlers        // Handlers Indictor
2333    )
2334 {
2335     NTSTATUS             Status = STATUS_SUCCESS;
2336     PDEVICE_OBJECT       DeviceObject;
2337     USHORT               i = 0;
2338
2339     DeviceObject = IoGetRelatedDeviceObject(AddressObject);
2340
2341     for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
2342
2343         //
2344         // Setup the tdi event callback handler if requested.
2345         //
2346
2347         if (Handlers->IsActive[i]) {
2348
2349             PIRP            Irp;
2350
2351             //
2352             // Building Tdi Internal Irp ...
2353             //
2354
2355             Irp = KsBuildTdiIrp(DeviceObject);
2356
2357             if (NULL == Irp) {
2358
2359                 Status = STATUS_INSUFFICIENT_RESOURCES;
2360
2361             } else {
2362
2363                 //
2364                 // Building the Irp to set the Event Handler ...
2365                 //
2366
2367                 TdiBuildSetEventHandler(
2368                     Irp,
2369                     DeviceObject,
2370                     AddressObject,
2371                     NULL,
2372                     NULL,
2373                     i,                      /* tdi event type */
2374                     Handlers->Handler[i],   /* tdi event handler */
2375                     EventContext            /* context for the handler */
2376                     );
2377
2378                 //
2379                 // Calling the Transprot Driver with the Prepared Irp
2380                 //
2381
2382                 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2383
2384                 //
2385                 // tcp/ip tdi does not support these two event callbacks
2386                 //
2387
2388                 if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
2389                      i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
2390                     cfs_enter_debugger();
2391                     Status = STATUS_SUCCESS;
2392                 }
2393             }
2394
2395             if (!NT_SUCCESS(Status)) {
2396                 cfs_enter_debugger();
2397                 goto errorout;
2398             }
2399         }
2400     }
2401
2402
2403 errorout:
2404
2405     if (!NT_SUCCESS(Status)) {
2406
2407         KsPrint((1, "KsSetEventHandlers: Error Status = %xh (%s)\n",
2408                     Status, KsNtStatusToString(Status) ));
2409     }
2410
2411     return (Status);
2412 }
2413
2414
2415
2416 /*
2417  * KsQueryAddressInfo
2418  *   Query the address of the FileObject specified
2419  *
2420  * Arguments:
2421  *   FileObject:  the FileObject to be queried
2422  *   AddressInfo: buffer to contain the address info
2423  *   AddressSize: length of the AddressInfo buffer
2424  *
2425  * Return Value:
2426  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2427  *                 or other error code)
2428  *
2429  * Notes:
2430  *   N/A
2431  */
2432
2433 NTSTATUS
2434 KsQueryAddressInfo(
2435     PFILE_OBJECT            FileObject,
2436     PTDI_ADDRESS_INFO       AddressInfo,
2437     PULONG                  AddressSize
2438    )
2439 {
2440     NTSTATUS          Status = STATUS_UNSUCCESSFUL;
2441     PIRP              Irp = NULL;
2442     PMDL              Mdl;
2443     PDEVICE_OBJECT    DeviceObject;
2444
2445     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2446
2447     DeviceObject = IoGetRelatedDeviceObject(FileObject);
2448
2449     RtlZeroMemory(AddressInfo, *(AddressSize));
2450
2451     //
2452     // Allocating the Tdi Setting Irp ...
2453     //
2454
2455     Irp = KsBuildTdiIrp(DeviceObject);
2456
2457     if (NULL == Irp) {
2458
2459         Status = STATUS_INSUFFICIENT_RESOURCES;
2460
2461     } else {
2462
2463         //
2464         // Locking the User Buffer / Allocating a MDL for it
2465         //
2466
2467         Status = KsLockUserBuffer(
2468                     AddressInfo,
2469                     FALSE,
2470                     *(AddressSize),
2471                     IoModifyAccess,
2472                     &Mdl
2473                     );
2474
2475         if (!NT_SUCCESS(Status)) {
2476
2477             IoFreeIrp(Irp);
2478             Irp = NULL;
2479         }
2480     }
2481
2482     if (Irp) {
2483
2484         LASSERT(NT_SUCCESS(Status));
2485
2486         TdiBuildQueryInformation(
2487                     Irp,
2488                     DeviceObject,
2489                     FileObject,
2490                     NULL,
2491                     NULL,
2492                     TDI_QUERY_ADDRESS_INFO,
2493                     Mdl
2494                     );
2495
2496         Status = KsSubmitTdiIrp(
2497                     DeviceObject,
2498                     Irp,
2499                     TRUE,
2500                     AddressSize
2501                     );
2502
2503         KsReleaseMdl(Mdl, FALSE);
2504     }
2505
2506     if (!NT_SUCCESS(Status)) {
2507
2508         cfs_enter_debugger();
2509         //TDI_BUFFER_OVERFLOW
2510     }
2511
2512     return (Status);
2513 }
2514
2515 /*
2516  * KsQueryProviderInfo
2517  *   Query the underlying transport device's information
2518  *
2519  * Arguments:
2520  *   TdiDeviceName:  the transport device's name string
2521  *   ProviderInfo:   TDI_PROVIDER_INFO struncture
2522  *
2523  * Return Value:
2524  *   NTSTATUS:       Nt system status code
2525   *
2526  * NOTES:
2527  *   N/A
2528  */
2529
2530 NTSTATUS
2531 KsQueryProviderInfo(
2532     PWSTR               TdiDeviceName,
2533     PTDI_PROVIDER_INFO  ProviderInfo
2534    )
2535 {
2536     NTSTATUS            Status = STATUS_SUCCESS;
2537
2538     PIRP                Irp = NULL;
2539     PMDL                Mdl = NULL;
2540
2541     UNICODE_STRING      ControlName;
2542
2543     HANDLE              Handle;
2544     PFILE_OBJECT        FileObject;
2545     PDEVICE_OBJECT      DeviceObject;
2546
2547     ULONG               ProviderSize = 0;
2548
2549     RtlInitUnicodeString(&ControlName, TdiDeviceName);
2550
2551     //
2552     // Open the Tdi Control Channel
2553     //
2554
2555     Status = KsOpenControl(
2556                 &ControlName,
2557                 &Handle,
2558                 &FileObject
2559                 );
2560
2561     if (!NT_SUCCESS(Status)) {
2562
2563         KsPrint((1, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
2564         return (Status);
2565     }
2566
2567     //
2568     // Obtain The Related Device Object
2569     //
2570
2571     DeviceObject = IoGetRelatedDeviceObject(FileObject);
2572
2573     ProviderSize = sizeof(TDI_PROVIDER_INFO);
2574     RtlZeroMemory(ProviderInfo, ProviderSize);
2575
2576     //
2577     // Allocating the Tdi Setting Irp ...
2578     //
2579
2580     Irp = KsBuildTdiIrp(DeviceObject);
2581
2582     if (NULL == Irp) {
2583
2584         Status = STATUS_INSUFFICIENT_RESOURCES;
2585
2586     } else {
2587
2588         //
2589         // Locking the User Buffer / Allocating a MDL for it
2590         //
2591
2592         Status = KsLockUserBuffer(
2593                     ProviderInfo,
2594                     FALSE,
2595                     ProviderSize,
2596                     IoModifyAccess,
2597                     &Mdl
2598                     );
2599
2600         if (!NT_SUCCESS(Status)) {
2601
2602             IoFreeIrp(Irp);
2603             Irp = NULL;
2604         }
2605     }
2606
2607     if (Irp) {
2608
2609         LASSERT(NT_SUCCESS(Status));
2610
2611         TdiBuildQueryInformation(
2612                     Irp,
2613                     DeviceObject,
2614                     FileObject,
2615                     NULL,
2616                     NULL,
2617                     TDI_QUERY_PROVIDER_INFO,
2618                     Mdl
2619                     );
2620
2621         Status = KsSubmitTdiIrp(
2622                     DeviceObject,
2623                     Irp,
2624                     TRUE,
2625                     &ProviderSize
2626                     );
2627
2628         KsReleaseMdl(Mdl, FALSE);
2629     }
2630
2631     if (!NT_SUCCESS(Status)) {
2632
2633         cfs_enter_debugger();
2634         //TDI_BUFFER_OVERFLOW
2635     }
2636
2637     KsCloseControl(Handle, FileObject);
2638
2639     return (Status);
2640 }
2641
2642 /*
2643  * KsQueryConnectionInfo
2644  *   Query the connection info of the FileObject specified
2645  *   (some statics data of the traffic)
2646  *
2647  * Arguments:
2648  *   FileObject:     the FileObject to be queried
2649  *   ConnectionInfo: buffer to contain the connection info
2650  *   ConnectionSize: length of the ConnectionInfo buffer
2651  *
2652  * Return Value:
2653  *   NTSTATUS:     kernel status code (STATUS_SUCCESS
2654  *                 or other error code)
2655  *
2656  * NOTES:
2657  *   N/A
2658  */
2659
2660 NTSTATUS
2661 KsQueryConnectionInfo(
2662     PFILE_OBJECT            ConnectionObject,
2663     PTDI_CONNECTION_INFO    ConnectionInfo,
2664     PULONG                  ConnectionSize
2665    )
2666 {
2667     NTSTATUS          Status = STATUS_UNSUCCESSFUL;
2668     PIRP              Irp = NULL;
2669     PMDL              Mdl;
2670     PDEVICE_OBJECT    DeviceObject;
2671
2672     LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2673
2674     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2675
2676     RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
2677
2678     //
2679     // Allocating the Tdi Query Irp ...
2680     //
2681
2682     Irp = KsBuildTdiIrp(DeviceObject);
2683
2684     if (NULL == Irp) {
2685
2686         Status = STATUS_INSUFFICIENT_RESOURCES;
2687
2688     } else {
2689
2690         //
2691         // Locking the User Buffer / Allocating a MDL for it
2692         //
2693
2694         Status = KsLockUserBuffer(
2695                     ConnectionInfo,
2696                     FALSE,
2697                     *(ConnectionSize),
2698                     IoModifyAccess,
2699                     &Mdl
2700                     );
2701
2702         if (NT_SUCCESS(Status)) {
2703
2704             IoFreeIrp(Irp);
2705             Irp = NULL;
2706         }
2707     }
2708
2709     if (Irp) {
2710
2711         LASSERT(NT_SUCCESS(Status));
2712
2713         TdiBuildQueryInformation(
2714                     Irp,
2715                     DeviceObject,
2716                     ConnectionObject,
2717                     NULL,
2718                     NULL,
2719                     TDI_QUERY_CONNECTION_INFO,
2720                     Mdl
2721                     );
2722
2723         Status = KsSubmitTdiIrp(
2724                     DeviceObject,
2725                     Irp,
2726                     TRUE,
2727                     ConnectionSize
2728                     );
2729
2730         KsReleaseMdl(Mdl, FALSE);
2731     }
2732
2733     return (Status);
2734 }
2735
2736
2737 /*
2738  * KsInitializeTdiAddress
2739  *   Initialize the tdi addresss
2740  *
2741  * Arguments:
2742  *   pTransportAddress: tdi address to be initialized
2743  *   IpAddress:         the ip address of object
2744  *   IpPort:            the ip port of the object
2745  *
2746  * Return Value:
2747  *   ULONG: the total size of the tdi address
2748  *
2749  * NOTES:
2750  *   N/A
2751  */
2752
2753 ULONG
2754 KsInitializeTdiAddress(
2755     IN OUT PTA_IP_ADDRESS   pTransportAddress,
2756     IN ULONG                IpAddress,
2757     IN USHORT               IpPort
2758     )
2759 {
2760     pTransportAddress->TAAddressCount = 1;
2761     pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
2762     pTransportAddress->Address[ 0 ].AddressType   = TDI_ADDRESS_TYPE_IP;
2763     pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
2764     pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr  = IpAddress;
2765
2766     return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
2767 }
2768
2769 /*
2770  * KsQueryTdiAddressLength
2771  *   Query the total size of the tdi address
2772  *
2773  * Arguments:
2774  *   pTransportAddress: tdi address to be queried
2775  *
2776  * Return Value:
2777  *   ULONG: the total size of the tdi address
2778  *
2779  * NOTES:
2780  *   N/A
2781  */
2782
2783 ULONG
2784 KsQueryTdiAddressLength(
2785     PTRANSPORT_ADDRESS      pTransportAddress
2786     )
2787 {
2788     ULONG                   TotalLength = 0;
2789     LONG                    i;
2790
2791     PTA_ADDRESS             pTaAddress = NULL;
2792
2793     ASSERT (NULL != pTransportAddress);
2794
2795     TotalLength  = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
2796                    FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
2797
2798     pTaAddress = (PTA_ADDRESS)pTransportAddress->Address;
2799
2800     for (i = 0; i < pTransportAddress->TAAddressCount; i++)
2801     {
2802         TotalLength += pTaAddress->AddressLength;
2803         pTaAddress = (PTA_ADDRESS)((PCHAR)pTaAddress +
2804                                            FIELD_OFFSET(TA_ADDRESS,Address) +
2805                                            pTaAddress->AddressLength );
2806     }
2807
2808     return (TotalLength);
2809 }
2810
2811
2812 /*
2813  * KsQueryIpAddress
2814  *   Query the ip address of the tdi object
2815  *
2816  * Arguments:
2817  *   FileObject: tdi object to be queried
2818  *   TdiAddress: TdiAddress buffer, to store the queried
2819  *               tdi ip address
2820  *   AddressLength: buffer length of the TdiAddress
2821  *
2822  * Return Value:
2823  *   ULONG: the total size of the tdi ip address
2824  *
2825  * NOTES:
2826  *   N/A
2827  */
2828
2829 NTSTATUS
2830 KsQueryIpAddress(
2831     PFILE_OBJECT    FileObject,
2832     PVOID           TdiAddress,
2833     ULONG*          AddressLength
2834     )
2835 {
2836     NTSTATUS        Status;
2837
2838     PTDI_ADDRESS_INFO   TdiAddressInfo;
2839     ULONG               Length;
2840
2841
2842     //
2843     // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
2844     //
2845
2846     Length = MAX_ADDRESS_LENGTH;
2847
2848     TdiAddressInfo = (PTDI_ADDRESS_INFO)
2849                         ExAllocatePoolWithTag(
2850                             NonPagedPool,
2851                             Length,
2852                             'KSAI' );
2853
2854     if (NULL == TdiAddressInfo) {
2855
2856         Status = STATUS_INSUFFICIENT_RESOURCES;
2857         goto errorout;
2858     }
2859
2860
2861     Status = KsQueryAddressInfo(
2862                 FileObject,
2863                 TdiAddressInfo,
2864                 &Length
2865                 );
2866
2867 errorout:
2868
2869     if (NT_SUCCESS(Status)) {
2870
2871         if (*AddressLength < Length) {
2872             Status = STATUS_BUFFER_TOO_SMALL;
2873         } else {
2874             *AddressLength = Length;
2875             RtlCopyMemory(
2876                 TdiAddress,
2877                 &(TdiAddressInfo->Address),
2878                 Length
2879                 );
2880             Status = STATUS_SUCCESS;
2881         }
2882     }
2883
2884     if (NULL != TdiAddressInfo) {
2885         ExFreePool(TdiAddressInfo);
2886     }
2887
2888     return Status;
2889 }
2890
2891
2892 /*
2893  * KsErrorEventHandler
2894  *   the common error event handler callback
2895  *
2896  * Arguments:
2897  *   TdiEventContext: should be the socket
2898  *   Status: the error code
2899  *
2900  * Return Value:
2901  *   Status: STATS_SUCCESS
2902  *
2903  * NOTES:
2904  *   We need not do anything in such a severe
2905  *   error case. System will process it for us.
2906  */
2907
2908 NTSTATUS
2909 KsErrorEventHandler(
2910     IN PVOID        TdiEventContext,
2911     IN NTSTATUS     Status
2912    )
2913 {
2914     KsPrint((1, "KsErrorEventHandler called at Irql = %xh ...\n",
2915                 KeGetCurrentIrql()));
2916
2917     cfs_enter_debugger();
2918
2919     return (STATUS_SUCCESS);
2920 }
2921
2922 /*
2923  * KsAcceptCompletionRoutine
2924  *   Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
2925  *
2926  *   Here system gives us a chance to check the conneciton is built
2927  *   ready or not.
2928  *
2929  * Arguments:
2930  *   DeviceObject:  the device object of the transport driver
2931  *   Irp:           the Irp is being completed.
2932  *   Context:       the context we specified when issuing the Irp
2933  *
2934  * Return Value:
2935  *   Nt status code
2936  *
2937  * Notes:
2938  *   N/A
2939  */
2940
2941 NTSTATUS
2942 KsAcceptCompletionRoutine(
2943     IN PDEVICE_OBJECT   DeviceObject,
2944     IN PIRP             Irp,
2945     IN PVOID            Context
2946     )
2947 {
2948     ks_tconn_t * child = (ks_tconn_t *) Context;
2949     ks_tconn_t * parent = child->child.kstc_parent;
2950
2951     KsPrint((2, "KsAcceptCompletionRoutine at Irql: %xh child: %p status: %p\n",
2952                  KeGetCurrentIrql(), child, Irp->IoStatus.Status));
2953
2954     LASSERT(child->kstc_type == kstt_child);
2955
2956         spin_lock(&(child->kstc_lock));
2957
2958     LASSERT(parent->kstc_state == ksts_listening);
2959     LASSERT(child->kstc_state == ksts_connecting);
2960
2961     if (NT_SUCCESS(Irp->IoStatus.Status)) {
2962
2963         child->child.kstc_accepted = TRUE;
2964
2965         child->kstc_state = ksts_connected;
2966
2967         /* wake up the daemon thread which waits on this event */
2968         KeSetEvent(
2969             &(parent->listener.kstc_accept_event),
2970             0,
2971             FALSE
2972             );
2973
2974         spin_unlock(&(child->kstc_lock));
2975
2976         KsPrint((2, "KsAcceptCompletionRoutine: singal parent: %p (child: %p)\n",
2977                     parent, child));
2978
2979     } else {
2980
2981         /* re-use this child connecton  */
2982         child->child.kstc_accepted = FALSE;
2983         child->child.kstc_busy = FALSE;
2984         child->kstc_state = ksts_associated;
2985
2986         spin_unlock(&(child->kstc_lock));
2987     }
2988
2989     /* now free the Irp */
2990     IoFreeIrp(Irp);
2991
2992     /* drop the refer count of the child */
2993     ks_put_tconn(child);
2994
2995     return (STATUS_MORE_PROCESSING_REQUIRED);
2996 }
2997
2998 ks_addr_slot_t *
2999 KsSearchIpAddress(PUNICODE_STRING  DeviceName)
3000 {
3001     ks_addr_slot_t * slot = NULL;
3002     PLIST_ENTRY      list = NULL;
3003
3004         spin_lock(&ks_data.ksnd_addrs_lock);
3005
3006     list = ks_data.ksnd_addrs_list.Flink;
3007     while (list != &ks_data.ksnd_addrs_list) {
3008         slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3009         if (RtlCompareUnicodeString(
3010                     DeviceName,
3011                     &slot->devname,
3012                     TRUE) == 0) {
3013             break;
3014         }
3015         list = list->Flink;
3016         slot = NULL;
3017     }
3018
3019         spin_unlock(&ks_data.ksnd_addrs_lock);
3020
3021         return slot;
3022 }
3023
3024 void
3025 KsCleanupIpAddresses()
3026 {
3027         spin_lock(&ks_data.ksnd_addrs_lock);
3028
3029     while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
3030
3031         ks_addr_slot_t * slot = NULL;
3032         PLIST_ENTRY      list = NULL;
3033
3034         list = RemoveHeadList(&ks_data.ksnd_addrs_list);
3035         slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3036         cfs_free(slot);
3037         ks_data.ksnd_naddrs--;
3038     }
3039
3040     cfs_assert(ks_data.ksnd_naddrs == 0);
3041         spin_unlock(&ks_data.ksnd_addrs_lock);
3042 }
3043
3044 VOID
3045 KsAddAddressHandler(
3046     IN  PTA_ADDRESS      Address,
3047     IN  PUNICODE_STRING  DeviceName,
3048     IN  PTDI_PNP_CONTEXT Context
3049     )
3050 {
3051     PTDI_ADDRESS_IP IpAddress = NULL;
3052
3053     if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3054          Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3055
3056         ks_addr_slot_t * slot = NULL;
3057
3058         IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3059         KsPrint((2, "KsAddAddressHandle: Device=%wZ Context=%xh "
3060                      "IpAddress=%xh(%d.%d.%d.%d)\n",
3061                      DeviceName, Context, IpAddress->in_addr,
3062                      (IpAddress->in_addr & 0x000000FF) >> 0,
3063                      (IpAddress->in_addr & 0x0000FF00) >> 8,
3064                      (IpAddress->in_addr & 0x00FF0000) >> 16,
3065                      (IpAddress->in_addr & 0xFF000000) >> 24
3066                ));
3067
3068         slot = KsSearchIpAddress(DeviceName);
3069
3070         if (slot != NULL) {
3071             slot->up = TRUE;
3072             slot->ip_addr = ntohl(IpAddress->in_addr);
3073         } else {
3074
3075             /* Matt: only add 192.168.10/5/92.xxx for temporary test */
3076             if ((IpAddress->in_addr & 0x00FFFFFF) != 0x000aa8c0 &&
3077                 (IpAddress->in_addr & 0x00FFFFFF) != 0x0092a8c0 &&
3078                 (IpAddress->in_addr & 0x00FFFFFF) != 0x0005a8c0 ) {
3079                 return;
3080             }
3081
3082             slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
3083             if (slot != NULL) {
3084                 spin_lock(&ks_data.ksnd_addrs_lock);
3085                 InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
3086                 sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
3087                 slot->ip_addr = ntohl(IpAddress->in_addr);
3088                 slot->netmask = 0x00FFFFFF; /* Matt: hardcode*/
3089                 slot->up = TRUE;
3090                 RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
3091                 slot->devname.Length = DeviceName->Length;
3092                 slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
3093                 slot->devname.Buffer = slot->buffer;
3094                 spin_unlock(&ks_data.ksnd_addrs_lock);
3095
3096                 KsPrint((0, "KsAddAddressHandle: %s added: ip=%xh(%d.%d.%d.%d)\n",
3097                             slot->iface, IpAddress->in_addr,
3098                             (IpAddress->in_addr & 0x000000FF) >> 0,
3099                             (IpAddress->in_addr & 0x0000FF00) >> 8,
3100                             (IpAddress->in_addr & 0x00FF0000) >> 16,
3101                             (IpAddress->in_addr & 0xFF000000) >> 24
3102                        ));
3103             }
3104         }
3105     }
3106 }
3107
3108 VOID
3109 KsDelAddressHandler(
3110     IN  PTA_ADDRESS      Address,
3111     IN  PUNICODE_STRING  DeviceName,
3112     IN  PTDI_PNP_CONTEXT Context
3113     )
3114 {
3115     PTDI_ADDRESS_IP IpAddress = NULL;
3116
3117     if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3118          Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3119
3120         ks_addr_slot_t * slot = NULL;
3121
3122         slot = KsSearchIpAddress(DeviceName);
3123
3124         if (slot != NULL) {
3125             slot->up = FALSE;
3126         }
3127
3128         IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3129         KsPrint((2, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
3130                   DeviceName, Context, IpAddress->in_addr,
3131                    (IpAddress->in_addr & 0xFF000000) >> 24,
3132                    (IpAddress->in_addr & 0x00FF0000) >> 16,
3133                    (IpAddress->in_addr & 0x0000FF00) >> 8,
3134                    (IpAddress->in_addr & 0x000000FF) >> 0 ));
3135     }
3136 }
3137
3138 NTSTATUS
3139 KsRegisterPnpHandlers()
3140 {
3141     TDI20_CLIENT_INTERFACE_INFO ClientInfo;
3142
3143     /* initialize the global ks_data members */
3144     RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
3145         spin_lock_init(&ks_data.ksnd_addrs_lock);
3146     InitializeListHead(&ks_data.ksnd_addrs_list);
3147
3148     /* register the pnp handlers */
3149     RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
3150     ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
3151
3152     ClientInfo.ClientName = &ks_data.ksnd_client_name;
3153     ClientInfo.AddAddressHandlerV2 =  KsAddAddressHandler;
3154     ClientInfo.DelAddressHandlerV2 =  KsDelAddressHandler;
3155
3156     return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
3157                                   &ks_data.ksnd_pnp_handle);
3158 }
3159
3160 VOID
3161 KsDeregisterPnpHandlers()
3162 {
3163     if (ks_data.ksnd_pnp_handle) {
3164
3165         /* De-register the pnp handlers */
3166
3167         TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
3168         ks_data.ksnd_pnp_handle = NULL;
3169
3170         /* cleanup all the ip address slots */
3171         KsCleanupIpAddresses();
3172     }
3173 }
3174
3175
3176 /*
3177  * KsGetVacancyBacklog
3178  *   Get a vacancy listeing child from the backlog list
3179  *
3180  * Arguments:
3181  *   parent: the listener daemon connection
3182  *
3183  * Return Value:
3184  *   the child listening connection or NULL in failure
3185  *
3186  * Notes
3187  *   Parent's lock should be acquired before calling.
3188  */
3189
3190 ks_tconn_t *
3191 KsGetVacancyBacklog(
3192     ks_tconn_t *  parent
3193     )
3194 {
3195     ks_tconn_t * child;
3196
3197     LASSERT(parent->kstc_type == kstt_listener);
3198     LASSERT(parent->kstc_state == ksts_listening);
3199
3200     if (cfs_list_empty(&(parent->listener.kstc_listening.list))) {
3201
3202         child = NULL;
3203
3204     } else {
3205
3206         cfs_list_t * tmp;
3207
3208         /* check the listening queue and try to get a free connecton */
3209
3210         cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
3211             child = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
3212             spin_lock(&(child->kstc_lock));
3213
3214             if (!child->child.kstc_busy) {
3215                 LASSERT(child->kstc_state == ksts_associated);
3216                 child->child.kstc_busy = TRUE;
3217                 spin_unlock(&(child->kstc_lock));
3218                 break;
3219             } else {
3220                 spin_unlock(&(child->kstc_lock));
3221                 child = NULL;
3222             }
3223         }
3224     }
3225
3226     return child;
3227 }
3228
3229 /*
3230  * KsConnectEventHandler
3231  *   Connect event handler event handler, called by the underlying TDI
3232  *   transport in response to an incoming request to the listening daemon.
3233  *
3234  *   it will grab a vacancy backlog from the children tconn list, and
3235  *   build an acception Irp with it, then transfer the Irp to TDI driver.
3236  *
3237  * Arguments:
3238  *   TdiEventContext:  the tdi connnection object of the listening daemon
3239  *   ......
3240  *
3241  * Return Value:
3242  *   Nt kernel status code
3243  *
3244  * Notes:
3245  *   N/A
3246  */
3247
3248 NTSTATUS
3249 KsConnectEventHandler(
3250     IN PVOID                    TdiEventContext,
3251     IN LONG                     RemoteAddressLength,
3252     IN PVOID                    RemoteAddress,
3253     IN LONG                     UserDataLength,
3254     IN PVOID                    UserData,
3255     IN LONG                     OptionsLength,
3256     IN PVOID                    Options,
3257     OUT CONNECTION_CONTEXT *    ConnectionContext,
3258     OUT PIRP *                  AcceptIrp
3259     )
3260 {
3261     ks_tconn_t *                parent;
3262     ks_tconn_t *                child;
3263
3264     PFILE_OBJECT                FileObject;
3265     PDEVICE_OBJECT              DeviceObject;
3266     NTSTATUS                    Status;
3267
3268     PIRP                        Irp = NULL;
3269     PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
3270
3271     KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
3272     parent = (ks_tconn_t *) TdiEventContext;
3273
3274     LASSERT(parent->kstc_type == kstt_listener);
3275
3276         spin_lock(&(parent->kstc_lock));
3277
3278     if (parent->kstc_state == ksts_listening) {
3279
3280         /* allocate a new ConnectionInfo to backup the peer's info */
3281
3282         ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
3283                 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
3284                 RemoteAddressLength, 'iCsK' );
3285
3286         if (NULL == ConnectionInfo) {
3287
3288             Status = STATUS_INSUFFICIENT_RESOURCES;
3289             cfs_enter_debugger();
3290             goto errorout;
3291         }
3292
3293         /* initializing ConnectionInfo structure ... */
3294
3295         ConnectionInfo->UserDataLength = UserDataLength;
3296         ConnectionInfo->UserData = UserData;
3297         ConnectionInfo->OptionsLength = OptionsLength;
3298         ConnectionInfo->Options = Options;
3299         ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
3300         ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
3301
3302         RtlCopyMemory(
3303                 ConnectionInfo->RemoteAddress,
3304                 RemoteAddress,
3305                 RemoteAddressLength
3306                 );
3307
3308         /* get the vacancy listening child tdi connections */
3309
3310         child = KsGetVacancyBacklog(parent);
3311
3312         if (child) {
3313
3314             spin_lock(&(child->kstc_lock));
3315             child->child.kstc_info.ConnectionInfo = ConnectionInfo;
3316             child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
3317             child->kstc_state = ksts_connecting;
3318             spin_unlock(&(child->kstc_lock));
3319
3320         } else {
3321
3322             KsPrint((1, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
3323             Status = STATUS_INSUFFICIENT_RESOURCES;
3324             goto errorout;
3325         }
3326
3327         FileObject = child->child.kstc_info.FileObject;
3328         DeviceObject = IoGetRelatedDeviceObject (FileObject);
3329
3330         Irp = KsBuildTdiIrp(DeviceObject);
3331
3332         TdiBuildAccept(
3333                 Irp,
3334                 DeviceObject,
3335                 FileObject,
3336                 KsAcceptCompletionRoutine,
3337                 child,
3338                 NULL,
3339                 NULL
3340                 );
3341
3342         IoSetNextIrpStackLocation(Irp);
3343
3344         /* grap the refer of the child tdi connection */
3345         ks_get_tconn(child);
3346
3347         Status = STATUS_MORE_PROCESSING_REQUIRED;
3348         *AcceptIrp = Irp;
3349         *ConnectionContext = child;
3350
3351     } else {
3352
3353         Status = STATUS_CONNECTION_REFUSED;
3354         goto errorout;
3355     }
3356
3357         spin_unlock(&(parent->kstc_lock));
3358
3359     return Status;
3360
3361 errorout:
3362
3363         spin_unlock(&(parent->kstc_lock));
3364
3365     *AcceptIrp = NULL;
3366     *ConnectionContext = NULL;
3367
3368     if (ConnectionInfo) {
3369         ExFreePool(ConnectionInfo);
3370     }
3371
3372     if (Irp) {
3373         IoFreeIrp (Irp);
3374     }
3375
3376     return Status;
3377 }
3378
3379 /*
3380  * KsDisconnectCompletionRoutine
3381  *   the Irp completion routine for TdiBuildDisconect
3382  *
3383  *   We just signal the event and return MORE_PRO... to
3384  *   let the caller take the responsibility of the Irp.
3385  *
3386  * Arguments:
3387  *   DeviceObject:  the device object of the transport
3388  *   Irp:           the Irp is being completed.
3389  *   Context:       the event specified by the caller
3390  *
3391  * Return Value:
3392  *   Nt status code
3393  *
3394  * Notes:
3395  *   N/A
3396  */
3397
3398 NTSTATUS
3399 KsDisconectCompletionRoutine (
3400     IN PDEVICE_OBJECT   DeviceObject,
3401     IN PIRP             Irp,
3402     IN PVOID            Context
3403     )
3404 {
3405
3406     KeSetEvent((PKEVENT) Context, 0, FALSE);
3407
3408     return STATUS_MORE_PROCESSING_REQUIRED;
3409
3410     UNREFERENCED_PARAMETER(DeviceObject);
3411 }
3412
3413
3414 /*
3415  * KsDisconnectHelper
3416  *   the routine to be executed in the WorkItem procedure
3417  *   this routine is to disconnect a tdi connection
3418  *
3419  * Arguments:
3420  *   Workitem:  the context transferred to the workitem
3421  *
3422  * Return Value:
3423  *   N/A
3424  *
3425  * Notes:
3426  *   tconn is already referred in abort_connecton ...
3427  */
3428
3429 VOID
3430 KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
3431 {
3432     ks_tconn_t * tconn = WorkItem->tconn;
3433
3434     KsPrint((1, "KsDisconnectHelper: disconnecting tconn=%p\n", tconn));
3435     ks_disconnect_tconn(tconn, WorkItem->Flags);
3436
3437     KeSetEvent(&(WorkItem->Event), 0, FALSE);
3438
3439         spin_lock(&(tconn->kstc_lock));
3440         cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3441         spin_unlock(&(tconn->kstc_lock));
3442         ks_put_tconn(tconn);
3443 }
3444
3445
3446 /*
3447  * KsDisconnectEventHandler
3448  *   Disconnect event handler event handler, called by the underlying TDI transport
3449  *   in response to an incoming disconnection notification from a remote node.
3450  *
3451  * Arguments:
3452  *   ConnectionContext:  tdi connnection object
3453  *   DisconnectFlags:    specifies the nature of the disconnection
3454  *   ......
3455  *
3456  * Return Value:
3457  *   Nt kernel status code
3458  *
3459  * Notes:
3460  *   N/A
3461  */
3462
3463
3464 NTSTATUS
3465 KsDisconnectEventHandler(
3466     IN PVOID                TdiEventContext,
3467     IN CONNECTION_CONTEXT   ConnectionContext,
3468     IN LONG                 DisconnectDataLength,
3469     IN PVOID                DisconnectData,
3470     IN LONG                 DisconnectInformationLength,
3471     IN PVOID                DisconnectInformation,
3472     IN ULONG                DisconnectFlags
3473     )
3474 {
3475     ks_tconn_t *            tconn;
3476     NTSTATUS                Status;
3477     PKS_DISCONNECT_WORKITEM WorkItem;
3478
3479     tconn = (ks_tconn_t *)ConnectionContext;
3480
3481     KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
3482                 KeGetCurrentIrql() ));
3483
3484     KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
3485                  tconn, DisconnectFlags));
3486
3487     ks_get_tconn(tconn);
3488     spin_lock(&(tconn->kstc_lock));
3489
3490     WorkItem = &(tconn->kstc_disconnect);
3491
3492     if (tconn->kstc_state != ksts_connected) {
3493
3494         Status = STATUS_SUCCESS;
3495
3496     } else {
3497
3498         if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
3499
3500             Status = STATUS_REMOTE_DISCONNECT;
3501
3502         } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
3503
3504             Status = STATUS_GRACEFUL_DISCONNECT;
3505         }
3506
3507         if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
3508
3509             ks_get_tconn(tconn);
3510
3511             WorkItem->Flags = DisconnectFlags;
3512             WorkItem->tconn = tconn;
3513
3514             cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3515
3516             /* queue the workitem to call */
3517             ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
3518         }
3519     }
3520
3521     spin_unlock(&(tconn->kstc_lock));
3522     ks_put_tconn(tconn);
3523
3524     return  (Status);
3525 }
3526
3527 NTSTATUS
3528 KsTcpReceiveCompletionRoutine(
3529     IN PIRP                         Irp,
3530     IN PKS_TCP_COMPLETION_CONTEXT   Context
3531     )
3532 {
3533     ks_tconn_t *tconn = Context->tconn;
3534     NTSTATUS    status = Irp->IoStatus.Status;
3535     ULONG       length = (ULONG)Irp->IoStatus.Information;
3536
3537     LASSERT(Context != NULL);
3538
3539     if (NT_SUCCESS(status)) {
3540
3541         PKS_TSDUMGR  TsduMgr = Context->TsduMgr;
3542         PCHAR        Buffer = Context->Buffer;
3543
3544         KsPrint((4, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
3545                     TsduMgr->TotalBytes ));
3546
3547         ks_lock_tsdumgr(TsduMgr);
3548         KsWriteTsduBuf(TsduMgr, Context->Buffer, length, 0);
3549         /* signal TsduMgr event */
3550         KeSetEvent(&(Context->TsduMgr->Event), 0, FALSE);
3551         ks_unlock_tsdumgr(TsduMgr);
3552
3553         /* re-active the ks connection and wake up the scheduler */
3554         if (KS_CAN_SCHED(TsduMgr)) {
3555             if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3556                 tconn->kstc_sched_cb(tconn, FALSE);
3557             }
3558         }
3559
3560         ks_put_tconn(tconn);
3561
3562     } else {
3563
3564         /* un-expected errors occur, we must abort the connection */
3565         ks_put_tconn(tconn);
3566         ks_abort_tconn(tconn);
3567     }
3568
3569
3570     if (Context) {
3571
3572         /* free the Context structure... */
3573         ASSERT(Context->Magic == KS_TCP_CONTEXT_MAGIC);
3574         Context->Magic = 'CDAB';
3575         cfs_free(Context);
3576     }
3577
3578     /* free the Irp */
3579     if (Irp) {
3580
3581         /* release mdl chain */
3582         if (Irp->MdlAddress) {
3583             KsReleaseMdl(Irp->MdlAddress, FALSE);
3584         }
3585
3586         /* free irp packet */
3587         IoFreeIrp(Irp);
3588     }
3589
3590     return (status);
3591 }
3592
3593
3594 /*
3595  * KsTcpCompletionRoutine
3596  *   the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
3597  *   We need call the use's own CompletionRoutine if specified. Or
3598  *   it's a synchronous case, we need signal the event.
3599  *
3600  * Arguments:
3601  *   DeviceObject:  the device object of the transport
3602  *   Irp:           the Irp is being completed.
3603  *   Context:       the context we specified when issuing the Irp
3604  *
3605  * Return Value:
3606  *   Nt status code
3607  *
3608  * Notes:
3609  *   N/A
3610  */
3611
3612 NTSTATUS
3613 KsTcpCompletionRoutine(
3614     IN PDEVICE_OBJECT   DeviceObject,
3615     IN PIRP             Irp,
3616     IN PVOID            Context
3617     )
3618 {
3619     if (Context) {
3620
3621         PKS_TCP_COMPLETION_CONTEXT  context = NULL;
3622         ks_tconn_t * tconn = NULL;
3623
3624         context = (PKS_TCP_COMPLETION_CONTEXT) Context;
3625         ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3626         tconn = context->tconn;
3627
3628         if (context->CompletionRoutine) {
3629
3630             //
3631             // Giving control to user specified CompletionRoutine ...
3632             //
3633
3634             context->CompletionRoutine(Irp, context);
3635
3636         } else {
3637
3638             //
3639             // Signaling  the Event ...
3640             //
3641             LASSERT(NULL != context->Event);
3642             KeSetEvent(context->Event, 0, FALSE);
3643
3644             /* drop the reference count of the tconn object */
3645             ks_put_tconn(tconn);
3646         }
3647
3648     } else {
3649
3650         /* cfs_enter_debugger(); */
3651     }
3652
3653     return STATUS_MORE_PROCESSING_REQUIRED;
3654 }
3655
3656 /*
3657  * KsTcpSendCompletionRoutine
3658  *   the user specified Irp completion routine for asynchronous
3659  *   data transmission requests.
3660  *
3661  *   It will do th cleanup job of the ks_tx_t and wake up the
3662  *   ks scheduler thread
3663  *
3664  * Arguments:
3665  *   Irp:           the Irp is being completed.
3666  *   Context:       the context we specified when issuing the Irp
3667  *
3668  * Return Value:
3669  *   Nt status code
3670  *
3671  * Notes:
3672  *   N/A
3673  */
3674
3675 NTSTATUS
3676 KsTcpSendCompletionRoutine(
3677     IN PIRP                         Irp,
3678     IN PKS_TCP_COMPLETION_CONTEXT   context
3679     )
3680 {
3681     NTSTATUS          status = Irp->IoStatus.Status;
3682     ULONG             rc = (ULONG)(ULONG_PTR)Irp->IoStatus.Information;
3683     ks_tconn_t *      tconn = context->tconn;
3684
3685     PKS_TSDUMGR       TsduMgr = context->TsduMgr;
3686     PKEVENT           Event = context->Event;
3687
3688     LASSERT(tconn != NULL && tconn->kstc_magic == KS_TCONN_MAGIC);
3689     LASSERT(context && context->Magic == KS_TCP_CONTEXT_MAGIC);
3690
3691     KsPrint((4, "KsTcpSendCompltionRoutine: tconn = %p TsduMgr = %p "
3692                 "status = %xh bytes = %xh/%x\n", tconn, TsduMgr, status,
3693                 Irp->IoStatus.Information, TsduMgr->TotalBytes));
3694
3695     ks_lock_tsdumgr(TsduMgr);
3696
3697     if (NT_SUCCESS(status)) {
3698
3699         /* cleanup processed TsduMgr queue */
3700         KsReleaseTsdus(tconn, TsduMgr, rc);
3701
3702         /* queue to delivery engine if there's still remained data */
3703         TsduMgr->Busy = FALSE;
3704         if (TsduMgr->TotalBytes > 0) {
3705             KsQueueTdiEngine(tconn, TsduMgr);
3706         }
3707         /* signal TsduMgr event */
3708         KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3709         ks_unlock_tsdumgr(TsduMgr);
3710
3711         /*
3712          * now it's time to re-queue the conns into the
3713          * scheduler queue and wake the scheduler thread.
3714          */
3715
3716         if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3717             tconn->kstc_sched_cb(tconn, TRUE);
3718         }
3719
3720     } else {
3721
3722         ks_unlock_tsdumgr(TsduMgr);
3723
3724         KsPrint((1, "KsTcpSendCompltionRoutine: failed tconn: %p "
3725                     "TsduMgr: %p status: %xh\n", tconn, TsduMgr, status));
3726
3727         /* cfs_enter_debugger(); */
3728
3729         /*
3730          *  for the case that the transmission is unsuccessful,
3731          *  we need abort the tdi connection, but not destroy it.
3732          *  the socknal conn will drop the refer count, then the
3733          *  tdi connection will be freed.
3734          */
3735
3736         ks_abort_tconn(tconn);
3737     }
3738
3739     /* drop tconn reference */
3740     ks_put_tconn(tconn);
3741
3742     /* freeing the context structure */
3743     if (context) {
3744         ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3745         context->Magic = 'CDAB';
3746         cfs_free(context);
3747     }
3748
3749     /* free the Irp structure */
3750     if (Irp) {
3751         /* mdl chain was released by KsReleaseTsdus*/
3752         Irp->MdlAddress = NULL;
3753         IoFreeIrp(Irp);
3754         Irp = NULL;
3755     }
3756
3757     return status;
3758 }
3759
3760 /*
3761  *  Normal receive event handler
3762  *
3763  *  It will move data from system Tsdu to our TsduList
3764  */
3765
3766 NTSTATUS
3767 KsTcpReceiveEventHandler(
3768     IN PVOID                TdiEventContext,
3769     IN CONNECTION_CONTEXT   ConnectionContext,
3770     IN ULONG                ReceiveFlags,
3771     IN ULONG                BytesIndicated,
3772     IN ULONG                BytesAvailable,
3773     OUT ULONG *             BytesTaken,
3774     IN PVOID                Tsdu,
3775     OUT PIRP *              IoRequestPacket
3776    )
3777 {
3778     NTSTATUS            status;
3779
3780     ks_tconn_t *        tconn;
3781
3782     BOOLEAN             bIsExpedited;
3783     BOOLEAN             bIsCompleteTsdu;
3784
3785     PCHAR               Buffer = NULL;
3786     PIRP                Irp = NULL;
3787     PMDL                Mdl = NULL;
3788     PFILE_OBJECT        FileObject;
3789     PDEVICE_OBJECT      DeviceObject;
3790     PKS_TSDUMGR         TsduMgr;
3791
3792     PKS_TCP_COMPLETION_CONTEXT context = NULL;
3793
3794     tconn = (ks_tconn_t *) ConnectionContext;
3795     ks_get_tconn(tconn);
3796
3797     /* check expedited flag */
3798     bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
3799
3800     /* check whether the whole body of payload is received or not */
3801     if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
3802          (BytesIndicated == BytesAvailable) ) {
3803         bIsCompleteTsdu = TRUE;
3804     } else {
3805         bIsCompleteTsdu = FALSE;
3806     }
3807
3808     KsPrint((4, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n",
3809                 BytesIndicated, BytesAvailable));
3810     KsPrint((4, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
3811
3812     /* check whether we are conntected or not listener */
3813     if ( !((tconn->kstc_state == ksts_connected) &&
3814            (tconn->kstc_type == kstt_sender ||
3815             tconn->kstc_type == kstt_child))) {
3816
3817         *BytesTaken = BytesIndicated;
3818         ks_put_tconn(tconn);
3819         return (STATUS_SUCCESS);
3820     }
3821
3822     /* query tsdu mgr */
3823     TsduMgr = KsQueryTsduMgr(tconn, bIsExpedited, FALSE);
3824
3825     ks_lock_tsdumgr(TsduMgr);
3826     if (bIsCompleteTsdu) {
3827
3828         *BytesTaken = KsWriteTsduDat(TsduMgr, Tsdu, BytesAvailable, 0);
3829         status = STATUS_SUCCESS;
3830
3831         /* signal TsduMgr event */
3832         KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3833         ks_unlock_tsdumgr(TsduMgr);
3834
3835         /* re-active the ks connection and wake up the scheduler */
3836         if (KS_CAN_SCHED(TsduMgr)) {
3837             if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3838                 tconn->kstc_sched_cb(tconn, FALSE);
3839             }
3840         }
3841
3842     } else {
3843
3844         ks_unlock_tsdumgr(TsduMgr);
3845
3846         /* allocate buffer for further data in tsdu queue */
3847         Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
3848         if (NULL == Buffer) {
3849             status = STATUS_INSUFFICIENT_RESOURCES;
3850             goto errorout;
3851         }
3852
3853         /* there's still data in tdi internal queue, we need issue a new
3854            Irp to receive all of them. first allocate the tcp context */
3855         context = cfs_alloc(sizeof(KS_TCP_COMPLETION_CONTEXT), 0);
3856         if (!context) {
3857             status = STATUS_INSUFFICIENT_RESOURCES;
3858             goto errorout;
3859         }
3860
3861         /* setup the context */
3862         RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
3863         context->Magic             = KS_TCP_CONTEXT_MAGIC;
3864         context->tconn             = tconn;
3865         context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
3866         context->CompletionContext = Buffer;
3867         context->TsduMgr           = TsduMgr;
3868         context->Buffer            = Buffer;
3869         context->Event             = &(TsduMgr->Event);
3870
3871         if (tconn->kstc_type == kstt_sender) {
3872             FileObject = tconn->sender.kstc_info.FileObject;
3873         } else {
3874             FileObject = tconn->child.kstc_info.FileObject;
3875         }
3876         DeviceObject = IoGetRelatedDeviceObject(FileObject);
3877
3878         /* build new tdi Irp and setup it. */
3879         Irp = KsBuildTdiIrp(DeviceObject);
3880         if (NULL == Irp) {
3881             goto errorout;
3882         }
3883
3884         status = KsLockUserBuffer(
3885                     Buffer,
3886                     FALSE,
3887                     BytesAvailable,
3888                     IoModifyAccess,
3889                     &Mdl
3890                     );
3891
3892         if (!NT_SUCCESS(status)) {
3893             goto errorout;
3894         }
3895
3896         TdiBuildReceive(
3897             Irp,
3898             DeviceObject,
3899             FileObject,
3900             KsTcpCompletionRoutine,
3901             context,
3902             Mdl,
3903             ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
3904             BytesAvailable
3905           );
3906
3907         IoSetNextIrpStackLocation(Irp);
3908
3909         /* return the newly built Irp to transport driver,
3910            it will process it to receive all the data */
3911
3912         *IoRequestPacket = Irp;
3913         *BytesTaken = 0;
3914
3915         ks_get_tconn(tconn);
3916         status = STATUS_MORE_PROCESSING_REQUIRED;
3917     }
3918
3919     ks_put_tconn(tconn);
3920
3921     return (status);
3922
3923 errorout:
3924
3925     if (Mdl) {
3926         KsReleaseMdl(Mdl, FALSE);
3927     }
3928
3929     if (Buffer) {
3930         ExFreePool(Buffer);
3931     }
3932
3933     if (Irp) {
3934         IoFreeIrp(Irp);
3935     }
3936
3937     if (context) {
3938         ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3939         context->Magic = 'CDAB';
3940         cfs_free(context);
3941     }
3942
3943     ks_abort_tconn(tconn);
3944     ks_put_tconn(tconn);
3945
3946     *BytesTaken = BytesAvailable;
3947
3948     return STATUS_SUCCESS;
3949 }
3950
3951 /*
3952  *  Expedited receive event handler
3953  */
3954
3955 NTSTATUS
3956 KsTcpReceiveExpeditedEventHandler(
3957     IN PVOID                TdiEventContext,
3958     IN CONNECTION_CONTEXT   ConnectionContext,
3959     IN ULONG                ReceiveFlags,
3960     IN ULONG                BytesIndicated,
3961     IN ULONG                BytesAvailable,
3962     OUT ULONG *             BytesTaken,
3963     IN PVOID                Tsdu,
3964     OUT PIRP *              IoRequestPacket
3965     )
3966 {
3967     return KsTcpReceiveEventHandler(
3968                 TdiEventContext,
3969                 ConnectionContext,
3970                 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
3971                 BytesIndicated,
3972                 BytesAvailable,
3973                 BytesTaken,
3974                 Tsdu,
3975                 IoRequestPacket
3976                 );
3977 }
3978
3979 /*
3980  *  Bulk receive event handler
3981  *
3982  *  It will queue all the system Tsdus to our TsduList.
3983  *  Then later ks_recv_mdl will release them.
3984  */
3985
3986 NTSTATUS
3987 KsTcpChainedReceiveEventHandler (
3988     IN PVOID TdiEventContext,       // the event context
3989     IN CONNECTION_CONTEXT ConnectionContext,
3990     IN ULONG ReceiveFlags,
3991     IN ULONG ReceiveLength,
3992     IN ULONG StartingOffset,        // offset of start of client data in TSDU
3993     IN PMDL  Tsdu,                  // TSDU data chain
3994     IN PVOID TsduDescriptor         // for call to TdiReturnChainedReceives
3995     )
3996 {
3997
3998     NTSTATUS            status;
3999     ks_tconn_t *        tconn;
4000
4001     PKS_TSDUMGR         TsduMgr;
4002
4003     BOOLEAN             expedited;
4004
4005     tconn = (ks_tconn_t *) ConnectionContext;
4006     expedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
4007
4008     KsPrint((4, "KsTcpChainedReceive: sock: %p conn: %p ReceiveLength: %xh "
4009                 "bIsExpedited: %d Tsdu=%p TsduDesc=%p data=%xh\n",
4010                  tconn, tconn->kstc_conn, ReceiveLength, expedited,
4011                  Tsdu, TsduDescriptor, *((PULONG)KsMapMdlBuffer(Tsdu))));
4012
4013     ks_get_tconn(tconn);
4014
4015     /* check whether we are conntected or not listener */
4016     if ( !((tconn->kstc_state == ksts_connected) &&
4017          (tconn->kstc_type == kstt_sender ||
4018           tconn->kstc_type == kstt_child))) {
4019
4020         ks_put_tconn(tconn);
4021         return (STATUS_SUCCESS);
4022     }
4023
4024     if (Tsdu) {
4025
4026         TsduMgr = KsQueryTsduMgr(tconn, expedited, FALSE);
4027         ks_lock_tsdumgr(TsduMgr);
4028 #if FALSE
4029         KsWriteTsduMdl(TsduMgr, Tsdu,  TsduDescriptor,
4030                        StartingOffset, ReceiveLength, 0);
4031         status = STATUS_PENDING;
4032 #else
4033         KsWriteTsduDat(TsduMgr, (PCHAR)KsMapMdlBuffer(Tsdu) + 
4034                        StartingOffset, ReceiveLength, 0);
4035         status = STATUS_SUCCESS;
4036 #endif
4037         KeSetEvent(&(TsduMgr->Event), 0, FALSE);
4038         ks_unlock_tsdumgr(TsduMgr);
4039
4040         /* re-active the ks connection and wake up the scheduler */
4041         if (KS_CAN_SCHED(TsduMgr)) {
4042             if (tconn->kstc_conn && tconn->kstc_sched_cb) {
4043                 tconn->kstc_sched_cb(tconn, FALSE);
4044             }
4045         }
4046
4047     } else {
4048
4049         ks_abort_tconn(tconn);
4050         status = STATUS_CONNECTION_ABORTED;
4051     }
4052
4053     ks_put_tconn(tconn);
4054
4055     /* Return STATUS_PENDING to system because we are still
4056        owning the MDL resources. ks_recv_mdl is expected
4057        to free the MDL resources. */
4058
4059     return (status);
4060 }
4061
4062
4063 /*
4064  *  Expedited & Bulk receive event handler
4065  */
4066
4067 NTSTATUS
4068 KsTcpChainedReceiveExpeditedEventHandler (
4069     IN PVOID                TdiEventContext,       // the event context
4070     IN CONNECTION_CONTEXT   ConnectionContext,
4071     IN ULONG                ReceiveFlags,
4072     IN ULONG                ReceiveLength,
4073     IN ULONG                StartingOffset,        // offset of start of client data in TSDU
4074     IN PMDL                 Tsdu,                  // TSDU data chain
4075     IN PVOID                TsduDescriptor         // for call to TdiReturnChainedReceives
4076     )
4077 {
4078     return KsTcpChainedReceiveEventHandler(
4079                 TdiEventContext,
4080                 ConnectionContext,
4081                 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
4082                 ReceiveLength,
4083                 StartingOffset,
4084                 Tsdu,
4085                 TsduDescriptor );
4086 }
4087
4088
4089 /*
4090  * KsSetHandlers
4091  *   setup all the event handler callbacks
4092  *
4093  * Arguments:
4094  *   tconn: the tdi connecton object
4095  *
4096  * Return Value:
4097  *   int: ks error code
4098  *
4099  * NOTES:
4100  *   N/A
4101  */
4102
4103 int
4104 KsSetHandlers(
4105     ks_tconn_t *     tconn
4106     )
4107 {
4108     NTSTATUS            status = STATUS_SUCCESS;
4109     KS_EVENT_HANDLERS   handlers;
4110
4111     /* to make sure the address object is opened already */
4112     if (tconn->kstc_addr.FileObject == NULL) {
4113         goto errorout;
4114     }
4115
4116     /* initialize the handlers indictor array. for sender and listenr,
4117        there are different set of callbacks. for child, we just return. */
4118
4119     memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4120
4121     SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
4122     SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
4123     SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
4124     SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
4125     SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
4126
4127     // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
4128
4129     if (tconn->kstc_type == kstt_listener) {
4130         SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
4131     } else if (tconn->kstc_type == kstt_child) {
4132         goto errorout;
4133     }
4134
4135     /* set all the event callbacks */
4136     status = KsSetEventHandlers(
4137                 tconn->kstc_addr.FileObject, /* Address File Object  */
4138                 tconn,                       /* Event Context */
4139                 &handlers                    /* Event callback handlers */
4140                 );
4141
4142 errorout:
4143
4144     return cfs_error_code(status);
4145 }
4146
4147
4148 /*
4149  * KsResetHandlers
4150  *   disable all the event handler callbacks (set to NULL)
4151  *
4152  * Arguments:
4153  *   tconn: the tdi connecton object
4154  *
4155  * Return Value:
4156  *   int: ks error code
4157  *
4158  * NOTES:
4159  *   N/A
4160  */
4161
4162 int
4163 KsResetHandlers(
4164     ks_tconn_t *     tconn
4165     )
4166 {
4167     NTSTATUS            status = STATUS_SUCCESS;
4168     KS_EVENT_HANDLERS   handlers;
4169
4170     /* to make sure the address object is opened already */
4171     if (tconn->kstc_addr.FileObject == NULL) {
4172         goto errorout;
4173     }
4174
4175     /* initialize the handlers indictor array. for sender and listenr,
4176        there are different set of callbacks. for child, we just return. */
4177
4178     memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4179
4180     SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
4181     SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
4182     SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
4183     SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
4184     SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
4185     // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
4186
4187     if (tconn->kstc_type == kstt_listener) {
4188         SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
4189     } else if (tconn->kstc_type == kstt_child) {
4190         goto errorout;
4191     }
4192
4193     /* set all the event callbacks */
4194     status = KsSetEventHandlers(
4195                 tconn->kstc_addr.FileObject, /* Address File Object  */
4196                 tconn,                       /* Event Context */
4197                 &handlers                    /* Event callback handlers */
4198                 );
4199
4200 errorout:
4201
4202     return cfs_error_code(status);
4203 }
4204
4205 VOID
4206 KsPrintProviderInfo(
4207    PWSTR DeviceName,
4208    PTDI_PROVIDER_INFO ProviderInfo
4209    )
4210 {
4211     KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
4212
4213     KsPrint((2, "  Version              : 0x%4.4X\n", ProviderInfo->Version ));
4214     KsPrint((2, "  MaxSendSize          : %d\n", ProviderInfo->MaxSendSize ));
4215     KsPrint((2, "  MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
4216     KsPrint((2, "  MaxDatagramSize      : %d\n", ProviderInfo->MaxDatagramSize ));
4217     KsPrint((2, "  ServiceFlags         : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
4218
4219     if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
4220         KsPrint((2, "  CONNECTION_MODE\n"));
4221     }
4222
4223     if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
4224         KsPrint((2, "  ORDERLY_RELEASE\n"));
4225     }
4226
4227     if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
4228         KsPrint((2, "  CONNECTIONLESS_MODE\n"));
4229     }
4230
4231     if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
4232         KsPrint((2, "  ERROR_FREE_DELIVERY\n"));
4233     }
4234
4235     if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
4236         KsPrint((2, "  SECURITY_LEVEL\n"));
4237     }
4238
4239     if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
4240         KsPrint((2, "  BROADCAST_SUPPORTED\n"));
4241     }
4242
4243     if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
4244         KsPrint((2, "  MULTICAST_SUPPORTED\n"));
4245     }
4246
4247     if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
4248         KsPrint((2, "  DELAYED_ACCEPTANCE\n"));
4249     }
4250
4251     if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
4252         KsPrint((2, "  EXPEDITED_DATA\n"));
4253     }
4254
4255     if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
4256         KsPrint((2, "  INTERNAL_BUFFERING\n"));
4257     }
4258
4259     if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
4260         KsPrint((2, "  ROUTE_DIRECTED\n"));
4261     }
4262
4263     if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
4264         KsPrint((2, "  NO_ZERO_LENGTH\n"));
4265     }
4266
4267     if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
4268         KsPrint((2, "  POINT_TO_POINT\n"));
4269     }
4270
4271     if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
4272         KsPrint((2, "  MESSAGE_MODE\n"));
4273     }
4274
4275     if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
4276         KsPrint((2, "  HALF_DUPLEX\n"));
4277     }
4278
4279     KsPrint((2, "  MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
4280     KsPrint((2, "  MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
4281     KsPrint((2, "  NumberOfResources    : %d\n", ProviderInfo->NumberOfResources ));
4282 }
4283
4284
4285 /*
4286  * ks_create_tconn
4287  *   allocate a new tconn structure from the SLAB cache or
4288  *   NonPaged sysetm pool
4289  *
4290  * Arguments:
4291  *   N/A
4292  *
4293  * Return Value:
4294  *   ks_tconn_t *: the address of tconn or NULL if it fails
4295  *
4296  * NOTES:
4297  *   N/A
4298  */
4299
4300 ks_tconn_t *
4301 ks_create_tconn()
4302 {
4303     ks_tconn_t * tconn = NULL;
4304
4305     /* allocate ksoc_tconn_t from the slab cache memory */
4306     tconn = (ks_tconn_t *)cfs_mem_cache_alloc(
4307                 ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
4308
4309     if (tconn) {
4310
4311         /* zero tconn elements */
4312         memset(tconn, 0, sizeof(ks_tconn_t));
4313
4314         /* initialize the tconn ... */
4315         tconn->kstc_magic = KS_TCONN_MAGIC;
4316
4317         ExInitializeWorkItem(
4318                 &(tconn->kstc_disconnect.WorkItem),
4319                 KsDisconnectHelper,
4320                 &(tconn->kstc_disconnect)
4321                 );
4322
4323         KeInitializeEvent(
4324                 &(tconn->kstc_disconnect.Event),
4325                 SynchronizationEvent,
4326                 FALSE );
4327
4328         ExInitializeWorkItem(
4329                 &(tconn->kstc_destroy),
4330                 ks_destroy_tconn,
4331                 tconn
4332             );
4333
4334         spin_lock_init(&(tconn->kstc_lock));
4335
4336         ks_get_tconn(tconn);
4337         spin_lock(&(ks_data.ksnd_tconn_lock));
4338
4339         /* attach it into global list in ks_data */
4340
4341         cfs_list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
4342         ks_data.ksnd_ntconns++;
4343         spin_unlock(&(ks_data.ksnd_tconn_lock));
4344
4345         tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
4346     }
4347     KsPrint((3, "ks_create_tconn: new connection: %p\n", tconn));
4348     return (tconn);
4349 }
4350
4351 /*
4352  * ks_free_tconn
4353  *   free the tconn structure to the SLAB cache or NonPaged
4354  *   sysetm pool
4355  *
4356  * Arguments:
4357  *   tconn:  the tcon is to be freed
4358  *
4359  * Return Value:
4360  *   N/A
4361  *
4362  * Notes:
4363  *   N/A
4364  */
4365
4366 void
4367 ks_free_tconn(ks_tconn_t * tconn)
4368 {
4369     LASSERT(cfs_atomic_read(&(tconn->kstc_refcount)) == 0);
4370
4371         spin_lock(&(ks_data.ksnd_tconn_lock));
4372
4373     /* remove it from the global list */
4374     cfs_list_del(&tconn->kstc_list);
4375     ks_data.ksnd_ntconns--;
4376
4377     /* if this is the last tconn, it would be safe for
4378        ks_tdi_fini_data to quit ... */
4379     if (ks_data.ksnd_ntconns == 0) {
4380         cfs_wake_event(&ks_data.ksnd_tconn_exit);
4381     }
4382         spin_unlock(&(ks_data.ksnd_tconn_lock));
4383
4384     /* free the structure memory */
4385     cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
4386
4387     KsPrint((3, "ks_free_tconn: tconn %p is freed.\n", tconn));
4388 }
4389
4390
4391 /*
4392  * ks_init_listener
4393  *   Initialize the tconn as a listener (daemon)
4394  *
4395  * Arguments:
4396  *   tconn: the listener tconn
4397  *
4398  * Return Value:
4399  *   N/A
4400  *
4401  * Notes:
4402  *   N/A
4403  */
4404
4405 void
4406 ks_init_listener(
4407     ks_tconn_t * tconn
4408     )
4409 {
4410     /* preparation: intialize the tconn members */
4411
4412     tconn->kstc_type = kstt_listener;
4413
4414     RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4415
4416     CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
4417     CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
4418
4419     cfs_init_event( &(tconn->listener.kstc_accept_event),
4420                     TRUE,
4421                     FALSE );
4422
4423     cfs_init_event( &(tconn->listener.kstc_destroy_event),
4424                     TRUE,
4425                     FALSE );
4426
4427     tconn->kstc_state = ksts_inited;
4428 }
4429
4430
4431 /*
4432  * ks_init_sender
4433  *   Initialize the tconn as a sender
4434  *
4435  * Arguments:
4436  *   tconn: the sender tconn
4437  *
4438  * Return Value:
4439  *   N/A
4440  *
4441  * Notes:
4442  *   N/A
4443  */
4444
4445 void
4446 ks_init_sender(
4447     ks_tconn_t * tconn
4448     )
4449 {
4450     tconn->kstc_type = kstt_sender;
4451     RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4452
4453     KsInitializeKsChain(&(tconn->sender.kstc_recv));
4454     KsInitializeKsChain(&(tconn->sender.kstc_send));
4455
4456     tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4457     tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4458
4459     tconn->kstc_state = ksts_inited;
4460 }
4461
4462 /*
4463  * ks_init_child
4464  *   Initialize the tconn as a child
4465  *
4466  * Arguments:
4467  *   tconn: the child tconn
4468  *
4469  * Return Value:
4470  *   N/A
4471  *
4472  * NOTES:
4473  *   N/A
4474  */
4475
4476 void
4477 ks_init_child(
4478     ks_tconn_t * tconn
4479     )
4480 {
4481     tconn->kstc_type = kstt_child;
4482     RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4483
4484     KsInitializeKsChain(&(tconn->child.kstc_recv));
4485     KsInitializeKsChain(&(tconn->child.kstc_send));
4486
4487     tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4488     tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4489
4490     tconn->kstc_state = ksts_inited;
4491 }
4492
4493 /*
4494  * ks_get_tconn
4495  *   increase the reference count of the tconn with 1
4496  *
4497  * Arguments:
4498  *   tconn: the tdi connection to be referred
4499  *
4500  * Return Value:
4501  *   N/A
4502  *
4503  * NOTES:
4504  *   N/A
4505  */
4506
4507 void
4508 ks_get_tconn(
4509     ks_tconn_t * tconn
4510     )
4511 {
4512     cfs_atomic_inc(&(tconn->kstc_refcount));
4513 }
4514
4515 /*
4516  * ks_put_tconn
4517  *   decrease the reference count of the tconn and destroy
4518  *   it if the refercount becomes 0.
4519  *
4520  * Arguments:
4521  *   tconn: the tdi connection to be dereferred
4522  *
4523  * Return Value:
4524  *   N/A
4525  *
4526  * NOTES:
4527  *   N/A
4528  */
4529
4530 void
4531 ks_put_tconn(
4532     ks_tconn_t *tconn
4533     )
4534 {
4535     if (cfs_atomic_dec_and_test(&(tconn->kstc_refcount))) {
4536
4537         spin_lock(&(tconn->kstc_lock));
4538
4539         if ( ( tconn->kstc_type == kstt_child ||
4540                tconn->kstc_type == kstt_sender ) &&
4541              ( tconn->kstc_state == ksts_connected ) ) {
4542
4543             spin_unlock(&(tconn->kstc_lock));
4544
4545             ks_abort_tconn(tconn);
4546
4547         } else {
4548
4549             if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
4550                 cfs_enter_debugger();
4551             } else {
4552                 ExQueueWorkItem(
4553                         &(tconn->kstc_destroy),
4554                         DelayedWorkQueue
4555                         );
4556
4557                 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
4558             }
4559
4560             spin_unlock(&(tconn->kstc_lock));
4561         }
4562     }
4563 }
4564
4565 /*
4566  * ks_destroy_tconn
4567  *   cleanup the tdi connection and free it
4568  *
4569  * Arguments:
4570  *   tconn: the tdi connection to be cleaned.
4571  *
4572  * Return Value:
4573  *   N/A
4574  *
4575  * NOTES:
4576  *   N/A
4577  */
4578
4579 void
4580 ks_destroy_tconn(
4581     ks_tconn_t *     tconn
4582     )
4583 {
4584     LASSERT(tconn->kstc_refcount.counter == 0);
4585
4586     if (tconn->kstc_type == kstt_listener) {
4587
4588         KsResetHandlers(tconn);
4589
4590         /* for listener, we just need to close the address object */
4591         KsCloseAddress(
4592                 tconn->kstc_addr.Handle,
4593                 tconn->kstc_addr.FileObject
4594                 );
4595
4596         tconn->kstc_state = ksts_inited;
4597
4598     } else if (tconn->kstc_type == kstt_child) {
4599
4600         /* for child tdi conections */
4601
4602         /* disassociate the relation between it's connection object
4603            and the address object */
4604
4605         if (tconn->kstc_state == ksts_associated) {
4606             KsDisassociateAddress(
4607                 tconn->child.kstc_info.FileObject
4608                 );
4609         }
4610
4611         /* release the connection object */
4612
4613         KsCloseConnection(
4614                 tconn->child.kstc_info.Handle,
4615                 tconn->child.kstc_info.FileObject
4616                 );
4617
4618         /* release it's refer of it's parent's address object */
4619         KsCloseAddress(
4620                 NULL,
4621                 tconn->kstc_addr.FileObject
4622                 );
4623
4624         spin_lock(&tconn->child.kstc_parent->kstc_lock);
4625         spin_lock(&tconn->kstc_lock);
4626
4627         tconn->kstc_state = ksts_inited;
4628
4629         /* remove it frome it's parent's queues */
4630
4631         if (tconn->child.kstc_queued) {
4632
4633             cfs_list_del(&(tconn->child.kstc_link));
4634
4635             if (tconn->child.kstc_queueno) {
4636
4637                 LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
4638                 tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
4639
4640             } else {
4641
4642                 LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
4643                 tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
4644             }
4645
4646             tconn->child.kstc_queued = FALSE;
4647         }
4648
4649         spin_unlock(&tconn->kstc_lock);
4650         spin_unlock(&tconn->child.kstc_parent->kstc_lock);
4651
4652         /* drop the reference of the parent tconn */
4653         ks_put_tconn(tconn->child.kstc_parent);
4654
4655     } else if (tconn->kstc_type == kstt_sender) {
4656
4657         KsResetHandlers(tconn);
4658
4659         /* release the connection object */
4660
4661         KsCloseConnection(
4662                 tconn->sender.kstc_info.Handle,
4663                 tconn->sender.kstc_info.FileObject
4664                 );
4665
4666         /* release it's refer of it's parent's address object */
4667         KsCloseAddress(
4668                 tconn->kstc_addr.Handle,
4669                 tconn->kstc_addr.FileObject
4670                 );
4671
4672         tconn->kstc_state = ksts_inited;
4673
4674     } else {
4675         cfs_enter_debugger();
4676     }
4677
4678     /* free the tconn structure ... */
4679
4680     ks_free_tconn(tconn);
4681 }
4682
4683 /*
4684  * ks_get_tcp_option
4685  *   Query the the options of the tcp stream connnection
4686  *
4687  * Arguments:
4688  *   tconn:         the tdi connection
4689  *   ID:            option id
4690  *   OptionValue:   buffer to store the option value
4691  *   Length:        the length of the value, to be returned
4692  *
4693  * Return Value:
4694  *   int:           ks return code
4695  *
4696  * NOTES:
4697  *   N/A
4698  */
4699
4700 int
4701 ks_get_tcp_option (
4702     ks_tconn_t *        tconn,
4703     ULONG               ID,
4704     PVOID               OptionValue,
4705     PULONG              Length
4706     )
4707 {
4708     NTSTATUS            Status = STATUS_SUCCESS;
4709
4710     IO_STATUS_BLOCK     IoStatus;
4711
4712     TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
4713
4714     PFILE_OBJECT        ConnectionObject;
4715     PDEVICE_OBJECT      DeviceObject = NULL;
4716
4717     PIRP                Irp = NULL;
4718     PIO_STACK_LOCATION  IrpSp = NULL;
4719
4720     KEVENT              Event;
4721
4722     /* make sure the tdi connection is connected ? */
4723
4724     ks_get_tconn(tconn);
4725
4726     if (tconn->kstc_state != ksts_connected) {
4727         Status = STATUS_INVALID_PARAMETER;
4728         goto errorout;
4729     }
4730
4731     LASSERT(tconn->kstc_type == kstt_sender ||
4732            tconn->kstc_type == kstt_child);
4733
4734     if (tconn->kstc_type == kstt_sender) {
4735         ConnectionObject = tconn->sender.kstc_info.FileObject;
4736     } else {
4737         ConnectionObject = tconn->child.kstc_info.FileObject;
4738     }
4739
4740     QueryInfoEx.ID.toi_id = ID;
4741     QueryInfoEx.ID.toi_type   = INFO_TYPE_CONNECTION;
4742     QueryInfoEx.ID.toi_class  = INFO_CLASS_PROTOCOL;
4743     QueryInfoEx.ID.toi_entity.tei_entity   = CO_TL_ENTITY;
4744     QueryInfoEx.ID.toi_entity.tei_instance = 0;
4745
4746     RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
4747
4748     KeInitializeEvent(&Event, NotificationEvent, FALSE);
4749     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4750
4751     Irp = IoBuildDeviceIoControlRequest(
4752                 IOCTL_TCP_QUERY_INFORMATION_EX,
4753                 DeviceObject,
4754                 &QueryInfoEx,
4755                 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
4756                 OptionValue,
4757                 *Length,
4758                 FALSE,
4759                 &Event,
4760                 &IoStatus
4761                 );
4762
4763     if (Irp == NULL) {
4764         Status = STATUS_INSUFFICIENT_RESOURCES;
4765         goto errorout;
4766     }
4767
4768     IrpSp = IoGetNextIrpStackLocation(Irp);
4769
4770     if (IrpSp == NULL) {
4771
4772         IoFreeIrp(Irp);
4773         Irp = NULL;
4774         Status = STATUS_INSUFFICIENT_RESOURCES;
4775         goto errorout;
4776     }
4777
4778     IrpSp->FileObject = ConnectionObject;
4779     IrpSp->DeviceObject = DeviceObject;
4780
4781     Status = IoCallDriver(DeviceObject, Irp);
4782
4783     if (Status == STATUS_PENDING) {
4784
4785         KeWaitForSingleObject(
4786                 &Event,
4787                 Executive,
4788                 KernelMode,
4789                 FALSE,
4790                 NULL
4791                 );
4792
4793         Status = IoStatus.Status;
4794     }
4795
4796
4797     if (NT_SUCCESS(Status)) {
4798         *Length = (ULONG)(ULONG_PTR)IoStatus.Information;
4799     } else {
4800         cfs_enter_debugger();
4801         memset(OptionValue, 0, *Length);
4802         Status = STATUS_SUCCESS;
4803     }
4804
4805 errorout:
4806
4807     ks_put_tconn(tconn);
4808
4809     return cfs_error_code(Status);
4810 }
4811
4812 /*
4813  * ks_set_tcp_option
4814  *   Set the the options for the tcp stream connnection
4815  *
4816  * Arguments:
4817  *   tconn:     the tdi connection
4818  *   ID:        option id
4819  *   OptionValue: buffer containing the new option value
4820  *   Length:    the length of the value
4821  *
4822  * Return Value:
4823  *   int:       ks return code
4824  *
4825  * NOTES:
4826  *   N/A
4827  */
4828
4829 NTSTATUS
4830 ks_set_tcp_option (
4831     ks_tconn_t *    tconn,
4832     ULONG           ID,
4833     PVOID           OptionValue,
4834     ULONG           Length
4835     )
4836 {
4837     NTSTATUS            Status = STATUS_SUCCESS;
4838
4839     IO_STATUS_BLOCK     IoStatus;
4840
4841     ULONG               SetInfoExLength;
4842     PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
4843
4844     PFILE_OBJECT        ConnectionObject;
4845     PDEVICE_OBJECT      DeviceObject = NULL;
4846
4847     PIRP                Irp = NULL;
4848     PIO_STACK_LOCATION  IrpSp = NULL;
4849
4850     PKEVENT             Event;
4851
4852     /* make sure the tdi connection is connected ? */
4853
4854     ks_get_tconn(tconn);
4855
4856     if (tconn->kstc_state != ksts_connected) {
4857         Status = STATUS_INVALID_PARAMETER;
4858         goto errorout;
4859     }
4860
4861     LASSERT(tconn->kstc_type == kstt_sender ||
4862            tconn->kstc_type == kstt_child);
4863
4864     if (tconn->kstc_type == kstt_sender) {
4865         ConnectionObject = tconn->sender.kstc_info.FileObject;
4866     } else {
4867         ConnectionObject = tconn->child.kstc_info.FileObject;
4868     }
4869
4870     SetInfoExLength =  sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
4871
4872     SetInfoEx = ExAllocatePoolWithTag(
4873                     NonPagedPool,
4874                     SetInfoExLength,
4875                     'TSSK'
4876                     );
4877
4878     if (SetInfoEx == NULL) {
4879         Status = STATUS_INSUFFICIENT_RESOURCES;
4880         goto errorout;
4881     }
4882
4883     SetInfoEx->ID.toi_id = ID;
4884
4885     SetInfoEx->ID.toi_type  = INFO_TYPE_CONNECTION;
4886     SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
4887     SetInfoEx->ID.toi_entity.tei_entity   = CO_TL_ENTITY;
4888     SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
4889
4890     SetInfoEx->BufferSize = Length;
4891     RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
4892
4893     Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
4894     KeInitializeEvent(Event, NotificationEvent, FALSE);
4895
4896     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4897
4898     Irp = IoBuildDeviceIoControlRequest(
4899                 IOCTL_TCP_SET_INFORMATION_EX,
4900                 DeviceObject,
4901                 SetInfoEx,
4902                 SetInfoExLength,
4903                 NULL,
4904                 0,
4905                 FALSE,
4906                 Event,
4907                 &IoStatus
4908                 );
4909
4910     if (Irp == NULL) {
4911         Status = STATUS_INSUFFICIENT_RESOURCES;
4912         goto errorout;
4913     }
4914
4915     IrpSp = IoGetNextIrpStackLocation(Irp);
4916
4917     if (IrpSp == NULL) {
4918         IoFreeIrp(Irp);
4919         Irp = NULL;
4920         Status = STATUS_INSUFFICIENT_RESOURCES;
4921         goto errorout;
4922     }
4923
4924     IrpSp->FileObject = ConnectionObject;
4925     IrpSp->DeviceObject = DeviceObject;
4926
4927     Status = IoCallDriver(DeviceObject, Irp);
4928
4929     if (Status == STATUS_PENDING) {
4930
4931         KeWaitForSingleObject(
4932                 Event,
4933                 Executive,
4934                 KernelMode,
4935                 FALSE,
4936                 NULL
4937                 );
4938
4939         Status = IoStatus.Status;
4940     }
4941
4942 errorout:
4943
4944     if (SetInfoEx) {
4945         ExFreePool(SetInfoEx);
4946     }
4947
4948     if (!NT_SUCCESS(Status)) {
4949         KsPrint((0, "ks_set_tcp_option: error setup tcp option: "
4950                     "ID (%d) Status = %xh\n", ID, Status));
4951         Status = STATUS_SUCCESS;
4952     }
4953
4954     ks_put_tconn(tconn);
4955
4956     return cfs_error_code(Status);
4957 }
4958
4959 /*
4960  * ks_bind_tconn
4961  *   bind the tdi connection object with an address
4962  *
4963  * Arguments:
4964  *   tconn:    tconn to be bound
4965  *   parent:   the parent tconn object
4966  *   ipaddr:   the ip address
4967  *   port:     the port number
4968  *
4969  * Return Value:
4970  *   int:   0 for success or ks error codes.
4971  *
4972  * NOTES:
4973  *   N/A
4974  */
4975
4976 int
4977 ks_bind_tconn (
4978     ks_tconn_t *    tconn,
4979     ks_tconn_t *    parent,
4980     ulong           addr,
4981     unsigned short  port
4982     )
4983 {
4984     NTSTATUS            status;
4985     int                 rc = 0;
4986
4987     ks_tdi_addr_t    taddr;
4988
4989     memset(&taddr, 0, sizeof(ks_tdi_addr_t));
4990
4991     if (tconn->kstc_state != ksts_inited) {
4992
4993         status = STATUS_INVALID_PARAMETER;
4994         rc = cfs_error_code(status);
4995         goto errorout;
4996
4997     } else if (tconn->kstc_type == kstt_child) {
4998
4999         if (NULL == parent) {
5000             status = STATUS_INVALID_PARAMETER;
5001             rc = cfs_error_code(status);
5002
5003             goto errorout;
5004         }
5005
5006         /* refer it's parent's address object */
5007
5008         taddr = parent->kstc_addr;
5009         ObReferenceObject(taddr.FileObject);
5010
5011         ks_get_tconn(parent);
5012
5013     } else {
5014
5015         PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
5016         ULONG              AddrLen = 0;
5017
5018         /* intialize the tdi address*/
5019
5020         TdiAddress->TAAddressCount = 1;
5021         TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5022         TdiAddress->Address[0].AddressType   = TDI_ADDRESS_TYPE_IP;
5023
5024         ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5025         ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5026
5027         memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5028
5029
5030         /* open the transport address object */
5031
5032         AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
5033                   TDI_ADDRESS_LENGTH_IP;
5034
5035         status = KsOpenAddress(
5036                     &(tconn->kstc_dev),
5037                     &(taddr.Tdi),
5038                     AddrLen,
5039                     &(taddr.Handle),
5040                     &(taddr.FileObject)
5041                     );
5042
5043         if (!NT_SUCCESS(status)) {
5044
5045             KsPrint((1, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
5046                         addr, port,  status ));
5047             rc = cfs_error_code(status);
5048             goto errorout;
5049         }
5050     }
5051
5052     if (tconn->kstc_type == kstt_child) {
5053         tconn->child.kstc_parent = parent;
5054     }
5055
5056     tconn->kstc_state = ksts_bind;
5057     tconn->kstc_addr  = taddr;
5058
5059 errorout:
5060
5061     return (rc);
5062 }
5063
5064 /*
5065  * ks_build_tconn
5066  *  build tcp/streaming connection to remote peer
5067  *
5068  * Arguments:
5069  *   tconn:    tconn to be connected to the peer
5070  *   addr:     the peer's ip address
5071  *   port:     the peer's port number
5072  *
5073  * Return Value:
5074  *   int:   0 for success or ks error codes.
5075  *
5076  * Notes:
5077  *   N/A
5078  */
5079
5080 int
5081 ks_build_tconn(
5082     ks_tconn_t *                    tconn,
5083     ulong                           addr,
5084     unsigned short                  port
5085     )
5086 {
5087     int                             rc = 0;
5088     NTSTATUS                        status = STATUS_SUCCESS;
5089
5090
5091     PFILE_OBJECT                    ConnectionObject = NULL;
5092     PDEVICE_OBJECT                  DeviceObject = NULL;
5093
5094     PTDI_CONNECTION_INFORMATION     ConnectionInfo = NULL;
5095     ULONG                           AddrLength;
5096
5097     PIRP                            Irp = NULL;
5098
5099     LASSERT(tconn->kstc_type == kstt_sender);
5100     LASSERT(tconn->kstc_state == ksts_bind);
5101
5102     ks_get_tconn(tconn);
5103
5104     {
5105         /* set the event callbacks */
5106         rc = KsSetHandlers(tconn);
5107
5108         if (rc < 0) {
5109             cfs_enter_debugger();
5110             goto errorout;
5111         }
5112     }
5113
5114     /* create the connection file handle / object  */
5115     status = KsOpenConnection(
5116                 &(tconn->kstc_dev),
5117                 (CONNECTION_CONTEXT)tconn,
5118                 &(tconn->sender.kstc_info.Handle),
5119                 &(tconn->sender.kstc_info.FileObject)
5120                 );
5121
5122     if (!NT_SUCCESS(status)) {
5123         rc = cfs_error_code(status);
5124         cfs_enter_debugger();
5125         goto errorout;
5126     }
5127
5128     /* associdate the the connection with the adress object of the tconn */
5129
5130     status = KsAssociateAddress(
5131                 tconn->kstc_addr.Handle,
5132                 tconn->sender.kstc_info.FileObject
5133                 );
5134
5135     if (!NT_SUCCESS(status)) {
5136         rc = cfs_error_code(status);
5137         cfs_enter_debugger();
5138         goto errorout;
5139     }
5140
5141     tconn->kstc_state = ksts_associated;
5142
5143     /* Allocating Connection Info Together with the Address */
5144     AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
5145                  + TDI_ADDRESS_LENGTH_IP;
5146
5147     ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
5148     NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
5149
5150     if (NULL == ConnectionInfo) {
5151
5152         status = STATUS_INSUFFICIENT_RESOURCES;
5153         rc = cfs_error_code(status);
5154         cfs_enter_debugger();
5155         goto errorout;
5156     }
5157
5158     /* Initializing ConnectionInfo ... */
5159     {
5160         PTRANSPORT_ADDRESS TdiAddress;
5161
5162         /* ConnectionInfo settings */
5163
5164         ConnectionInfo->UserDataLength = 0;
5165         ConnectionInfo->UserData = NULL;
5166         ConnectionInfo->OptionsLength = 0;
5167         ConnectionInfo->Options = NULL;
5168         ConnectionInfo->RemoteAddressLength = AddrLength;
5169         ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
5170
5171
5172         /* intialize the tdi address*/
5173
5174         TdiAddress = ConnectionInfo->RemoteAddress;
5175
5176         TdiAddress->TAAddressCount = 1;
5177         TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5178         TdiAddress->Address[0].AddressType   = TDI_ADDRESS_TYPE_IP;
5179
5180         ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5181         ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5182
5183         memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5184     }
5185
5186     /* Now prepare to connect the remote peer ... */
5187
5188     ConnectionObject = tconn->sender.kstc_info.FileObject;
5189     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5190
5191     /* allocate a new Irp */
5192
5193     Irp = KsBuildTdiIrp(DeviceObject);
5194
5195     if (NULL == Irp) {
5196
5197         status = STATUS_INSUFFICIENT_RESOURCES;
5198         rc = cfs_error_code(status);
5199         cfs_enter_debugger();
5200         goto errorout;
5201     }
5202
5203     /* setup the Irp */
5204
5205     TdiBuildConnect(
5206             Irp,
5207             DeviceObject,
5208             ConnectionObject,
5209             NULL,
5210             NULL,
5211             NULL,
5212             ConnectionInfo,
5213             NULL
5214             );
5215
5216
5217     /* sumbit the Irp to the underlying transport driver */
5218     status = KsSubmitTdiIrp(
5219                     DeviceObject,
5220                     Irp,
5221                     TRUE,
5222                     NULL
5223                     );
5224
5225         spin_lock(&(tconn->kstc_lock));
5226
5227     if (NT_SUCCESS(status)) {
5228
5229         /* Connected! the conneciton is built successfully. */
5230
5231         tconn->kstc_state = ksts_connected;
5232
5233         tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
5234         tconn->sender.kstc_info.Remote         = ConnectionInfo->RemoteAddress;
5235
5236         spin_unlock(&(tconn->kstc_lock));
5237
5238     } else {
5239
5240         /* Not connected! Abort it ... */
5241
5242         if (rc != 0) {
5243             cfs_enter_debugger();
5244         }
5245
5246         Irp = NULL;
5247         rc = cfs_error_code(status);
5248
5249         tconn->kstc_state = ksts_associated;
5250         spin_unlock(&(tconn->kstc_lock));
5251
5252         /* disassocidate the connection and the address object,
5253            after cleanup,  it's safe to set the state to abort ... */
5254
5255         if ( NT_SUCCESS(KsDisassociateAddress(
5256                         tconn->sender.kstc_info.FileObject))) {
5257             tconn->kstc_state = ksts_aborted;
5258         }
5259
5260         /* reset the event callbacks */
5261         rc = KsResetHandlers(tconn);
5262
5263         goto errorout;
5264     }
5265
5266 errorout:
5267
5268     if (NT_SUCCESS(status)) {
5269
5270         ks_query_local_ipaddr(tconn);
5271
5272     } else {
5273
5274         if (ConnectionInfo) {
5275             ExFreePool(ConnectionInfo);
5276         }
5277         if (Irp) {
5278             IoFreeIrp(Irp);
5279         }
5280     }
5281
5282     ks_put_tconn(tconn);
5283
5284     return (rc);
5285 }
5286
5287
5288 /*
5289  * ks_disconnect_tconn
5290  *   disconnect the tconn from a connection
5291  *
5292  * Arguments:
5293  *   tconn: the tdi connecton object connected already
5294  *   flags: flags & options for disconnecting
5295  *
5296  * Return Value:
5297  *   int: ks error code
5298  *
5299  * Notes:
5300  *   N/A
5301  */
5302
5303 int
5304 ks_disconnect_tconn(
5305     ks_tconn_t *    tconn,
5306     ulong           flags
5307     )
5308 {
5309     NTSTATUS            status = STATUS_SUCCESS;
5310
5311     ks_tconn_info_t *   info;
5312
5313     PFILE_OBJECT        ConnectionObject;
5314     PDEVICE_OBJECT      DeviceObject = NULL;
5315
5316     PIRP                Irp = NULL;
5317
5318     KEVENT              Event;
5319
5320     ks_get_tconn(tconn);
5321
5322     /* make sure tt's connected already and it
5323        must be a sender or a child ...       */
5324
5325     LASSERT(tconn->kstc_state == ksts_connected);
5326     LASSERT( tconn->kstc_type == kstt_sender ||
5327             tconn->kstc_type == kstt_child);
5328
5329     /* reset all the event handlers to NULL */
5330
5331     if (tconn->kstc_type != kstt_child) {
5332         KsResetHandlers (tconn);
5333     }
5334
5335     /* Disconnecting to the remote peer ... */
5336
5337     if (tconn->kstc_type == kstt_sender) {
5338         info = &(tconn->sender.kstc_info);
5339     } else {
5340         info = &(tconn->child.kstc_info);
5341     }
5342
5343     ConnectionObject = info->FileObject;
5344     DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5345
5346     /* allocate an Irp and setup it */
5347
5348     Irp = KsBuildTdiIrp(DeviceObject);
5349
5350     if (NULL == Irp) {
5351
5352         status = STATUS_INSUFFICIENT_RESOURCES;
5353         cfs_enter_debugger();
5354         goto errorout;
5355     }
5356
5357     KeInitializeEvent(
5358             &Event,
5359             SynchronizationEvent,
5360             FALSE
5361             );
5362
5363     TdiBuildDisconnect(
5364             Irp,
5365             DeviceObject,
5366             ConnectionObject,
5367             KsDisconectCompletionRoutine,
5368             &Event,
5369             NULL,
5370             flags,
5371             NULL,
5372             NULL
5373             );
5374
5375     /* issue the Irp to the underlying transport
5376        driver to disconnect the connection    */
5377
5378     status = IoCallDriver(DeviceObject, Irp);
5379
5380     if (STATUS_PENDING == status) {
5381
5382         status = KeWaitForSingleObject(
5383                      &Event,
5384                      Executive,
5385                      KernelMode,
5386                      FALSE,
5387                      NULL
5388                      );
5389
5390         status = Irp->IoStatus.Status;
5391     }
5392
5393     KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
5394                 status, KsNtStatusToString(status)));
5395
5396     IoFreeIrp(Irp);
5397
5398     if (info->ConnectionInfo) {
5399
5400         /* disassociate the association between connection/address objects */
5401
5402         status = KsDisassociateAddress(ConnectionObject);
5403
5404         if (!NT_SUCCESS(status)) {
5405             cfs_enter_debugger();
5406         }
5407
5408         spin_lock(&(tconn->kstc_lock));
5409
5410         /* cleanup the tsdumgr Lists */
5411         KsCleanupTsdu (tconn);
5412
5413         /* set the state of the tconn */
5414         if (NT_SUCCESS(status)) {
5415             tconn->kstc_state = ksts_disconnected;
5416         } else {
5417             tconn->kstc_state = ksts_associated;
5418         }
5419
5420         /* free  the connection info to system pool*/
5421         ExFreePool(info->ConnectionInfo);
5422         info->ConnectionInfo = NULL;
5423         info->Remote = NULL;
5424
5425         spin_unlock(&(tconn->kstc_lock));
5426     }
5427
5428     status = STATUS_SUCCESS;
5429
5430 errorout:
5431
5432     ks_put_tconn(tconn);
5433
5434     return cfs_error_code(status);
5435 }
5436
5437
5438 /*
5439  * ks_abort_tconn
5440  *   The connection is broken un-expectedly. We need do
5441  *   some cleanup.
5442  *
5443  * Arguments:
5444  *   tconn: the tdi connection
5445  *
5446  * Return Value:
5447  *   N/A
5448  *
5449  * Notes:
5450  *   N/A
5451  */
5452
5453 void
5454 ks_abort_tconn(
5455     ks_tconn_t *     tconn
5456     )
5457 {
5458     PKS_DISCONNECT_WORKITEM WorkItem = NULL;
5459
5460     WorkItem = &(tconn->kstc_disconnect);
5461
5462     ks_get_tconn(tconn);
5463         spin_lock(&(tconn->kstc_lock));
5464
5465     if (tconn->kstc_state != ksts_connected) {
5466         ks_put_tconn(tconn);
5467     } else {
5468
5469         if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
5470
5471             WorkItem->Flags = TDI_DISCONNECT_ABORT;
5472             WorkItem->tconn = tconn;
5473
5474             cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
5475
5476             ExQueueWorkItem(
5477                     &(WorkItem->WorkItem),
5478                     DelayedWorkQueue
5479                     );
5480         }
5481     }
5482
5483         spin_unlock(&(tconn->kstc_lock));
5484 }
5485
5486
5487 /*
5488  * ks_query_local_ipaddr
5489  *   query the local connection ip address
5490  *
5491  * Arguments:
5492  *   tconn:  the tconn which is connected
5493  *
5494  * Return Value:
5495  *   int: ks error code
5496  *
5497  * Notes:
5498  *   N/A
5499  */
5500
5501 int
5502 ks_query_local_ipaddr(
5503     ks_tconn_t *     tconn
5504     )
5505 {
5506     PFILE_OBJECT    FileObject = NULL;
5507     NTSTATUS        status;
5508
5509     PTRANSPORT_ADDRESS TdiAddress;
5510     ULONG              AddressLength;
5511
5512     if (tconn->kstc_type == kstt_sender) {
5513         FileObject = tconn->sender.kstc_info.FileObject;
5514     } else if (tconn->kstc_type == kstt_child) {
5515         FileObject = tconn->child.kstc_info.FileObject;
5516     } else {
5517         status = STATUS_INVALID_PARAMETER;
5518         goto errorout;
5519     }
5520
5521     TdiAddress = &(tconn->kstc_addr.Tdi);
5522     AddressLength = MAX_ADDRESS_LENGTH;
5523
5524     status =  KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
5525
5526     if (NT_SUCCESS(status)) {
5527         KsPrint((2, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
5528                 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
5529                 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
5530     } else {
5531         KsPrint((2, "ks_query_local_ipaddr: Failed to query the connection local ip address.\n"));
5532     }
5533
5534 errorout:
5535
5536     return cfs_error_code(status);
5537 }
5538
5539 int
5540 KsCalcWhichEngine(ks_tconn_t * tconn)
5541 {
5542     PTRANSPORT_ADDRESS TdiAddress = &(tconn->kstc_addr.Tdi);
5543     ULONG addr = ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr;
5544     ULONG sum = (addr & 0xFF) + ((addr & 0xFF00) >> 8) + ((addr & 0xFF0000) >> 16);
5545
5546     return (int)(sum % ks_data.ksnd_engine_nums);
5547 }
5548
5549 void
5550 KsQueueTdiEngine(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5551 {
5552     ks_engine_mgr_t *   engm;
5553     ks_engine_slot_t *  engs;
5554
5555     engm = &ks_data.ksnd_engine_mgr[KsCalcWhichEngine(tconn)];
5556     engs = &TsduMgr->Slot;
5557
5558     if (!engs->queued) {
5559         spin_lock(&engm->lock);
5560         if (!engs->queued) {
5561             cfs_list_add_tail(&engs->link, &engm->list);
5562             engs->queued = TRUE;
5563             engs->tconn = tconn;
5564             engs->emgr = engm;
5565             engs->tsdumgr = TsduMgr;
5566             KeSetEvent(&(engm->start),0, FALSE);
5567         }
5568         spin_unlock(&engm->lock);
5569         KsPrint((4, "KsQueueTdiEngine: TsduMgr=%p is queued to engine %p\n",
5570                     TsduMgr, engm));
5571     }
5572     KeSetEvent(&(engm->start),0, FALSE);
5573 }
5574
5575 void
5576 KsRemoveTdiEngine(PKS_TSDUMGR TsduMgr)
5577 {
5578     ks_engine_mgr_t *   engm;
5579     ks_engine_slot_t *  engs;
5580
5581     engs = &TsduMgr->Slot;
5582     if (engs->queued) {
5583         engm = engs->emgr;
5584         LASSERT(engm != NULL);
5585         spin_lock(&engm->lock);
5586         if (engs->queued) {
5587             cfs_list_del(&engs->link);
5588             engs->queued = FALSE;
5589             engs->tconn = NULL;
5590             engs->emgr = NULL;
5591             engs->tsdumgr = NULL;
5592         }
5593         spin_unlock(&engm->lock);
5594         KsPrint((4, "KsQueueTdiEngine: TsduMgr %p is removed from engine %p\n",
5595                     TsduMgr, engm));
5596     }
5597 }
5598
5599 int
5600 KsDeliveryIrp(ks_tconn_t * tconn, PIRP irp)
5601 {
5602     PFILE_OBJECT        connobj;
5603     PDEVICE_OBJECT      devobj;
5604     NTSTATUS            status;
5605     int                 rc = 0;
5606
5607     /* construct Irp */
5608     if (tconn->kstc_type == kstt_sender) {
5609         connobj = tconn->sender.kstc_info.FileObject;
5610     } else {
5611         LASSERT(tconn->kstc_type == kstt_child);
5612         connobj = tconn->child.kstc_info.FileObject;
5613     }
5614     devobj = IoGetRelatedDeviceObject(connobj);
5615     
5616     /* send irp to transport layer */
5617     status = IoCallDriver(devobj, irp);
5618
5619     /* convert status to linux error code */
5620     if (!NT_SUCCESS(status)) {
5621         rc = cfs_error_code(status);
5622     }
5623
5624     KsPrint((4, "KsDeliveryIrp: tconn=%p irp=%p status=%xh rc=%d.\n",
5625                  tconn, irp, status, rc));
5626     return rc;
5627 }
5628
5629 PIRP
5630 KsBuildSend(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr,
5631             ks_mdl_t * mdl, ulong flags )
5632 {
5633     ks_tdi_tx_t *       context;
5634     PIRP                irp = NULL;
5635     PFILE_OBJECT        connobj;
5636     PDEVICE_OBJECT      devobj;
5637     NTSTATUS            status;
5638     ULONG               length;
5639
5640     int                 rc = 0;
5641
5642     /* query mdl chain total length */
5643     length = KsQueryMdlsSize(mdl);
5644
5645     /* we need allocate the ks_tx_t structure from memory pool. */
5646     context = cfs_alloc(sizeof(ks_tdi_tx_t), 0);
5647     if (!context) {
5648         status = STATUS_INSUFFICIENT_RESOURCES;
5649         goto errorout;
5650     }
5651
5652     /* intialize the TcpContext */
5653     memset(context,0, sizeof(ks_tdi_tx_t));
5654     context->Magic = KS_TCP_CONTEXT_MAGIC;
5655     context->tconn = tconn;
5656     context->CompletionRoutine = KsTcpSendCompletionRoutine;
5657     context->TsduMgr = TsduMgr;
5658     context->Length = length;
5659
5660     /* construct Irp */
5661     if (tconn->kstc_type == kstt_sender) {
5662         connobj = tconn->sender.kstc_info.FileObject;
5663     } else {
5664         LASSERT(tconn->kstc_type == kstt_child);
5665         connobj = tconn->child.kstc_info.FileObject;
5666     }
5667     devobj = IoGetRelatedDeviceObject(connobj);
5668     irp = KsBuildTdiIrp(devobj);
5669     if (NULL == irp) {
5670         status = STATUS_INSUFFICIENT_RESOURCES;
5671         goto errorout;
5672     }
5673
5674     /* grab tconn reference */
5675     ks_get_tconn(tconn);
5676
5677     /* delivery the sending request */
5678     TdiBuildSend(
5679         irp,
5680         devobj,
5681         connobj,
5682         KsTcpCompletionRoutine,
5683         context,
5684         mdl,
5685         flags,
5686         length
5687       );
5688
5689       return irp;
5690
5691 errorout:
5692
5693     /* free the context if is not used at all */
5694     if (context) {
5695         ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
5696         context->Magic = 'CDAB';
5697         cfs_free(context);
5698     }
5699
5700     /* here need free the Irp. */
5701     if (irp) {
5702         IoFreeIrp(irp);
5703         irp = NULL;
5704     }
5705
5706     return NULL;
5707 }
5708
5709 int
5710 KsDeliveryTsdus(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5711 {
5712     int                 rc = 0;
5713     ulong               length = 0;
5714     ulong               tflags = 0;
5715     ks_mdl_t *          mdl = NULL;
5716     PIRP                irp = NULL;
5717     BOOLEAN             expedited;
5718
5719     LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5720
5721     ks_get_tconn(tconn);
5722     ks_lock_tsdumgr(TsduMgr);
5723
5724     if ( tconn->kstc_type != kstt_sender &&
5725          tconn->kstc_type != kstt_child) {
5726         rc = -EINVAL;
5727         ks_unlock_tsdumgr(TsduMgr);
5728         goto errorout;
5729     }
5730
5731     if (tconn->kstc_state != ksts_connected) {
5732         rc = -ENOTCONN;
5733         ks_unlock_tsdumgr(TsduMgr);
5734         goto errorout;
5735     }
5736
5737     if (TsduMgr->OOB) {
5738         tflags = TDI_SEND_NON_BLOCKING | TDI_SEND_EXPEDITED;
5739     } else {
5740         tflags = TDI_SEND_NON_BLOCKING;
5741     }
5742    
5743     if (cfs_list_empty(&TsduMgr->TsduList)) {
5744         LASSERT(TsduMgr->TotalBytes == 0);
5745         ks_unlock_tsdumgr(TsduMgr);
5746         goto errorout;
5747     }
5748
5749     /* check whether there's outstanding sending requests */
5750     if (TsduMgr->Busy) {
5751         rc = -EAGAIN;
5752         ks_unlock_tsdumgr(TsduMgr);
5753         goto errorout;
5754     }
5755
5756     /* probe all Tsdus and merge buffers together */
5757     mdl = KsLockTsdus(tconn, TsduMgr, &tflags, &length);
5758     if (NULL == mdl) {
5759          if (length == 0) {
5760             LASSERT(TsduMgr->TotalBytes == 0);
5761             rc = -EAGAIN;
5762         } else {
5763             rc = -ENOMEM;
5764         }
5765         ks_unlock_tsdumgr(TsduMgr);
5766         goto errorout;
5767     }
5768
5769     KsPrint((4, "KsDeliveryTsdus: tconn=%p TsudMgr=%p, length=%xh/%xh\n",
5770                 tconn, TsduMgr, length, TsduMgr->TotalBytes));
5771
5772     /* build send irp request */
5773     irp = KsBuildSend(tconn, TsduMgr, mdl, tflags);
5774     if (NULL == irp) {
5775         rc = -ENOMEM;
5776         ks_unlock_tsdumgr(TsduMgr);
5777         goto errorout;
5778     }
5779     TsduMgr->Busy = TRUE;
5780     ks_unlock_tsdumgr(TsduMgr);
5781
5782     /* delivery mdl chain */
5783     LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5784     rc = KsDeliveryIrp(tconn, irp);
5785     if (rc < 0) {
5786         goto errorout;
5787     }
5788
5789 errorout:
5790
5791     LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5792     ks_put_tconn(tconn);
5793     return rc;
5794 }
5795
5796 int
5797 KsDeliveryEngineThread(void * context)
5798 {
5799     ks_engine_mgr_t *   engm = context;
5800     ks_engine_slot_t *  engs;
5801     cfs_list_t *        list;
5802     ks_tconn_t *        tconn;
5803
5804     cfs_set_thread_priority(31);
5805
5806     while (!engm->stop) {
5807
5808         cfs_wait_event_internal(&engm->start, 0);
5809
5810         spin_lock(&engm->lock);
5811         if (cfs_list_empty(&engm->list)) {
5812             spin_unlock(&engm->lock);
5813             continue;
5814         }
5815
5816         list = engm->list.next;
5817         cfs_list_del(list);
5818         engs = cfs_list_entry(list, ks_engine_slot_t, link);
5819         LASSERT(engs->emgr == engm);
5820         LASSERT(engs->queued);
5821         engs->emgr = NULL;
5822         engs->queued = FALSE;
5823         spin_unlock(&engm->lock);
5824
5825         tconn = engs->tconn;
5826         LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5827
5828         KsPrint((4, "KsDeliveryEngineThread: %p active: tconn=%p "
5829                     "TsduMgr=%p\n", engm, tconn, engs->tsdumgr));
5830         KsDeliveryTsdus(tconn, engs->tsdumgr);
5831
5832         LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5833     }
5834
5835     KeSetEvent(&engm->exit, 0, FALSE);
5836
5837     return 0;
5838 }
5839
5840 /*
5841  * ks_init_tdi_data
5842  *   initialize the global data in ksockal_data
5843  *
5844  * Arguments:
5845  *   N/A
5846  *
5847  * Return Value:
5848  *   int: ks error code
5849  *
5850  * Notes:
5851  *   N/A
5852  */
5853
5854 int
5855 ks_init_tdi_data()
5856 {
5857     int rc = 0, i;
5858
5859     /* initialize tconn related globals */
5860     RtlZeroMemory(&ks_data, sizeof(ks_tdi_data_t));
5861
5862         spin_lock_init(&ks_data.ksnd_tconn_lock);
5863     CFS_INIT_LIST_HEAD(&ks_data.ksnd_tconns);
5864     cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
5865
5866     ks_data.ksnd_tconn_slab = cfs_mem_cache_create(
5867         "tcon", sizeof(ks_tconn_t) , 0, 0);
5868
5869     if (!ks_data.ksnd_tconn_slab) {
5870         rc = -ENOMEM;
5871         goto errorout;
5872     }
5873
5874     /* initialize tsdu related globals */
5875         spin_lock_init(&ks_data.ksnd_tsdu_lock);
5876     CFS_INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
5877     ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
5878     ks_data.ksnd_tsdu_slab = cfs_mem_cache_create(
5879         "tsdu", ks_data.ksnd_tsdu_size, 0, 0);
5880
5881     if (!ks_data.ksnd_tsdu_slab) {
5882         rc = -ENOMEM;
5883         goto errorout;
5884     }
5885
5886     /* initialize engine threads list */
5887     ks_data.ksnd_engine_nums = cfs_num_online_cpus();
5888     if (ks_data.ksnd_engine_nums < 4) {
5889         ks_data.ksnd_engine_nums = 4;
5890     }
5891     ks_data.ksnd_engine_mgr = cfs_alloc(sizeof(ks_engine_mgr_t) * 
5892                          ks_data.ksnd_engine_nums,CFS_ALLOC_ZERO);
5893     if (ks_data.ksnd_engine_mgr == NULL) {
5894         rc = -ENOMEM;
5895         goto errorout;
5896     }
5897     for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5898                 spin_lock_init(&ks_data.ksnd_engine_mgr[i].lock);
5899         cfs_init_event(&ks_data.ksnd_engine_mgr[i].start, TRUE, FALSE);
5900         cfs_init_event(&ks_data.ksnd_engine_mgr[i].exit, TRUE, FALSE);
5901         CFS_INIT_LIST_HEAD(&ks_data.ksnd_engine_mgr[i].list);
5902         cfs_create_thread(KsDeliveryEngineThread, &ks_data.ksnd_engine_mgr[i], 0);
5903     }
5904
5905     /* register pnp handlers to watch network condition */
5906     KsRegisterPnpHandlers();
5907
5908 errorout:
5909
5910     /* do cleanup in case we get failures */
5911     if (rc < 0) {
5912         if (ks_data.ksnd_tconn_slab) {
5913             cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5914             ks_data.ksnd_tconn_slab = NULL;
5915         }
5916     }
5917
5918     return rc;
5919 }
5920
5921
5922 /*
5923  * ks_fini_tdi_data
5924  *   finalize the global data in ksockal_data
5925  *
5926  * Arguments:
5927  *   N/A
5928  *
5929  * Return Value:
5930  *   int: ks error code
5931  *
5932  * Notes:
5933  *   N/A
5934  */
5935
5936 void
5937 ks_fini_tdi_data()
5938 {
5939     PKS_TSDU            KsTsdu = NULL;
5940     cfs_list_t *        list   = NULL;
5941     int i;
5942
5943     /* clean up the pnp handler and address slots */
5944     KsDeregisterPnpHandlers();
5945
5946     /* stop all tcp sending engines */
5947     for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5948         ks_data.ksnd_engine_mgr[i].stop = TRUE;
5949         KeSetEvent(&ks_data.ksnd_engine_mgr[i].start, 0, FALSE);
5950     }
5951
5952     for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5953         cfs_wait_event_internal(&ks_data.ksnd_engine_mgr[i].exit, 0);
5954     }
5955
5956     /* we need wait until all the tconn are freed */
5957         spin_lock(&(ks_data.ksnd_tconn_lock));
5958
5959     if (cfs_list_empty(&(ks_data.ksnd_tconns))) {
5960         cfs_wake_event(&ks_data.ksnd_tconn_exit);
5961     }
5962         spin_unlock(&(ks_data.ksnd_tconn_lock));
5963
5964     /* now wait on the tconn exit event */
5965     cfs_wait_event_internal(&ks_data.ksnd_tconn_exit, 0);
5966
5967     /* it's safe to delete the tconn slab ... */
5968     cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5969     ks_data.ksnd_tconn_slab = NULL;
5970
5971     /* clean up all the tsud buffers in the free list */
5972         spin_lock(&(ks_data.ksnd_tsdu_lock));
5973     cfs_list_for_each (list, &ks_data.ksnd_freetsdus) {
5974         KsTsdu = cfs_list_entry (list, KS_TSDU, Link);
5975
5976         cfs_mem_cache_free(
5977                 ks_data.ksnd_tsdu_slab,
5978                 KsTsdu );
5979     }
5980         spin_unlock(&(ks_data.ksnd_tsdu_lock));
5981
5982     /* it's safe to delete the tsdu slab ... */
5983     cfs_mem_cache_destroy(ks_data.ksnd_tsdu_slab);
5984     ks_data.ksnd_tsdu_slab = NULL;
5985
5986     /* good! it's smooth to do the cleaning up...*/
5987 }
5988
5989 /*
5990  * ks_create_child_tconn
5991  *   Create the backlog child connection for a listener
5992  *
5993  * Arguments:
5994  *   parent: the listener daemon connection
5995  *
5996  * Return Value:
5997  *   the child connection or NULL in failure
5998  *
5999  * Notes:
6000  *   N/A
6001  */
6002
6003 ks_tconn_t *
6004 ks_create_child_tconn(
6005     ks_tconn_t * parent
6006     )
6007 {
6008     NTSTATUS            status;
6009     ks_tconn_t *        backlog;
6010
6011     /* allocate the tdi connecton object */
6012     backlog = ks_create_tconn();
6013
6014     if (!backlog) {
6015         goto errorout;
6016     }
6017
6018     /* initialize the tconn as a child */
6019     ks_init_child(backlog);
6020
6021
6022     /* now bind it */
6023     if (ks_bind_tconn(backlog, parent, 0, 0) < 0) {
6024         ks_free_tconn(backlog);
6025         backlog = NULL;
6026         goto errorout;
6027     }
6028
6029     /* open the connection object */
6030     status = KsOpenConnection(
6031                 &(backlog->kstc_dev),
6032                 (PVOID)backlog,
6033                 &(backlog->child.kstc_info.Handle),
6034                 &(backlog->child.kstc_info.FileObject)
6035                 );
6036
6037     if (!NT_SUCCESS(status)) {
6038
6039         ks_put_tconn(backlog);
6040         backlog = NULL;
6041         cfs_enter_debugger();
6042         goto errorout;
6043     }
6044
6045     /* associate it now ... */
6046     status = KsAssociateAddress(
6047                 backlog->kstc_addr.Handle,
6048                 backlog->child.kstc_info.FileObject
6049                 );
6050
6051     if (!NT_SUCCESS(status)) {
6052
6053         ks_put_tconn(backlog);
6054         backlog = NULL;
6055         cfs_enter_debugger();
6056         goto errorout;
6057     }
6058
6059     backlog->kstc_state = ksts_associated;
6060
6061 errorout:
6062
6063     return backlog;
6064 }
6065
6066 /*
6067  * ks_replenish_backlogs(
6068  *   to replenish the backlogs listening...
6069  *
6070  * Arguments:
6071  *   tconn: the parent listen tdi connect
6072  *   nbacklog: number fo child connections in queue
6073  *
6074  * Return Value:
6075  *   N/A
6076  *
6077  * Notes:
6078  *   N/A
6079  */
6080
6081 void
6082 ks_replenish_backlogs(
6083     ks_tconn_t *    parent,
6084     int             nbacklog
6085     )
6086 {
6087     ks_tconn_t *    backlog;
6088     int             n = 0;
6089
6090     /* calculate how many backlogs needed */
6091     if ( ( parent->listener.kstc_listening.num +
6092            parent->listener.kstc_accepted.num ) < nbacklog ) {
6093         n = nbacklog - ( parent->listener.kstc_listening.num +
6094             parent->listener.kstc_accepted.num );
6095     } else {
6096         n = 0;
6097     }
6098
6099     while (n--) {
6100
6101         /* create the backlog child tconn */
6102         backlog = ks_create_child_tconn(parent);
6103
6104         spin_lock(&(parent->kstc_lock));
6105
6106         if (backlog) {
6107             spin_lock(&backlog->kstc_lock);
6108             /* attch it into the listing list of daemon */
6109             cfs_list_add( &backlog->child.kstc_link,
6110                       &parent->listener.kstc_listening.list );
6111             parent->listener.kstc_listening.num++;
6112
6113             backlog->child.kstc_queued = TRUE;
6114             spin_unlock(&backlog->kstc_lock);
6115         } else {
6116             cfs_enter_debugger();
6117         }
6118
6119         spin_unlock(&(parent->kstc_lock));
6120     }
6121 }
6122
6123 /*
6124  * ks_start_listen
6125  *   setup the listener tdi connection and make it listen
6126  *    on the user specified ip address and port.
6127  *
6128  * Arguments:
6129  *   tconn: the parent listen tdi connect
6130  *   nbacklog: number fo child connections in queue
6131  *
6132  * Return Value:
6133  *   ks error code >=: success; otherwise error.
6134  *
6135  * Notes:
6136  *   N/A
6137  */
6138
6139 int
6140 ks_start_listen(ks_tconn_t *tconn, int nbacklog)
6141 {
6142     int rc = 0;
6143
6144     /* now replenish the backlogs */
6145     ks_replenish_backlogs(tconn, nbacklog);
6146
6147     /* set the event callback handlers */
6148     rc = KsSetHandlers(tconn);
6149
6150     if (rc < 0) {
6151         return rc;
6152     }
6153
6154         spin_lock(&(tconn->kstc_lock));
6155         tconn->listener.nbacklog = nbacklog;
6156         tconn->kstc_state = ksts_listening;
6157         cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6158         spin_unlock(&(tconn->kstc_lock));
6159
6160         return rc;
6161 }
6162
6163 void
6164 ks_stop_listen(ks_tconn_t *tconn)
6165 {
6166     cfs_list_t *            list;
6167     ks_tconn_t *            backlog;
6168
6169     /* reset all tdi event callbacks to NULL */
6170     KsResetHandlers (tconn);
6171
6172         spin_lock(&tconn->kstc_lock);
6173
6174     cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6175
6176     /* cleanup all the listening backlog child connections */
6177     cfs_list_for_each (list, &(tconn->listener.kstc_listening.list)) {
6178         backlog = cfs_list_entry(list, ks_tconn_t, child.kstc_link);
6179
6180         /* destory and free it */
6181         ks_put_tconn(backlog);
6182     }
6183
6184         spin_unlock(&tconn->kstc_lock);
6185
6186     /* wake up it from the waiting on new incoming connections */
6187     KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
6188
6189     /* free the listening daemon tconn */
6190     ks_put_tconn(tconn);
6191 }
6192
6193
6194 /*
6195  * ks_wait_child_tconn
6196  *   accept a child connection from peer
6197  *
6198  * Arguments:
6199  *   parent:   the daemon tdi connection listening
6200  *   child:    to contain the accepted connection
6201  *
6202  * Return Value:
6203  *   ks error code;
6204  *
6205  * Notes:
6206  *   N/A
6207  */
6208
6209 int
6210 ks_wait_child_tconn(
6211     ks_tconn_t *    parent,
6212     ks_tconn_t **   child
6213     )
6214 {
6215     cfs_list_t * tmp;
6216     ks_tconn_t * backlog = NULL;
6217
6218     ks_replenish_backlogs(parent, parent->listener.nbacklog);
6219
6220         spin_lock(&(parent->kstc_lock));
6221
6222         if (parent->listener.kstc_listening.num <= 0) {
6223                 spin_unlock(&(parent->kstc_lock));
6224         return -1;
6225     }
6226
6227 again:
6228
6229     /* check the listening queue and try to search the accepted connecton */
6230
6231     cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
6232         backlog = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
6233
6234         spin_lock(&(backlog->kstc_lock));
6235
6236         if (backlog->child.kstc_accepted) {
6237
6238             LASSERT(backlog->kstc_state == ksts_connected);
6239             LASSERT(backlog->child.kstc_busy);
6240
6241             cfs_list_del(&(backlog->child.kstc_link));
6242             cfs_list_add(&(backlog->child.kstc_link),
6243                          &(parent->listener.kstc_accepted.list));
6244             parent->listener.kstc_accepted.num++;
6245             parent->listener.kstc_listening.num--;
6246             backlog->child.kstc_queueno = 1;
6247
6248             spin_unlock(&(backlog->kstc_lock));
6249
6250             break;
6251         } else {
6252             spin_unlock(&(backlog->kstc_lock));
6253             backlog = NULL;
6254         }
6255     }
6256
6257         spin_unlock(&(parent->kstc_lock));
6258
6259     /* we need wait until new incoming connections are requested
6260        or the case of shuting down the listenig daemon thread  */
6261     if (backlog == NULL) {
6262
6263         NTSTATUS    Status;
6264
6265         Status = KeWaitForSingleObject(
6266                 &(parent->listener.kstc_accept_event),
6267                 Executive,
6268                 KernelMode,
6269                 FALSE,
6270                 NULL
6271                 );
6272
6273         spin_lock(&(parent->kstc_lock));
6274
6275         /* check whether it's exptected to exit ? */
6276         if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
6277             spin_unlock(&(parent->kstc_lock));
6278         } else {
6279             goto again;
6280         }
6281     }
6282
6283     KsPrint((2, "ks_wait_child_tconn: connection %p accepted.\n", backlog));
6284
6285     if (backlog) {
6286         /* query the local ip address of the connection */
6287         ks_query_local_ipaddr(backlog);
6288     } else {
6289         return -EINTR;
6290     }
6291     *child = backlog;
6292
6293     return 0;
6294 }
6295
6296 int
6297 ks_query_iovs_length(struct iovec  *iov, int niov)
6298 {
6299     int             i;
6300     int             total = 0;
6301
6302     LASSERT(iov != NULL);
6303     LASSERT(niov > 0);
6304
6305     for (i=0; i < niov; i++) {
6306         total += iov[i].iov_len;
6307     }
6308
6309     return total;
6310 }
6311
6312 int
6313 ks_query_kiovs_length(lnet_kiov_t *kiov, int nkiov)
6314 {
6315     int             i;
6316     int             total = 0;
6317
6318     LASSERT(kiov != NULL);
6319     LASSERT(nkiov > 0);
6320
6321     for (i=0; i < nkiov; i++) {
6322         total += kiov[i].kiov_len;
6323     }
6324
6325     return total;
6326 }
6327
6328 int
6329 ks_sock_buf_cb(void *tsdu, int ns, int off, char **buf)
6330 {
6331     int rc = 0;
6332
6333     if (off < ns) {
6334         *buf = (char *)tsdu + off;
6335         rc = ns - off;
6336     }
6337     return rc;
6338 }
6339
6340 int
6341 ks_sock_iov_cb(void *tsdu, int ns, int off, char **buf)
6342 {
6343     int rc = 0, i;
6344     struct iovec *iov = tsdu;
6345
6346     for (i=0; i < ns; i++) {
6347         if ((size_t)off >= iov[i].iov_len) {
6348             off -= iov[i].iov_len;
6349         } else {
6350             *buf = (char *)iov[i].iov_base + off;
6351             rc = iov[i].iov_len - off;
6352             break;
6353         }
6354     }
6355     return rc;
6356 }
6357
6358 int
6359 ks_sock_kiov_cb(void *tsdu, int ns, int off, char **buf)
6360 {
6361     int rc = 0, i;
6362     lnet_kiov_t *kiov = tsdu;
6363
6364     for (i=0; i < ns; i++) {
6365         if ((size_t)off >= kiov[i].kiov_len) {
6366             off -= kiov[i].kiov_len;
6367         } else {
6368             *buf = (char *)kiov[i].kiov_page->addr +
6369                     kiov[i].kiov_offset + off;
6370             rc = kiov[i].kiov_len - off;
6371             break;
6372         }
6373     }
6374     return rc;
6375 }
6376
6377 typedef int (*ks_tsdu_cb_t)(void *tsdu, int ns, int off, char **buf);
6378
6379 int
6380 ks_sock_io(ks_tconn_t *tconn, void *tsdu, int ns, int reqlen,
6381            int flags, int timeout, int out, ks_tsdu_cb_t callback)
6382 {
6383     ULONG       tflags;
6384     BOOLEAN     expedited;
6385     PKS_TSDUMGR TsduMgr;
6386
6387     int         rc;
6388     int         length;
6389     int         total = 0;
6390     int64_t     remained;
6391     PCHAR       buffer;
6392     BOOLEAN     async;
6393
6394     LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6395     remained = (int64_t)cfs_time_seconds(timeout);
6396
6397     /* query tsdu manager */
6398     expedited = cfs_is_flag_set(flags, MSG_OOB);
6399     TsduMgr = KsQueryTsduMgr(tconn, expedited, (BOOLEAN)out);
6400
6401     /* check whether equest is nonblocking */
6402     if (async = cfs_is_flag_set(flags, MSG_DONTWAIT)) {
6403         timeout = 0;
6404     }
6405
6406     ks_get_tconn(tconn);
6407     ks_lock_tsdumgr(TsduMgr);
6408     if ( tconn->kstc_type != kstt_sender &&
6409          tconn->kstc_type != kstt_child) {
6410         rc = -EINVAL;
6411         goto errorout;
6412     }
6413
6414     while (length = callback(tsdu, ns, total, &buffer)) {
6415
6416         /* check whether socket is stil valid */
6417         if (tconn->kstc_state != ksts_connected) {
6418             rc = -ENOTCONN;
6419             goto errorout;
6420         }
6421
6422         if (out) {
6423             tflags = KsTdiSendFlags(flags);
6424             rc = KsWriteTsdus(TsduMgr, buffer, length, tflags);
6425         } else {
6426             tflags = KsTdiRecvFlags(flags);
6427             rc = KsReadTsdus(TsduMgr, buffer, length, tflags);
6428         }
6429
6430         if (rc > 0) {
6431             total += rc;
6432         } else if (!async && rc == -EAGAIN) {
6433             if (timeout) {
6434                 if (remained) { 
6435                     ks_unlock_tsdumgr(TsduMgr);
6436                     remained = cfs_wait_event_internal(
6437                                     &TsduMgr->Event,
6438                                     remained );
6439                 } else {
6440                     goto errorout;
6441                 }
6442             } else {
6443                 ks_unlock_tsdumgr(TsduMgr);
6444                 cfs_wait_event_internal(&TsduMgr->Event, 0);
6445             }
6446             ks_lock_tsdumgr(TsduMgr);
6447         } else {
6448             break;
6449         }
6450     }
6451
6452 errorout:
6453
6454     if (!out) {
6455         TsduMgr->Payload = reqlen - total;
6456     }
6457     ks_unlock_tsdumgr(TsduMgr);
6458
6459     KsPrint((4, "ks_sock_io: tconn=%p tsdumgr=%p %c total=%xh/%xh rc=%d\n",
6460                 tconn, TsduMgr, out?'W':'R', total, TsduMgr->TotalBytes, rc));
6461
6462     if (total) {
6463         if (out) {
6464             /* signal Tdi sending engine */
6465             KsQueueTdiEngine(tconn, TsduMgr);
6466         }
6467         rc = total;
6468     }
6469
6470     ks_put_tconn(tconn);
6471
6472     LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6473     return rc;
6474 }
6475
6476 int ks_send_buf(ks_tconn_t * tconn, char *buf,
6477                 int len, int flags, int timeout)
6478 {
6479     return ks_sock_io(tconn, buf, len, len, flags,
6480                       timeout, 1, ks_sock_buf_cb);
6481 }
6482
6483 int ks_recv_buf(ks_tconn_t * tconn, char *buf,
6484                 int len, int flags, int timeout)
6485 {
6486     return ks_sock_io(tconn, buf, len, len, flags,
6487                       timeout, 0, ks_sock_buf_cb);
6488 }
6489
6490 int ks_send_iovs(ks_tconn_t * tconn, struct iovec *iov,
6491                  int niov, int flags, int timeout)
6492 {
6493     int reqlen = ks_query_iovs_length(iov, niov);
6494     return ks_sock_io(tconn, iov, niov, reqlen, flags,
6495                       timeout, TRUE, ks_sock_iov_cb);
6496 }
6497
6498 int ks_recv_iovs(ks_tconn_t * tconn, struct iovec *iov,
6499                  int niov, int flags, int timeout)
6500 {
6501     int reqlen = ks_query_iovs_length(iov, niov);
6502     return ks_sock_io(tconn, iov, niov, reqlen, flags,
6503                       timeout, FALSE, ks_sock_iov_cb);
6504 }
6505
6506 int ks_send_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6507                   int nkiov, int flags, int timeout)
6508 {
6509     int reqlen = ks_query_kiovs_length(kiov, nkiov);
6510     return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6511                       timeout, TRUE, ks_sock_kiov_cb);
6512 }
6513
6514 int ks_recv_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6515                   int nkiov, int flags, int timeout)
6516 {
6517     int reqlen = ks_query_kiovs_length(kiov, nkiov);
6518     return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6519                       timeout, FALSE, ks_sock_kiov_cb);
6520 }
6521
6522 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
6523 {
6524     ks_addr_slot_t * slot = NULL;
6525     PLIST_ENTRY      list = NULL;
6526
6527         spin_lock(&ks_data.ksnd_addrs_lock);
6528
6529     list = ks_data.ksnd_addrs_list.Flink;
6530     while (list != &ks_data.ksnd_addrs_list) {
6531         slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6532         if (_stricmp(name, &slot->iface[0]) == 0) {
6533             *up = slot->up;
6534             *ip = slot->ip_addr;
6535             *mask = slot->netmask;
6536             break;
6537         }
6538         list = list->Flink;
6539         slot = NULL;
6540     }
6541
6542         spin_unlock(&ks_data.ksnd_addrs_lock);
6543
6544     return (int)(slot == NULL);
6545 }
6546
6547 int libcfs_ipif_enumerate(char ***names)
6548 {
6549     ks_addr_slot_t * slot = NULL;
6550     PLIST_ENTRY      list = NULL;
6551     int              nips = 0;
6552
6553         spin_lock(&ks_data.ksnd_addrs_lock);
6554
6555     *names = cfs_alloc(sizeof(char *) * ks_data.ksnd_naddrs, CFS_ALLOC_ZERO);
6556     if (*names == NULL) {
6557         goto errorout;
6558     }
6559
6560     list = ks_data.ksnd_addrs_list.Flink;
6561     while (list != &ks_data.ksnd_addrs_list) {
6562         slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6563         list = list->Flink;
6564         (*names)[nips++] = slot->iface;
6565         cfs_assert(nips <= ks_data.ksnd_naddrs);
6566     }
6567
6568     cfs_assert(nips == ks_data.ksnd_naddrs);
6569
6570 errorout:
6571
6572         spin_unlock(&ks_data.ksnd_addrs_lock);
6573     return nips;
6574 }
6575
6576 void libcfs_ipif_free_enumeration(char **names, int n)
6577 {
6578     if (names) {
6579         cfs_free(names);
6580     }
6581 }
6582
6583 int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
6584 {
6585     int                 rc = 0;
6586     ks_tconn_t *        parent;
6587
6588     parent = ks_create_tconn();
6589     if (!parent) {
6590         rc = -ENOMEM;
6591         goto errorout;
6592     }
6593
6594     /* initialize the tconn as a listener */
6595     ks_init_listener(parent);
6596
6597     /* bind the daemon->tconn */
6598     rc = ks_bind_tconn(parent, NULL, ip, (unsigned short)port);
6599
6600     if (rc < 0) {
6601         ks_free_tconn(parent);
6602         goto errorout;
6603     }
6604
6605     /* create listening children and make it to listen state*/
6606     rc = ks_start_listen(parent, backlog);
6607     if (rc < 0) {
6608         ks_stop_listen(parent);
6609         goto errorout;
6610     }
6611
6612     *sockp = parent;
6613
6614 errorout:
6615
6616     return rc;
6617 }
6618
6619 int libcfs_sock_accept(struct socket **newsockp, struct socket *sock)
6620 {
6621     /* wait for incoming connecitons */
6622     return ks_wait_child_tconn(sock, newsockp);
6623 }
6624
6625 void libcfs_sock_abort_accept(struct socket *sock)
6626 {
6627     LASSERT(sock->kstc_type == kstt_listener);
6628
6629         spin_lock(&(sock->kstc_lock));
6630
6631     /* clear the daemon flag */
6632     cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
6633
6634     /* wake up it from the waiting on new incoming connections */
6635     KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
6636
6637         spin_unlock(&(sock->kstc_lock));
6638 }
6639
6640 /*
6641  * libcfs_sock_connect
6642  *   build a conntion between local ip/port and the peer ip/port.
6643  *
6644  * Arguments:
6645  *   laddr: local ip address
6646  *   lport: local port number
6647  *   paddr: peer's ip address
6648  *   pport: peer's port number
6649  *
6650  * Return Value:
6651  *   int:   return code ...
6652  *
6653  * Notes:
6654  *   N/A
6655  */
6656
6657
6658 int libcfs_sock_connect(struct socket **sockp, int *fatal,
6659                         __u32 local_ip, int local_port,
6660                         __u32 peer_ip, int peer_port)
6661 {
6662     ks_tconn_t *    tconn = NULL;
6663     int             rc = 0;
6664
6665     *sockp = NULL;
6666     if (fatal) *fatal = 0;
6667
6668     KsPrint((2, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
6669                 peer_ip, peer_port, local_ip, local_port ));
6670
6671     /* create the tdi connecion structure */
6672     tconn = ks_create_tconn();
6673     if (!tconn) {
6674         rc = -ENOMEM;
6675         goto errorout;
6676     }
6677
6678     /* initialize the tdi sender connection */
6679     ks_init_sender(tconn);
6680
6681     /* bind the local ip address with the tconn */
6682     rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
6683     if (rc < 0) {
6684         KsPrint((1, "libcfs_sock_connect: failed to bind address %x:%d...\n",
6685                     local_ip, local_port ));
6686         ks_free_tconn(tconn);
6687         goto errorout;
6688     }
6689
6690     /* connect to the remote peer */
6691     rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
6692     if (rc < 0) {
6693         KsPrint((1, "libcfs_sock_connect: failed to connect %x:%d ...\n",
6694                     peer_ip, peer_port ));
6695
6696         ks_put_tconn(tconn);
6697         goto errorout;
6698     }
6699
6700     *sockp = tconn;
6701
6702 errorout:
6703
6704     return rc;
6705 }
6706
6707 int libcfs_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize)
6708 {
6709     return 0;
6710 }
6711
6712 int libcfs_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize)
6713 {
6714     return 0;
6715 }
6716
6717 int libcfs_sock_getaddr(struct socket *socket, int remote, __u32 *ip, int *port)
6718 {
6719     PTRANSPORT_ADDRESS  taddr = NULL;
6720
6721         spin_lock(&socket->kstc_lock);
6722     if (remote) {
6723         if (socket->kstc_type == kstt_sender) {
6724             taddr = socket->sender.kstc_info.Remote;
6725         } else if (socket->kstc_type == kstt_child) {
6726             taddr = socket->child.kstc_info.Remote;
6727         }
6728     } else {
6729         taddr = &(socket->kstc_addr.Tdi);
6730     }
6731
6732     if (taddr) {
6733         PTDI_ADDRESS_IP addr = (PTDI_ADDRESS_IP)(&(taddr->Address[0].Address));
6734         if (ip != NULL)
6735             *ip = ntohl (addr->in_addr);
6736         if (port != NULL)
6737             *port = ntohs (addr->sin_port);
6738     } else {
6739                 spin_unlock(&socket->kstc_lock);
6740                 return -ENOTCONN;
6741         }
6742
6743         spin_unlock(&socket->kstc_lock);
6744         return 0;
6745 }
6746
6747 int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
6748 {
6749     int           rc;
6750     int           offset = 0;
6751
6752     while (nob > offset) {
6753
6754         rc = ks_send_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6755
6756         if (rc <= 0) {
6757             goto errorout;
6758         } else {
6759             offset += rc;
6760             rc = 0;
6761         }
6762     }
6763
6764 errorout:
6765
6766     KsPrint((4, "libcfs_sock_write: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6767     return rc;
6768 }
6769
6770 int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
6771 {
6772     int           rc = 0;
6773     int           offset = 0;
6774
6775     while (nob > offset) {
6776
6777         rc = ks_recv_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6778
6779         if (rc <= 0) {
6780             goto errorout;
6781         } else {
6782             offset += rc;
6783             rc = 0;
6784         }
6785     }
6786
6787 errorout:
6788
6789     KsPrint((4, "libcfs_sock_read: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6790     return rc;
6791 }
6792
6793 void libcfs_sock_release(struct socket *sock)
6794 {
6795     if (sock->kstc_type == kstt_listener &&
6796         sock->kstc_state == ksts_listening) {
6797         ks_stop_listen(sock);
6798     } else {
6799         ks_put_tconn(sock);
6800     }
6801 }