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