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