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