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