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