1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
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
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_LIBCFS
39 #include <libcfs/libcfs.h>
40 #include <libcfs/kp30.h>
41 #include <lnet/lnet.h>
43 #define TDILND_MODULE_NAME L"Tdilnd"
48 ks_tdi_send_flags(ULONG SockFlags)
52 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
53 cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
56 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
57 cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
60 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
61 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
68 KsIrpCompletionRoutine(
69 IN PDEVICE_OBJECT DeviceObject,
74 if (NULL != Context) {
75 KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
78 return STATUS_MORE_PROCESSING_REQUIRED;
80 UNREFERENCED_PARAMETER(DeviceObject);
81 UNREFERENCED_PARAMETER(Irp);
87 * Allocate a new IRP and initialize it to be issued to tdi
90 * DeviceObject: device object created by the underlying
91 * TDI transport driver
94 * PRIP: the allocated Irp in success or NULL in failure.
102 IN PDEVICE_OBJECT DeviceObject
106 PIO_STACK_LOCATION IrpSp;
109 // Allocating the IRP ...
112 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
117 // Getting the Next Stack Location ...
120 IrpSp = IoGetNextIrpStackLocation(Irp);
123 // Initializing Irp ...
126 IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
127 IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
135 * Issue the Irp to the underlying tdi driver
138 * DeviceObject: the device object created by TDI driver
139 * Irp: the I/O request packet to be processed
140 * bSynchronous: synchronous or not. If true, we need wait
141 * until the process is finished.
142 * Information: returned info
145 * NTSTATUS: kernel status code
153 IN PDEVICE_OBJECT DeviceObject,
155 IN BOOLEAN bSynchronous,
156 OUT PULONG Information
166 SynchronizationEvent,
171 IoSetCompletionRoutine(
173 KsIrpCompletionRoutine,
181 Status = IoCallDriver(DeviceObject, Irp);
185 if (STATUS_PENDING == Status) {
187 Status = KeWaitForSingleObject(
196 Status = Irp->IoStatus.Status;
199 *Information = (ULONG)(Irp->IoStatus.Information);
202 Irp->MdlAddress = NULL;
206 if (!NT_SUCCESS(Status)) {
208 KsPrint((2, "KsSubmitTdiIrp: Error when submitting the Irp: Status = %xh (%s) ...\n",
209 Status, KsNtStatusToString(Status)));
219 * Open the Control Channel Object ...
222 * DeviceName: the device name to be opened
223 * Handle: opened handle in success case
224 * FileObject: the fileobject of the device
227 * NTSTATUS: kernel status code (STATUS_SUCCESS
228 * or other error code)
236 IN PUNICODE_STRING DeviceName,
238 OUT PFILE_OBJECT * FileObject
241 NTSTATUS Status = STATUS_SUCCESS;
243 OBJECT_ATTRIBUTES ObjectAttributes;
244 IO_STATUS_BLOCK IoStatus;
247 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
253 InitializeObjectAttributes(
256 OBJ_CASE_INSENSITIVE |
262 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
265 // Creating the Transport Address Object ...
268 Status = ZwCreateFile(
270 FILE_READ_DATA | FILE_WRITE_DATA,
274 FILE_ATTRIBUTE_NORMAL,
275 FILE_SHARE_READ | FILE_SHARE_WRITE,
283 if (NT_SUCCESS(Status)) {
286 // Now Obtaining the FileObject of the Transport Address ...
289 Status = ObReferenceObjectByHandle(
298 if (!NT_SUCCESS(Status)) {
300 cfs_enter_debugger();
306 cfs_enter_debugger();
315 * Release the Control Channel Handle and FileObject
318 * Handle: the channel handle to be released
319 * FileObject: the fileobject to be released
322 * NTSTATUS: kernel status code (STATUS_SUCCESS
323 * or other error code)
332 IN PFILE_OBJECT FileObject
335 NTSTATUS Status = STATUS_SUCCESS;
337 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
341 ObDereferenceObject(FileObject);
346 Status = ZwClose(Handle);
349 ASSERT(NT_SUCCESS(Status));
357 * Open the tdi address object
360 * DeviceName: device name of the address object
361 * pAddress: tdi address of the address object
362 * AddressLength: length in bytes of the tdi address
363 * Handle: the newly opened handle
364 * FileObject: the newly opened fileobject
367 * NTSTATUS: kernel status code (STATUS_SUCCESS
368 * or other error code)
376 IN PUNICODE_STRING DeviceName,
377 IN PTRANSPORT_ADDRESS pAddress,
378 IN ULONG AddressLength,
380 OUT PFILE_OBJECT * FileObject
383 NTSTATUS Status = STATUS_SUCCESS;
385 PFILE_FULL_EA_INFORMATION Ea = NULL;
387 UCHAR EaBuffer[EA_MAX_LENGTH];
389 OBJECT_ATTRIBUTES ObjectAttributes;
390 IO_STATUS_BLOCK IoStatus;
393 // Building EA for the Address Object to be Opened ...
396 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
397 Ea->NextEntryOffset = 0;
399 Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
400 Ea->EaValueLength = (USHORT)AddressLength;
407 &(Ea->EaName[Ea->EaNameLength + 1]),
411 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
412 Ea->EaNameLength + AddressLength;
414 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
421 InitializeObjectAttributes(
424 OBJ_CASE_INSENSITIVE |
430 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
433 // Creating the Transport Address Object ...
436 Status = ZwCreateFile(
438 FILE_READ_DATA | FILE_WRITE_DATA,
442 FILE_ATTRIBUTE_NORMAL,
443 FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
451 if (NT_SUCCESS(Status)) {
454 // Now Obtaining the FileObject of the Transport Address ...
457 Status = ObReferenceObjectByHandle(
466 if (!NT_SUCCESS(Status)) {
468 cfs_enter_debugger();
474 cfs_enter_debugger();
482 * Release the Hanlde and FileObject of an opened tdi
486 * Handle: the handle to be released
487 * FileObject: the fileobject to be released
490 * NTSTATUS: kernel status code (STATUS_SUCCESS
491 * or other error code)
500 IN PFILE_OBJECT FileObject
503 NTSTATUS Status = STATUS_SUCCESS;
507 ObDereferenceObject(FileObject);
512 Status = ZwClose(Handle);
515 ASSERT(NT_SUCCESS(Status));
523 * Open a tdi connection object
526 * DeviceName: device name of the connection object
527 * ConnectionContext: the connection context
528 * Handle: the newly opened handle
529 * FileObject: the newly opened fileobject
532 * NTSTATUS: kernel status code (STATUS_SUCCESS
533 * or other error code)
541 IN PUNICODE_STRING DeviceName,
542 IN CONNECTION_CONTEXT ConnectionContext,
544 OUT PFILE_OBJECT * FileObject
547 NTSTATUS Status = STATUS_SUCCESS;
549 PFILE_FULL_EA_INFORMATION Ea = NULL;
551 UCHAR EaBuffer[EA_MAX_LENGTH];
553 OBJECT_ATTRIBUTES ObjectAttributes;
554 IO_STATUS_BLOCK IoStatus;
557 // Building EA for the Address Object to be Opened ...
560 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
561 Ea->NextEntryOffset = 0;
563 Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
564 Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
567 TdiConnectionContext,
571 &(Ea->EaName[Ea->EaNameLength + 1]),
573 sizeof(CONNECTION_CONTEXT)
575 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
576 Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
578 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
585 InitializeObjectAttributes(
588 OBJ_CASE_INSENSITIVE |
594 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
597 // Creating the Connection Object ...
600 Status = ZwCreateFile(
602 FILE_READ_DATA | FILE_WRITE_DATA,
606 FILE_ATTRIBUTE_NORMAL,
615 if (NT_SUCCESS(Status)) {
618 // Now Obtaining the FileObject of the Transport Address ...
621 Status = ObReferenceObjectByHandle(
630 if (!NT_SUCCESS(Status)) {
632 cfs_enter_debugger();
638 cfs_enter_debugger();
646 * Release the Hanlde and FileObject of an opened tdi
650 * Handle: the handle to be released
651 * FileObject: the fileobject to be released
654 * NTSTATUS: kernel status code (STATUS_SUCCESS
655 * or other error code)
664 IN PFILE_OBJECT FileObject
667 NTSTATUS Status = STATUS_SUCCESS;
671 ObDereferenceObject(FileObject);
676 Status = ZwClose(Handle);
679 ASSERT(NT_SUCCESS(Status));
687 * Associate an address object with a connection object
690 * AddressHandle: the handle of the address object
691 * ConnectionObject: the FileObject of the connection
694 * NTSTATUS: kernel status code (STATUS_SUCCESS
695 * or other error code)
703 IN HANDLE AddressHandle,
704 IN PFILE_OBJECT ConnectionObject
708 PDEVICE_OBJECT DeviceObject;
712 // Getting the DeviceObject from Connection FileObject
715 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
718 // Building Tdi Internal Irp ...
721 Irp = KsBuildTdiIrp(DeviceObject);
725 Status = STATUS_INSUFFICIENT_RESOURCES;
730 // Assocating the Address Object with the Connection Object
733 TdiBuildAssociateAddress(
743 // Calling the Transprot Driver with the Prepared Irp
746 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
754 * KsDisassociateAddress
755 * Disassociate the connection object (the relationship will
756 * the corresponding address object will be dismissed. )
759 * ConnectionObject: the FileObject of the connection
762 * NTSTATUS: kernel status code (STATUS_SUCCESS
763 * or other error code)
770 KsDisassociateAddress(
771 IN PFILE_OBJECT ConnectionObject
775 PDEVICE_OBJECT DeviceObject;
779 // Getting the DeviceObject from Connection FileObject
782 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
785 // Building Tdi Internal Irp ...
788 Irp = KsBuildTdiIrp(DeviceObject);
792 Status = STATUS_INSUFFICIENT_RESOURCES;
797 // Disassocating the Address Object with the Connection Object
800 TdiBuildDisassociateAddress(
809 // Calling the Transprot Driver with the Prepared Irp
812 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
822 // Connection Control Event Callbacks
830 // Tcp Event Callbacks
834 TDI_EVENT_RECEIVE_EXPEDITED
835 TDI_EVENT_CHAINED_RECEIVE
836 TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
839 // Udp Event Callbacks
842 TDI_EVENT_RECEIVE_DATAGRAM
843 TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
850 * Set the tdi event callbacks with an address object
853 * AddressObject: the FileObject of the address object
854 * EventContext: the parameter for the callbacks
855 * Handlers: the handlers indictor array
858 * NTSTATUS: kernel status code (STATUS_SUCCESS
859 * or other error code)
867 IN PFILE_OBJECT AddressObject, // Address File Object
868 IN PVOID EventContext, // Context for Handlers
869 IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
872 NTSTATUS Status = STATUS_SUCCESS;
873 PDEVICE_OBJECT DeviceObject;
876 DeviceObject = IoGetRelatedDeviceObject(AddressObject);
878 for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
881 // Setup the tdi event callback handler if requested.
884 if (Handlers->IsActive[i]) {
889 // Building Tdi Internal Irp ...
892 Irp = KsBuildTdiIrp(DeviceObject);
896 Status = STATUS_INSUFFICIENT_RESOURCES;
901 // Building the Irp to set the Event Handler ...
904 TdiBuildSetEventHandler(
910 i, /* tdi event type */
911 Handlers->Handler[i], /* tdi event handler */
912 EventContext /* context for the handler */
916 // Calling the Transprot Driver with the Prepared Irp
919 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
922 // tcp/ip tdi does not support these two event callbacks
925 if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
926 i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
927 cfs_enter_debugger();
928 Status = STATUS_SUCCESS;
932 if (!NT_SUCCESS(Status)) {
933 cfs_enter_debugger();
942 if (!NT_SUCCESS(Status)) {
944 KsPrint((2, "KsSetEventHandlers: Error Status = %xh (%s)\n",
945 Status, KsNtStatusToString(Status) ));
955 * Query the address of the FileObject specified
958 * FileObject: the FileObject to be queried
959 * AddressInfo: buffer to contain the address info
960 * AddressSize: length of the AddressInfo buffer
963 * NTSTATUS: kernel status code (STATUS_SUCCESS
964 * or other error code)
972 PFILE_OBJECT FileObject,
973 PTDI_ADDRESS_INFO AddressInfo,
977 NTSTATUS Status = STATUS_UNSUCCESSFUL;
980 PDEVICE_OBJECT DeviceObject;
982 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
984 DeviceObject = IoGetRelatedDeviceObject(FileObject);
986 RtlZeroMemory(AddressInfo, *(AddressSize));
989 // Allocating the Tdi Setting Irp ...
992 Irp = KsBuildTdiIrp(DeviceObject);
996 Status = STATUS_INSUFFICIENT_RESOURCES;
1001 // Locking the User Buffer / Allocating a MDL for it
1004 Status = KsLockUserBuffer(
1012 if (!NT_SUCCESS(Status)) {
1021 LASSERT(NT_SUCCESS(Status));
1023 TdiBuildQueryInformation(
1029 TDI_QUERY_ADDRESS_INFO,
1033 Status = KsSubmitTdiIrp(
1040 KsReleaseMdl(Mdl, FALSE);
1043 if (!NT_SUCCESS(Status)) {
1045 cfs_enter_debugger();
1046 //TDI_BUFFER_OVERFLOW
1053 * KsQueryProviderInfo
1054 * Query the underlying transport device's information
1057 * TdiDeviceName: the transport device's name string
1058 * ProviderInfo: TDI_PROVIDER_INFO struncture
1061 * NTSTATUS: Nt system status code
1068 KsQueryProviderInfo(
1069 PWSTR TdiDeviceName,
1070 PTDI_PROVIDER_INFO ProviderInfo
1073 NTSTATUS Status = STATUS_SUCCESS;
1078 UNICODE_STRING ControlName;
1081 PFILE_OBJECT FileObject;
1082 PDEVICE_OBJECT DeviceObject;
1084 ULONG ProviderSize = 0;
1086 RtlInitUnicodeString(&ControlName, TdiDeviceName);
1089 // Open the Tdi Control Channel
1092 Status = KsOpenControl(
1098 if (!NT_SUCCESS(Status)) {
1100 KsPrint((2, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
1105 // Obtain The Related Device Object
1108 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1110 ProviderSize = sizeof(TDI_PROVIDER_INFO);
1111 RtlZeroMemory(ProviderInfo, ProviderSize);
1114 // Allocating the Tdi Setting Irp ...
1117 Irp = KsBuildTdiIrp(DeviceObject);
1121 Status = STATUS_INSUFFICIENT_RESOURCES;
1126 // Locking the User Buffer / Allocating a MDL for it
1129 Status = KsLockUserBuffer(
1137 if (!NT_SUCCESS(Status)) {
1146 LASSERT(NT_SUCCESS(Status));
1148 TdiBuildQueryInformation(
1154 TDI_QUERY_PROVIDER_INFO,
1158 Status = KsSubmitTdiIrp(
1165 KsReleaseMdl(Mdl, FALSE);
1168 if (!NT_SUCCESS(Status)) {
1170 cfs_enter_debugger();
1171 //TDI_BUFFER_OVERFLOW
1174 KsCloseControl(Handle, FileObject);
1180 * KsQueryConnectionInfo
1181 * Query the connection info of the FileObject specified
1182 * (some statics data of the traffic)
1185 * FileObject: the FileObject to be queried
1186 * ConnectionInfo: buffer to contain the connection info
1187 * ConnectionSize: length of the ConnectionInfo buffer
1190 * NTSTATUS: kernel status code (STATUS_SUCCESS
1191 * or other error code)
1198 KsQueryConnectionInfo(
1199 PFILE_OBJECT ConnectionObject,
1200 PTDI_CONNECTION_INFO ConnectionInfo,
1201 PULONG ConnectionSize
1204 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1207 PDEVICE_OBJECT DeviceObject;
1209 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1211 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
1213 RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
1216 // Allocating the Tdi Query Irp ...
1219 Irp = KsBuildTdiIrp(DeviceObject);
1223 Status = STATUS_INSUFFICIENT_RESOURCES;
1228 // Locking the User Buffer / Allocating a MDL for it
1231 Status = KsLockUserBuffer(
1239 if (NT_SUCCESS(Status)) {
1248 LASSERT(NT_SUCCESS(Status));
1250 TdiBuildQueryInformation(
1256 TDI_QUERY_CONNECTION_INFO,
1260 Status = KsSubmitTdiIrp(
1267 KsReleaseMdl(Mdl, FALSE);
1275 * KsInitializeTdiAddress
1276 * Initialize the tdi addresss
1279 * pTransportAddress: tdi address to be initialized
1280 * IpAddress: the ip address of object
1281 * IpPort: the ip port of the object
1284 * ULONG: the total size of the tdi address
1291 KsInitializeTdiAddress(
1292 IN OUT PTA_IP_ADDRESS pTransportAddress,
1297 pTransportAddress->TAAddressCount = 1;
1298 pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
1299 pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
1300 pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
1301 pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
1303 return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
1307 * KsQueryTdiAddressLength
1308 * Query the total size of the tdi address
1311 * pTransportAddress: tdi address to be queried
1314 * ULONG: the total size of the tdi address
1321 KsQueryTdiAddressLength(
1322 PTRANSPORT_ADDRESS pTransportAddress
1325 ULONG TotalLength = 0;
1328 PTA_ADDRESS UNALIGNED pTaAddress = NULL;
1330 ASSERT (NULL != pTransportAddress);
1332 TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
1333 FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
1335 pTaAddress = (TA_ADDRESS UNALIGNED *)pTransportAddress->Address;
1337 for (i = 0; i < pTransportAddress->TAAddressCount; i++)
1339 TotalLength += pTaAddress->AddressLength;
1340 pTaAddress = (TA_ADDRESS UNALIGNED *)((PCHAR)pTaAddress +
1341 FIELD_OFFSET(TA_ADDRESS,Address) +
1342 pTaAddress->AddressLength );
1345 return (TotalLength);
1351 * Query the ip address of the tdi object
1354 * FileObject: tdi object to be queried
1355 * TdiAddress: TdiAddress buffer, to store the queried
1357 * AddressLength: buffer length of the TdiAddress
1360 * ULONG: the total size of the tdi ip address
1368 PFILE_OBJECT FileObject,
1370 ULONG* AddressLength
1375 PTDI_ADDRESS_INFO TdiAddressInfo;
1380 // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
1383 Length = MAX_ADDRESS_LENGTH;
1385 TdiAddressInfo = (PTDI_ADDRESS_INFO)
1386 ExAllocatePoolWithTag(
1391 if (NULL == TdiAddressInfo) {
1393 Status = STATUS_INSUFFICIENT_RESOURCES;
1398 Status = KsQueryAddressInfo(
1406 if (NT_SUCCESS(Status))
1408 if (*AddressLength < Length) {
1410 Status = STATUS_BUFFER_TOO_SMALL;
1414 *AddressLength = Length;
1417 &(TdiAddressInfo->Address),
1421 Status = STATUS_SUCCESS;
1429 if (NULL != TdiAddressInfo) {
1431 ExFreePool(TdiAddressInfo);
1439 * KsErrorEventHandler
1440 * the common error event handler callback
1443 * TdiEventContext: should be the socket
1444 * Status: the error code
1447 * Status: STATS_SUCCESS
1450 * We need not do anything in such a severe
1451 * error case. System will process it for us.
1455 KsErrorEventHandler(
1456 IN PVOID TdiEventContext,
1460 KsPrint((2, "KsErrorEventHandler called at Irql = %xh ...\n",
1461 KeGetCurrentIrql()));
1463 cfs_enter_debugger();
1465 return (STATUS_SUCCESS);
1471 * setup all the event handler callbacks
1474 * tconn: the tdi connecton object
1477 * int: ks error code
1485 ksock_tconn_t * tconn
1488 NTSTATUS status = STATUS_SUCCESS;
1489 KS_EVENT_HANDLERS handlers;
1491 /* to make sure the address object is opened already */
1492 if (tconn->kstc_addr.FileObject == NULL) {
1496 /* initialize the handlers indictor array. for sender and listenr,
1497 there are different set of callbacks. for child, we just return. */
1499 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
1501 SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
1502 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
1503 SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
1504 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
1505 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
1507 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
1509 if (tconn->kstc_type == kstt_listener) {
1510 SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
1511 } else if (tconn->kstc_type == kstt_child) {
1515 /* set all the event callbacks */
1516 status = KsSetEventHandlers(
1517 tconn->kstc_addr.FileObject, /* Address File Object */
1518 tconn, /* Event Context */
1519 &handlers /* Event callback handlers */
1524 return cfs_error_code(status);
1530 * disable all the event handler callbacks (set to NULL)
1533 * tconn: the tdi connecton object
1536 * int: ks error code
1544 ksock_tconn_t * tconn
1547 NTSTATUS status = STATUS_SUCCESS;
1548 KS_EVENT_HANDLERS handlers;
1550 /* to make sure the address object is opened already */
1551 if (tconn->kstc_addr.FileObject == NULL) {
1555 /* initialize the handlers indictor array. for sender and listenr,
1556 there are different set of callbacks. for child, we just return. */
1558 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
1560 SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
1561 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
1562 SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
1563 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
1564 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
1565 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
1567 if (tconn->kstc_type == kstt_listener) {
1568 SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
1569 } else if (tconn->kstc_type == kstt_child) {
1573 /* set all the event callbacks */
1574 status = KsSetEventHandlers(
1575 tconn->kstc_addr.FileObject, /* Address File Object */
1576 tconn, /* Event Context */
1577 &handlers /* Event callback handlers */
1582 return cfs_error_code(status);
1587 * KsAcceptCompletionRoutine
1588 * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
1590 * Here system gives us a chance to check the conneciton is built
1594 * DeviceObject: the device object of the transport driver
1595 * Irp: the Irp is being completed.
1596 * Context: the context we specified when issuing the Irp
1606 KsAcceptCompletionRoutine(
1607 IN PDEVICE_OBJECT DeviceObject,
1612 ksock_tconn_t * child = (ksock_tconn_t *) Context;
1613 ksock_tconn_t * parent = child->child.kstc_parent;
1615 KsPrint((2, "KsAcceptCompletionRoutine: called at Irql: %xh\n",
1616 KeGetCurrentIrql() ));
1618 KsPrint((2, "KsAcceptCompletionRoutine: Context = %xh Status = %xh\n",
1619 Context, Irp->IoStatus.Status));
1621 LASSERT(child->kstc_type == kstt_child);
1623 spin_lock(&(child->kstc_lock));
1625 LASSERT(parent->kstc_state == ksts_listening);
1626 LASSERT(child->kstc_state == ksts_connecting);
1628 if (NT_SUCCESS(Irp->IoStatus.Status)) {
1630 child->child.kstc_accepted = TRUE;
1632 child->kstc_state = ksts_connected;
1634 /* wake up the daemon thread which waits on this event */
1636 &(parent->listener.kstc_accept_event),
1641 spin_unlock(&(child->kstc_lock));
1643 KsPrint((2, "KsAcceptCompletionRoutine: Get %xh now signal the event ...\n", parent));
1647 /* re-use this child connecton */
1648 child->child.kstc_accepted = FALSE;
1649 child->child.kstc_busy = FALSE;
1650 child->kstc_state = ksts_associated;
1652 spin_unlock(&(child->kstc_lock));
1655 /* now free the Irp */
1658 /* drop the refer count of the child */
1659 ks_put_tconn(child);
1661 return (STATUS_MORE_PROCESSING_REQUIRED);
1666 * ks_get_vacancy_backlog
1667 * Get a vacancy listeing child from the backlog list
1670 * parent: the listener daemon connection
1673 * the child listening connection or NULL in failure
1676 * Parent's lock should be acquired before calling.
1680 ks_get_vacancy_backlog(
1681 ksock_tconn_t * parent
1684 ksock_tconn_t * child;
1686 LASSERT(parent->kstc_type == kstt_listener);
1687 LASSERT(parent->kstc_state == ksts_listening);
1689 if (list_empty(&(parent->listener.kstc_listening.list))) {
1695 struct list_head * tmp;
1697 /* check the listening queue and try to get a free connecton */
1699 list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
1700 child = list_entry (tmp, ksock_tconn_t, child.kstc_link);
1701 spin_lock(&(child->kstc_lock));
1703 if (!child->child.kstc_busy) {
1704 LASSERT(child->kstc_state == ksts_associated);
1705 child->child.kstc_busy = TRUE;
1706 spin_unlock(&(child->kstc_lock));
1709 spin_unlock(&(child->kstc_lock));
1719 KsSearchIpAddress(PUNICODE_STRING DeviceName)
1721 ks_addr_slot_t * slot = NULL;
1722 PLIST_ENTRY list = NULL;
1724 spin_lock(&ks_data.ksnd_addrs_lock);
1726 list = ks_data.ksnd_addrs_list.Flink;
1727 while (list != &ks_data.ksnd_addrs_list) {
1728 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
1729 if (RtlCompareUnicodeString(
1739 spin_unlock(&ks_data.ksnd_addrs_lock);
1745 KsCleanupIpAddresses()
1747 spin_lock(&ks_data.ksnd_addrs_lock);
1749 while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
1751 ks_addr_slot_t * slot = NULL;
1752 PLIST_ENTRY list = NULL;
1754 list = RemoveHeadList(&ks_data.ksnd_addrs_list);
1755 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
1757 ks_data.ksnd_naddrs--;
1760 cfs_assert(ks_data.ksnd_naddrs == 0);
1761 spin_unlock(&ks_data.ksnd_addrs_lock);
1765 KsAddAddressHandler(
1766 IN PTA_ADDRESS Address,
1767 IN PUNICODE_STRING DeviceName,
1768 IN PTDI_PNP_CONTEXT Context
1771 PTDI_ADDRESS_IP IpAddress = NULL;
1773 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
1774 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
1776 ks_addr_slot_t * slot = NULL;
1778 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
1779 KsPrint((1, "KsAddAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
1780 DeviceName, Context, IpAddress->in_addr,
1781 (IpAddress->in_addr & 0xFF000000) >> 24,
1782 (IpAddress->in_addr & 0x00FF0000) >> 16,
1783 (IpAddress->in_addr & 0x0000FF00) >> 8,
1784 (IpAddress->in_addr & 0x000000FF) >> 0 ));
1786 slot = KsSearchIpAddress(DeviceName);
1790 slot->ip_addr = ntohl(IpAddress->in_addr);
1792 slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
1794 spin_lock(&ks_data.ksnd_addrs_lock);
1795 InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
1796 sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
1797 slot->ip_addr = ntohl(IpAddress->in_addr);
1799 RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
1800 slot->devname.Length = DeviceName->Length;
1801 slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
1802 slot->devname.Buffer = slot->buffer;
1803 spin_unlock(&ks_data.ksnd_addrs_lock);
1810 KsDelAddressHandler(
1811 IN PTA_ADDRESS Address,
1812 IN PUNICODE_STRING DeviceName,
1813 IN PTDI_PNP_CONTEXT Context
1816 PTDI_ADDRESS_IP IpAddress = NULL;
1818 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
1819 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
1821 ks_addr_slot_t * slot = NULL;
1823 slot = KsSearchIpAddress(DeviceName);
1829 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
1830 KsPrint((1, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
1831 DeviceName, Context, IpAddress->in_addr,
1832 (IpAddress->in_addr & 0xFF000000) >> 24,
1833 (IpAddress->in_addr & 0x00FF0000) >> 16,
1834 (IpAddress->in_addr & 0x0000FF00) >> 8,
1835 (IpAddress->in_addr & 0x000000FF) >> 0 ));
1840 KsRegisterPnpHandlers()
1842 TDI20_CLIENT_INTERFACE_INFO ClientInfo;
1844 /* initialize the global ks_data members */
1845 RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
1846 spin_lock_init(&ks_data.ksnd_addrs_lock);
1847 InitializeListHead(&ks_data.ksnd_addrs_list);
1849 /* register the pnp handlers */
1850 RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
1851 ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
1853 ClientInfo.ClientName = &ks_data.ksnd_client_name;
1854 ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
1855 ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
1857 return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
1858 &ks_data.ksnd_pnp_handle);
1862 KsDeregisterPnpHandlers()
1864 if (ks_data.ksnd_pnp_handle) {
1866 /* De-register the pnp handlers */
1868 TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
1869 ks_data.ksnd_pnp_handle = NULL;
1871 /* cleanup all the ip address slots */
1872 KsCleanupIpAddresses();
1877 * KsConnectEventHandler
1878 * Connect event handler event handler, called by the underlying TDI
1879 * transport in response to an incoming request to the listening daemon.
1881 * it will grab a vacancy backlog from the children tconn list, and
1882 * build an acception Irp with it, then transfer the Irp to TDI driver.
1885 * TdiEventContext: the tdi connnection object of the listening daemon
1889 * Nt kernel status code
1896 KsConnectEventHandler(
1897 IN PVOID TdiEventContext,
1898 IN LONG RemoteAddressLength,
1899 IN PVOID RemoteAddress,
1900 IN LONG UserDataLength,
1902 IN LONG OptionsLength,
1904 OUT CONNECTION_CONTEXT * ConnectionContext,
1905 OUT PIRP * AcceptIrp
1908 ksock_tconn_t * parent;
1909 ksock_tconn_t * child;
1911 PFILE_OBJECT FileObject;
1912 PDEVICE_OBJECT DeviceObject;
1916 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
1918 KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
1919 parent = (ksock_tconn_t *) TdiEventContext;
1921 LASSERT(parent->kstc_type == kstt_listener);
1923 spin_lock(&(parent->kstc_lock));
1925 if (parent->kstc_state == ksts_listening) {
1927 /* allocate a new ConnectionInfo to backup the peer's info */
1929 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
1930 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
1931 RemoteAddressLength, 'iCsK' );
1933 if (NULL == ConnectionInfo) {
1935 Status = STATUS_INSUFFICIENT_RESOURCES;
1936 cfs_enter_debugger();
1940 /* initializing ConnectionInfo structure ... */
1942 ConnectionInfo->UserDataLength = UserDataLength;
1943 ConnectionInfo->UserData = UserData;
1944 ConnectionInfo->OptionsLength = OptionsLength;
1945 ConnectionInfo->Options = Options;
1946 ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
1947 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
1950 ConnectionInfo->RemoteAddress,
1955 /* get the vacancy listening child tdi connections */
1957 child = ks_get_vacancy_backlog(parent);
1961 spin_lock(&(child->kstc_lock));
1962 child->child.kstc_info.ConnectionInfo = ConnectionInfo;
1963 child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
1964 child->kstc_state = ksts_connecting;
1965 spin_unlock(&(child->kstc_lock));
1969 KsPrint((2, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
1971 Status = STATUS_INSUFFICIENT_RESOURCES;
1976 FileObject = child->child.kstc_info.FileObject;
1977 DeviceObject = IoGetRelatedDeviceObject (FileObject);
1979 Irp = KsBuildTdiIrp(DeviceObject);
1985 KsAcceptCompletionRoutine,
1991 IoSetNextIrpStackLocation(Irp);
1993 /* grap the refer of the child tdi connection */
1994 ks_get_tconn(child);
1996 Status = STATUS_MORE_PROCESSING_REQUIRED;
1999 *ConnectionContext = child;
2003 Status = STATUS_CONNECTION_REFUSED;
2007 spin_unlock(&(parent->kstc_lock));
2013 spin_unlock(&(parent->kstc_lock));
2017 *ConnectionContext = NULL;
2019 if (ConnectionInfo) {
2021 ExFreePool(ConnectionInfo);
2034 * KsDisconnectCompletionRoutine
2035 * the Irp completion routine for TdiBuildDisconect
2037 * We just signal the event and return MORE_PRO... to
2038 * let the caller take the responsibility of the Irp.
2041 * DeviceObject: the device object of the transport
2042 * Irp: the Irp is being completed.
2043 * Context: the event specified by the caller
2053 KsDisconectCompletionRoutine (
2054 IN PDEVICE_OBJECT DeviceObject,
2060 KeSetEvent((PKEVENT) Context, 0, FALSE);
2062 return STATUS_MORE_PROCESSING_REQUIRED;
2064 UNREFERENCED_PARAMETER(DeviceObject);
2069 * KsDisconnectHelper
2070 * the routine to be executed in the WorkItem procedure
2071 * this routine is to disconnect a tdi connection
2074 * Workitem: the context transferred to the workitem
2080 * tconn is already referred in abort_connecton ...
2084 KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
2086 ksock_tconn_t * tconn = WorkItem->tconn;
2088 DbgPrint("KsDisconnectHelper: disconnecting tconn=%p\n", tconn);
2089 ks_disconnect_tconn(tconn, WorkItem->Flags);
2091 KeSetEvent(&(WorkItem->Event), 0, FALSE);
2093 spin_lock(&(tconn->kstc_lock));
2094 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
2095 spin_unlock(&(tconn->kstc_lock));
2096 ks_put_tconn(tconn);
2101 * KsDisconnectEventHandler
2102 * Disconnect event handler event handler, called by the underlying TDI transport
2103 * in response to an incoming disconnection notification from a remote node.
2106 * ConnectionContext: tdi connnection object
2107 * DisconnectFlags: specifies the nature of the disconnection
2111 * Nt kernel status code
2119 KsDisconnectEventHandler(
2120 IN PVOID TdiEventContext,
2121 IN CONNECTION_CONTEXT ConnectionContext,
2122 IN LONG DisconnectDataLength,
2123 IN PVOID DisconnectData,
2124 IN LONG DisconnectInformationLength,
2125 IN PVOID DisconnectInformation,
2126 IN ULONG DisconnectFlags
2129 ksock_tconn_t * tconn;
2131 PKS_DISCONNECT_WORKITEM WorkItem;
2133 tconn = (ksock_tconn_t *)ConnectionContext;
2135 KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
2136 KeGetCurrentIrql() ));
2138 KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
2139 tconn, DisconnectFlags));
2141 ks_get_tconn(tconn);
2142 spin_lock(&(tconn->kstc_lock));
2144 WorkItem = &(tconn->kstc_disconnect);
2146 if (tconn->kstc_state != ksts_connected) {
2148 Status = STATUS_SUCCESS;
2152 if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
2154 Status = STATUS_REMOTE_DISCONNECT;
2156 } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
2158 Status = STATUS_GRACEFUL_DISCONNECT;
2161 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
2163 ks_get_tconn(tconn);
2165 WorkItem->Flags = DisconnectFlags;
2166 WorkItem->tconn = tconn;
2168 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
2170 /* queue the workitem to call */
2171 ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
2175 spin_unlock(&(tconn->kstc_lock));
2176 ks_put_tconn(tconn);
2182 KsTcpReceiveCompletionRoutine(
2184 IN PKS_TCP_COMPLETION_CONTEXT Context
2187 NTSTATUS Status = Irp->IoStatus.Status;
2189 if (NT_SUCCESS(Status)) {
2191 ksock_tconn_t *tconn = Context->tconn;
2193 PKS_TSDU_DAT KsTsduDat = Context->CompletionContext;
2194 PKS_TSDU_BUF KsTsduBuf = Context->CompletionContext;
2196 KsPrint((1, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
2197 Context->KsTsduMgr->TotalBytes ));
2199 spin_lock(&(tconn->kstc_lock));
2201 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
2202 if (cfs_is_flag_set(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING)) {
2203 cfs_clear_flag(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING);
2205 cfs_enter_debugger();
2208 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
2209 if (cfs_is_flag_set(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING)) {
2210 cfs_clear_flag(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING);
2212 cfs_enter_debugger();
2216 spin_unlock(&(tconn->kstc_lock));
2218 /* wake up the thread waiting for the completion of this Irp */
2219 KeSetEvent(Context->Event, 0, FALSE);
2221 /* re-active the ks connection and wake up the scheduler */
2222 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
2223 tconn->kstc_sched_cb( tconn, FALSE, NULL,
2224 Context->KsTsduMgr->TotalBytes );
2229 /* un-expected errors occur, we must abort the connection */
2230 ks_abort_tconn(Context->tconn);
2235 /* Freeing the Context structure... */
2236 ExFreePool(Context);
2251 * KsTcpCompletionRoutine
2252 * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
2253 * We need call the use's own CompletionRoutine if specified. Or
2254 * it's a synchronous case, we need signal the event.
2257 * DeviceObject: the device object of the transport
2258 * Irp: the Irp is being completed.
2259 * Context: the context we specified when issuing the Irp
2269 KsTcpCompletionRoutine(
2270 IN PDEVICE_OBJECT DeviceObject,
2277 PKS_TCP_COMPLETION_CONTEXT CompletionContext = NULL;
2278 ksock_tconn_t * tconn = NULL;
2280 CompletionContext = (PKS_TCP_COMPLETION_CONTEXT) Context;
2281 tconn = CompletionContext->tconn;
2283 /* release the chained mdl */
2284 KsReleaseMdl(Irp->MdlAddress, FALSE);
2285 Irp->MdlAddress = NULL;
2287 if (CompletionContext->CompletionRoutine) {
2289 if ( CompletionContext->bCounted &&
2290 InterlockedDecrement(&CompletionContext->ReferCount) != 0 ) {
2295 // Giving control to user specified CompletionRoutine ...
2298 CompletionContext->CompletionRoutine(
2306 // Signaling the Event ...
2309 KeSetEvent(CompletionContext->Event, 0, FALSE);
2312 /* drop the reference count of the tconn object */
2313 ks_put_tconn(tconn);
2317 cfs_enter_debugger();
2322 return STATUS_MORE_PROCESSING_REQUIRED;
2326 * KsTcpSendCompletionRoutine
2327 * the user specified Irp completion routine for asynchronous
2328 * data transmission requests.
2330 * It will do th cleanup job of the ksock_tx_t and wake up the
2331 * ks scheduler thread
2334 * Irp: the Irp is being completed.
2335 * Context: the context we specified when issuing the Irp
2345 KsTcpSendCompletionRoutine(
2347 IN PKS_TCP_COMPLETION_CONTEXT Context
2350 NTSTATUS Status = Irp->IoStatus.Status;
2351 ULONG rc = Irp->IoStatus.Information;
2352 ksock_tconn_t * tconn = Context->tconn;
2353 PKS_TSDUMGR KsTsduMgr = Context->KsTsduMgr;
2359 if (NT_SUCCESS(Status)) {
2361 if (Context->bCounted) {
2362 PVOID tx = Context->CompletionContext;
2364 ASSERT(tconn->kstc_update_tx != NULL);
2366 /* update the tx, rebasing the kiov or iov pointers */
2367 tx = tconn->kstc_update_tx(tconn, tx, rc);
2369 /* update the KsTsudMgr total bytes */
2370 spin_lock(&tconn->kstc_lock);
2371 KsTsduMgr->TotalBytes -= rc;
2372 spin_unlock(&tconn->kstc_lock);
2375 * now it's time to re-queue the conns into the
2376 * scheduler queue and wake the scheduler thread.
2379 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
2380 tconn->kstc_sched_cb( tconn, TRUE, tx, 0);
2385 PKS_TSDU KsTsdu = Context->CompletionContext;
2386 PKS_TSDU_BUF KsTsduBuf = Context->CompletionContext2;
2387 PKS_TSDU_DAT KsTsduDat = Context->CompletionContext2;
2389 spin_lock(&tconn->kstc_lock);
2390 /* This is bufferred sending ... */
2391 ASSERT(KsTsduBuf->StartOffset == 0);
2393 if (KsTsduBuf->DataLength > Irp->IoStatus.Information) {
2394 /* not fully sent .... we have to abort the connection */
2395 spin_unlock(&tconn->kstc_lock);
2396 ks_abort_tconn(tconn);
2400 if (KsTsduBuf->TsduType == TSDU_TYPE_BUF) {
2401 /* free the buffer */
2402 ExFreePool(KsTsduBuf->UserBuffer);
2403 KsTsduMgr->TotalBytes -= KsTsduBuf->DataLength;
2404 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
2405 } else if (KsTsduDat->TsduType == TSDU_TYPE_DAT) {
2406 KsTsduMgr->TotalBytes -= KsTsduDat->DataLength;
2407 KsTsdu->StartOffset += KsTsduDat->TotalLength;
2409 cfs_enter_debugger(); /* shoult not get here */
2412 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
2414 list_del(&KsTsdu->Link);
2415 KsTsduMgr->NumOfTsdu--;
2416 KsPutKsTsdu(KsTsdu);
2419 spin_unlock(&tconn->kstc_lock);
2424 /* cfs_enter_debugger(); */
2427 * for the case that the transmission is ussuccessful,
2428 * we need abort the tdi connection, but not destroy it.
2429 * the socknal conn will drop the refer count, then the
2430 * tdi connection will be freed.
2433 ks_abort_tconn(tconn);
2438 /* freeing the Context structure... */
2441 ExFreePool(Context);
2445 /* it's our duty to free the Irp. */
2458 * Normal receive event handler
2460 * It will move data from system Tsdu to our TsduList
2464 KsTcpReceiveEventHandler(
2465 IN PVOID TdiEventContext,
2466 IN CONNECTION_CONTEXT ConnectionContext,
2467 IN ULONG ReceiveFlags,
2468 IN ULONG BytesIndicated,
2469 IN ULONG BytesAvailable,
2470 OUT ULONG * BytesTaken,
2472 OUT PIRP * IoRequestPacket
2477 ksock_tconn_t * tconn;
2480 PKS_TSDUMGR KsTsduMgr;
2482 PKS_TSDU_DAT KsTsduDat;
2483 PKS_TSDU_BUF KsTsduBuf;
2485 BOOLEAN bIsExpedited;
2486 BOOLEAN bIsCompleteTsdu;
2488 BOOLEAN bNewTsdu = FALSE;
2489 BOOLEAN bNewBuff = FALSE;
2491 PCHAR Buffer = NULL;
2495 PFILE_OBJECT FileObject;
2496 PDEVICE_OBJECT DeviceObject;
2498 ULONG BytesReceived = 0;
2500 PKS_TCP_COMPLETION_CONTEXT context = NULL;
2503 tconn = (ksock_tconn_t *) ConnectionContext;
2505 ks_get_tconn(tconn);
2507 /* check whether the whole body of payload is received or not */
2508 if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
2509 (BytesIndicated == BytesAvailable) ) {
2510 bIsCompleteTsdu = TRUE;
2512 bIsCompleteTsdu = FALSE;
2515 bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
2517 KsPrint((2, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n", BytesIndicated, BytesAvailable));
2518 KsPrint((2, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
2520 spin_lock(&(tconn->kstc_lock));
2522 /* check whether we are conntected or not listener ¡Â*/
2523 if ( !((tconn->kstc_state == ksts_connected) &&
2524 (tconn->kstc_type == kstt_sender ||
2525 tconn->kstc_type == kstt_child))) {
2527 *BytesTaken = BytesIndicated;
2529 spin_unlock(&(tconn->kstc_lock));
2530 ks_put_tconn(tconn);
2532 return (STATUS_SUCCESS);
2535 if (tconn->kstc_type == kstt_sender) {
2536 KsChain = &(tconn->sender.kstc_recv);
2538 LASSERT(tconn->kstc_type == kstt_child);
2539 KsChain = &(tconn->child.kstc_recv);
2543 KsTsduMgr = &(KsChain->Expedited);
2545 KsTsduMgr = &(KsChain->Normal);
2548 /* if the Tsdu is even larger than the biggest Tsdu, we have
2549 to allocate new buffer and use TSDU_TYOE_BUF to store it */
2551 if ( KS_TSDU_STRU_SIZE(BytesAvailable) > ks_data.ksnd_tsdu_size -
2552 KS_DWORD_ALIGN(sizeof(KS_TSDU))) {
2556 /* retrieve the latest Tsdu buffer form TsduMgr
2557 list if the list is not empty. */
2559 if (list_empty(&(KsTsduMgr->TsduList))) {
2561 LASSERT(KsTsduMgr->NumOfTsdu == 0);
2566 LASSERT(KsTsduMgr->NumOfTsdu > 0);
2567 KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
2569 /* if this Tsdu does not contain enough space, we need
2570 allocate a new Tsdu queue. */
2573 if ( KsTsdu->LastOffset + sizeof(KS_TSDU_BUF) >
2574 KsTsdu->TotalLength ) {
2578 if ( KS_TSDU_STRU_SIZE(BytesAvailable) >
2579 KsTsdu->TotalLength - KsTsdu->LastOffset ) {
2585 /* allocating the buffer for TSDU_TYPE_BUF */
2587 Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
2588 if (NULL == Buffer) {
2589 /* there's no enough memory for us. We just try to
2590 receive maximum bytes with a new Tsdu */
2596 /* allocate a new Tsdu in case we are not statisfied. */
2598 if (NULL == KsTsdu) {
2600 KsTsdu = KsAllocateKsTsdu();
2602 if (NULL == KsTsdu) {
2609 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
2610 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
2614 /* setup up the KS_TSDU_BUF record */
2616 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
2617 KsTsduBuf->TsduFlags = 0;
2618 KsTsduBuf->StartOffset = 0;
2619 KsTsduBuf->UserBuffer = Buffer;
2620 KsTsduBuf->DataLength = BytesReceived = BytesAvailable;
2622 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
2626 /* setup the KS_TSDU_DATA to contain all the messages */
2628 KsTsduDat->TsduType = TSDU_TYPE_DAT;
2629 KsTsduDat->TsduFlags = 0;
2631 if ( KsTsdu->TotalLength - KsTsdu->LastOffset >=
2632 KS_TSDU_STRU_SIZE(BytesAvailable) ) {
2633 BytesReceived = BytesAvailable;
2635 BytesReceived = KsTsdu->TotalLength - KsTsdu->LastOffset -
2636 FIELD_OFFSET(KS_TSDU_DAT, Data);
2637 BytesReceived &= (~((ULONG)3));
2639 KsTsduDat->DataLength = BytesReceived;
2640 KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(BytesReceived);
2641 KsTsduDat->StartOffset = 0;
2643 Buffer = &KsTsduDat->Data[0];
2645 KsTsdu->LastOffset += KsTsduDat->TotalLength;
2648 KsTsduMgr->TotalBytes += BytesReceived;
2650 if (bIsCompleteTsdu) {
2652 /* It's a complete receive, we just move all
2653 the data from system to our Tsdu */
2661 *BytesTaken = BytesReceived;
2662 Status = STATUS_SUCCESS;
2665 list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
2666 KsTsduMgr->NumOfTsdu++;
2669 KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
2671 /* re-active the ks connection and wake up the scheduler */
2672 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
2673 tconn->kstc_sched_cb( tconn, FALSE, NULL,
2674 KsTsduMgr->TotalBytes );
2679 /* there's still data in tdi internal queue, we need issue a new
2680 Irp to receive all of them. first allocate the tcp context */
2682 context = ExAllocatePoolWithTag(
2684 sizeof(KS_TCP_COMPLETION_CONTEXT),
2689 Status = STATUS_INSUFFICIENT_RESOURCES;
2693 /* setup the context */
2694 RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
2696 context->tconn = tconn;
2697 context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
2698 context->CompletionContext = KsTsdu;
2699 context->CompletionContext = bNewBuff ? (PVOID)KsTsduBuf : (PVOID)KsTsduDat;
2700 context->KsTsduMgr = KsTsduMgr;
2701 context->Event = &(KsTsduMgr->Event);
2703 if (tconn->kstc_type == kstt_sender) {
2704 FileObject = tconn->sender.kstc_info.FileObject;
2706 FileObject = tconn->child.kstc_info.FileObject;
2709 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2711 /* build new tdi Irp and setup it. */
2712 Irp = KsBuildTdiIrp(DeviceObject);
2718 Status = KsLockUserBuffer(
2726 if (!NT_SUCCESS(Status)) {
2734 KsTcpCompletionRoutine,
2737 ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
2741 IoSetNextIrpStackLocation(Irp);
2743 /* return the newly built Irp to transport driver,
2744 it will process it to receive all the data */
2746 *IoRequestPacket = Irp;
2751 list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
2752 KsTsduMgr->NumOfTsdu++;
2756 cfs_set_flag(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING);
2758 cfs_set_flag(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING);
2760 ks_get_tconn(tconn);
2761 Status = STATUS_MORE_PROCESSING_REQUIRED;
2764 spin_unlock(&(tconn->kstc_lock));
2765 ks_put_tconn(tconn);
2771 spin_unlock(&(tconn->kstc_lock));
2773 if (bNewTsdu && (KsTsdu != NULL)) {
2774 KsFreeKsTsdu(KsTsdu);
2778 KsReleaseMdl(Mdl, FALSE);
2786 ExFreePool(context);
2789 ks_abort_tconn(tconn);
2790 ks_put_tconn(tconn);
2792 *BytesTaken = BytesAvailable;
2793 Status = STATUS_SUCCESS;
2799 * Expedited receive event handler
2803 KsTcpReceiveExpeditedEventHandler(
2804 IN PVOID TdiEventContext,
2805 IN CONNECTION_CONTEXT ConnectionContext,
2806 IN ULONG ReceiveFlags,
2807 IN ULONG BytesIndicated,
2808 IN ULONG BytesAvailable,
2809 OUT ULONG * BytesTaken,
2811 OUT PIRP * IoRequestPacket
2814 return KsTcpReceiveEventHandler(
2817 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
2828 * Bulk receive event handler
2830 * It will queue all the system Tsdus to our TsduList.
2831 * Then later ks_recv_mdl will release them.
2835 KsTcpChainedReceiveEventHandler (
2836 IN PVOID TdiEventContext, // the event context
2837 IN CONNECTION_CONTEXT ConnectionContext,
2838 IN ULONG ReceiveFlags,
2839 IN ULONG ReceiveLength,
2840 IN ULONG StartingOffset, // offset of start of client data in TSDU
2841 IN PMDL Tsdu, // TSDU data chain
2842 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
2848 ksock_tconn_t * tconn;
2851 PKS_TSDUMGR KsTsduMgr;
2853 PKS_TSDU_MDL KsTsduMdl;
2855 BOOLEAN bIsExpedited;
2856 BOOLEAN bNewTsdu = FALSE;
2858 tconn = (ksock_tconn_t *) ConnectionContext;
2860 bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
2862 KsPrint((2, "KsTcpChainedReceive: ReceiveLength = %xh bIsExpedited = %d\n", ReceiveLength, bIsExpedited));
2864 ks_get_tconn(tconn);
2865 spin_lock(&(tconn->kstc_lock));
2867 /* check whether we are conntected or not listener ¡Â*/
2868 if ( !((tconn->kstc_state == ksts_connected) &&
2869 (tconn->kstc_type == kstt_sender ||
2870 tconn->kstc_type == kstt_child))) {
2872 spin_unlock(&(tconn->kstc_lock));
2873 ks_put_tconn(tconn);
2875 return (STATUS_SUCCESS);
2878 /* get the latest Tsdu buffer form TsduMgr list.
2879 just set NULL if the list is empty. */
2881 if (tconn->kstc_type == kstt_sender) {
2882 KsChain = &(tconn->sender.kstc_recv);
2884 LASSERT(tconn->kstc_type == kstt_child);
2885 KsChain = &(tconn->child.kstc_recv);
2889 KsTsduMgr = &(KsChain->Expedited);
2891 KsTsduMgr = &(KsChain->Normal);
2894 if (list_empty(&(KsTsduMgr->TsduList))) {
2896 LASSERT(KsTsduMgr->NumOfTsdu == 0);
2901 LASSERT(KsTsduMgr->NumOfTsdu > 0);
2902 KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
2903 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
2905 if (sizeof(KS_TSDU_MDL) > KsTsdu->TotalLength - KsTsdu->LastOffset) {
2910 /* if there's no Tsdu or the free size is not enough for this
2911 KS_TSDU_MDL structure. We need re-allocate a new Tsdu. */
2913 if (NULL == KsTsdu) {
2915 KsTsdu = KsAllocateKsTsdu();
2917 if (NULL == KsTsdu) {
2924 /* just queue the KS_TSDU_MDL to the Tsdu buffer */
2926 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
2928 KsTsduMdl->TsduType = TSDU_TYPE_MDL;
2929 KsTsduMdl->DataLength = ReceiveLength;
2930 KsTsduMdl->StartOffset = StartingOffset;
2931 KsTsduMdl->Mdl = Tsdu;
2932 KsTsduMdl->Descriptor = TsduDescriptor;
2934 KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
2935 KsTsduMgr->TotalBytes += ReceiveLength;
2937 KsPrint((2, "KsTcpChainedReceiveEventHandler: Total %xh bytes.\n",
2938 KsTsduMgr->TotalBytes ));
2940 Status = STATUS_PENDING;
2942 /* attach it to the TsduMgr list if the Tsdu is newly created. */
2945 list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
2946 KsTsduMgr->NumOfTsdu++;
2949 spin_unlock(&(tconn->kstc_lock));
2951 /* wake up the threads waiing in ks_recv_mdl */
2952 KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
2954 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
2955 tconn->kstc_sched_cb( tconn, FALSE, NULL,
2956 KsTsduMgr->TotalBytes );
2959 ks_put_tconn(tconn);
2961 /* Return STATUS_PENDING to system because we are still
2962 owning the MDL resources. ks_recv_mdl is expected
2963 to free the MDL resources. */
2969 spin_unlock(&(tconn->kstc_lock));
2971 if (bNewTsdu && (KsTsdu != NULL)) {
2972 KsFreeKsTsdu(KsTsdu);
2975 /* abort the tdi connection */
2976 ks_abort_tconn(tconn);
2977 ks_put_tconn(tconn);
2980 Status = STATUS_SUCCESS;
2987 * Expedited & Bulk receive event handler
2991 KsTcpChainedReceiveExpeditedEventHandler (
2992 IN PVOID TdiEventContext, // the event context
2993 IN CONNECTION_CONTEXT ConnectionContext,
2994 IN ULONG ReceiveFlags,
2995 IN ULONG ReceiveLength,
2996 IN ULONG StartingOffset, // offset of start of client data in TSDU
2997 IN PMDL Tsdu, // TSDU data chain
2998 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
3001 return KsTcpChainedReceiveEventHandler(
3004 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
3013 KsPrintProviderInfo(
3015 PTDI_PROVIDER_INFO ProviderInfo
3018 KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
3020 KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
3021 KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
3022 KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
3023 KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
3024 KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
3026 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
3027 KsPrint((2, " CONNECTION_MODE\n"));
3030 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
3031 KsPrint((2, " ORDERLY_RELEASE\n"));
3034 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
3035 KsPrint((2, " CONNECTIONLESS_MODE\n"));
3038 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
3039 KsPrint((2, " ERROR_FREE_DELIVERY\n"));
3042 if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
3043 KsPrint((2, " SECURITY_LEVEL\n"));
3046 if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
3047 KsPrint((2, " BROADCAST_SUPPORTED\n"));
3050 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
3051 KsPrint((2, " MULTICAST_SUPPORTED\n"));
3054 if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
3055 KsPrint((2, " DELAYED_ACCEPTANCE\n"));
3058 if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
3059 KsPrint((2, " EXPEDITED_DATA\n"));
3062 if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
3063 KsPrint((2, " INTERNAL_BUFFERING\n"));
3066 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
3067 KsPrint((2, " ROUTE_DIRECTED\n"));
3070 if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
3071 KsPrint((2, " NO_ZERO_LENGTH\n"));
3074 if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
3075 KsPrint((2, " POINT_TO_POINT\n"));
3078 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
3079 KsPrint((2, " MESSAGE_MODE\n"));
3082 if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
3083 KsPrint((2, " HALF_DUPLEX\n"));
3086 KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
3087 KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
3088 KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
3094 * Reuse a Tsdu from the freelist or allocate a new Tsdu
3095 * from the LookAsideList table or the NonPagedPool
3101 * PKS_Tsdu: the new Tsdu or NULL if it fails
3110 PKS_TSDU KsTsdu = NULL;
3112 spin_lock(&(ks_data.ksnd_tsdu_lock));
3114 if (!list_empty (&(ks_data.ksnd_freetsdus))) {
3116 LASSERT(ks_data.ksnd_nfreetsdus > 0);
3118 KsTsdu = list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
3119 list_del(&(KsTsdu->Link));
3120 ks_data.ksnd_nfreetsdus--;
3124 KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
3125 ks_data.ksnd_tsdu_slab, 0);
3128 spin_unlock(&(ks_data.ksnd_tsdu_lock));
3130 if (NULL != KsTsdu) {
3131 KsInitializeKsTsdu(KsTsdu, ks_data.ksnd_tsdu_size);
3140 * Move the Tsdu to the free tsdu list in ks_data.
3143 * KsTsdu: Tsdu to be moved.
3157 spin_lock(&(ks_data.ksnd_tsdu_lock));
3159 list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
3160 ks_data.ksnd_nfreetsdus++;
3162 spin_unlock(&(ks_data.ksnd_tsdu_lock));
3168 * Release a Tsdu: uninitialize then free it.
3171 * KsTsdu: Tsdu to be freed.
3186 ks_data.ksnd_tsdu_slab,
3192 * KsInitializeKsTsdu
3193 * Initialize the Tsdu buffer header
3196 * KsTsdu: the Tsdu to be initialized
3197 * Length: the total length of the Tsdu
3212 RtlZeroMemory(KsTsdu, Length);
3213 KsTsdu->Magic = KS_TSDU_MAGIC;
3214 KsTsdu->TotalLength = Length;
3215 KsTsdu->StartOffset = KsTsdu->LastOffset =
3216 KS_DWORD_ALIGN(sizeof(KS_TSDU));
3221 * KsInitializeKsTsduMgr
3222 * Initialize the management structure of
3226 * TsduMgr: the TsduMgr to be initialized
3236 KsInitializeKsTsduMgr(
3247 &(TsduMgr->TsduList)
3250 TsduMgr->NumOfTsdu = 0;
3251 TsduMgr->TotalBytes = 0;
3256 * KsInitializeKsChain
3257 * Initialize the China structure for receiving
3261 * KsChain: the KsChain to be initialized
3271 KsInitializeKsChain(
3275 KsInitializeKsTsduMgr(&(KsChain->Normal));
3276 KsInitializeKsTsduMgr(&(KsChain->Expedited));
3282 * Clean up all the Tsdus in the TsduMgr list
3285 * KsTsduMgr: the Tsdu list manager
3288 * NTSTATUS: nt status code
3296 PKS_TSDUMGR KsTsduMgr
3300 PKS_TSDU_DAT KsTsduDat;
3301 PKS_TSDU_BUF KsTsduBuf;
3302 PKS_TSDU_MDL KsTsduMdl;
3304 LASSERT(NULL != KsTsduMgr);
3306 KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
3308 while (!list_empty(&KsTsduMgr->TsduList)) {
3310 KsTsdu = list_entry(KsTsduMgr->TsduList.next, KS_TSDU, Link);
3311 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
3313 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
3316 // KsTsdu is empty now, we need free it ...
3319 list_del(&(KsTsdu->Link));
3320 KsTsduMgr->NumOfTsdu--;
3322 KsFreeKsTsdu(KsTsdu);
3326 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
3327 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
3328 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
3330 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
3332 KsTsdu->StartOffset += KsTsduDat->TotalLength;
3334 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
3336 ASSERT(KsTsduBuf->UserBuffer != NULL);
3338 if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
3339 ExFreePool(KsTsduBuf->UserBuffer);
3341 cfs_enter_debugger();
3344 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
3346 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
3349 // MDL Tsdu Unit ...
3352 TdiReturnChainedReceives(
3353 &(KsTsduMdl->Descriptor),
3356 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
3361 return STATUS_SUCCESS;
3367 * Clean up the TsduMgrs of the KsChain
3370 * KsChain: the chain managing TsduMgr
3373 * NTSTATUS: nt status code
3386 LASSERT(NULL != KsChain);
3388 Status = KsCleanupTsduMgr(
3392 if (!NT_SUCCESS(Status)) {
3393 cfs_enter_debugger();
3397 Status = KsCleanupTsduMgr(
3398 &(KsChain->Expedited)
3401 if (!NT_SUCCESS(Status)) {
3402 cfs_enter_debugger();
3414 * Clean up all the Tsdus of a tdi connected object
3417 * tconn: the tdi connection which is connected already.
3428 ksock_tconn_t * tconn
3431 NTSTATUS Status = STATUS_SUCCESS;
3434 if (tconn->kstc_type != kstt_sender &&
3435 tconn->kstc_type != kstt_child ) {
3440 if (tconn->kstc_type == kstt_sender) {
3442 Status = KsCleanupKsChain(
3443 &(tconn->sender.kstc_recv)
3446 if (!NT_SUCCESS(Status)) {
3447 cfs_enter_debugger();
3451 Status = KsCleanupKsChain(
3452 &(tconn->sender.kstc_send)
3455 if (!NT_SUCCESS(Status)) {
3456 cfs_enter_debugger();
3462 Status = KsCleanupKsChain(
3463 &(tconn->child.kstc_recv)
3466 if (!NT_SUCCESS(Status)) {
3467 cfs_enter_debugger();
3471 Status = KsCleanupKsChain(
3472 &(tconn->child.kstc_send)
3475 if (!NT_SUCCESS(Status)) {
3476 cfs_enter_debugger();
3489 * KsCopyMdlChainToMdlChain
3490 * Copy data from a [chained] Mdl to anther [chained] Mdl.
3491 * Tdi library does not provide this function. We have to
3492 * realize it ourselives.
3495 * SourceMdlChain: the source mdl
3496 * SourceOffset: start offset of the source
3497 * DestinationMdlChain: the dst mdl
3498 * DestinationOffset: the offset where data are to be copied.
3499 * BytesTobecopied: the expteced bytes to be copied
3500 * BytesCopied: to store the really copied data length
3503 * NTSTATUS: STATUS_SUCCESS or other error code
3506 * The length of source mdl must be >= SourceOffset + BytesTobecopied
3510 KsCopyMdlChainToMdlChain(
3511 IN PMDL SourceMdlChain,
3512 IN ULONG SourceOffset,
3513 IN PMDL DestinationMdlChain,
3514 IN ULONG DestinationOffset,
3515 IN ULONG BytesTobecopied,
3516 OUT PULONG BytesCopied
3519 PMDL SrcMdl = SourceMdlChain;
3520 PMDL DstMdl = DestinationMdlChain;
3522 PUCHAR SrcBuf = NULL;
3523 PUCHAR DstBuf = NULL;
3527 NTSTATUS Status = STATUS_SUCCESS;
3530 while (dwBytes < BytesTobecopied) {
3534 while (MmGetMdlByteCount(SrcMdl) <= SourceOffset) {
3536 SourceOffset -= MmGetMdlByteCount(SrcMdl);
3538 SrcMdl = SrcMdl->Next;
3540 if (NULL == SrcMdl) {
3542 Status = STATUS_INVALID_PARAMETER;
3547 while (MmGetMdlByteCount(DstMdl) <= DestinationOffset) {
3549 DestinationOffset -= MmGetMdlByteCount(DstMdl);
3551 DstMdl = DstMdl->Next;
3553 if (NULL == DstMdl) {
3555 Status = STATUS_INVALID_PARAMETER;
3560 DstBuf = (PUCHAR)KsMapMdlBuffer(DstMdl);
3562 if ((NULL == DstBuf)) {
3563 Status = STATUS_INSUFFICIENT_RESOURCES;
3568 // Here we need skip the OVERFLOW case via RtlCopyMemory :-(
3571 if ( KsQueryMdlsSize(SrcMdl) - SourceOffset >
3572 MmGetMdlByteCount(DstMdl) - DestinationOffset ) {
3574 Length = BytesTobecopied - dwBytes;
3576 if (Length > KsQueryMdlsSize(SrcMdl) - SourceOffset) {
3577 Length = KsQueryMdlsSize(SrcMdl) - SourceOffset;
3580 if (Length > MmGetMdlByteCount(DstMdl) - DestinationOffset) {
3581 Length = MmGetMdlByteCount(DstMdl) - DestinationOffset;
3584 SrcBuf = (PUCHAR)KsMapMdlBuffer(SrcMdl);
3586 if ((NULL == DstBuf)) {
3587 Status = STATUS_INSUFFICIENT_RESOURCES;
3592 DstBuf + DestinationOffset,
3593 SrcBuf + SourceOffset,
3599 Status = TdiCopyMdlToBuffer(
3604 MmGetMdlByteCount(DstMdl),
3608 if (STATUS_BUFFER_OVERFLOW == Status) {
3609 cfs_enter_debugger();
3610 } else if (!NT_SUCCESS(Status)) {
3611 cfs_enter_debugger();
3616 SourceOffset += Length;
3617 DestinationOffset += Length;
3623 if (NT_SUCCESS(Status)) {
3624 *BytesCopied = dwBytes;
3636 * Query the whole size of a MDL (may be chained)
3639 * Mdl: the Mdl to be queried
3642 * ULONG: the total size of the mdl
3649 KsQueryMdlsSize (PMDL Mdl)
3656 // Walking the MDL Chain ...
3660 Length += MmGetMdlByteCount(Next);
3670 * Allocate MDL for the buffer and lock the pages into
3674 * UserBuffer: the user buffer to be locked
3675 * Length: length in bytes of the buffer
3676 * Operation: read or write access
3677 * pMdl: the result of the created mdl
3680 * NTSTATUS: kernel status code (STATUS_SUCCESS
3681 * or other error code)
3689 IN PVOID UserBuffer,
3692 IN LOCK_OPERATION Operation,
3699 LASSERT(UserBuffer != NULL);
3703 Mdl = IoAllocateMdl(
3713 Status = STATUS_INSUFFICIENT_RESOURCES;
3720 MmProbeAndLockPages(
3726 MmBuildMdlForNonPagedPool(
3731 Status = STATUS_SUCCESS;
3735 } __except (EXCEPTION_EXECUTE_HANDLER) {
3741 cfs_enter_debugger();
3743 Status = STATUS_INVALID_USER_BUFFER;
3752 * Map the mdl into a buffer in kernel space
3755 * Mdl: the mdl to be mapped
3758 * PVOID: the buffer mapped or NULL in failure
3765 KsMapMdlBuffer (PMDL Mdl)
3767 LASSERT(Mdl != NULL);
3769 return MmGetSystemAddressForMdlSafe(
3778 * Unlock all the pages in the mdl
3781 * Mdl: memory description list to be released
3791 KsReleaseMdl (IN PMDL Mdl,
3794 LASSERT(Mdl != NULL);
3815 * allocate MDL for the user spepcified buffer and lock (paging-in)
3816 * all the pages of the buffer into system memory
3819 * buffer: the user buffer to be locked
3820 * length: length in bytes of the buffer
3821 * access: read or write access
3822 * mdl: the result of the created mdl
3825 * int: the ks error code: 0: success / -x: failture
3836 LOCK_OPERATION access,
3842 status = KsLockUserBuffer(
3850 return cfs_error_code(status);
3856 * Map the mdl pages into kernel space
3859 * mdl: the mdl to be mapped
3862 * void *: the buffer mapped or NULL in failure
3869 ks_map_mdl (ksock_mdl_t * mdl)
3871 LASSERT(mdl != NULL);
3873 return KsMapMdlBuffer(mdl);
3878 * Unlock all the pages in the mdl and release the mdl
3881 * mdl: memory description list to be released
3891 ks_release_mdl (ksock_mdl_t *mdl, int paged)
3893 LASSERT(mdl != NULL);
3895 KsReleaseMdl(mdl, paged);
3901 * allocate a new tconn structure from the SLAB cache or
3902 * NonPaged sysetm pool
3908 * ksock_tconn_t *: the address of tconn or NULL if it fails
3917 ksock_tconn_t * tconn = NULL;
3919 /* allocate ksoc_tconn_t from the slab cache memory */
3921 tconn = (ksock_tconn_t *)cfs_mem_cache_alloc(
3922 ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
3926 /* zero tconn elements */
3927 memset(tconn, 0, sizeof(ksock_tconn_t));
3929 /* initialize the tconn ... */
3930 tconn->kstc_magic = KS_TCONN_MAGIC;
3932 ExInitializeWorkItem(
3933 &(tconn->kstc_disconnect.WorkItem),
3935 &(tconn->kstc_disconnect)
3939 &(tconn->kstc_disconnect.Event),
3940 SynchronizationEvent,
3943 ExInitializeWorkItem(
3944 &(tconn->kstc_destroy),
3949 spin_lock_init(&(tconn->kstc_lock));
3951 ks_get_tconn(tconn);
3953 spin_lock(&(ks_data.ksnd_tconn_lock));
3955 /* attach it into global list in ks_data */
3957 list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
3958 ks_data.ksnd_ntconns++;
3959 spin_unlock(&(ks_data.ksnd_tconn_lock));
3961 tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
3970 * free the tconn structure to the SLAB cache or NonPaged
3974 * tconn: the tcon is to be freed
3984 ks_free_tconn(ksock_tconn_t * tconn)
3986 LASSERT(atomic_read(&(tconn->kstc_refcount)) == 0);
3988 spin_lock(&(ks_data.ksnd_tconn_lock));
3990 /* remove it from the global list */
3991 list_del(&tconn->kstc_list);
3992 ks_data.ksnd_ntconns--;
3994 /* if this is the last tconn, it would be safe for
3995 ks_tdi_fini_data to quit ... */
3996 if (ks_data.ksnd_ntconns == 0) {
3997 cfs_wake_event(&ks_data.ksnd_tconn_exit);
3999 spin_unlock(&(ks_data.ksnd_tconn_lock));
4001 /* free the structure memory */
4002 cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
4008 * Initialize the tconn as a listener (daemon)
4011 * tconn: the listener tconn
4022 ksock_tconn_t * tconn
4025 /* preparation: intialize the tconn members */
4027 tconn->kstc_type = kstt_listener;
4029 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4031 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
4032 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
4034 cfs_init_event( &(tconn->listener.kstc_accept_event),
4038 cfs_init_event( &(tconn->listener.kstc_destroy_event),
4042 tconn->kstc_state = ksts_inited;
4048 * Initialize the tconn as a sender
4051 * tconn: the sender tconn
4062 ksock_tconn_t * tconn
4065 tconn->kstc_type = kstt_sender;
4066 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4068 KsInitializeKsChain(&(tconn->sender.kstc_recv));
4069 KsInitializeKsChain(&(tconn->sender.kstc_send));
4071 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4072 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4074 tconn->kstc_state = ksts_inited;
4079 * Initialize the tconn as a child
4082 * tconn: the child tconn
4093 ksock_tconn_t * tconn
4096 tconn->kstc_type = kstt_child;
4097 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4099 KsInitializeKsChain(&(tconn->child.kstc_recv));
4100 KsInitializeKsChain(&(tconn->child.kstc_send));
4102 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4103 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4105 tconn->kstc_state = ksts_inited;
4110 * increase the reference count of the tconn with 1
4113 * tconn: the tdi connection to be referred
4124 ksock_tconn_t * tconn
4127 atomic_inc(&(tconn->kstc_refcount));
4132 * decrease the reference count of the tconn and destroy
4133 * it if the refercount becomes 0.
4136 * tconn: the tdi connection to be dereferred
4147 ksock_tconn_t *tconn
4150 if (atomic_dec_and_test(&(tconn->kstc_refcount))) {
4152 spin_lock(&(tconn->kstc_lock));
4154 if ( ( tconn->kstc_type == kstt_child ||
4155 tconn->kstc_type == kstt_sender ) &&
4156 ( tconn->kstc_state == ksts_connected ) ) {
4158 spin_unlock(&(tconn->kstc_lock));
4160 ks_abort_tconn(tconn);
4164 if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
4165 cfs_enter_debugger();
4168 &(tconn->kstc_destroy),
4172 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
4175 spin_unlock(&(tconn->kstc_lock));
4182 * cleanup the tdi connection and free it
4185 * tconn: the tdi connection to be cleaned.
4196 ksock_tconn_t * tconn
4199 LASSERT(tconn->kstc_refcount.counter == 0);
4201 if (tconn->kstc_type == kstt_listener) {
4203 ks_reset_handlers(tconn);
4205 /* for listener, we just need to close the address object */
4207 tconn->kstc_addr.Handle,
4208 tconn->kstc_addr.FileObject
4211 tconn->kstc_state = ksts_inited;
4213 } else if (tconn->kstc_type == kstt_child) {
4215 /* for child tdi conections */
4217 /* disassociate the relation between it's connection object
4218 and the address object */
4220 if (tconn->kstc_state == ksts_associated) {
4221 KsDisassociateAddress(
4222 tconn->child.kstc_info.FileObject
4226 /* release the connection object */
4229 tconn->child.kstc_info.Handle,
4230 tconn->child.kstc_info.FileObject
4233 /* release it's refer of it's parent's address object */
4236 tconn->kstc_addr.FileObject
4239 spin_lock(&tconn->child.kstc_parent->kstc_lock);
4240 spin_lock(&tconn->kstc_lock);
4242 tconn->kstc_state = ksts_inited;
4244 /* remove it frome it's parent's queues */
4246 if (tconn->child.kstc_queued) {
4248 list_del(&(tconn->child.kstc_link));
4250 if (tconn->child.kstc_queueno) {
4252 LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
4253 tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
4257 LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
4258 tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
4261 tconn->child.kstc_queued = FALSE;
4264 spin_unlock(&tconn->kstc_lock);
4265 spin_unlock(&tconn->child.kstc_parent->kstc_lock);
4267 /* drop the reference of the parent tconn */
4268 ks_put_tconn(tconn->child.kstc_parent);
4270 } else if (tconn->kstc_type == kstt_sender) {
4272 ks_reset_handlers(tconn);
4274 /* release the connection object */
4277 tconn->sender.kstc_info.Handle,
4278 tconn->sender.kstc_info.FileObject
4281 /* release it's refer of it's parent's address object */
4283 tconn->kstc_addr.Handle,
4284 tconn->kstc_addr.FileObject
4287 tconn->kstc_state = ksts_inited;
4290 cfs_enter_debugger();
4293 /* free the tconn structure ... */
4295 ks_free_tconn(tconn);
4300 ksock_tconn_t * tconn,
4307 PKS_TSDUMGR KsTsduMgr;
4311 ks_get_tconn(tconn);
4312 spin_lock(&(tconn->kstc_lock));
4314 if ( tconn->kstc_type != kstt_sender &&
4315 tconn->kstc_type != kstt_child) {
4317 spin_unlock(&(tconn->kstc_lock));
4321 if (tconn->kstc_state != ksts_connected) {
4323 spin_unlock(&(tconn->kstc_lock));
4327 if (tconn->kstc_type == kstt_sender) {
4328 KsChain = &(tconn->sender.kstc_recv);
4330 LASSERT(tconn->kstc_type == kstt_child);
4331 KsChain = &(tconn->child.kstc_recv);
4335 KsTsduMgr = &(KsChain->Expedited);
4337 KsTsduMgr = &(KsChain->Normal);
4340 *size = KsTsduMgr->TotalBytes;
4341 spin_unlock(&(tconn->kstc_lock));
4345 ks_put_tconn(tconn);
4352 * Query the the options of the tcp stream connnection
4355 * tconn: the tdi connection
4357 * OptionValue: buffer to store the option value
4358 * Length: the length of the value, to be returned
4361 * int: ks return code
4369 ksock_tconn_t * tconn,
4375 NTSTATUS Status = STATUS_SUCCESS;
4377 IO_STATUS_BLOCK IoStatus;
4379 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
4381 PFILE_OBJECT ConnectionObject;
4382 PDEVICE_OBJECT DeviceObject = NULL;
4385 PIO_STACK_LOCATION IrpSp = NULL;
4389 /* make sure the tdi connection is connected ? */
4391 ks_get_tconn(tconn);
4393 if (tconn->kstc_state != ksts_connected) {
4394 Status = STATUS_INVALID_PARAMETER;
4398 LASSERT(tconn->kstc_type == kstt_sender ||
4399 tconn->kstc_type == kstt_child);
4401 if (tconn->kstc_type == kstt_sender) {
4402 ConnectionObject = tconn->sender.kstc_info.FileObject;
4404 ConnectionObject = tconn->child.kstc_info.FileObject;
4407 QueryInfoEx.ID.toi_id = ID;
4408 QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
4409 QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
4410 QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
4411 QueryInfoEx.ID.toi_entity.tei_instance = 0;
4413 RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
4415 KeInitializeEvent(&Event, NotificationEvent, FALSE);
4416 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4418 Irp = IoBuildDeviceIoControlRequest(
4419 IOCTL_TCP_QUERY_INFORMATION_EX,
4422 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
4431 Status = STATUS_INSUFFICIENT_RESOURCES;
4435 IrpSp = IoGetNextIrpStackLocation(Irp);
4437 if (IrpSp == NULL) {
4441 Status = STATUS_INSUFFICIENT_RESOURCES;
4445 IrpSp->FileObject = ConnectionObject;
4446 IrpSp->DeviceObject = DeviceObject;
4448 Status = IoCallDriver(DeviceObject, Irp);
4450 if (Status == STATUS_PENDING) {
4452 KeWaitForSingleObject(
4460 Status = IoStatus.Status;
4464 if (NT_SUCCESS(Status)) {
4465 *Length = IoStatus.Information;
4467 cfs_enter_debugger();
4468 memset(OptionValue, 0, *Length);
4469 Status = STATUS_SUCCESS;
4474 ks_put_tconn(tconn);
4476 return cfs_error_code(Status);
4481 * Set the the options for the tcp stream connnection
4484 * tconn: the tdi connection
4486 * OptionValue: buffer containing the new option value
4487 * Length: the length of the value
4490 * int: ks return code
4498 ksock_tconn_t * tconn,
4504 NTSTATUS Status = STATUS_SUCCESS;
4506 IO_STATUS_BLOCK IoStatus;
4508 ULONG SetInfoExLength;
4509 PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
4511 PFILE_OBJECT ConnectionObject;
4512 PDEVICE_OBJECT DeviceObject = NULL;
4515 PIO_STACK_LOCATION IrpSp = NULL;
4519 /* make sure the tdi connection is connected ? */
4521 ks_get_tconn(tconn);
4523 if (tconn->kstc_state != ksts_connected) {
4524 Status = STATUS_INVALID_PARAMETER;
4528 LASSERT(tconn->kstc_type == kstt_sender ||
4529 tconn->kstc_type == kstt_child);
4531 if (tconn->kstc_type == kstt_sender) {
4532 ConnectionObject = tconn->sender.kstc_info.FileObject;
4534 ConnectionObject = tconn->child.kstc_info.FileObject;
4537 SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
4539 SetInfoEx = ExAllocatePoolWithTag(
4545 if (SetInfoEx == NULL) {
4546 Status = STATUS_INSUFFICIENT_RESOURCES;
4550 SetInfoEx->ID.toi_id = ID;
4552 SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
4553 SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
4554 SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
4555 SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
4557 SetInfoEx->BufferSize = Length;
4558 RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
4560 Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
4561 KeInitializeEvent(Event, NotificationEvent, FALSE);
4563 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4565 Irp = IoBuildDeviceIoControlRequest(
4566 IOCTL_TCP_SET_INFORMATION_EX,
4578 Status = STATUS_INSUFFICIENT_RESOURCES;
4582 IrpSp = IoGetNextIrpStackLocation(Irp);
4584 if (IrpSp == NULL) {
4587 Status = STATUS_INSUFFICIENT_RESOURCES;
4591 IrpSp->FileObject = ConnectionObject;
4592 IrpSp->DeviceObject = DeviceObject;
4594 Status = IoCallDriver(DeviceObject, Irp);
4596 if (Status == STATUS_PENDING) {
4598 KeWaitForSingleObject(
4606 Status = IoStatus.Status;
4612 ExFreePool(SetInfoEx);
4615 if (!NT_SUCCESS(Status)) {
4616 printk("ks_set_tcp_option: error setup tcp option: ID (%d), Status = %xh\n",
4618 Status = STATUS_SUCCESS;
4621 ks_put_tconn(tconn);
4623 return cfs_error_code(Status);
4628 * bind the tdi connection object with an address
4631 * tconn: tconn to be bound
4632 * parent: the parent tconn object
4633 * ipaddr: the ip address
4634 * port: the port number
4637 * int: 0 for success or ks error codes.
4645 ksock_tconn_t * tconn,
4646 ksock_tconn_t * parent,
4654 ksock_tdi_addr_t taddr;
4656 memset(&taddr, 0, sizeof(ksock_tdi_addr_t));
4658 if (tconn->kstc_state != ksts_inited) {
4660 status = STATUS_INVALID_PARAMETER;
4661 rc = cfs_error_code(status);
4665 } else if (tconn->kstc_type == kstt_child) {
4667 if (NULL == parent) {
4668 status = STATUS_INVALID_PARAMETER;
4669 rc = cfs_error_code(status);
4674 /* refer it's parent's address object */
4676 taddr = parent->kstc_addr;
4677 ObReferenceObject(taddr.FileObject);
4679 ks_get_tconn(parent);
4683 PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
4686 /* intialize the tdi address*/
4688 TdiAddress->TAAddressCount = 1;
4689 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
4690 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
4692 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
4693 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = htonl(addr);
4695 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
4698 /* open the transport address object */
4700 AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
4701 TDI_ADDRESS_LENGTH_IP;
4703 status = KsOpenAddress(
4711 if (!NT_SUCCESS(status)) {
4713 KsPrint((0, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
4714 addr, port, status ));
4715 rc = cfs_error_code(status);
4720 if (tconn->kstc_type == kstt_child) {
4721 tconn->child.kstc_parent = parent;
4724 tconn->kstc_state = ksts_bind;
4725 tconn->kstc_addr = taddr;
4734 * build tcp/streaming connection to remote peer
4737 * tconn: tconn to be connected to the peer
4738 * addr: the peer's ip address
4739 * port: the peer's port number
4742 * int: 0 for success or ks error codes.
4750 ksock_tconn_t * tconn,
4756 NTSTATUS status = STATUS_SUCCESS;
4759 PFILE_OBJECT ConnectionObject = NULL;
4760 PDEVICE_OBJECT DeviceObject = NULL;
4762 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
4767 LASSERT(tconn->kstc_type == kstt_sender);
4768 LASSERT(tconn->kstc_state == ksts_bind);
4770 ks_get_tconn(tconn);
4773 /* set the event callbacks */
4774 rc = ks_set_handlers(tconn);
4777 cfs_enter_debugger();
4782 /* create the connection file handle / object */
4783 status = KsOpenConnection(
4785 (CONNECTION_CONTEXT)tconn,
4786 &(tconn->sender.kstc_info.Handle),
4787 &(tconn->sender.kstc_info.FileObject)
4790 if (!NT_SUCCESS(status)) {
4791 rc = cfs_error_code(status);
4792 cfs_enter_debugger();
4796 /* associdate the the connection with the adress object of the tconn */
4798 status = KsAssociateAddress(
4799 tconn->kstc_addr.Handle,
4800 tconn->sender.kstc_info.FileObject
4803 if (!NT_SUCCESS(status)) {
4804 rc = cfs_error_code(status);
4805 cfs_enter_debugger();
4809 tconn->kstc_state = ksts_associated;
4811 /* Allocating Connection Info Together with the Address */
4812 AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
4813 + TDI_ADDRESS_LENGTH_IP;
4815 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
4816 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
4818 if (NULL == ConnectionInfo) {
4820 status = STATUS_INSUFFICIENT_RESOURCES;
4821 rc = cfs_error_code(status);
4822 cfs_enter_debugger();
4826 /* Initializing ConnectionInfo ... */
4828 PTRANSPORT_ADDRESS TdiAddress;
4830 /* ConnectionInfo settings */
4832 ConnectionInfo->UserDataLength = 0;
4833 ConnectionInfo->UserData = NULL;
4834 ConnectionInfo->OptionsLength = 0;
4835 ConnectionInfo->Options = NULL;
4836 ConnectionInfo->RemoteAddressLength = AddrLength;
4837 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
4840 /* intialize the tdi address*/
4842 TdiAddress = ConnectionInfo->RemoteAddress;
4844 TdiAddress->TAAddressCount = 1;
4845 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
4846 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
4848 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
4849 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = htonl(addr);
4851 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
4854 /* Now prepare to connect the remote peer ... */
4856 ConnectionObject = tconn->sender.kstc_info.FileObject;
4857 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4859 /* allocate a new Irp */
4861 Irp = KsBuildTdiIrp(DeviceObject);
4865 status = STATUS_INSUFFICIENT_RESOURCES;
4866 rc = cfs_error_code(status);
4867 cfs_enter_debugger();
4885 /* sumbit the Irp to the underlying transport driver */
4886 status = KsSubmitTdiIrp(
4893 spin_lock(&(tconn->kstc_lock));
4895 if (NT_SUCCESS(status)) {
4897 /* Connected! the conneciton is built successfully. */
4899 tconn->kstc_state = ksts_connected;
4901 tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
4902 tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
4904 spin_unlock(&(tconn->kstc_lock));
4908 /* Not connected! Abort it ... */
4911 cfs_enter_debugger();
4915 rc = cfs_error_code(status);
4917 tconn->kstc_state = ksts_associated;
4918 spin_unlock(&(tconn->kstc_lock));
4920 /* disassocidate the connection and the address object,
4921 after cleanup, it's safe to set the state to abort ... */
4923 if ( NT_SUCCESS(KsDisassociateAddress(
4924 tconn->sender.kstc_info.FileObject))) {
4925 tconn->kstc_state = ksts_aborted;
4928 /* reset the event callbacks */
4929 rc = ks_reset_handlers(tconn);
4936 if (NT_SUCCESS(status)) {
4938 ks_query_local_ipaddr(tconn);
4942 if (ConnectionInfo) {
4943 ExFreePool(ConnectionInfo);
4950 ks_put_tconn(tconn);
4957 * ks_disconnect_tconn
4958 * disconnect the tconn from a connection
4961 * tconn: the tdi connecton object connected already
4962 * flags: flags & options for disconnecting
4965 * int: ks error code
4972 ks_disconnect_tconn(
4973 ksock_tconn_t * tconn,
4977 NTSTATUS status = STATUS_SUCCESS;
4979 ksock_tconn_info_t * info;
4981 PFILE_OBJECT ConnectionObject;
4982 PDEVICE_OBJECT DeviceObject = NULL;
4988 ks_get_tconn(tconn);
4990 /* make sure tt's connected already and it
4991 must be a sender or a child ... */
4993 LASSERT(tconn->kstc_state == ksts_connected);
4994 LASSERT( tconn->kstc_type == kstt_sender ||
4995 tconn->kstc_type == kstt_child);
4997 /* reset all the event handlers to NULL */
4999 if (tconn->kstc_type != kstt_child) {
5000 ks_reset_handlers (tconn);
5003 /* Disconnecting to the remote peer ... */
5005 if (tconn->kstc_type == kstt_sender) {
5006 info = &(tconn->sender.kstc_info);
5008 info = &(tconn->child.kstc_info);
5011 ConnectionObject = info->FileObject;
5012 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5014 /* allocate an Irp and setup it */
5016 Irp = KsBuildTdiIrp(DeviceObject);
5020 status = STATUS_INSUFFICIENT_RESOURCES;
5021 cfs_enter_debugger();
5027 SynchronizationEvent,
5035 KsDisconectCompletionRoutine,
5043 /* issue the Irp to the underlying transport
5044 driver to disconnect the connection */
5046 status = IoCallDriver(DeviceObject, Irp);
5048 if (STATUS_PENDING == status) {
5050 status = KeWaitForSingleObject(
5058 status = Irp->IoStatus.Status;
5061 KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
5062 status, KsNtStatusToString(status)));
5066 if (info->ConnectionInfo) {
5068 /* disassociate the association between connection/address objects */
5070 status = KsDisassociateAddress(ConnectionObject);
5072 if (!NT_SUCCESS(status)) {
5073 cfs_enter_debugger();
5076 spin_lock(&(tconn->kstc_lock));
5078 /* cleanup the tsdumgr Lists */
5079 KsCleanupTsdu (tconn);
5081 /* set the state of the tconn */
5082 if (NT_SUCCESS(status)) {
5083 tconn->kstc_state = ksts_disconnected;
5085 tconn->kstc_state = ksts_associated;
5088 /* free the connection info to system pool*/
5089 ExFreePool(info->ConnectionInfo);
5090 info->ConnectionInfo = NULL;
5091 info->Remote = NULL;
5093 spin_unlock(&(tconn->kstc_lock));
5096 status = STATUS_SUCCESS;
5100 ks_put_tconn(tconn);
5102 return cfs_error_code(status);
5108 * The connection is broken un-expectedly. We need do
5112 * tconn: the tdi connection
5123 ksock_tconn_t * tconn
5126 PKS_DISCONNECT_WORKITEM WorkItem = NULL;
5128 WorkItem = &(tconn->kstc_disconnect);
5130 ks_get_tconn(tconn);
5131 spin_lock(&(tconn->kstc_lock));
5133 if (tconn->kstc_state != ksts_connected) {
5134 ks_put_tconn(tconn);
5137 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
5139 WorkItem->Flags = TDI_DISCONNECT_ABORT;
5140 WorkItem->tconn = tconn;
5142 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
5145 &(WorkItem->WorkItem),
5151 spin_unlock(&(tconn->kstc_lock));
5156 * ks_query_local_ipaddr
5157 * query the local connection ip address
5160 * tconn: the tconn which is connected
5163 * int: ks error code
5170 ks_query_local_ipaddr(
5171 ksock_tconn_t * tconn
5174 PFILE_OBJECT FileObject = NULL;
5177 PTRANSPORT_ADDRESS TdiAddress;
5178 ULONG AddressLength;
5180 if (tconn->kstc_type == kstt_sender) {
5181 FileObject = tconn->sender.kstc_info.FileObject;
5182 } else if (tconn->kstc_type == kstt_child) {
5183 FileObject = tconn->child.kstc_info.FileObject;
5185 status = STATUS_INVALID_PARAMETER;
5189 TdiAddress = &(tconn->kstc_addr.Tdi);
5190 AddressLength = MAX_ADDRESS_LENGTH;
5192 status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
5194 if (NT_SUCCESS(status)) {
5196 KsPrint((0, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
5197 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
5198 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
5200 KsPrint((0, "KsQueryonnectionIpAddress: Failed to query the connection local ip address.\n"));
5205 return cfs_error_code(status);
5210 * send MDL chain to the peer for a stream connection
5213 * tconn: tdi connection object
5214 * tx: the transmit context
5215 * mdl: the mdl chain containing the data
5216 * len: length of the data
5217 * flags: flags of the transmission
5228 ksock_tconn_t * tconn,
5239 ksock_tdi_tx_t * context;
5242 PKS_TSDUMGR KsTsduMgr;
5244 PKS_TSDU_BUF KsTsduBuf;
5245 PKS_TSDU_DAT KsTsduDat;
5247 BOOLEAN bNewTsdu = FALSE; /* newly allocated */
5248 BOOLEAN bNewBuff = FALSE; /* newly allocated */
5250 BOOLEAN bBuffed; /* bufferred sending */
5252 PUCHAR Buffer = NULL;
5253 ksock_mdl_t * NewMdl = NULL;
5256 PFILE_OBJECT ConnObject;
5257 PDEVICE_OBJECT DeviceObject;
5259 BOOLEAN bIsNonBlock;
5261 ks_get_tconn(tconn);
5263 tflags = ks_tdi_send_flags(flags);
5264 bIsNonBlock = cfs_is_flag_set(flags, MSG_DONTWAIT);
5266 spin_lock(&tconn->kstc_lock);
5268 LASSERT( tconn->kstc_type == kstt_sender ||
5269 tconn->kstc_type == kstt_child );
5271 if (tconn->kstc_state != ksts_connected) {
5272 spin_unlock(&tconn->kstc_lock);
5273 ks_put_tconn(tconn);
5277 /* get the latest Tsdu buffer form TsduMgr list.
5278 just set NULL if the list is empty. */
5280 if (tconn->kstc_type == kstt_sender) {
5281 KsChain = &(tconn->sender.kstc_send);
5283 LASSERT(tconn->kstc_type == kstt_child);
5284 KsChain = &(tconn->child.kstc_send);
5287 if (cfs_is_flag_set(tflags, TDI_SEND_EXPEDITED)) {
5288 KsTsduMgr = &(KsChain->Expedited);
5290 KsTsduMgr = &(KsChain->Normal);
5293 if (KsTsduMgr->TotalBytes + len <= tconn->kstc_snd_wnd) {
5299 /* do the preparation work for bufferred sending */
5303 /* if the data is even larger than the biggest Tsdu, we have
5304 to allocate new buffer and use TSDU_TYOE_BUF to store it */
5306 if ( KS_TSDU_STRU_SIZE((ULONG)len) > ks_data.ksnd_tsdu_size
5307 - KS_DWORD_ALIGN(sizeof(KS_TSDU))) {
5311 if (list_empty(&(KsTsduMgr->TsduList))) {
5313 LASSERT(KsTsduMgr->NumOfTsdu == 0);
5318 LASSERT(KsTsduMgr->NumOfTsdu > 0);
5319 KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
5320 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
5323 /* check whether KsTsdu free space is enough, or we need alloc new Tsdu */
5325 if (sizeof(KS_TSDU_BUF) + KsTsdu->LastOffset > KsTsdu->TotalLength) {
5329 if ( KS_TSDU_STRU_SIZE((ULONG)len) >
5330 KsTsdu->TotalLength - KsTsdu->LastOffset ) {
5336 /* if there's no Tsdu or the free size is not enough for the
5337 KS_TSDU_BUF or KS_TSDU_DAT. We need re-allocate a new Tsdu. */
5339 if (NULL == KsTsdu) {
5341 KsTsdu = KsAllocateKsTsdu();
5343 if (NULL == KsTsdu) {
5351 /* process the case that a new buffer is to be allocated from system memory */
5354 /* now allocating internal buffer to contain the payload */
5355 Buffer = ExAllocatePool(NonPagedPool, len);
5357 if (NULL == Buffer) {
5367 /* queue a new KS_TSDU_BUF to the Tsdu buffer */
5368 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
5370 KsTsduBuf->TsduFlags = 0;
5371 KsTsduBuf->DataLength = (ULONG)len;
5372 KsTsduBuf->StartOffset = 0;
5373 KsTsduBuf->UserBuffer = Buffer;
5375 /* queue a new KS_TSDU_BUF to the Tsdu buffer */
5376 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
5378 KsTsduDat->TsduFlags = 0;
5379 KsTsduDat->DataLength = (ULONG)len;
5380 KsTsduDat->StartOffset = 0;
5381 KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE((ULONG)len);
5383 Buffer = &KsTsduDat->Data[0];
5386 /* now locking the Buffer and copy user payload into the buffer */
5387 ASSERT(Buffer != NULL);
5389 rc = ks_lock_buffer(Buffer, FALSE, len, IoReadAccess, &NewMdl);
5391 printk("ks_send_mdl: bufferred: error allocating mdl.\n");
5394 ULONG BytesCopied = 0;
5395 TdiCopyMdlToBuffer(mdl, 0, Buffer, 0, (ULONG)len, &BytesCopied);
5396 if (BytesCopied != (ULONG) len) {
5401 /* Do the finializing job if we succeed to to lock the buffer and move
5402 user data. Or we need do cleaning up ... */
5406 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
5407 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
5410 KsTsduDat->TsduType = TSDU_TYPE_DAT;
5411 KsTsdu->LastOffset += KsTsduDat->TotalLength;
5414 /* attach it to the TsduMgr list if the Tsdu is newly created. */
5417 list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
5418 KsTsduMgr->NumOfTsdu++;
5424 ks_release_mdl(NewMdl, FALSE);
5436 /* update the TotalBytes being in sending */
5437 KsTsduMgr->TotalBytes += (ULONG)len;
5439 spin_unlock(&tconn->kstc_lock);
5441 /* cleanup the Tsdu if not successful */
5442 if (!bBuffed && bNewTsdu) {
5443 KsPutKsTsdu(KsTsdu);
5448 /* we need allocate the ksock_tx_t structure from memory pool. */
5450 context = cfs_alloc(sizeof(ksock_tdi_tx_t) + sizeof(KEVENT),0);
5452 /* release the chained mdl */
5453 ks_release_mdl(mdl, FALSE);
5455 Status = STATUS_INSUFFICIENT_RESOURCES;
5459 /* intialize the TcpContext */
5461 memset(context,0, sizeof(ksock_tdi_tx_t) + sizeof(KEVENT));
5463 context->tconn = tconn;
5464 context->Event = (PKEVENT) ((PUCHAR)context + sizeof(ksock_tdi_tx_t));
5466 KeInitializeEvent(context->Event, SynchronizationEvent, FALSE);
5470 /* for bufferred transmission, we need set
5471 the internal completion routine. */
5473 context->CompletionRoutine = KsTcpSendCompletionRoutine;
5474 context->KsTsduMgr = KsTsduMgr;
5475 context->CompletionContext = KsTsdu;
5476 context->CompletionContext2 = (bNewBuff ? (PVOID)KsTsduBuf : (PVOID)KsTsduDat);
5477 context->bCounted = FALSE;
5479 } else if (bIsNonBlock) {
5481 /* for non-blocking transmission, we need set
5482 the internal completion routine too. */
5484 context->CompletionRoutine = KsTcpSendCompletionRoutine;
5485 context->CompletionContext = tx;
5486 context->KsTsduMgr = KsTsduMgr;
5487 context->bCounted = TRUE;
5488 context->ReferCount = 2;
5491 if (tconn->kstc_type == kstt_sender) {
5492 ConnObject = tconn->sender.kstc_info.FileObject;
5494 LASSERT(tconn->kstc_type == kstt_child);
5495 ConnObject = tconn->child.kstc_info.FileObject;
5498 DeviceObject = IoGetRelatedDeviceObject(ConnObject);
5500 Irp = KsBuildTdiIrp(DeviceObject);
5504 /* release the chained mdl */
5505 ks_release_mdl(mdl, FALSE);
5507 Status = STATUS_INSUFFICIENT_RESOURCES;
5511 length = KsQueryMdlsSize(mdl);
5513 LASSERT((ULONG)len <= length);
5515 ks_get_tconn(tconn);
5521 KsTcpCompletionRoutine,
5523 (bBuffed ? NewMdl : mdl),
5524 (bBuffed ? (tflags | TDI_SEND_NON_BLOCKING) : tflags),
5528 Status = IoCallDriver(DeviceObject, Irp);
5531 ks_release_mdl(mdl, FALSE);
5535 if (!NT_SUCCESS(Status)) {
5536 cfs_enter_debugger();
5537 rc = cfs_error_code(Status);
5542 Status = STATUS_SUCCESS;
5547 if (InterlockedDecrement(&context->ReferCount) == 0) {
5548 Status = Irp->IoStatus.Status;
5550 Status = STATUS_PENDING;
5554 if (STATUS_PENDING == Status) {
5555 Status = KeWaitForSingleObject(
5563 if (NT_SUCCESS(Status)) {
5564 Status = Irp->IoStatus.Status;
5569 if (Status == STATUS_SUCCESS) {
5570 rc = (int)(Irp->IoStatus.Information);
5572 spin_lock(&tconn->kstc_lock);
5573 KsTsduMgr->TotalBytes -= rc;
5574 spin_unlock(&tconn->kstc_lock);
5577 rc = cfs_error_code(Status);
5586 ks_release_mdl(NewMdl, FALSE);
5591 if (!NT_SUCCESS(Status)) {
5599 if (Status != STATUS_PENDING) {
5603 /* Freeing the Irp ... */
5611 if (!NT_SUCCESS(Status)) {
5613 spin_lock(&tconn->kstc_lock);
5615 KsTsduMgr->TotalBytes -= (ULONG)len;
5619 /* attach it to the TsduMgr list if the Tsdu is newly created. */
5622 list_del(&(KsTsdu->Link));
5623 KsTsduMgr->NumOfTsdu--;
5625 KsPutKsTsdu(KsTsdu);
5628 if ( (ulong_ptr)KsTsduBuf + sizeof(KS_TSDU_BUF) ==
5629 (ulong_ptr)KsTsdu + KsTsdu->LastOffset) {
5630 KsTsdu->LastOffset -= sizeof(KS_TSDU_BUF);
5631 KsTsduBuf->TsduType = 0;
5633 cfs_enter_debugger();
5634 KsTsduBuf->StartOffset = KsTsduBuf->DataLength;
5637 if ( (ulong_ptr)KsTsduDat + KsTsduDat->TotalLength ==
5638 (ulong_ptr)KsTsdu + KsTsdu->LastOffset) {
5639 KsTsdu->LastOffset -= KsTsduDat->TotalLength;
5640 KsTsduDat->TsduType = 0;
5642 cfs_enter_debugger();
5643 KsTsduDat->StartOffset = KsTsduDat->DataLength;
5649 spin_unlock(&tconn->kstc_lock);
5652 /* free the context if is not used at all */
5657 ks_put_tconn(tconn);
5664 * Receive data from the peer for a stream connection
5667 * tconn: tdi connection object
5668 * mdl: the mdl chain to contain the incoming data
5669 * len: length of the data
5670 * flags: flags of the receiving
5681 ksock_tconn_t * tconn,
5687 NTSTATUS Status = STATUS_SUCCESS;
5690 BOOLEAN bIsNonBlock;
5691 BOOLEAN bIsExpedited;
5694 PKS_TSDUMGR KsTsduMgr;
5696 PKS_TSDU_DAT KsTsduDat;
5697 PKS_TSDU_BUF KsTsduBuf;
5698 PKS_TSDU_MDL KsTsduMdl;
5702 ULONG BytesRecved = 0;
5705 bIsNonBlock = cfs_is_flag_set(flags, MSG_DONTWAIT);
5706 bIsExpedited = cfs_is_flag_set(flags, MSG_OOB);
5708 ks_get_tconn(tconn);
5714 spin_lock(&(tconn->kstc_lock));
5716 if ( tconn->kstc_type != kstt_sender &&
5717 tconn->kstc_type != kstt_child) {
5720 spin_unlock(&(tconn->kstc_lock));
5725 if (tconn->kstc_state != ksts_connected) {
5728 spin_unlock(&(tconn->kstc_lock));
5733 if (tconn->kstc_type == kstt_sender) {
5734 KsChain = &(tconn->sender.kstc_recv);
5736 LASSERT(tconn->kstc_type == kstt_child);
5737 KsChain = &(tconn->child.kstc_recv);
5741 KsTsduMgr = &(KsChain->Expedited);
5743 KsTsduMgr = &(KsChain->Normal);
5748 if (list_empty(&(KsTsduMgr->TsduList))) {
5751 // It's a notification event. We need reset it to
5752 // un-signaled state in case there no any tsdus.
5755 KeResetEvent(&(KsTsduMgr->Event));
5759 KsTsdu = list_entry(KsTsduMgr->TsduList.next, KS_TSDU, Link);
5760 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
5762 /* remove the KsTsdu from TsduMgr list to release the lock */
5763 list_del(&(KsTsdu->Link));
5764 KsTsduMgr->NumOfTsdu--;
5766 spin_unlock(&(tconn->kstc_lock));
5768 while ((ULONG)size > BytesRecved) {
5770 ULONG BytesCopied = 0;
5771 ULONG BytesToCopy = 0;
5772 ULONG StartOffset = 0;
5774 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
5775 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
5776 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
5778 if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
5779 TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
5783 // Data Tsdu Unit ...
5786 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
5788 if (cfs_is_flag_set(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING)) {
5789 /* data is not ready yet*/
5790 KeResetEvent(&(KsTsduMgr->Event));
5791 printk("ks_recv_mdl: KsTsduDat (%xh) is not ready yet !!!!!!!\n", KsTsduDat);
5795 Buffer = &KsTsduDat->Data[0];
5796 StartOffset = KsTsduDat->StartOffset;
5797 if (KsTsduDat->DataLength - KsTsduDat->StartOffset > size - BytesRecved) {
5798 /* Recvmsg requst could be statisfied ... */
5799 BytesToCopy = size - BytesRecved;
5801 BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
5806 if (cfs_is_flag_set(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING)) {
5807 /* data is not ready yet*/
5808 KeResetEvent(&(KsTsduMgr->Event));
5809 DbgPrint("ks_recv_mdl: KsTsduBuf (%xh) is not ready yet !!!!!!!\n", KsTsduBuf);
5813 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
5814 Buffer = KsTsduBuf->UserBuffer;
5815 StartOffset = KsTsduBuf->StartOffset;
5817 if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > size - BytesRecved) {
5818 /* Recvmsg requst could be statisfied ... */
5819 BytesToCopy = size - BytesRecved;
5821 BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
5825 if (BytesToCopy > 0) {
5826 Status = TdiCopyBufferToMdl(
5835 if (NT_SUCCESS(Status)) {
5837 if (BytesToCopy != BytesCopied) {
5838 cfs_enter_debugger();
5841 BytesRecved += BytesCopied;
5842 RecvedOnce += BytesCopied;
5846 cfs_enter_debugger();
5848 if (STATUS_BUFFER_OVERFLOW == Status) {
5853 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
5855 KsTsduDat->StartOffset += BytesCopied;
5857 if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
5858 KsTsdu->StartOffset += KsTsduDat->TotalLength;
5863 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
5864 KsTsduBuf->StartOffset += BytesCopied;
5865 if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
5866 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
5867 /* now we need release the buf to system pool */
5868 ExFreePool(KsTsduBuf->UserBuffer);
5872 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
5875 // MDL Tsdu Unit ...
5878 if (KsTsduMdl->DataLength > size - BytesRecved) {
5880 /* Recvmsg requst could be statisfied ... */
5882 BytesToCopy = size - BytesRecved;
5886 BytesToCopy = KsTsduMdl->DataLength;
5889 Status = KsCopyMdlChainToMdlChain(
5891 KsTsduMdl->StartOffset,
5898 if (NT_SUCCESS(Status)) {
5900 if (BytesToCopy != BytesCopied) {
5901 cfs_enter_debugger();
5904 KsTsduMdl->StartOffset += BytesCopied;
5905 KsTsduMdl->DataLength -= BytesCopied;
5907 BytesRecved += BytesCopied;
5908 RecvedOnce += BytesCopied;
5910 cfs_enter_debugger();
5913 if (0 == KsTsduMdl->DataLength) {
5916 // Call TdiReturnChainedReceives to release the Tsdu memory
5919 TdiReturnChainedReceives(
5920 &(KsTsduMdl->Descriptor),
5923 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
5927 printk("ks_recv_mdl: unknown tsdu slot: slot = %x type = %x Start= %x\n",
5928 KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength);
5929 printk(" Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x",
5930 KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength);
5931 cfs_enter_debugger();
5934 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
5937 // KsTsdu is empty now, we need free it ...
5940 KsPutKsTsdu(KsTsdu);
5947 spin_lock(&(tconn->kstc_lock));
5949 /* we need attach the KsTsdu to the list header */
5951 KsTsduMgr->NumOfTsdu++;
5952 list_add(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
5953 } else if ((ULONG)size > BytesRecved) {
5958 if (KsTsduMgr->TotalBytes < RecvedOnce) {
5959 cfs_enter_debugger();
5960 KsTsduMgr->TotalBytes = 0;
5962 KsTsduMgr->TotalBytes -= RecvedOnce;
5965 spin_unlock(&(tconn->kstc_lock));
5967 if (NT_SUCCESS(Status)) {
5969 if ((BytesRecved < (ulong_ptr)size) && (!bIsNonBlock)) {
5971 KeWaitForSingleObject(
5972 &(KsTsduMgr->Event),
5982 if (bIsNonBlock && (BytesRecved == 0)) {
5991 ks_put_tconn(tconn);
5994 KsPrint((1, "ks_recv_mdl: recvieving %d bytes ...\n", rc));
5996 KsPrint((0, "ks_recv_mdl: recvieving error code = %d Stauts = %xh ...\n", rc, Status));
5999 /* release the chained mdl */
6000 ks_release_mdl(mdl, FALSE);
6008 * initialize the global data in ksockal_data
6014 * int: ks error code
6025 /* initialize tconn related globals */
6026 RtlZeroMemory(&ks_data, sizeof(ks_data_t));
6028 spin_lock_init(&ks_data.ksnd_tconn_lock);
6029 CFS_INIT_LIST_HEAD(&ks_data.ksnd_tconns);
6030 cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
6032 ks_data.ksnd_tconn_slab = cfs_mem_cache_create(
6033 "tcon", sizeof(ksock_tconn_t) , 0, 0);
6035 if (!ks_data.ksnd_tconn_slab) {
6040 /* initialize tsdu related globals */
6042 spin_lock_init(&ks_data.ksnd_tsdu_lock);
6043 CFS_INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
6044 ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
6045 ks_data.ksnd_tsdu_slab = cfs_mem_cache_create(
6046 "tsdu", ks_data.ksnd_tsdu_size, 0, 0);
6048 if (!ks_data.ksnd_tsdu_slab) {
6050 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
6051 ks_data.ksnd_tconn_slab = NULL;
6055 /* initialize daemon related globals */
6057 spin_lock_init(&ks_data.ksnd_daemon_lock);
6058 CFS_INIT_LIST_HEAD(&ks_data.ksnd_daemons);
6059 cfs_init_event(&ks_data.ksnd_daemon_exit, TRUE, FALSE);
6061 KsRegisterPnpHandlers();
6071 * finalize the global data in ksockal_data
6077 * int: ks error code
6086 PKS_TSDU KsTsdu = NULL;
6087 struct list_head * list = NULL;
6089 /* clean up the pnp handler and address slots */
6090 KsDeregisterPnpHandlers();
6092 /* we need wait until all the tconn are freed */
6093 spin_lock(&(ks_data.ksnd_tconn_lock));
6095 if (list_empty(&(ks_data.ksnd_tconns))) {
6096 cfs_wake_event(&ks_data.ksnd_tconn_exit);
6098 spin_unlock(&(ks_data.ksnd_tconn_lock));
6100 /* now wait on the tconn exit event */
6101 cfs_wait_event(&ks_data.ksnd_tconn_exit, 0);
6103 /* it's safe to delete the tconn slab ... */
6104 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
6105 ks_data.ksnd_tconn_slab = NULL;
6107 /* clean up all the tsud buffers in the free list */
6108 spin_lock(&(ks_data.ksnd_tsdu_lock));
6109 list_for_each (list, &ks_data.ksnd_freetsdus) {
6110 KsTsdu = list_entry (list, KS_TSDU, Link);
6113 ks_data.ksnd_tsdu_slab,
6116 spin_unlock(&(ks_data.ksnd_tsdu_lock));
6118 /* it's safe to delete the tsdu slab ... */
6119 cfs_mem_cache_destroy(ks_data.ksnd_tsdu_slab);
6120 ks_data.ksnd_tsdu_slab = NULL;
6122 /* good! it's smooth to do the cleaning up...*/
6126 * ks_create_child_tconn
6127 * Create the backlog child connection for a listener
6130 * parent: the listener daemon connection
6133 * the child connection or NULL in failure
6140 ks_create_child_tconn(
6141 ksock_tconn_t * parent
6145 ksock_tconn_t * backlog;
6147 /* allocate the tdi connecton object */
6148 backlog = ks_create_tconn();
6154 /* initialize the tconn as a child */
6155 ks_init_child(backlog);
6159 if (ks_bind_tconn(backlog, parent, 0, 0) < 0) {
6160 ks_free_tconn(backlog);
6165 /* open the connection object */
6166 status = KsOpenConnection(
6167 &(backlog->kstc_dev),
6169 &(backlog->child.kstc_info.Handle),
6170 &(backlog->child.kstc_info.FileObject)
6173 if (!NT_SUCCESS(status)) {
6175 ks_put_tconn(backlog);
6177 cfs_enter_debugger();
6181 /* associate it now ... */
6182 status = KsAssociateAddress(
6183 backlog->kstc_addr.Handle,
6184 backlog->child.kstc_info.FileObject
6187 if (!NT_SUCCESS(status)) {
6189 ks_put_tconn(backlog);
6191 cfs_enter_debugger();
6195 backlog->kstc_state = ksts_associated;
6203 * ks_replenish_backlogs(
6204 * to replenish the backlogs listening...
6207 * tconn: the parent listen tdi connect
6208 * nbacklog: number fo child connections in queue
6218 ks_replenish_backlogs(
6219 ksock_tconn_t * parent,
6223 ksock_tconn_t * backlog;
6226 /* calculate how many backlogs needed */
6227 if ( ( parent->listener.kstc_listening.num +
6228 parent->listener.kstc_accepted.num ) < nbacklog ) {
6229 n = nbacklog - ( parent->listener.kstc_listening.num +
6230 parent->listener.kstc_accepted.num );
6237 /* create the backlog child tconn */
6238 backlog = ks_create_child_tconn(parent);
6240 spin_lock(&(parent->kstc_lock));
6243 spin_lock(&backlog->kstc_lock);
6244 /* attch it into the listing list of daemon */
6245 list_add( &backlog->child.kstc_link,
6246 &parent->listener.kstc_listening.list );
6247 parent->listener.kstc_listening.num++;
6249 backlog->child.kstc_queued = TRUE;
6250 spin_unlock(&backlog->kstc_lock);
6252 cfs_enter_debugger();
6255 spin_unlock(&(parent->kstc_lock));
6261 * setup the listener tdi connection and make it listen
6262 * on the user specified ip address and port.
6265 * tconn: the parent listen tdi connect
6266 * nbacklog: number fo child connections in queue
6269 * ks error code >=: success; otherwise error.
6276 ks_start_listen(ksock_tconn_t *tconn, int nbacklog)
6280 /* now replenish the backlogs */
6281 ks_replenish_backlogs(tconn, nbacklog);
6283 /* set the event callback handlers */
6284 rc = ks_set_handlers(tconn);
6290 spin_lock(&(tconn->kstc_lock));
6291 tconn->listener.nbacklog = nbacklog;
6292 tconn->kstc_state = ksts_listening;
6293 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6294 spin_unlock(&(tconn->kstc_lock));
6300 ks_stop_listen(ksock_tconn_t *tconn)
6302 struct list_head * list;
6303 ksock_tconn_t * backlog;
6305 /* reset all tdi event callbacks to NULL */
6306 ks_reset_handlers (tconn);
6308 spin_lock(&tconn->kstc_lock);
6310 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6312 /* cleanup all the listening backlog child connections */
6313 list_for_each (list, &(tconn->listener.kstc_listening.list)) {
6314 backlog = list_entry(list, ksock_tconn_t, child.kstc_link);
6316 /* destory and free it */
6317 ks_put_tconn(backlog);
6320 spin_unlock(&tconn->kstc_lock);
6322 /* wake up it from the waiting on new incoming connections */
6323 KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
6325 /* free the listening daemon tconn */
6326 ks_put_tconn(tconn);
6331 * ks_wait_child_tconn
6332 * accept a child connection from peer
6335 * parent: the daemon tdi connection listening
6336 * child: to contain the accepted connection
6346 ks_wait_child_tconn(
6347 ksock_tconn_t * parent,
6348 ksock_tconn_t ** child
6351 struct list_head * tmp;
6352 ksock_tconn_t * backlog = NULL;
6354 ks_replenish_backlogs(parent, parent->listener.nbacklog);
6356 spin_lock(&(parent->kstc_lock));
6358 if (parent->listener.kstc_listening.num <= 0) {
6359 spin_unlock(&(parent->kstc_lock));
6365 /* check the listening queue and try to search the accepted connecton */
6367 list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
6368 backlog = list_entry (tmp, ksock_tconn_t, child.kstc_link);
6370 spin_lock(&(backlog->kstc_lock));
6372 if (backlog->child.kstc_accepted) {
6374 LASSERT(backlog->kstc_state == ksts_connected);
6375 LASSERT(backlog->child.kstc_busy);
6377 list_del(&(backlog->child.kstc_link));
6378 list_add(&(backlog->child.kstc_link),
6379 &(parent->listener.kstc_accepted.list));
6380 parent->listener.kstc_accepted.num++;
6381 parent->listener.kstc_listening.num--;
6382 backlog->child.kstc_queueno = 1;
6384 spin_unlock(&(backlog->kstc_lock));
6388 spin_unlock(&(backlog->kstc_lock));
6393 spin_unlock(&(parent->kstc_lock));
6395 /* we need wait until new incoming connections are requested
6396 or the case of shuting down the listenig daemon thread */
6397 if (backlog == NULL) {
6401 Status = KeWaitForSingleObject(
6402 &(parent->listener.kstc_accept_event),
6409 spin_lock(&(parent->kstc_lock));
6411 /* check whether it's exptected to exit ? */
6412 if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
6413 spin_unlock(&(parent->kstc_lock));
6420 /* query the local ip address of the connection */
6421 ks_query_local_ipaddr(backlog);
6429 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
6431 ks_addr_slot_t * slot = NULL;
6432 PLIST_ENTRY list = NULL;
6434 spin_lock(&ks_data.ksnd_addrs_lock);
6436 list = ks_data.ksnd_addrs_list.Flink;
6437 while (list != &ks_data.ksnd_addrs_list) {
6438 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6439 if (_stricmp(name, &slot->iface[0]) == 0) {
6441 *ip = slot->ip_addr;
6442 *mask = slot->netmask;
6449 spin_unlock(&ks_data.ksnd_addrs_lock);
6451 return (int)(slot == NULL);
6454 int libcfs_ipif_enumerate(char ***names)
6456 ks_addr_slot_t * slot = NULL;
6457 PLIST_ENTRY list = NULL;
6460 spin_lock(&ks_data.ksnd_addrs_lock);
6462 *names = cfs_alloc(sizeof(char *) * ks_data.ksnd_naddrs, CFS_ALLOC_ZERO);
6463 if (*names == NULL) {
6467 list = ks_data.ksnd_addrs_list.Flink;
6468 while (list != &ks_data.ksnd_addrs_list) {
6469 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6471 (*names)[nips++] = slot->iface;
6472 cfs_assert(nips <= ks_data.ksnd_naddrs);
6475 cfs_assert(nips == ks_data.ksnd_naddrs);
6479 spin_unlock(&ks_data.ksnd_addrs_lock);
6483 void libcfs_ipif_free_enumeration(char **names, int n)
6490 int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
6493 ksock_tconn_t * parent;
6495 parent = ks_create_tconn();
6501 /* initialize the tconn as a listener */
6502 ks_init_listener(parent);
6504 /* bind the daemon->tconn */
6505 rc = ks_bind_tconn(parent, NULL, ip, (unsigned short)port);
6508 ks_free_tconn(parent);
6512 /* create listening children and make it to listen state*/
6513 rc = ks_start_listen(parent, backlog);
6515 ks_stop_listen(parent);
6526 int libcfs_sock_accept(struct socket **newsockp, struct socket *sock)
6528 /* wait for incoming connecitons */
6529 return ks_wait_child_tconn(sock, newsockp);
6532 void libcfs_sock_abort_accept(struct socket *sock)
6534 LASSERT(sock->kstc_type == kstt_listener);
6536 spin_lock(&(sock->kstc_lock));
6538 /* clear the daemon flag */
6539 cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
6541 /* wake up it from the waiting on new incoming connections */
6542 KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
6544 spin_unlock(&(sock->kstc_lock));
6548 * libcfs_sock_connect
6549 * build a conntion between local ip/port and the peer ip/port.
6552 * laddr: local ip address
6553 * lport: local port number
6554 * paddr: peer's ip address
6555 * pport: peer's port number
6558 * int: return code ...
6565 int libcfs_sock_connect(struct socket **sockp, int *fatal,
6566 __u32 local_ip, int local_port,
6567 __u32 peer_ip, int peer_port)
6569 ksock_tconn_t * tconn = NULL;
6574 KsPrint((1, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
6575 peer_ip, peer_port, local_ip, local_port ));
6577 /* create the tdi connecion structure */
6578 tconn = ks_create_tconn();
6584 /* initialize the tdi sender connection */
6585 ks_init_sender(tconn);
6587 /* bind the local ip address with the tconn */
6588 rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
6590 KsPrint((0, "libcfs_sock_connect: failed to bind address %x:%d...\n",
6591 local_ip, local_port ));
6592 ks_free_tconn(tconn);
6596 /* connect to the remote peer */
6597 rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
6599 KsPrint((0, "libcfs_sock_connect: failed to connect %x:%d ...\n",
6600 peer_ip, peer_port ));
6602 ks_put_tconn(tconn);
6613 int libcfs_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize)
6618 int libcfs_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize)
6623 int libcfs_sock_getaddr(struct socket *socket, int remote, __u32 *ip, int *port)
6625 PTRANSPORT_ADDRESS taddr = NULL;
6627 spin_lock(&socket->kstc_lock);
6629 if (socket->kstc_type == kstt_sender) {
6630 taddr = socket->sender.kstc_info.Remote;
6631 } else if (socket->kstc_type == kstt_child) {
6632 taddr = socket->child.kstc_info.Remote;
6635 taddr = &(socket->kstc_addr.Tdi);
6639 PTDI_ADDRESS_IP addr = (PTDI_ADDRESS_IP)(&(taddr->Address[0].Address));
6641 *ip = ntohl (addr->in_addr);
6643 *port = ntohs (addr->sin_port);
6645 spin_unlock(&socket->kstc_lock);
6649 spin_unlock(&socket->kstc_lock);
6653 int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
6660 while (nob > offset) {
6662 /* lock the user buffer */
6663 rc = ks_lock_buffer( (char *)buffer + offset,
6664 FALSE, nob - offset, IoReadAccess, &mdl );
6670 /* send out the whole mdl */
6671 rc = ks_send_mdl( sock, NULL, mdl, nob - offset, 0 );
6683 int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
6690 while (nob > offset) {
6692 /* lock the user buffer */
6693 rc = ks_lock_buffer( (char *)buffer + offset,
6694 FALSE, nob - offset, IoWriteAccess, &mdl );
6700 /* recv the requested buffer */
6701 rc = ks_recv_mdl( sock, mdl, nob - offset, 0 );
6713 void libcfs_sock_release(struct socket *sock)
6715 if (sock->kstc_type == kstt_listener &&
6716 sock->kstc_state == ksts_listening) {
6717 ks_stop_listen(sock);