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