/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=4:tabstop=4:
*
- * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ * GPL HEADER START
*
- * This file is part of Lustre, http://www.lustre.org.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Lustre is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
*/
-#define DEBUG_SUBSYSTEM S_LIBCFS
+#define DEBUG_SUBSYSTEM S_LNET
#include <libcfs/libcfs.h>
-#include <libcfs/kp30.h>
#include <lnet/lnet.h>
-#define TDILND_MODULE_NAME L"Tdilnd"
+#define TDILND_MODULE_NAME L"tdilnd"
-ks_data_t ks_data;
+ks_tdi_data_t ks_data;
-ULONG
-ks_tdi_send_flags(ULONG SockFlags)
+VOID
+KsDumpPrint(PCHAR buffer, ULONG length)
{
- ULONG TdiFlags = 0;
-
- if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
- cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
- }
-
- if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
- cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
+ ULONG i;
+ for (i=0; i < length; i++) {
+ if (((i+1) % 31) == 0)
+ printk("\n");
+ printk("%2.2x ", (UCHAR)buffer[i]);
}
-
- if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
- cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
- }
-
- return TdiFlags;
+ printk("\n");
}
-NTSTATUS
-KsIrpCompletionRoutine(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
-{
- if (NULL != Context) {
- KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
- }
-
- return STATUS_MORE_PROCESSING_REQUIRED;
+PVOID
+KsMapMdlBuffer (PMDL Mdl);
- UNREFERENCED_PARAMETER(DeviceObject);
- UNREFERENCED_PARAMETER(Irp);
+VOID
+KsDumpMdlChain(PMDL Mdl, ULONG length)
+{
+ PMDL mdl = Mdl;
+ PCHAR buffer = NULL;
+ ULONG len = 0;
+ int i = 0;
+
+ while (mdl) {
+ printk("mdl %d:\n", i);
+ buffer = KsMapMdlBuffer(mdl);
+ KsDumpPrint(buffer, mdl->ByteCount);
+ len += mdl->ByteCount;
+ mdl = mdl->Next;
+ }
+ ASSERT(len == length);
}
-
/*
- * KsBuildTdiIrp
- * Allocate a new IRP and initialize it to be issued to tdi
+ * KsLockUserBuffer
+ * Allocate MDL for the buffer and lock the pages into
+ * nonpaged pool
*
* Arguments:
- * DeviceObject: device object created by the underlying
- * TDI transport driver
+ * UserBuffer: the user buffer to be locked
+ * Length: length in bytes of the buffer
+ * Operation: read or write access
+ * pMdl: the result of the created mdl
*
* Return Value:
- * PRIP: the allocated Irp in success or NULL in failure.
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* NOTES:
* N/A
*/
-PIRP
-KsBuildTdiIrp(
- IN PDEVICE_OBJECT DeviceObject
+NTSTATUS
+KsLockUserBuffer (
+ IN PVOID UserBuffer,
+ IN BOOLEAN bPaged,
+ IN ULONG Length,
+ IN LOCK_OPERATION Operation,
+ OUT PMDL * pMdl
)
{
- PIRP Irp;
- PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+ PMDL Mdl = NULL;
- //
- // Allocating the IRP ...
- //
+ LASSERT(UserBuffer != NULL);
- Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+ *pMdl = NULL;
- if (NULL != Irp) {
+ Mdl = IoAllocateMdl(
+ UserBuffer,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ );
- //
- // Getting the Next Stack Location ...
- //
+ if (Mdl == NULL) {
- IrpSp = IoGetNextIrpStackLocation(Irp);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
- //
- // Initializing Irp ...
- //
+ } else {
- IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
+ __try {
+
+ if (bPaged) {
+ MmProbeAndLockPages(
+ Mdl,
+ KernelMode,
+ Operation
+ );
+ } else {
+ MmBuildMdlForNonPagedPool(
+ Mdl
+ );
+ }
+
+ Status = STATUS_SUCCESS;
+
+ *pMdl = Mdl;
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ IoFreeMdl(Mdl);
+
+ Mdl = NULL;
+
+ cfs_enter_debugger();
+
+ Status = STATUS_INVALID_USER_BUFFER;
+ }
}
- return Irp;
+ return Status;
}
/*
- * KsSubmitTdiIrp
- * Issue the Irp to the underlying tdi driver
+ * KsMapMdlBuffer
+ * Map the mdl into a buffer in kernel space
*
* Arguments:
- * DeviceObject: the device object created by TDI driver
- * Irp: the I/O request packet to be processed
- * bSynchronous: synchronous or not. If true, we need wait
- * until the process is finished.
- * Information: returned info
+ * Mdl: the mdl to be mapped
*
* Return Value:
- * NTSTATUS: kernel status code
+ * PVOID: the buffer mapped or NULL in failure
*
* NOTES:
* N/A
*/
-NTSTATUS
-KsSubmitTdiIrp(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN BOOLEAN bSynchronous,
- OUT PULONG Information
- )
+PVOID
+KsMapMdlBuffer (PMDL Mdl)
{
- NTSTATUS Status;
- KEVENT Event;
-
- if (bSynchronous) {
-
- KeInitializeEvent(
- &Event,
- SynchronizationEvent,
- FALSE
- );
+ LASSERT(Mdl != NULL);
+ return MmGetSystemAddressForMdlSafe(
+ Mdl,
+ NormalPagePriority
+ );
+}
- IoSetCompletionRoutine(
- Irp,
- KsIrpCompletionRoutine,
- &Event,
- TRUE,
- TRUE,
- TRUE
- );
- }
- Status = IoCallDriver(DeviceObject, Irp);
+/*
+ * KsReleaseMdl
+ * Unlock all the pages in the mdl
+ *
+ * Arguments:
+ * Mdl: memory description list to be released
+ *
+ * Return Value:
+ * N/A
+ *
+ * NOTES:
+ * N/A
+ */
- if (bSynchronous) {
+VOID
+KsReleaseMdl (IN PMDL Mdl,
+ IN int Paged )
+{
+ LASSERT(Mdl != NULL);
- if (STATUS_PENDING == Status) {
+ while (Mdl) {
- Status = KeWaitForSingleObject(
- &Event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
- }
+ PMDL Next;
- Status = Irp->IoStatus.Status;
+ Next = Mdl->Next;
- if (Information) {
- *Information = (ULONG)(Irp->IoStatus.Information);
+ if (Paged) {
+ MmUnlockPages(Mdl);
}
- Irp->MdlAddress = NULL;
- IoFreeIrp(Irp);
- }
-
- if (!NT_SUCCESS(Status)) {
+ IoFreeMdl(Mdl);
- KsPrint((2, "KsSubmitTdiIrp: Error when submitting the Irp: Status = %xh (%s) ...\n",
- Status, KsNtStatusToString(Status)));
+ Mdl = Next;
}
-
- return (Status);
}
-
-
/*
- * KsOpenControl
- * Open the Control Channel Object ...
+ * KsQueryMdlsSize
+ * Query the whole size of a MDL (may be chained)
*
* Arguments:
- * DeviceName: the device name to be opened
- * Handle: opened handle in success case
- * FileObject: the fileobject of the device
+ * Mdl: the Mdl to be queried
*
* Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
+ * ULONG: the total size of the mdl
*
- * Notes:
+ * NOTES:
* N/A
*/
-NTSTATUS
-KsOpenControl(
- IN PUNICODE_STRING DeviceName,
- OUT HANDLE * Handle,
- OUT PFILE_OBJECT * FileObject
- )
+ULONG
+KsQueryMdlsSize (PMDL Mdl)
{
- NTSTATUS Status = STATUS_SUCCESS;
-
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatus;
-
+ PMDL Next = Mdl;
+ ULONG Length = 0;
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
//
- // Initializing ...
+ // Walking the MDL Chain ...
//
- InitializeObjectAttributes(
- &ObjectAttributes,
- DeviceName,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL
- );
-
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
-
- //
- // Creating the Transport Address Object ...
- //
+ while (Next) {
+ Length += MmGetMdlByteCount(Next);
+ Next = Next->Next;
+ }
- Status = ZwCreateFile(
- Handle,
- FILE_READ_DATA | FILE_WRITE_DATA,
- &ObjectAttributes,
- &IoStatus,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN,
- 0,
- NULL,
- 0
- );
+ return (Length);
+}
+/*
+ * KsCopyMdlToBuffer
+ * Copy payload from Mdl to buffer
+ *
+ * Arguments:
+ * SourceMdl: the source mdl
+ * SourceOffset: start offset of the source
+ * DestinationBuffer: the dst buffer
+ * DestinationOffset: the offset where data are to be copied.
+ * BytesTobecopied: the expteced bytes to be copied
+ *
+ * Return Value:
+ * Length of data copied from MDL to user buffer
+ *
+ * NOTES:
+ * N/A
+ */
- if (NT_SUCCESS(Status)) {
+ULONG
+KsCopyMdlToBuffer(
+ IN PMDL SourceMdl,
+ IN ULONG SourceOffset,
+ IN PVOID DestinationBuffer,
+ IN ULONG DestinationOffset,
+ IN ULONG BytesTobeCopied
+ )
+{
+ PUCHAR SourceBuffer = NULL;
+ PUCHAR TargetBuffer = DestinationBuffer;
+ ULONG BytesCopied = 0;
- //
- // Now Obtaining the FileObject of the Transport Address ...
- //
+ if (MmGetMdlByteCount(SourceMdl) <= SourceOffset) {
+ return 0;
+ }
- Status = ObReferenceObjectByHandle(
- *Handle,
- FILE_ANY_ACCESS,
- NULL,
- KernelMode,
- FileObject,
- NULL
- );
+ BytesCopied = MmGetMdlByteCount(SourceMdl) - SourceOffset;
+ if (BytesCopied > BytesTobeCopied) {
+ BytesCopied = BytesTobeCopied;
+ }
- if (!NT_SUCCESS(Status)) {
+ SourceBuffer = (PUCHAR)KsMapMdlBuffer(SourceMdl);
- cfs_enter_debugger();
- ZwClose(*Handle);
- }
+ RtlMoveMemory(TargetBuffer + DestinationOffset,
+ SourceBuffer + SourceOffset, BytesCopied);
- } else {
+ return BytesCopied;
+}
- cfs_enter_debugger();
- }
+/*
+ * KsInitializeKsTsdu
+ * Initialize the Tsdu buffer header
+ *
+ * Arguments:
+ * KsTsdu: the Tsdu to be initialized
+ * Length: the total length of the Tsdu
+ *
+ * Return Value:
+ * VOID
+ *
+ * NOTES:
+ * N/A
+ */
- return (Status);
+VOID
+KsInitializeKsTsdu(
+ PKS_TSDU KsTsdu,
+ ULONG Length
+ )
+{
+ KsTsdu->Magic = KS_TSDU_MAGIC;
+ KsTsdu->TotalLength = Length;
+ KsTsdu->StartOffset = KsTsdu->LastOffset =
+ KS_QWORD_ALIGN(sizeof(KS_TSDU));
}
-
/*
- * KsCloseControl
- * Release the Control Channel Handle and FileObject
+ * KsAllocateKsTsdu
+ * Reuse a Tsdu from the freelist or allocate a new Tsdu
+ * from the LookAsideList table or the NonPagedPool
*
* Arguments:
- * Handle: the channel handle to be released
- * FileObject: the fileobject to be released
+ * N/A
*
* Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
+ * PKS_Tsdu: the new Tsdu or NULL if it fails
*
* Notes:
* N/A
*/
-NTSTATUS
-KsCloseControl(
- IN HANDLE Handle,
- IN PFILE_OBJECT FileObject
- )
+PKS_TSDU
+KsAllocateKsTsdu()
{
- NTSTATUS Status = STATUS_SUCCESS;
+ PKS_TSDU KsTsdu = NULL;
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
- if (FileObject) {
+ if (!cfs_list_empty (&(ks_data.ksnd_freetsdus))) {
- ObDereferenceObject(FileObject);
- }
+ LASSERT(ks_data.ksnd_nfreetsdus > 0);
- if (Handle) {
+ KsTsdu = cfs_list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
+ cfs_list_del(&(KsTsdu->Link));
+ ks_data.ksnd_nfreetsdus--;
- Status = ZwClose(Handle);
+ } else {
+
+ KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
+ ks_data.ksnd_tsdu_slab, 0);
}
- ASSERT(NT_SUCCESS(Status));
+ cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
- return (Status);
+ if (NULL != KsTsdu) {
+ RtlZeroMemory(KsTsdu, ks_data.ksnd_tsdu_size);
+ KsInitializeKsTsdu(KsTsdu, (ULONG)ks_data.ksnd_tsdu_size);
+ }
+
+ return (KsTsdu);
}
+/*
+ * KsFreeKsTsdu
+ * Release a Tsdu: uninitialize then free it.
+ *
+ * Arguments:
+ * KsTsdu: Tsdu to be freed.
+ *
+ * Return Value:
+ * N/A
+ *
+ * Notes:
+ * N/A
+ */
+
+VOID
+KsFreeKsTsdu(
+ PKS_TSDU KsTsdu
+ )
+{
+ cfs_mem_cache_free(
+ ks_data.ksnd_tsdu_slab,
+ KsTsdu );
+}
/*
- * KsOpenAddress
- * Open the tdi address object
+ * KsPutKsTsdu
+ * Move the Tsdu to the free tsdu list in ks_data.
*
* Arguments:
- * DeviceName: device name of the address object
- * pAddress: tdi address of the address object
- * AddressLength: length in bytes of the tdi address
- * Handle: the newly opened handle
- * FileObject: the newly opened fileobject
+ * KsTsdu: Tsdu to be moved.
*
* Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
+ * N/A
*
* Notes:
* N/A
*/
-NTSTATUS
-KsOpenAddress(
- IN PUNICODE_STRING DeviceName,
- IN PTRANSPORT_ADDRESS pAddress,
- IN ULONG AddressLength,
- OUT HANDLE * Handle,
- OUT PFILE_OBJECT * FileObject
- )
+VOID
+KsPutKsTsdu(
+ PKS_TSDU KsTsdu
+ )
{
- NTSTATUS Status = STATUS_SUCCESS;
+ cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
+ if (ks_data.ksnd_nfreetsdus > 128) {
+ KsFreeKsTsdu(KsTsdu);
+ } else {
+ cfs_list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
+ ks_data.ksnd_nfreetsdus++;
+ }
+ cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
+}
- PFILE_FULL_EA_INFORMATION Ea = NULL;
- ULONG EaLength;
- UCHAR EaBuffer[EA_MAX_LENGTH];
+/* with tconn lock acquired */
+ks_mdl_t *
+KsLockTsdus(
+ ks_tconn_t * tconn,
+ PKS_TSDUMGR TsduMgr,
+ PULONG Flags,
+ PULONG Length
+ )
+{
+
+ ks_mdl_t * mdl = NULL;
+ ks_mdl_t * tail = NULL;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatus;
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_DAT KsTsduDat;
+ PKS_TSDU_BUF KsTsduBuf;
+ PKS_TSDU_MDL KsTsduMdl;
- //
- // Building EA for the Address Object to be Opened ...
- //
+ *Length = 0;
- Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
- Ea->NextEntryOffset = 0;
- Ea->Flags = 0;
- Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
- Ea->EaValueLength = (USHORT)AddressLength;
- RtlCopyMemory(
- &(Ea->EaName),
- TdiTransportAddress,
- Ea->EaNameLength + 1
- );
- RtlMoveMemory(
- &(Ea->EaName[Ea->EaNameLength + 1]),
- pAddress,
- AddressLength
- );
- EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
- Ea->EaNameLength + AddressLength;
+ cfs_list_for_each_entry_typed(KsTsdu,
+ &TsduMgr->TsduList,KS_TSDU, Link) {
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ ULONG start = 0;
+ LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
+ start = KsTsdu->StartOffset;
- //
- // Initializing ...
- //
+ while (start < KsTsdu->LastOffset) {
- InitializeObjectAttributes(
- &ObjectAttributes,
- DeviceName,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL
- );
+ ks_mdl_t * iov = NULL;
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
+ KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
+ LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
+ KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
+ KsTsduMdl->TsduType == TSDU_TYPE_MDL);
- //
- // Creating the Transport Address Object ...
- //
+ if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- Status = ZwCreateFile(
- Handle,
- FILE_READ_DATA | FILE_WRITE_DATA,
- &ObjectAttributes,
- &IoStatus,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
- FILE_OPEN,
- 0,
- Ea,
- EaLength
- );
+ ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->TotalLength);
+ if (KsTsduDat->Mdl) {
+ iov = KsTsduDat->Mdl;
+ } else {
+ KsLockUserBuffer(
+ &KsTsduDat->Data[KsTsduDat->StartOffset],
+ FALSE,
+ KsTsduDat->DataLength,
+ IoReadAccess,
+ &iov );
+ KsTsduDat->Mdl = iov;
+ }
+/*
+ printk("KsLockTsdus: %u\n", KsTsduDat->DataLength);
+ KsDumpPrint(
+ &KsTsduDat->Data[KsTsduDat->StartOffset],
+ KsTsduDat->DataLength);
+*/
+ *Length += KsTsduDat->DataLength;
+ start += KsTsduDat->TotalLength;
+ } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
- if (NT_SUCCESS(Status)) {
+ ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
+ if (KsTsduBuf->Mdl) {
+ iov = KsTsduBuf->Mdl;
+ } else {
+ KsLockUserBuffer(
+ (PUCHAR)KsTsduBuf->UserBuffer +
+ KsTsduBuf->StartOffset,
+ FALSE,
+ KsTsduBuf->DataLength,
+ IoReadAccess,
+ &iov );
+ KsTsduBuf->Mdl = iov;
+ }
- //
- // Now Obtaining the FileObject of the Transport Address ...
- //
+ *Length += KsTsduBuf->DataLength;
+ start += sizeof(KS_TSDU_BUF);
- Status = ObReferenceObjectByHandle(
- *Handle,
- FILE_ANY_ACCESS,
- NULL,
- KernelMode,
- FileObject,
- NULL
- );
-
- if (!NT_SUCCESS(Status)) {
+ } else {
- cfs_enter_debugger();
- ZwClose(*Handle);
- }
+ LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
+ ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
+ iov = KsTsduMdl->Mdl;
+ *Length += KsTsduMdl->DataLength;
+ start += sizeof(KS_TSDU_MDL);
+ }
- } else {
+ if (!iov) {
+ cfs_enter_debugger();
+ goto cleanup;
+ }
- cfs_enter_debugger();
+ if (tail) {
+ tail->Next = iov;
+ } else {
+ mdl = iov;
+ }
+ tail = iov;
+ tail->Next = NULL;
+/*
+ printk("KsLockTsdus: mdl %d\n", tail->ByteCount);
+ KsDumpMdlChain(tail, tail->ByteCount);
+*/
+ }
}
+#if 0
+ if (Flags) {
+ *Flags = TsduFlags;
+ }
+#endif
+ return mdl;
- return (Status);
+cleanup:
+
+ *Length = 0;
+ return NULL;
}
-/*
- * KsCloseAddress
- * Release the Hanlde and FileObject of an opened tdi
- * address object
- *
- * Arguments:
- * Handle: the handle to be released
- * FileObject: the fileobject to be released
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
-
-NTSTATUS
-KsCloseAddress(
- IN HANDLE Handle,
- IN PFILE_OBJECT FileObject
-)
+ks_mdl_t *
+KsSplitMdl(
+ IN ks_mdl_t * master,
+ IN ULONG offset,
+ IN ULONG length
+ )
{
- NTSTATUS Status = STATUS_SUCCESS;
-
- if (FileObject) {
+ ks_mdl_t * mdl = NULL;
+ char * ptr = NULL;
- ObDereferenceObject(FileObject);
- }
+ /* calculate the start virtual address */
+ ptr = (char *)KsMapMdlBuffer(master) + offset;
- if (Handle) {
+ /* allocate new mdl for new memory range */
+ mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
- Status = ZwClose(Handle);
+ if (!mdl) {
+ return NULL;
}
+
+ /* initialize the mdl */
+ IoBuildPartialMdl(master, mdl, (PVOID)ptr, length);
- ASSERT(NT_SUCCESS(Status));
-
- return (Status);
+ return mdl;
}
+/* with tconn lock acquired */
+VOID
+KsReleaseTsdus(
+ ks_tconn_t * tconn,
+ PKS_TSDUMGR TsduMgr,
+ ULONG length
+ )
+{
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_DAT KsTsduDat;
+ PKS_TSDU_BUF KsTsduBuf;
+ PKS_TSDU_MDL KsTsduMdl;
+#if DBG
+ ULONG total = TsduMgr->TotalBytes;
+ ULONG size = length;
+#endif
-/*
- * KsOpenConnection
- * Open a tdi connection object
- *
- * Arguments:
- * DeviceName: device name of the connection object
- * ConnectionContext: the connection context
- * Handle: the newly opened handle
- * FileObject: the newly opened fileobject
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
+ LASSERT(TsduMgr->TotalBytes >= length);
-NTSTATUS
-KsOpenConnection(
- IN PUNICODE_STRING DeviceName,
- IN CONNECTION_CONTEXT ConnectionContext,
- OUT HANDLE * Handle,
- OUT PFILE_OBJECT * FileObject
- )
-{
- NTSTATUS Status = STATUS_SUCCESS;
+ while (!cfs_list_empty(&TsduMgr->TsduList)) {
- PFILE_FULL_EA_INFORMATION Ea = NULL;
- ULONG EaLength;
- UCHAR EaBuffer[EA_MAX_LENGTH];
+ ULONG start = 0;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatus;
+ KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
+ LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
+ start = KsTsdu->StartOffset;
- //
- // Building EA for the Address Object to be Opened ...
- //
+ while (length > 0 && start < KsTsdu->LastOffset) {
- Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
- Ea->NextEntryOffset = 0;
- Ea->Flags = 0;
- Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
- Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
- RtlCopyMemory(
- &(Ea->EaName),
- TdiConnectionContext,
- Ea->EaNameLength + 1
- );
- RtlMoveMemory(
- &(Ea->EaName[Ea->EaNameLength + 1]),
- &ConnectionContext,
- sizeof(CONNECTION_CONTEXT)
- );
- EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
- Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
+ ULONG size = 0;
+ ks_mdl_t * mdl = NULL;
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
+ KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
+ LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
+ KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
+ KsTsduMdl->TsduType == TSDU_TYPE_MDL);
+ if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- //
- // Initializing ...
- //
+ ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->DataLength);
+ if (length >= KsTsduDat->DataLength) {
+ /* whole tsdu is sent out */
+ size = KsTsduDat->DataLength;
+ start += KsTsduDat->TotalLength;
+ } else {
+ size = length;
+ KsTsduDat->StartOffset += size;
+ }
- InitializeObjectAttributes(
- &ObjectAttributes,
- DeviceName,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL
- );
+ if (KsTsduDat->Mdl) {
+ mdl = KsTsduDat->Mdl;
+ KsTsduDat->Mdl = NULL;
+ }
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ KsTsduDat->DataLength -= size;
- //
- // Creating the Connection Object ...
- //
+ } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
- Status = ZwCreateFile(
- Handle,
- FILE_READ_DATA | FILE_WRITE_DATA,
- &ObjectAttributes,
- &IoStatus,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- 0,
- FILE_OPEN,
- 0,
- Ea,
- EaLength
- );
+ ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
+ if (length >= KsTsduBuf->DataLength) {
+ /* whole tsdu is sent out */
+ size = KsTsduBuf->DataLength;
+ start += sizeof(KS_TSDU_BUF);
+ LASSERT(KsTsduBuf->UserBuffer);
+ ExFreePool(KsTsduBuf->UserBuffer);
+ KsTsduBuf->UserBuffer = NULL;
+ } else {
+ KsTsduBuf->StartOffset += length;
+ size = length;
+ }
+ if (KsTsduBuf->Mdl) {
+ mdl = KsTsduBuf->Mdl;
+ KsTsduBuf->Mdl = NULL;
+ }
- if (NT_SUCCESS(Status)) {
+ KsTsduBuf->DataLength -= size;
+
+ } else {
- //
- // Now Obtaining the FileObject of the Transport Address ...
- //
+ LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
+ ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
+ mdl = KsTsduMdl->Mdl;
+ if (length >= KsTsduMdl->DataLength) {
+ /* whole mdl is sent out */
+ size = KsTsduMdl->DataLength;
+ start += sizeof(KS_TSDU_MDL);
+ KsTsduMdl->Mdl = NULL;
+ } else {
+ /* now split the remained data out */
+ ks_mdl_t * mdl1 = KsSplitMdl(mdl, length,
+ KsTsduMdl->DataLength - length);
+ if (NULL == mdl1) {
+ mdl->ByteOffset += length;
+ mdl = NULL;
+ } else {
+ KsTsduMdl->Mdl = mdl1;
+ }
+ size = length;
+ KsTsduMdl->StartOffset += size;
+ }
- Status = ObReferenceObjectByHandle(
- *Handle,
- FILE_ANY_ACCESS,
- NULL,
- KernelMode,
- FileObject,
- NULL
- );
+ KsTsduMdl->DataLength -= size;
+ }
- if (!NT_SUCCESS(Status)) {
+ length -= size;
+ TsduMgr->TotalBytes -= size;
- cfs_enter_debugger();
- ZwClose(*Handle);
+ if (mdl) {
+ mdl->Next = NULL;
+ KsReleaseMdl(mdl, FALSE);
+ }
+
+ KsTsdu->StartOffset = start;
}
- } else {
+ if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
- cfs_enter_debugger();
+ /* remove KsTsdu from list */
+ cfs_list_del(&KsTsdu->Link);
+ TsduMgr->NumOfTsdu--;
+ KsPutKsTsdu(KsTsdu);
+ }
+
+ if (length == 0) {
+ break;
+ }
}
- return (Status);
+ LASSERT(length == 0);
+#if DBG
+ LASSERT(total - size == TsduMgr->TotalBytes);
+ KsPrint((4, "KsReleaseTsdus: TsduMgr=%p Remained=%xh (%xh)\n",
+ TsduMgr, TsduMgr->TotalBytes, size ));
+#endif
}
-/*
- * KsCloseConnection
- * Release the Hanlde and FileObject of an opened tdi
- * connection object
- *
- * Arguments:
- * Handle: the handle to be released
- * FileObject: the fileobject to be released
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
-
-NTSTATUS
-KsCloseConnection(
- IN HANDLE Handle,
- IN PFILE_OBJECT FileObject
+PKS_TSDUMGR
+KsQueryTsduMgr(
+ ks_tconn_t * tconn,
+ BOOLEAN expedited,
+ BOOLEAN sending
)
{
- NTSTATUS Status = STATUS_SUCCESS;
- if (FileObject) {
-
- ObDereferenceObject(FileObject);
- }
+ PKS_CHAIN KsChain;
+ PKS_TSDUMGR TsduMgr;
- if (Handle) {
+ /* get the latest Tsdu buffer form TsduMgr list.
+ just set NULL if the list is empty. */
- Status = ZwClose(Handle);
+ if (sending) {
+ if (tconn->kstc_type == kstt_sender) {
+ KsChain = &(tconn->sender.kstc_send);
+ } else {
+ LASSERT(tconn->kstc_type == kstt_child);
+ KsChain = &(tconn->child.kstc_send);
+ }
+ } else {
+ if (tconn->kstc_type == kstt_sender) {
+ KsChain = &(tconn->sender.kstc_recv);
+ } else {
+ LASSERT(tconn->kstc_type == kstt_child);
+ KsChain = &(tconn->child.kstc_recv);
+ }
}
- ASSERT(NT_SUCCESS(Status));
+ if (expedited) {
+ TsduMgr = &(KsChain->Expedited);
+ } else {
+ TsduMgr = &(KsChain->Normal);
+ }
- return (Status);
+ return TsduMgr;
}
-
-/*
- * KsAssociateAddress
- * Associate an address object with a connection object
- *
- * Arguments:
- * AddressHandle: the handle of the address object
- * ConnectionObject: the FileObject of the connection
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
-
-NTSTATUS
-KsAssociateAddress(
- IN HANDLE AddressHandle,
- IN PFILE_OBJECT ConnectionObject
- )
+PKS_TSDU
+KsGetTsdu(PKS_TSDUMGR TsduMgr, ULONG Length)
{
- NTSTATUS Status;
- PDEVICE_OBJECT DeviceObject;
- PIRP Irp;
+ PKS_TSDU KsTsdu = NULL;
- //
- // Getting the DeviceObject from Connection FileObject
- //
+ /* retrieve the latest Tsdu buffer form TsduMgr
+ list if the list is not empty. */
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ if (cfs_list_empty(&(TsduMgr->TsduList))) {
- //
- // Building Tdi Internal Irp ...
- //
-
- Irp = KsBuildTdiIrp(DeviceObject);
-
- if (NULL == Irp) {
-
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ LASSERT(TsduMgr->NumOfTsdu == 0);
+ KsTsdu = NULL;
} else {
- //
- // Assocating the Address Object with the Connection Object
- //
+ LASSERT(TsduMgr->NumOfTsdu > 0);
+ KsTsdu = cfs_list_entry(TsduMgr->TsduList.prev, KS_TSDU, Link);
- TdiBuildAssociateAddress(
- Irp,
- DeviceObject,
- ConnectionObject,
- NULL,
- NULL,
- AddressHandle
- );
+ /* if this Tsdu does not contain enough space, we need
+ allocate a new Tsdu queue. */
- //
- // Calling the Transprot Driver with the Prepared Irp
- //
+ if (KsTsdu->LastOffset + Length > KsTsdu->TotalLength) {
+ KsTsdu = NULL;
+ }
+ }
- Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
+ /* allocate a new Tsdu in case we are not statisfied. */
+ if (NULL == KsTsdu) {
+ KsTsdu = KsAllocateKsTsdu();
+ if (NULL != KsTsdu) {
+ cfs_list_add_tail(&(KsTsdu->Link), &(TsduMgr->TsduList));
+ TsduMgr->NumOfTsdu++;
+ }
}
- return (Status);
+ return KsTsdu;
}
+ULONG
+KsWriteTsduDat(
+ PKS_TSDUMGR TsduMgr,
+ PCHAR buffer,
+ ULONG length,
+ ULONG flags
+ )
+{
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_DAT KsTsduDat;
+ PKS_TSDU_BUF KsTsduBuf;
+
+ BOOLEAN bNewBuff = FALSE;
+ PCHAR Buffer = NULL;
/*
- * KsDisassociateAddress
- * Disassociate the connection object (the relationship will
- * the corresponding address object will be dismissed. )
- *
- * Arguments:
- * ConnectionObject: the FileObject of the connection
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
+ printk("KsWriteTsduDat: %u\n", length);
+ KsDumpPrint(buffer, length);
+*/
+ /* if the Tsdu is even larger than the biggest Tsdu, we have
+ to allocate new buffer and use TSDU_TYPE_BUF to store it */
-NTSTATUS
-KsDisassociateAddress(
- IN PFILE_OBJECT ConnectionObject
- )
-{
- NTSTATUS Status;
- PDEVICE_OBJECT DeviceObject;
- PIRP Irp;
+ if ( KS_TSDU_STRU_SIZE(length) > ks_data.ksnd_tsdu_size -
+ KS_QWORD_ALIGN(sizeof(KS_TSDU))) {
+ bNewBuff = TRUE;
+ }
- //
- // Getting the DeviceObject from Connection FileObject
- //
+ /* allocating the buffer for TSDU_TYPE_BUF */
+ if (bNewBuff) {
+ Buffer = ExAllocatePool(NonPagedPool, length);
+ if (NULL == Buffer) {
+ /* there's no enough memory for us. We just try to
+ receive maximum bytes with a new Tsdu */
+ bNewBuff = FALSE;
+ length = ks_data.ksnd_tsdu_size - KS_TSDU_STRU_SIZE(0) -
+ KS_QWORD_ALIGN(sizeof(KS_TSDU));
+ }
+ }
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ /* get empty Tsdu from TsduMgr */
+ KsTsdu = KsGetTsdu(TsduMgr, bNewBuff ? sizeof(KS_TSDU_BUF) :
+ KS_TSDU_STRU_SIZE(length) );
- //
- // Building Tdi Internal Irp ...
- //
+ /* allocate a new Tsdu in case we are not statisfied. */
+ if (NULL == KsTsdu) {
+ goto errorout;
+ }
- Irp = KsBuildTdiIrp(DeviceObject);
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
- if (NULL == Irp) {
+ if (bNewBuff) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ /* setup up the KS_TSDU_BUF record */
+ KsTsduBuf->TsduType = TSDU_TYPE_BUF;
+ KsTsduBuf->TsduFlags = 0;
+ KsTsduBuf->StartOffset = 0;
+ KsTsduBuf->UserBuffer = Buffer;
+ KsTsduBuf->DataLength = length;
+ KsTsduBuf->Mdl = NULL;
+ if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
+ KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
+ }
+
+ KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
} else {
- //
- // Disassocating the Address Object with the Connection Object
- //
+ /* setup the KS_TSDU_DATA to contain all the messages */
- TdiBuildDisassociateAddress(
- Irp,
- DeviceObject,
- ConnectionObject,
- NULL,
- NULL
- );
+ KsTsduDat->TsduType = TSDU_TYPE_DAT;
+ KsTsduDat->TsduFlags = 0;
- //
- // Calling the Transprot Driver with the Prepared Irp
- //
+ if ( KsTsdu->TotalLength - KsTsdu->LastOffset <
+ KS_TSDU_STRU_SIZE(length) ) {
+ length = KsTsdu->TotalLength - KsTsdu->LastOffset -
+ FIELD_OFFSET(KS_TSDU_DAT, Data);
+ }
+ KsTsduDat->DataLength = length;
+ KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(length);
+ KsTsduDat->StartOffset = 0;
+ KsTsduDat->Mdl = NULL;
+ if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
+ KsTsduDat->TsduFlags |= KS_TSDU_COMM_PARTIAL;
+ }
- Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
+ Buffer = &KsTsduDat->Data[0];
+ KsTsdu->LastOffset += KsTsduDat->TotalLength;
}
- return (Status);
-}
-
+ RtlMoveMemory(Buffer, buffer, length);
+ TsduMgr->TotalBytes += length;
-/*
+ KsPrint((4, "KsWriteTsduDat: TsduMgr=%p bytes in queue:%xh (%xh)\n",
+ TsduMgr, TsduMgr->TotalBytes, length));
+ return length;
-//
-// Connection Control Event Callbacks
-//
+errorout:
-TDI_EVENT_CONNECT
-TDI_EVENT_DISCONNECT
-TDI_EVENT_ERROR
+ return 0;
+}
-//
-// Tcp Event Callbacks
-//
+ULONG
+KsWriteTsduBuf(
+ PKS_TSDUMGR TsduMgr,
+ PCHAR buffer,
+ ULONG length,
+ ULONG flags
+ )
+{
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_BUF KsTsduBuf;
-TDI_EVENT_RECEIVE
-TDI_EVENT_RECEIVE_EXPEDITED
-TDI_EVENT_CHAINED_RECEIVE
-TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
+ /* get empty Tsdu from TsduMgr */
+ KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_BUF));
-//
-// Udp Event Callbacks
-//
+ /* allocate a new Tsdu in case we are not statisfied. */
+ if (NULL == KsTsdu) {
+ goto errorout;
+ }
-TDI_EVENT_RECEIVE_DATAGRAM
-TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
+ /* setup up the KS_TSDU_BUF record */
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ KsTsduBuf->TsduType = TSDU_TYPE_BUF;
+ KsTsduBuf->TsduFlags = 0;
+ KsTsduBuf->StartOffset = 0;
+ KsTsduBuf->UserBuffer = buffer;
+ KsTsduBuf->DataLength = length;
+ KsTsduBuf->Mdl = NULL;
+ KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
+ if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
+ KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
+ }
-*/
+ TsduMgr->TotalBytes += length;
+ KsPrint((4, "KsWriteTsduBuf: TsduMgr=%p bytes in queue:%xh (%xh)\n",
+ TsduMgr, TsduMgr->TotalBytes, length));
+ return length;
-/*
- * KsSetEventHandlers
- * Set the tdi event callbacks with an address object
- *
- * Arguments:
- * AddressObject: the FileObject of the address object
- * EventContext: the parameter for the callbacks
- * Handlers: the handlers indictor array
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * NOTES:
- * N/A
- */
+errorout:
+ return 0;
+}
-NTSTATUS
-KsSetEventHandlers(
- IN PFILE_OBJECT AddressObject, // Address File Object
- IN PVOID EventContext, // Context for Handlers
- IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
- )
+ULONG
+KsWriteTsduMdl(
+ PKS_TSDUMGR TsduMgr,
+ ks_mdl_t * mdl,
+ PVOID desc,
+ ULONG offset,
+ ULONG length,
+ ULONG flags
+ )
{
- NTSTATUS Status = STATUS_SUCCESS;
- PDEVICE_OBJECT DeviceObject;
- USHORT i = 0;
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_MDL KsTsduMdl;
- DeviceObject = IoGetRelatedDeviceObject(AddressObject);
+ /* get empty Tsdu from TsduMgr */
+ KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_MDL));
- for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
+ /* allocate a new Tsdu in case we are not statisfied. */
+ if (NULL == KsTsdu) {
+ goto errorout;
+ }
- //
- // Setup the tdi event callback handler if requested.
- //
+ /* setup up the KS_TSDU_MDL record */
+ KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ KsTsduMdl->TsduType = TSDU_TYPE_MDL;
+ KsTsduMdl->TsduFlags = 0;
+ KsTsduMdl->StartOffset = 0;
+ KsTsduMdl->BaseOffset = offset;
+ KsTsduMdl->DataLength = length;
+ KsTsduMdl->Mdl = mdl;
+ KsTsduMdl->Descriptor = desc;
+ KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
+ if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
+ KsTsduMdl->TsduFlags |= KS_TSDU_COMM_PARTIAL;
+ }
- if (Handlers->IsActive[i]) {
+ TsduMgr->TotalBytes += length;
+ KsPrint((4, "KsWriteTsduMdl: TsduMgr=%p bytes in queue:%xh (%xh)\n",
+ TsduMgr, TsduMgr->TotalBytes, length));
- PIRP Irp;
+ return length;
- //
- // Building Tdi Internal Irp ...
- //
+errorout:
+ return 0;
+}
- Irp = KsBuildTdiIrp(DeviceObject);
+ULONG
+KsReadTsdu (
+ PKS_TSDUMGR TsduMgr,
+ PCHAR buffer,
+ ULONG length,
+ ULONG flags
+ )
+{
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_DAT KsTsduDat;
+ PKS_TSDU_BUF KsTsduBuf;
+ PKS_TSDU_MDL KsTsduMdl;
- if (NULL == Irp) {
+ PUCHAR Buffer;
+ ULONG BytesRecved = 0;
+#if DBG
+ ULONG TotalBytes = TsduMgr->TotalBytes;
+#endif
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ KsPrint((4, "KsReadTsdu: TsduMgr=%p request=%xh total=%xh\n",
+ TsduMgr, length, TsduMgr->TotalBytes ));
+NextTsdu:
- } else {
+ if (TsduMgr->TotalBytes == 0) {
- //
- // Building the Irp to set the Event Handler ...
- //
+ /* It's a notification event. We need reset it to
+ un-signaled state in case there no any tsdus. */
- TdiBuildSetEventHandler(
- Irp,
- DeviceObject,
- AddressObject,
- NULL,
- NULL,
- i, /* tdi event type */
- Handlers->Handler[i], /* tdi event handler */
- EventContext /* context for the handler */
- );
+ KeResetEvent(&(TsduMgr->Event));
- //
- // Calling the Transprot Driver with the Prepared Irp
- //
+ } else {
- Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
+ KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
+ LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
- //
- // tcp/ip tdi does not support these two event callbacks
- //
+ /* remove the KsTsdu from TsduMgr list to release the lock */
+ cfs_list_del(&(KsTsdu->Link));
+ TsduMgr->NumOfTsdu--;
- if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
- i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
- cfs_enter_debugger();
- Status = STATUS_SUCCESS;
- }
- }
+ while (length > BytesRecved) {
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
+ ULONG BytesToCopy = 0;
+ ULONG StartOffset = 0;
+ ULONG BytesCopied = 0;
+
+ if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
+ /* KsTsdu is empty now, we need free it ... */
+ KsPutKsTsdu(KsTsdu);
+ KsTsdu = NULL;
+ break;
}
- }
- }
+ KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
+ KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
-errorout:
+ if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
+ TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
- if (!NT_SUCCESS(Status)) {
+ if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- KsPrint((2, "KsSetEventHandlers: Error Status = %xh (%s)\n",
- Status, KsNtStatusToString(Status) ));
- }
+ /* Data Tsdu Unit ... */
+ Buffer = &KsTsduDat->Data[0];
+ StartOffset = KsTsduDat->StartOffset;
+ if (KsTsduDat->DataLength - KsTsduDat->StartOffset > length - BytesRecved) {
+ /* Recvmsg requst could be statisfied ... */
+ BytesToCopy = length - BytesRecved;
+ } else {
+ BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
+ }
- return (Status);
-}
+ } else {
+ /* Buffer Tsdu Unit */
+ ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
+ Buffer = KsTsduBuf->UserBuffer;
+ StartOffset = KsTsduBuf->StartOffset;
+ if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > length - BytesRecved) {
+ /* Recvmsg requst could be statisfied ... */
+ BytesToCopy = length - BytesRecved;
+ } else {
+ BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
+ }
+ }
-/*
- * KsQueryAddressInfo
- * Query the address of the FileObject specified
- *
- * Arguments:
- * FileObject: the FileObject to be queried
- * AddressInfo: buffer to contain the address info
- * AddressSize: length of the AddressInfo buffer
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * Notes:
- * N/A
- */
+ if (BytesToCopy > 0) {
+ RtlMoveMemory(buffer + BytesRecved, Buffer + StartOffset, BytesToCopy);
+ }
+ BytesCopied = BytesToCopy;
+ BytesRecved += BytesCopied;
+ LASSERT(TsduMgr->TotalBytes >= BytesCopied);
+ TsduMgr->TotalBytes -= BytesCopied;
+ KsPrint((4, "KsReadTsdu: TsduMgr=%p copied=%xh recved=%xh\n",
+ TsduMgr, BytesCopied, BytesRecved ));
-NTSTATUS
-KsQueryAddressInfo(
- PFILE_OBJECT FileObject,
- PTDI_ADDRESS_INFO AddressInfo,
- PULONG AddressSize
- )
-{
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PIRP Irp = NULL;
- PMDL Mdl;
- PDEVICE_OBJECT DeviceObject;
+ if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ KsTsduDat->StartOffset += BytesCopied;
+ if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
+ if (KsTsduDat->Mdl) {
+ KsTsduDat->Mdl->Next = NULL;
+ KsReleaseMdl(KsTsduDat->Mdl, FALSE);
+ }
+ KsTsdu->StartOffset += KsTsduDat->TotalLength;
+ }
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ } else {
- RtlZeroMemory(AddressInfo, *(AddressSize));
+ ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
+ KsTsduBuf->StartOffset += BytesCopied;
+ if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
+ KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
+ /* now we need release the buf to system pool */
+ if (KsTsduBuf->Mdl) {
+ KsTsduBuf->Mdl->Next = NULL;
+ KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
+ }
+ ExFreePool(KsTsduBuf->UserBuffer);
+ }
+ }
- //
- // Allocating the Tdi Setting Irp ...
- //
+ } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
- Irp = KsBuildTdiIrp(DeviceObject);
+ /* MDL Tsdu Unit ... */
+ if (KsTsduMdl->DataLength > length - BytesRecved) {
+ /* Recvmsg requst could be statisfied ... */
+ BytesToCopy = length - BytesRecved;
+ } else {
+ BytesToCopy = KsTsduMdl->DataLength;
+ }
- if (NULL == Irp) {
+ BytesCopied =
+ KsCopyMdlToBuffer(
+ KsTsduMdl->Mdl,
+ KsTsduMdl->StartOffset +
+ KsTsduMdl->BaseOffset,
+ buffer,
+ BytesRecved,
+ BytesToCopy
+ );
+ KsPrint((4, "KsReadTsdu: TsduMgr=%p mdl=%p dec=%p copied=%xh "
+ "recved=%xh\n",
+ TsduMgr, KsTsduMdl->Mdl, KsTsduMdl->Descriptor,
+ BytesCopied, BytesRecved + BytesCopied));
+ if (BytesCopied == 0) {
+ cfs_enter_debugger();
+ break;
+ }
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ KsTsduMdl->StartOffset += BytesCopied;
+ KsTsduMdl->DataLength -= BytesCopied;
+ BytesRecved += BytesCopied;
+ LASSERT(TsduMgr->TotalBytes >= BytesCopied);
+ TsduMgr->TotalBytes -= BytesCopied;
- } else {
+ if (0 == KsTsduMdl->DataLength) {
- //
- // Locking the User Buffer / Allocating a MDL for it
- //
+ /* Call TdiReturnChainedReceives to release the Tsdu memory */
+ LASSERT(KsTsduMdl->Descriptor != NULL);
+ if (KsTsduMdl->Descriptor) {
+ TdiReturnChainedReceives(
+ &(KsTsduMdl->Descriptor),
+ 1 );
+ }
- Status = KsLockUserBuffer(
- AddressInfo,
- FALSE,
- *(AddressSize),
- IoModifyAccess,
- &Mdl
- );
+ KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
+ }
- if (!NT_SUCCESS(Status)) {
+ } else {
+ KsPrint((1, "KsReadTsdu: unknown tsdu slot: slot = %x type = %x Start= %x Length=%x\n",
+ KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength));
+ KsPrint((1, " Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x\n",
+ KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength));
+ cfs_enter_debugger();
+ }
+ }
- IoFreeIrp(Irp);
- Irp = NULL;
+ /* we need attach the KsTsdu to the list header */
+ if (KsTsdu) {
+ if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
+ KsPutKsTsdu(KsTsdu);
+ KsTsdu = NULL;
+ } else {
+ TsduMgr->NumOfTsdu++;
+ cfs_list_add(&(KsTsdu->Link), &(TsduMgr->TsduList));
+ }
+ }
+
+ if (length > BytesRecved) {
+ goto NextTsdu;
}
}
- if (Irp) {
+#if DBG
+ LASSERT(TotalBytes == TsduMgr->TotalBytes + BytesRecved);
+#endif
+ KsPrint((4, "KsReadTsdu: TsduMgr=%p recved=%xh (%xh) remained=%xh\n",
+ TsduMgr, BytesRecved, length, TsduMgr->TotalBytes ));
- LASSERT(NT_SUCCESS(Status));
+ return BytesRecved;
+}
- TdiBuildQueryInformation(
- Irp,
- DeviceObject,
- FileObject,
- NULL,
- NULL,
- TDI_QUERY_ADDRESS_INFO,
- Mdl
- );
- Status = KsSubmitTdiIrp(
- DeviceObject,
- Irp,
- TRUE,
- AddressSize
- );
+ULONG
+KsTdiSendFlags(int SockFlags)
+{
+ ULONG TdiFlags = 0;
- KsReleaseMdl(Mdl, FALSE);
+ if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
+ cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
}
- if (!NT_SUCCESS(Status)) {
+ if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
+ cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
+ }
- cfs_enter_debugger();
- //TDI_BUFFER_OVERFLOW
+ if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
+ cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
}
- return (Status);
+ return TdiFlags;
}
-/*
- * KsQueryProviderInfo
- * Query the underlying transport device's information
- *
- * Arguments:
- * TdiDeviceName: the transport device's name string
- * ProviderInfo: TDI_PROVIDER_INFO struncture
- *
- * Return Value:
- * NTSTATUS: Nt system status code
- *
- * NOTES:
- * N/A
- */
-
-NTSTATUS
-KsQueryProviderInfo(
- PWSTR TdiDeviceName,
- PTDI_PROVIDER_INFO ProviderInfo
- )
+ULONG
+KsTdiRecvFlags(int SockFlags)
{
- NTSTATUS Status = STATUS_SUCCESS;
-
- PIRP Irp = NULL;
- PMDL Mdl = NULL;
-
- UNICODE_STRING ControlName;
+ ULONG TdiFlags = 0;
- HANDLE Handle;
- PFILE_OBJECT FileObject;
- PDEVICE_OBJECT DeviceObject;
+ if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
+ cfs_set_flag(TdiFlags, TDI_RECEIVE_EXPEDITED);
+ }
- ULONG ProviderSize = 0;
+ if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
+ cfs_set_flag(TdiFlags, TDI_RECEIVE_PARTIAL);
+ }
- RtlInitUnicodeString(&ControlName, TdiDeviceName);
+ if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
+ cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
+ }
- //
- // Open the Tdi Control Channel
- //
+ return TdiFlags;
+}
- Status = KsOpenControl(
- &ControlName,
- &Handle,
- &FileObject
- );
+int
+KsWriteTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
+{
+ int rc = 0;
- if (!NT_SUCCESS(Status)) {
+ if (TsduMgr->TotalBytes <= TDINAL_MAX_TSDU_QUEUE_SIZE) {
+ rc = KsWriteTsduDat(TsduMgr, buffer, length, flags);
+ }
- KsPrint((2, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
- return (Status);
+ if (rc > 0) {
+ return rc;
}
- //
- // Obtain The Related Device Object
- //
+ return -EAGAIN;
+}
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
+int
+KsReadTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
+{
+ int rc = KsReadTsdu(TsduMgr, buffer, length, flags);
- ProviderSize = sizeof(TDI_PROVIDER_INFO);
- RtlZeroMemory(ProviderInfo, ProviderSize);
+ if (rc > 0) {
+ return rc;
+ }
- //
- // Allocating the Tdi Setting Irp ...
- //
+ return -EAGAIN;
+}
- Irp = KsBuildTdiIrp(DeviceObject);
+/*
+ * KsInitializeKsTsduMgr
+ * Initialize the management structure of
+ * Tsdu buffers
+ *
+ * Arguments:
+ * TsduMgr: the TsduMgr to be initialized
+ *
+ * Return Value:
+ * VOID
+ *
+ * NOTES:
+ * N/A
+ */
- if (NULL == Irp) {
-
- Status = STATUS_INSUFFICIENT_RESOURCES;
-
- } else {
-
- //
- // Locking the User Buffer / Allocating a MDL for it
- //
-
- Status = KsLockUserBuffer(
- ProviderInfo,
- FALSE,
- ProviderSize,
- IoModifyAccess,
- &Mdl
- );
-
- if (!NT_SUCCESS(Status)) {
-
- IoFreeIrp(Irp);
- Irp = NULL;
- }
- }
-
- if (Irp) {
-
- LASSERT(NT_SUCCESS(Status));
-
- TdiBuildQueryInformation(
- Irp,
- DeviceObject,
- FileObject,
- NULL,
- NULL,
- TDI_QUERY_PROVIDER_INFO,
- Mdl
- );
+VOID
+KsInitializeKsTsduMgr(
+ PKS_TSDUMGR TsduMgr
+ )
+{
+ KeInitializeEvent(
+ &(TsduMgr->Event),
+ NotificationEvent,
+ FALSE
+ );
- Status = KsSubmitTdiIrp(
- DeviceObject,
- Irp,
- TRUE,
- &ProviderSize
- );
+ CFS_INIT_LIST_HEAD(
+ &(TsduMgr->TsduList)
+ );
- KsReleaseMdl(Mdl, FALSE);
- }
+ TsduMgr->NumOfTsdu = 0;
+ TsduMgr->TotalBytes = 0;
- if (!NT_SUCCESS(Status)) {
+ cfs_spin_lock_init(&TsduMgr->Lock);
+}
- cfs_enter_debugger();
- //TDI_BUFFER_OVERFLOW
- }
- KsCloseControl(Handle, FileObject);
+/*
+ * KsInitializeKsChain
+ * Initialize the China structure for receiving
+ * or transmitting
+ *
+ * Arguments:
+ * KsChain: the KsChain to be initialized
+ *
+ * Return Value:
+ * VOID
+ *
+ * NOTES:
+ * N/A
+ */
- return (Status);
+VOID
+KsInitializeKsChain(
+ PKS_CHAIN KsChain
+ )
+{
+ KsInitializeKsTsduMgr(&(KsChain->Normal));
+ KsInitializeKsTsduMgr(&(KsChain->Expedited));
+ KsChain->Expedited.OOB = TRUE;
}
+
/*
- * KsQueryConnectionInfo
- * Query the connection info of the FileObject specified
- * (some statics data of the traffic)
+ * KsCleanupTsduMgr
+ * Clean up all the Tsdus in the TsduMgr list
*
* Arguments:
- * FileObject: the FileObject to be queried
- * ConnectionInfo: buffer to contain the connection info
- * ConnectionSize: length of the ConnectionInfo buffer
+ * TsduMgr: the Tsdu list manager
*
* Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
+ * NTSTATUS: nt status code
*
* NOTES:
* N/A
*/
NTSTATUS
-KsQueryConnectionInfo(
- PFILE_OBJECT ConnectionObject,
- PTDI_CONNECTION_INFO ConnectionInfo,
- PULONG ConnectionSize
- )
+KsCleanupTsduMgr(
+ PKS_TSDUMGR TsduMgr
+ )
{
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PIRP Irp = NULL;
- PMDL Mdl;
- PDEVICE_OBJECT DeviceObject;
+ PKS_TSDU KsTsdu;
+ PKS_TSDU_DAT KsTsduDat;
+ PKS_TSDU_BUF KsTsduBuf;
+ PKS_TSDU_MDL KsTsduMdl;
- LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
+ LASSERT(NULL != TsduMgr);
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ KsRemoveTdiEngine(TsduMgr);
+ KeSetEvent(&(TsduMgr->Event), 0, FALSE);
- RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
+ while (!cfs_list_empty(&TsduMgr->TsduList)) {
- //
- // Allocating the Tdi Query Irp ...
- //
+ KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
+ LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
- Irp = KsBuildTdiIrp(DeviceObject);
+ if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
- if (NULL == Irp) {
+ //
+ // KsTsdu is empty now, we need free it ...
+ //
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ cfs_list_del(&(KsTsdu->Link));
+ TsduMgr->NumOfTsdu--;
- } else {
+ KsFreeKsTsdu(KsTsdu);
- //
- // Locking the User Buffer / Allocating a MDL for it
- //
+ } else {
- Status = KsLockUserBuffer(
- ConnectionInfo,
- FALSE,
- *(ConnectionSize),
- IoModifyAccess,
- &Mdl
- );
+ KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
+ KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
+ KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
- if (NT_SUCCESS(Status)) {
+ if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- IoFreeIrp(Irp);
- Irp = NULL;
- }
- }
+ KsTsdu->StartOffset += KsTsduDat->TotalLength;
- if (Irp) {
+ } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
- LASSERT(NT_SUCCESS(Status));
+ ASSERT(KsTsduBuf->UserBuffer != NULL);
- TdiBuildQueryInformation(
- Irp,
- DeviceObject,
- ConnectionObject,
- NULL,
- NULL,
- TDI_QUERY_CONNECTION_INFO,
- Mdl
- );
+ if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
+ if (KsTsduBuf->Mdl) {
+ KsTsduBuf->Mdl->Next = NULL;
+ KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
+ }
+ ExFreePool(KsTsduBuf->UserBuffer);
+ } else {
+ cfs_enter_debugger();
+ }
- Status = KsSubmitTdiIrp(
- DeviceObject,
- Irp,
- TRUE,
- ConnectionSize
- );
+ KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
- KsReleaseMdl(Mdl, FALSE);
+ } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
+
+ //
+ // MDL Tsdu Unit ...
+ //
+ if (KsTsduMdl->Descriptor) {
+ TdiReturnChainedReceives(
+ &(KsTsduMdl->Descriptor),
+ 1 );
+ } else if (KsTsduMdl->Mdl) {
+ KsTsduMdl->Mdl->Next = NULL;
+ KsReleaseMdl(KsTsduMdl->Mdl, FALSE);
+ }
+
+ KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
+ }
+ }
}
- return (Status);
+ return STATUS_SUCCESS;
}
/*
- * KsInitializeTdiAddress
- * Initialize the tdi addresss
+ * KsCleanupKsChain
+ * Clean up the TsduMgrs of the KsChain
*
* Arguments:
- * pTransportAddress: tdi address to be initialized
- * IpAddress: the ip address of object
- * IpPort: the ip port of the object
+ * KsChain: the chain managing TsduMgr
*
* Return Value:
- * ULONG: the total size of the tdi address
+ * NTSTATUS: nt status code
*
* NOTES:
* N/A
*/
-ULONG
-KsInitializeTdiAddress(
- IN OUT PTA_IP_ADDRESS pTransportAddress,
- IN ULONG IpAddress,
- IN USHORT IpPort
+NTSTATUS
+KsCleanupKsChain(
+ PKS_CHAIN KsChain
)
{
- pTransportAddress->TAAddressCount = 1;
- pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
- pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
- pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
- pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
+ NTSTATUS Status;
- return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
+ LASSERT(NULL != KsChain);
+
+ Status = KsCleanupTsduMgr(
+ &(KsChain->Normal)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
+
+ Status = KsCleanupTsduMgr(
+ &(KsChain->Expedited)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
+
+errorout:
+
+ return Status;
}
+
/*
- * KsQueryTdiAddressLength
- * Query the total size of the tdi address
+ * KsCleanupTsdu
+ * Clean up all the Tsdus of a tdi connected object
*
* Arguments:
- * pTransportAddress: tdi address to be queried
+ * tconn: the tdi connection which is connected already.
*
* Return Value:
- * ULONG: the total size of the tdi address
- *
- * NOTES:
- * N/A
- */
-
-ULONG
-KsQueryTdiAddressLength(
- PTRANSPORT_ADDRESS pTransportAddress
- )
-{
- ULONG TotalLength = 0;
- LONG i;
-
- PTA_ADDRESS UNALIGNED pTaAddress = NULL;
-
- ASSERT (NULL != pTransportAddress);
-
- TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
- FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
-
- pTaAddress = (TA_ADDRESS UNALIGNED *)pTransportAddress->Address;
-
- for (i = 0; i < pTransportAddress->TAAddressCount; i++)
- {
- TotalLength += pTaAddress->AddressLength;
- pTaAddress = (TA_ADDRESS UNALIGNED *)((PCHAR)pTaAddress +
- FIELD_OFFSET(TA_ADDRESS,Address) +
- pTaAddress->AddressLength );
- }
-
- return (TotalLength);
-}
-
-
-/*
- * KsQueryIpAddress
- * Query the ip address of the tdi object
- *
- * Arguments:
- * FileObject: tdi object to be queried
- * TdiAddress: TdiAddress buffer, to store the queried
- * tdi ip address
- * AddressLength: buffer length of the TdiAddress
- *
- * Return Value:
- * ULONG: the total size of the tdi ip address
+ * Nt status code
*
* NOTES:
* N/A
*/
NTSTATUS
-KsQueryIpAddress(
- PFILE_OBJECT FileObject,
- PVOID TdiAddress,
- ULONG* AddressLength
+KsCleanupTsdu(
+ ks_tconn_t * tconn
)
{
- NTSTATUS Status;
-
- PTDI_ADDRESS_INFO TdiAddressInfo;
- ULONG Length;
-
-
- //
- // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
- //
-
- Length = MAX_ADDRESS_LENGTH;
+ NTSTATUS Status = STATUS_SUCCESS;
- TdiAddressInfo = (PTDI_ADDRESS_INFO)
- ExAllocatePoolWithTag(
- NonPagedPool,
- Length,
- 'KSAI' );
- if (NULL == TdiAddressInfo) {
+ if (tconn->kstc_type != kstt_sender &&
+ tconn->kstc_type != kstt_child ) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
+ if (tconn->kstc_type == kstt_sender) {
- Status = KsQueryAddressInfo(
- FileObject,
- TdiAddressInfo,
- &Length
- );
-
-errorout:
-
- if (NT_SUCCESS(Status))
- {
- if (*AddressLength < Length) {
-
- Status = STATUS_BUFFER_TOO_SMALL;
+ Status = KsCleanupKsChain(
+ &(tconn->sender.kstc_recv)
+ );
- } else {
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
- *AddressLength = Length;
- RtlCopyMemory(
- TdiAddress,
- &(TdiAddressInfo->Address),
- Length
- );
+ Status = KsCleanupKsChain(
+ &(tconn->sender.kstc_send)
+ );
- Status = STATUS_SUCCESS;
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
}
} else {
- }
+ Status = KsCleanupKsChain(
+ &(tconn->child.kstc_recv)
+ );
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
- if (NULL != TdiAddressInfo) {
+ Status = KsCleanupKsChain(
+ &(tconn->child.kstc_send)
+ );
- ExFreePool(TdiAddressInfo);
- }
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
- return Status;
-}
+ }
+errorout:
-/*
- * KsErrorEventHandler
- * the common error event handler callback
- *
- * Arguments:
- * TdiEventContext: should be the socket
- * Status: the error code
- *
- * Return Value:
- * Status: STATS_SUCCESS
- *
- * NOTES:
- * We need not do anything in such a severe
- * error case. System will process it for us.
- */
+ return (Status);
+}
NTSTATUS
-KsErrorEventHandler(
- IN PVOID TdiEventContext,
- IN NTSTATUS Status
- )
+KsIrpCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
{
- KsPrint((2, "KsErrorEventHandler called at Irql = %xh ...\n",
- KeGetCurrentIrql()));
+ if (NULL != Context) {
+ KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
+ }
- cfs_enter_debugger();
+ return STATUS_MORE_PROCESSING_REQUIRED;
- return (STATUS_SUCCESS);
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
}
/*
- * ks_set_handlers
- * setup all the event handler callbacks
+ * KsBuildTdiIrp
+ * Allocate a new IRP and initialize it to be issued to tdi
*
* Arguments:
- * tconn: the tdi connecton object
+ * DeviceObject: device object created by the underlying
+ * TDI transport driver
*
* Return Value:
- * int: ks error code
+ * PRIP: the allocated Irp in success or NULL in failure.
*
* NOTES:
* N/A
*/
-int
-ks_set_handlers(
- ksock_tconn_t * tconn
+PIRP
+KsBuildTdiIrp(
+ IN PDEVICE_OBJECT DeviceObject
)
{
- NTSTATUS status = STATUS_SUCCESS;
- KS_EVENT_HANDLERS handlers;
-
- /* to make sure the address object is opened already */
- if (tconn->kstc_addr.FileObject == NULL) {
- goto errorout;
- }
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
- /* initialize the handlers indictor array. for sender and listenr,
- there are different set of callbacks. for child, we just return. */
+ //
+ // Allocating the IRP ...
+ //
- memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
+ Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
- SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
- SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
- SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
- SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
+ if (NULL != Irp) {
- // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
+ //
+ // Getting the Next Stack Location ...
+ //
- if (tconn->kstc_type == kstt_listener) {
- SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
- } else if (tconn->kstc_type == kstt_child) {
- goto errorout;
- }
+ IrpSp = IoGetNextIrpStackLocation(Irp);
- /* set all the event callbacks */
- status = KsSetEventHandlers(
- tconn->kstc_addr.FileObject, /* Address File Object */
- tconn, /* Event Context */
- &handlers /* Event callback handlers */
- );
+ //
+ // Initializing Irp ...
+ //
-errorout:
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
+ }
- return cfs_error_code(status);
+ return Irp;
}
-
/*
- * ks_reset_handlers
- * disable all the event handler callbacks (set to NULL)
+ * KsSubmitTdiIrp
+ * Issue the Irp to the underlying tdi driver
*
* Arguments:
- * tconn: the tdi connecton object
+ * DeviceObject: the device object created by TDI driver
+ * Irp: the I/O request packet to be processed
+ * bSynchronous: synchronous or not. If true, we need wait
+ * until the process is finished.
+ * Information: returned info
*
* Return Value:
- * int: ks error code
+ * NTSTATUS: kernel status code
*
* NOTES:
* N/A
*/
-int
-ks_reset_handlers(
- ksock_tconn_t * tconn
+NTSTATUS
+KsSubmitTdiIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN BOOLEAN bSynchronous,
+ OUT PULONG Information
)
{
- NTSTATUS status = STATUS_SUCCESS;
- KS_EVENT_HANDLERS handlers;
-
- /* to make sure the address object is opened already */
- if (tconn->kstc_addr.FileObject == NULL) {
- goto errorout;
- }
+ NTSTATUS Status;
+ KEVENT Event;
- /* initialize the handlers indictor array. for sender and listenr,
- there are different set of callbacks. for child, we just return. */
+ if (bSynchronous) {
- memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
+ KeInitializeEvent(
+ &Event,
+ SynchronizationEvent,
+ FALSE
+ );
- SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
- SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
- SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
- SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
- SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
- // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
- if (tconn->kstc_type == kstt_listener) {
- SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
- } else if (tconn->kstc_type == kstt_child) {
- goto errorout;
+ IoSetCompletionRoutine(
+ Irp,
+ KsIrpCompletionRoutine,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE
+ );
}
- /* set all the event callbacks */
- status = KsSetEventHandlers(
- tconn->kstc_addr.FileObject, /* Address File Object */
- tconn, /* Event Context */
- &handlers /* Event callback handlers */
- );
+ Status = IoCallDriver(DeviceObject, Irp);
-errorout:
+ if (bSynchronous) {
- return cfs_error_code(status);
+ if (STATUS_PENDING == Status) {
+
+ Status = KeWaitForSingleObject(
+ &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+
+ Status = Irp->IoStatus.Status;
+
+ if (Information) {
+ *Information = (ULONG)(Irp->IoStatus.Information);
+ }
+
+ IoFreeIrp(Irp);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+
+ KsPrint((1, "KsSubmitTdiIrp: Error when submitting the Irp: "
+ "Status = %xh (%s)\n", Status, KsNtStatusToString(Status)));
+ }
+
+ return (Status);
}
+
/*
- * KsAcceptCompletionRoutine
- * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
- *
- * Here system gives us a chance to check the conneciton is built
- * ready or not.
+ * KsOpenControl
+ * Open the Control Channel Object ...
*
* Arguments:
- * DeviceObject: the device object of the transport driver
- * Irp: the Irp is being completed.
- * Context: the context we specified when issuing the Irp
+ * DeviceName: the device name to be opened
+ * Handle: opened handle in success case
+ * FileObject: the fileobject of the device
*
* Return Value:
- * Nt status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
* N/A
*/
NTSTATUS
-KsAcceptCompletionRoutine(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
+KsOpenControl(
+ IN PUNICODE_STRING DeviceName,
+ OUT HANDLE * Handle,
+ OUT PFILE_OBJECT * FileObject
+ )
{
- ksock_tconn_t * child = (ksock_tconn_t *) Context;
- ksock_tconn_t * parent = child->child.kstc_parent;
+ NTSTATUS Status = STATUS_SUCCESS;
- KsPrint((2, "KsAcceptCompletionRoutine: called at Irql: %xh\n",
- KeGetCurrentIrql() ));
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatus;
- KsPrint((2, "KsAcceptCompletionRoutine: Context = %xh Status = %xh\n",
- Context, Irp->IoStatus.Status));
- LASSERT(child->kstc_type == kstt_child);
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- spin_lock(&(child->kstc_lock));
+ //
+ // Initializing ...
+ //
- LASSERT(parent->kstc_state == ksts_listening);
- LASSERT(child->kstc_state == ksts_connecting);
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ DeviceName,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
- if (NT_SUCCESS(Irp->IoStatus.Status)) {
+ LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL );
- child->child.kstc_accepted = TRUE;
+ //
+ // Creating the Transport Address Object ...
+ //
- child->kstc_state = ksts_connected;
+ Status = ZwCreateFile(
+ Handle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ NULL,
+ 0
+ );
- /* wake up the daemon thread which waits on this event */
- KeSetEvent(
- &(parent->listener.kstc_accept_event),
- 0,
- FALSE
- );
- spin_unlock(&(child->kstc_lock));
+ if (NT_SUCCESS(Status)) {
- KsPrint((2, "KsAcceptCompletionRoutine: Get %xh now signal the event ...\n", parent));
+ //
+ // Now Obtaining the FileObject of the Transport Address ...
+ //
- } else {
+ Status = ObReferenceObjectByHandle(
+ *Handle,
+ FILE_ANY_ACCESS,
+ NULL,
+ KernelMode,
+ FileObject,
+ NULL
+ );
- /* re-use this child connecton */
- child->child.kstc_accepted = FALSE;
- child->child.kstc_busy = FALSE;
- child->kstc_state = ksts_associated;
+ if (!NT_SUCCESS(Status)) {
- spin_unlock(&(child->kstc_lock));
- }
+ cfs_enter_debugger();
+ ZwClose(*Handle);
+ }
- /* now free the Irp */
- IoFreeIrp(Irp);
+ } else {
- /* drop the refer count of the child */
- ks_put_tconn(child);
+ cfs_enter_debugger();
+ }
- return (STATUS_MORE_PROCESSING_REQUIRED);
+ return (Status);
}
/*
- * ks_get_vacancy_backlog
- * Get a vacancy listeing child from the backlog list
+ * KsCloseControl
+ * Release the Control Channel Handle and FileObject
*
* Arguments:
- * parent: the listener daemon connection
+ * Handle: the channel handle to be released
+ * FileObject: the fileobject to be released
*
* Return Value:
- * the child listening connection or NULL in failure
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
- * Notes
- * Parent's lock should be acquired before calling.
+ * Notes:
+ * N/A
*/
-ksock_tconn_t *
-ks_get_vacancy_backlog(
- ksock_tconn_t * parent
- )
+NTSTATUS
+KsCloseControl(
+ IN HANDLE Handle,
+ IN PFILE_OBJECT FileObject
+ )
{
- ksock_tconn_t * child;
-
- LASSERT(parent->kstc_type == kstt_listener);
- LASSERT(parent->kstc_state == ksts_listening);
-
- if (list_empty(&(parent->listener.kstc_listening.list))) {
-
- child = NULL;
-
- } else {
-
- struct list_head * tmp;
+ NTSTATUS Status = STATUS_SUCCESS;
- /* check the listening queue and try to get a free connecton */
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
- child = list_entry (tmp, ksock_tconn_t, child.kstc_link);
- spin_lock(&(child->kstc_lock));
+ if (FileObject) {
- if (!child->child.kstc_busy) {
- LASSERT(child->kstc_state == ksts_associated);
- child->child.kstc_busy = TRUE;
- spin_unlock(&(child->kstc_lock));
- break;
- } else {
- spin_unlock(&(child->kstc_lock));
- child = NULL;
- }
- }
+ ObDereferenceObject(FileObject);
}
- return child;
-}
-
-ks_addr_slot_t *
-KsSearchIpAddress(PUNICODE_STRING DeviceName)
-{
- ks_addr_slot_t * slot = NULL;
- PLIST_ENTRY list = NULL;
-
- spin_lock(&ks_data.ksnd_addrs_lock);
+ if (Handle) {
- list = ks_data.ksnd_addrs_list.Flink;
- while (list != &ks_data.ksnd_addrs_list) {
- slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
- if (RtlCompareUnicodeString(
- DeviceName,
- &slot->devname,
- TRUE) == 0) {
- break;
- }
- list = list->Flink;
- slot = NULL;
+ Status = ZwClose(Handle);
}
- spin_unlock(&ks_data.ksnd_addrs_lock);
+ ASSERT(NT_SUCCESS(Status));
- return slot;
+ return (Status);
}
-void
-KsCleanupIpAddresses()
+
+/*
+ * KsOpenAddress
+ * Open the tdi address object
+ *
+ * Arguments:
+ * DeviceName: device name of the address object
+ * pAddress: tdi address of the address object
+ * AddressLength: length in bytes of the tdi address
+ * Handle: the newly opened handle
+ * FileObject: the newly opened fileobject
+ *
+ * Return Value:
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
+ *
+ * Notes:
+ * N/A
+ */
+
+NTSTATUS
+KsOpenAddress(
+ IN PUNICODE_STRING DeviceName,
+ IN PTRANSPORT_ADDRESS pAddress,
+ IN ULONG AddressLength,
+ OUT HANDLE * Handle,
+ OUT PFILE_OBJECT * FileObject
+ )
{
- spin_lock(&ks_data.ksnd_addrs_lock);
+ NTSTATUS Status = STATUS_SUCCESS;
- while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
+ PFILE_FULL_EA_INFORMATION Ea = NULL;
+ ULONG EaLength;
+ UCHAR EaBuffer[EA_MAX_LENGTH];
- ks_addr_slot_t * slot = NULL;
- PLIST_ENTRY list = NULL;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatus;
- list = RemoveHeadList(&ks_data.ksnd_addrs_list);
- slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
- cfs_free(slot);
- ks_data.ksnd_naddrs--;
- }
+ //
+ // Building EA for the Address Object to be Opened ...
+ //
- cfs_assert(ks_data.ksnd_naddrs == 0);
- spin_unlock(&ks_data.ksnd_addrs_lock);
-}
+ Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
+ Ea->NextEntryOffset = 0;
+ Ea->Flags = 0;
+ Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ Ea->EaValueLength = (USHORT)AddressLength;
+ RtlCopyMemory(
+ &(Ea->EaName),
+ TdiTransportAddress,
+ Ea->EaNameLength + 1
+ );
+ RtlMoveMemory(
+ &(Ea->EaName[Ea->EaNameLength + 1]),
+ pAddress,
+ AddressLength
+ );
+ EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ Ea->EaNameLength + AddressLength;
-VOID
-KsAddAddressHandler(
- IN PTA_ADDRESS Address,
- IN PUNICODE_STRING DeviceName,
- IN PTDI_PNP_CONTEXT Context
- )
-{
- PTDI_ADDRESS_IP IpAddress = NULL;
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
- Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
- ks_addr_slot_t * slot = NULL;
+ //
+ // Initializing ...
+ //
- IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
- KsPrint((1, "KsAddAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
- DeviceName, Context, IpAddress->in_addr,
- (IpAddress->in_addr & 0xFF000000) >> 24,
- (IpAddress->in_addr & 0x00FF0000) >> 16,
- (IpAddress->in_addr & 0x0000FF00) >> 8,
- (IpAddress->in_addr & 0x000000FF) >> 0 ));
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ DeviceName,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
- slot = KsSearchIpAddress(DeviceName);
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- if (slot != NULL) {
- slot->up = TRUE;
- slot->ip_addr = ntohl(IpAddress->in_addr);
- } else {
- slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
- if (slot != NULL) {
- spin_lock(&ks_data.ksnd_addrs_lock);
- InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
- sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
- slot->ip_addr = ntohl(IpAddress->in_addr);
- slot->up = TRUE;
- RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
- slot->devname.Length = DeviceName->Length;
- slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
- slot->devname.Buffer = slot->buffer;
- spin_unlock(&ks_data.ksnd_addrs_lock);
- }
- }
- }
-}
+ //
+ // Creating the Transport Address Object ...
+ //
-VOID
-KsDelAddressHandler(
- IN PTA_ADDRESS Address,
- IN PUNICODE_STRING DeviceName,
- IN PTDI_PNP_CONTEXT Context
- )
-{
- PTDI_ADDRESS_IP IpAddress = NULL;
+ Status = ZwCreateFile(
+ Handle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
+ FILE_OPEN,
+ 0,
+ Ea,
+ EaLength
+ );
- if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
- Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
- ks_addr_slot_t * slot = NULL;
+ if (NT_SUCCESS(Status)) {
- slot = KsSearchIpAddress(DeviceName);
+ //
+ // Now Obtaining the FileObject of the Transport Address ...
+ //
- if (slot != NULL) {
- slot->up = FALSE;
+ Status = ObReferenceObjectByHandle(
+ *Handle,
+ FILE_ANY_ACCESS,
+ NULL,
+ KernelMode,
+ FileObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ cfs_enter_debugger();
+ ZwClose(*Handle);
}
- IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
- KsPrint((1, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
- DeviceName, Context, IpAddress->in_addr,
- (IpAddress->in_addr & 0xFF000000) >> 24,
- (IpAddress->in_addr & 0x00FF0000) >> 16,
- (IpAddress->in_addr & 0x0000FF00) >> 8,
- (IpAddress->in_addr & 0x000000FF) >> 0 ));
+ } else {
+
+ cfs_enter_debugger();
}
+
+ return (Status);
}
+/*
+ * KsCloseAddress
+ * Release the Hanlde and FileObject of an opened tdi
+ * address object
+ *
+ * Arguments:
+ * Handle: the handle to be released
+ * FileObject: the fileobject to be released
+ *
+ * Return Value:
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
+ *
+ * Notes:
+ * N/A
+ */
+
NTSTATUS
-KsRegisterPnpHandlers()
+KsCloseAddress(
+ IN HANDLE Handle,
+ IN PFILE_OBJECT FileObject
+)
{
- TDI20_CLIENT_INTERFACE_INFO ClientInfo;
-
- /* initialize the global ks_data members */
- RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
- spin_lock_init(&ks_data.ksnd_addrs_lock);
- InitializeListHead(&ks_data.ksnd_addrs_list);
-
- /* register the pnp handlers */
- RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
- ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
+ NTSTATUS Status = STATUS_SUCCESS;
- ClientInfo.ClientName = &ks_data.ksnd_client_name;
- ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
- ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
+ if (FileObject) {
- return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
- &ks_data.ksnd_pnp_handle);
-}
+ ObDereferenceObject(FileObject);
+ }
-VOID
-KsDeregisterPnpHandlers()
-{
- if (ks_data.ksnd_pnp_handle) {
+ if (Handle) {
- /* De-register the pnp handlers */
+ Status = ZwClose(Handle);
+ }
- TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
- ks_data.ksnd_pnp_handle = NULL;
+ ASSERT(NT_SUCCESS(Status));
- /* cleanup all the ip address slots */
- KsCleanupIpAddresses();
- }
+ return (Status);
}
+
/*
- * KsConnectEventHandler
- * Connect event handler event handler, called by the underlying TDI
- * transport in response to an incoming request to the listening daemon.
- *
- * it will grab a vacancy backlog from the children tconn list, and
- * build an acception Irp with it, then transfer the Irp to TDI driver.
+ * KsOpenConnection
+ * Open a tdi connection object
*
* Arguments:
- * TdiEventContext: the tdi connnection object of the listening daemon
- * ......
+ * DeviceName: device name of the connection object
+ * ConnectionContext: the connection context
+ * Handle: the newly opened handle
+ * FileObject: the newly opened fileobject
*
* Return Value:
- * Nt kernel status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
* N/A
*/
NTSTATUS
-KsConnectEventHandler(
- IN PVOID TdiEventContext,
- IN LONG RemoteAddressLength,
- IN PVOID RemoteAddress,
- IN LONG UserDataLength,
- IN PVOID UserData,
- IN LONG OptionsLength,
- IN PVOID Options,
- OUT CONNECTION_CONTEXT * ConnectionContext,
- OUT PIRP * AcceptIrp
- )
+KsOpenConnection(
+ IN PUNICODE_STRING DeviceName,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ OUT HANDLE * Handle,
+ OUT PFILE_OBJECT * FileObject
+ )
{
- ksock_tconn_t * parent;
- ksock_tconn_t * child;
+ NTSTATUS Status = STATUS_SUCCESS;
- PFILE_OBJECT FileObject;
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION Ea = NULL;
+ ULONG EaLength;
+ UCHAR EaBuffer[EA_MAX_LENGTH];
- PIRP Irp = NULL;
- PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatus;
- KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
- parent = (ksock_tconn_t *) TdiEventContext;
+ //
+ // Building EA for the Address Object to be Opened ...
+ //
- LASSERT(parent->kstc_type == kstt_listener);
+ Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
+ Ea->NextEntryOffset = 0;
+ Ea->Flags = 0;
+ Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
+ Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
+ RtlCopyMemory(
+ &(Ea->EaName),
+ TdiConnectionContext,
+ Ea->EaNameLength + 1
+ );
+ RtlMoveMemory(
+ &(Ea->EaName[Ea->EaNameLength + 1]),
+ &ConnectionContext,
+ sizeof(CONNECTION_CONTEXT)
+ );
+ EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
+ Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
- spin_lock(&(parent->kstc_lock));
-
- if (parent->kstc_state == ksts_listening) {
-
- /* allocate a new ConnectionInfo to backup the peer's info */
-
- ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
- NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
- RemoteAddressLength, 'iCsK' );
-
- if (NULL == ConnectionInfo) {
-
- Status = STATUS_INSUFFICIENT_RESOURCES;
- cfs_enter_debugger();
- goto errorout;
- }
-
- /* initializing ConnectionInfo structure ... */
-
- ConnectionInfo->UserDataLength = UserDataLength;
- ConnectionInfo->UserData = UserData;
- ConnectionInfo->OptionsLength = OptionsLength;
- ConnectionInfo->Options = Options;
- ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
- ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
-
- RtlCopyMemory(
- ConnectionInfo->RemoteAddress,
- RemoteAddress,
- RemoteAddressLength
- );
-
- /* get the vacancy listening child tdi connections */
-
- child = ks_get_vacancy_backlog(parent);
-
- if (child) {
-
- spin_lock(&(child->kstc_lock));
- child->child.kstc_info.ConnectionInfo = ConnectionInfo;
- child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
- child->kstc_state = ksts_connecting;
- spin_unlock(&(child->kstc_lock));
-
- } else {
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- KsPrint((2, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ //
+ // Initializing ...
+ //
- goto errorout;
- }
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ DeviceName,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
- FileObject = child->child.kstc_info.FileObject;
- DeviceObject = IoGetRelatedDeviceObject (FileObject);
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- Irp = KsBuildTdiIrp(DeviceObject);
+ //
+ // Creating the Connection Object ...
+ //
- TdiBuildAccept(
- Irp,
- DeviceObject,
- FileObject,
- KsAcceptCompletionRoutine,
- child,
+ Status = ZwCreateFile(
+ Handle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
NULL,
- NULL
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ Ea,
+ EaLength
);
- IoSetNextIrpStackLocation(Irp);
-
- /* grap the refer of the child tdi connection */
- ks_get_tconn(child);
-
- Status = STATUS_MORE_PROCESSING_REQUIRED;
-
- *AcceptIrp = Irp;
- *ConnectionContext = child;
-
- } else {
-
- Status = STATUS_CONNECTION_REFUSED;
- goto errorout;
- }
-
- spin_unlock(&(parent->kstc_lock));
-
- return Status;
-errorout:
+ if (NT_SUCCESS(Status)) {
- spin_unlock(&(parent->kstc_lock));
+ //
+ // Now Obtaining the FileObject of the Transport Address ...
+ //
- {
- *AcceptIrp = NULL;
- *ConnectionContext = NULL;
+ Status = ObReferenceObjectByHandle(
+ *Handle,
+ FILE_ANY_ACCESS,
+ NULL,
+ KernelMode,
+ FileObject,
+ NULL
+ );
- if (ConnectionInfo) {
+ if (!NT_SUCCESS(Status)) {
- ExFreePool(ConnectionInfo);
+ cfs_enter_debugger();
+ ZwClose(*Handle);
}
- if (Irp) {
+ } else {
- IoFreeIrp (Irp);
- }
+ cfs_enter_debugger();
}
- return Status;
+ return (Status);
}
/*
- * KsDisconnectCompletionRoutine
- * the Irp completion routine for TdiBuildDisconect
- *
- * We just signal the event and return MORE_PRO... to
- * let the caller take the responsibility of the Irp.
+ * KsCloseConnection
+ * Release the Hanlde and FileObject of an opened tdi
+ * connection object
*
* Arguments:
- * DeviceObject: the device object of the transport
- * Irp: the Irp is being completed.
- * Context: the event specified by the caller
+ * Handle: the handle to be released
+ * FileObject: the fileobject to be released
*
* Return Value:
- * Nt status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
* N/A
*/
NTSTATUS
-KsDisconectCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
+KsCloseConnection(
+ IN HANDLE Handle,
+ IN PFILE_OBJECT FileObject
)
{
+ NTSTATUS Status = STATUS_SUCCESS;
- KeSetEvent((PKEVENT) Context, 0, FALSE);
+ if (FileObject) {
- return STATUS_MORE_PROCESSING_REQUIRED;
+ ObDereferenceObject(FileObject);
+ }
- UNREFERENCED_PARAMETER(DeviceObject);
+ if (Handle) {
+
+ Status = ZwClose(Handle);
+ }
+
+ ASSERT(NT_SUCCESS(Status));
+
+ return (Status);
}
/*
- * KsDisconnectHelper
- * the routine to be executed in the WorkItem procedure
- * this routine is to disconnect a tdi connection
+ * KsAssociateAddress
+ * Associate an address object with a connection object
*
* Arguments:
- * Workitem: the context transferred to the workitem
+ * AddressHandle: the handle of the address object
+ * ConnectionObject: the FileObject of the connection
*
* Return Value:
- * N/A
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
- * tconn is already referred in abort_connecton ...
+ * N/A
*/
-VOID
-KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
+NTSTATUS
+KsAssociateAddress(
+ IN HANDLE AddressHandle,
+ IN PFILE_OBJECT ConnectionObject
+ )
{
- ksock_tconn_t * tconn = WorkItem->tconn;
+ NTSTATUS Status;
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
- DbgPrint("KsDisconnectHelper: disconnecting tconn=%p\n", tconn);
- ks_disconnect_tconn(tconn, WorkItem->Flags);
+ //
+ // Getting the DeviceObject from Connection FileObject
+ //
- KeSetEvent(&(WorkItem->Event), 0, FALSE);
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
- spin_lock(&(tconn->kstc_lock));
- cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
- spin_unlock(&(tconn->kstc_lock));
- ks_put_tconn(tconn);
+ //
+ // Building Tdi Internal Irp ...
+ //
+
+ Irp = KsBuildTdiIrp(DeviceObject);
+
+ if (NULL == Irp) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ //
+ // Assocating the Address Object with the Connection Object
+ //
+
+ TdiBuildAssociateAddress(
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL,
+ AddressHandle
+ );
+
+ //
+ // Calling the Transprot Driver with the Prepared Irp
+ //
+
+ Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
+ }
+
+ return (Status);
}
/*
- * KsDisconnectEventHandler
- * Disconnect event handler event handler, called by the underlying TDI transport
- * in response to an incoming disconnection notification from a remote node.
+ * KsDisassociateAddress
+ * Disassociate the connection object (the relationship will
+ * the corresponding address object will be dismissed. )
*
* Arguments:
- * ConnectionContext: tdi connnection object
- * DisconnectFlags: specifies the nature of the disconnection
- * ......
+ * ConnectionObject: the FileObject of the connection
*
* Return Value:
- * Nt kernel status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
* N/A
*/
-
NTSTATUS
-KsDisconnectEventHandler(
- IN PVOID TdiEventContext,
- IN CONNECTION_CONTEXT ConnectionContext,
- IN LONG DisconnectDataLength,
- IN PVOID DisconnectData,
- IN LONG DisconnectInformationLength,
- IN PVOID DisconnectInformation,
- IN ULONG DisconnectFlags
+KsDisassociateAddress(
+ IN PFILE_OBJECT ConnectionObject
)
{
- ksock_tconn_t * tconn;
- NTSTATUS Status;
- PKS_DISCONNECT_WORKITEM WorkItem;
-
- tconn = (ksock_tconn_t *)ConnectionContext;
+ NTSTATUS Status;
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
- KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
- KeGetCurrentIrql() ));
+ //
+ // Getting the DeviceObject from Connection FileObject
+ //
- KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
- tconn, DisconnectFlags));
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
- ks_get_tconn(tconn);
- spin_lock(&(tconn->kstc_lock));
+ //
+ // Building Tdi Internal Irp ...
+ //
- WorkItem = &(tconn->kstc_disconnect);
+ Irp = KsBuildTdiIrp(DeviceObject);
- if (tconn->kstc_state != ksts_connected) {
+ if (NULL == Irp) {
- Status = STATUS_SUCCESS;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
- if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
-
- Status = STATUS_REMOTE_DISCONNECT;
-
- } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
-
- Status = STATUS_GRACEFUL_DISCONNECT;
- }
-
- if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
-
- ks_get_tconn(tconn);
+ //
+ // Disassocating the Address Object with the Connection Object
+ //
- WorkItem->Flags = DisconnectFlags;
- WorkItem->tconn = tconn;
+ TdiBuildDisassociateAddress(
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL
+ );
- cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
+ //
+ // Calling the Transprot Driver with the Prepared Irp
+ //
- /* queue the workitem to call */
- ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
- }
+ Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
}
- spin_unlock(&(tconn->kstc_lock));
- ks_put_tconn(tconn);
-
- return (Status);
+ return (Status);
}
-NTSTATUS
-KsTcpReceiveCompletionRoutine(
- IN PIRP Irp,
- IN PKS_TCP_COMPLETION_CONTEXT Context
- )
-{
- NTSTATUS Status = Irp->IoStatus.Status;
-
- if (NT_SUCCESS(Status)) {
-
- ksock_tconn_t *tconn = Context->tconn;
-
- PKS_TSDU_DAT KsTsduDat = Context->CompletionContext;
- PKS_TSDU_BUF KsTsduBuf = Context->CompletionContext;
- KsPrint((1, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
- Context->KsTsduMgr->TotalBytes ));
-
- spin_lock(&(tconn->kstc_lock));
-
- if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
- if (cfs_is_flag_set(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING)) {
- cfs_clear_flag(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING);
- } else {
- cfs_enter_debugger();
- }
- } else {
- ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
- if (cfs_is_flag_set(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING)) {
- cfs_clear_flag(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING);
- } else {
- cfs_enter_debugger();
- }
- }
-
- spin_unlock(&(tconn->kstc_lock));
-
- /* wake up the thread waiting for the completion of this Irp */
- KeSetEvent(Context->Event, 0, FALSE);
-
- /* re-active the ks connection and wake up the scheduler */
- if (tconn->kstc_conn && tconn->kstc_sched_cb) {
- tconn->kstc_sched_cb( tconn, FALSE, NULL,
- Context->KsTsduMgr->TotalBytes );
- }
+/*
- } else {
+//
+// Connection Control Event Callbacks
+//
- /* un-expected errors occur, we must abort the connection */
- ks_abort_tconn(Context->tconn);
- }
+TDI_EVENT_CONNECT
+TDI_EVENT_DISCONNECT
+TDI_EVENT_ERROR
- if (Context) {
+//
+// Tcp Event Callbacks
+//
- /* Freeing the Context structure... */
- ExFreePool(Context);
- Context = NULL;
- }
+TDI_EVENT_RECEIVE
+TDI_EVENT_RECEIVE_EXPEDITED
+TDI_EVENT_CHAINED_RECEIVE
+TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
+//
+// Udp Event Callbacks
+//
- /* free the Irp */
- if (Irp) {
- IoFreeIrp(Irp);
- }
+TDI_EVENT_RECEIVE_DATAGRAM
+TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
- return (Status);
-}
+*/
/*
- * KsTcpCompletionRoutine
- * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
- * We need call the use's own CompletionRoutine if specified. Or
- * it's a synchronous case, we need signal the event.
+ * KsSetEventHandlers
+ * Set the tdi event callbacks with an address object
*
* Arguments:
- * DeviceObject: the device object of the transport
- * Irp: the Irp is being completed.
- * Context: the context we specified when issuing the Irp
+ * AddressObject: the FileObject of the address object
+ * EventContext: the parameter for the callbacks
+ * Handlers: the handlers indictor array
*
* Return Value:
- * Nt status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
- * Notes:
+ * NOTES:
* N/A
*/
NTSTATUS
-KsTcpCompletionRoutine(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
+KsSetEventHandlers(
+ IN PFILE_OBJECT AddressObject, // Address File Object
+ IN PVOID EventContext, // Context for Handlers
+ IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
+ )
{
- if (Context) {
+ NTSTATUS Status = STATUS_SUCCESS;
+ PDEVICE_OBJECT DeviceObject;
+ USHORT i = 0;
- PKS_TCP_COMPLETION_CONTEXT CompletionContext = NULL;
- ksock_tconn_t * tconn = NULL;
+ DeviceObject = IoGetRelatedDeviceObject(AddressObject);
- CompletionContext = (PKS_TCP_COMPLETION_CONTEXT) Context;
- tconn = CompletionContext->tconn;
+ for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
- /* release the chained mdl */
- KsReleaseMdl(Irp->MdlAddress, FALSE);
- Irp->MdlAddress = NULL;
+ //
+ // Setup the tdi event callback handler if requested.
+ //
- if (CompletionContext->CompletionRoutine) {
+ if (Handlers->IsActive[i]) {
- if ( CompletionContext->bCounted &&
- InterlockedDecrement(&CompletionContext->ReferCount) != 0 ) {
- goto errorout;
- }
+ PIRP Irp;
//
- // Giving control to user specified CompletionRoutine ...
+ // Building Tdi Internal Irp ...
//
- CompletionContext->CompletionRoutine(
+ Irp = KsBuildTdiIrp(DeviceObject);
+
+ if (NULL == Irp) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ //
+ // Building the Irp to set the Event Handler ...
+ //
+
+ TdiBuildSetEventHandler(
Irp,
- CompletionContext
+ DeviceObject,
+ AddressObject,
+ NULL,
+ NULL,
+ i, /* tdi event type */
+ Handlers->Handler[i], /* tdi event handler */
+ EventContext /* context for the handler */
);
- } else {
-
- //
- // Signaling the Event ...
- //
+ //
+ // Calling the Transprot Driver with the Prepared Irp
+ //
- KeSetEvent(CompletionContext->Event, 0, FALSE);
- }
+ Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
- /* drop the reference count of the tconn object */
- ks_put_tconn(tconn);
+ //
+ // tcp/ip tdi does not support these two event callbacks
+ //
- } else {
+ if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
+ i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
+ cfs_enter_debugger();
+ Status = STATUS_SUCCESS;
+ }
+ }
- cfs_enter_debugger();
+ if (!NT_SUCCESS(Status)) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
+ }
}
+
errorout:
- return STATUS_MORE_PROCESSING_REQUIRED;
+ if (!NT_SUCCESS(Status)) {
+
+ KsPrint((1, "KsSetEventHandlers: Error Status = %xh (%s)\n",
+ Status, KsNtStatusToString(Status) ));
+ }
+
+ return (Status);
}
+
+
/*
- * KsTcpSendCompletionRoutine
- * the user specified Irp completion routine for asynchronous
- * data transmission requests.
- *
- * It will do th cleanup job of the ksock_tx_t and wake up the
- * ks scheduler thread
+ * KsQueryAddressInfo
+ * Query the address of the FileObject specified
*
* Arguments:
- * Irp: the Irp is being completed.
- * Context: the context we specified when issuing the Irp
+ * FileObject: the FileObject to be queried
+ * AddressInfo: buffer to contain the address info
+ * AddressSize: length of the AddressInfo buffer
*
* Return Value:
- * Nt status code
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
*
* Notes:
* N/A
*/
NTSTATUS
-KsTcpSendCompletionRoutine(
- IN PIRP Irp,
- IN PKS_TCP_COMPLETION_CONTEXT Context
- )
+KsQueryAddressInfo(
+ PFILE_OBJECT FileObject,
+ PTDI_ADDRESS_INFO AddressInfo,
+ PULONG AddressSize
+ )
{
- NTSTATUS Status = Irp->IoStatus.Status;
- ULONG rc = Irp->IoStatus.Information;
- ksock_tconn_t * tconn = Context->tconn;
- PKS_TSDUMGR KsTsduMgr = Context->KsTsduMgr;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PIRP Irp = NULL;
+ PMDL Mdl;
+ PDEVICE_OBJECT DeviceObject;
- ENTRY;
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- LASSERT(tconn) ;
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
- if (NT_SUCCESS(Status)) {
+ RtlZeroMemory(AddressInfo, *(AddressSize));
- if (Context->bCounted) {
- PVOID tx = Context->CompletionContext;
+ //
+ // Allocating the Tdi Setting Irp ...
+ //
- ASSERT(tconn->kstc_update_tx != NULL);
+ Irp = KsBuildTdiIrp(DeviceObject);
- /* update the tx, rebasing the kiov or iov pointers */
- tx = tconn->kstc_update_tx(tconn, tx, rc);
+ if (NULL == Irp) {
- /* update the KsTsudMgr total bytes */
- spin_lock(&tconn->kstc_lock);
- KsTsduMgr->TotalBytes -= rc;
- spin_unlock(&tconn->kstc_lock);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
- /*
- * now it's time to re-queue the conns into the
- * scheduler queue and wake the scheduler thread.
- */
+ } else {
- if (tconn->kstc_conn && tconn->kstc_sched_cb) {
- tconn->kstc_sched_cb( tconn, TRUE, tx, 0);
- }
+ //
+ // Locking the User Buffer / Allocating a MDL for it
+ //
- } else {
-
- PKS_TSDU KsTsdu = Context->CompletionContext;
- PKS_TSDU_BUF KsTsduBuf = Context->CompletionContext2;
- PKS_TSDU_DAT KsTsduDat = Context->CompletionContext2;
-
- spin_lock(&tconn->kstc_lock);
- /* This is bufferred sending ... */
- ASSERT(KsTsduBuf->StartOffset == 0);
-
- if (KsTsduBuf->DataLength > Irp->IoStatus.Information) {
- /* not fully sent .... we have to abort the connection */
- spin_unlock(&tconn->kstc_lock);
- ks_abort_tconn(tconn);
- goto errorout;
- }
-
- if (KsTsduBuf->TsduType == TSDU_TYPE_BUF) {
- /* free the buffer */
- ExFreePool(KsTsduBuf->UserBuffer);
- KsTsduMgr->TotalBytes -= KsTsduBuf->DataLength;
- KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
- } else if (KsTsduDat->TsduType == TSDU_TYPE_DAT) {
- KsTsduMgr->TotalBytes -= KsTsduDat->DataLength;
- KsTsdu->StartOffset += KsTsduDat->TotalLength;
- } else {
- cfs_enter_debugger(); /* shoult not get here */
- }
-
- if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
+ Status = KsLockUserBuffer(
+ AddressInfo,
+ FALSE,
+ *(AddressSize),
+ IoModifyAccess,
+ &Mdl
+ );
- list_del(&KsTsdu->Link);
- KsTsduMgr->NumOfTsdu--;
- KsPutKsTsdu(KsTsdu);
- }
+ if (!NT_SUCCESS(Status)) {
- spin_unlock(&tconn->kstc_lock);
+ IoFreeIrp(Irp);
+ Irp = NULL;
}
+ }
- } else {
-
- /* cfs_enter_debugger(); */
-
- /*
- * for the case that the transmission is ussuccessful,
- * we need abort the tdi connection, but not destroy it.
- * the socknal conn will drop the refer count, then the
- * tdi connection will be freed.
- */
+ if (Irp) {
- ks_abort_tconn(tconn);
- }
+ LASSERT(NT_SUCCESS(Status));
-errorout:
+ TdiBuildQueryInformation(
+ Irp,
+ DeviceObject,
+ FileObject,
+ NULL,
+ NULL,
+ TDI_QUERY_ADDRESS_INFO,
+ Mdl
+ );
- /* freeing the Context structure... */
+ Status = KsSubmitTdiIrp(
+ DeviceObject,
+ Irp,
+ TRUE,
+ AddressSize
+ );
- if (Context) {
- ExFreePool(Context);
- Context = NULL;
+ KsReleaseMdl(Mdl, FALSE);
}
- /* it's our duty to free the Irp. */
+ if (!NT_SUCCESS(Status)) {
- if (Irp) {
- IoFreeIrp(Irp);
- Irp = NULL;
+ cfs_enter_debugger();
+ //TDI_BUFFER_OVERFLOW
}
- EXIT;
-
- return Status;
+ return (Status);
}
/*
- * Normal receive event handler
+ * KsQueryProviderInfo
+ * Query the underlying transport device's information
*
- * It will move data from system Tsdu to our TsduList
+ * Arguments:
+ * TdiDeviceName: the transport device's name string
+ * ProviderInfo: TDI_PROVIDER_INFO struncture
+ *
+ * Return Value:
+ * NTSTATUS: Nt system status code
+ *
+ * NOTES:
+ * N/A
*/
NTSTATUS
-KsTcpReceiveEventHandler(
- IN PVOID TdiEventContext,
- IN CONNECTION_CONTEXT ConnectionContext,
- IN ULONG ReceiveFlags,
- IN ULONG BytesIndicated,
- IN ULONG BytesAvailable,
- OUT ULONG * BytesTaken,
- IN PVOID Tsdu,
- OUT PIRP * IoRequestPacket
+KsQueryProviderInfo(
+ PWSTR TdiDeviceName,
+ PTDI_PROVIDER_INFO ProviderInfo
)
{
- NTSTATUS Status;
-
- ksock_tconn_t * tconn;
-
- PKS_CHAIN KsChain;
- PKS_TSDUMGR KsTsduMgr;
- PKS_TSDU KsTsdu;
- PKS_TSDU_DAT KsTsduDat;
- PKS_TSDU_BUF KsTsduBuf;
-
- BOOLEAN bIsExpedited;
- BOOLEAN bIsCompleteTsdu;
-
- BOOLEAN bNewTsdu = FALSE;
- BOOLEAN bNewBuff = FALSE;
-
- PCHAR Buffer = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
PIRP Irp = NULL;
PMDL Mdl = NULL;
+
+ UNICODE_STRING ControlName;
+
+ HANDLE Handle;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
- ULONG BytesReceived = 0;
+ ULONG ProviderSize = 0;
- PKS_TCP_COMPLETION_CONTEXT context = NULL;
+ RtlInitUnicodeString(&ControlName, TdiDeviceName);
+ //
+ // Open the Tdi Control Channel
+ //
- tconn = (ksock_tconn_t *) ConnectionContext;
+ Status = KsOpenControl(
+ &ControlName,
+ &Handle,
+ &FileObject
+ );
- ks_get_tconn(tconn);
+ if (!NT_SUCCESS(Status)) {
- /* check whether the whole body of payload is received or not */
- if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
- (BytesIndicated == BytesAvailable) ) {
- bIsCompleteTsdu = TRUE;
- } else {
- bIsCompleteTsdu = FALSE;
+ KsPrint((1, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
+ return (Status);
}
- bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
+ //
+ // Obtain The Related Device Object
+ //
- KsPrint((2, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n", BytesIndicated, BytesAvailable));
- KsPrint((2, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
- spin_lock(&(tconn->kstc_lock));
+ ProviderSize = sizeof(TDI_PROVIDER_INFO);
+ RtlZeroMemory(ProviderInfo, ProviderSize);
- /* check whether we are conntected or not listener ¡Â*/
- if ( !((tconn->kstc_state == ksts_connected) &&
- (tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child))) {
+ //
+ // Allocating the Tdi Setting Irp ...
+ //
- *BytesTaken = BytesIndicated;
+ Irp = KsBuildTdiIrp(DeviceObject);
- spin_unlock(&(tconn->kstc_lock));
- ks_put_tconn(tconn);
+ if (NULL == Irp) {
- return (STATUS_SUCCESS);
- }
+ Status = STATUS_INSUFFICIENT_RESOURCES;
- if (tconn->kstc_type == kstt_sender) {
- KsChain = &(tconn->sender.kstc_recv);
} else {
- LASSERT(tconn->kstc_type == kstt_child);
- KsChain = &(tconn->child.kstc_recv);
- }
- if (bIsExpedited) {
- KsTsduMgr = &(KsChain->Expedited);
- } else {
- KsTsduMgr = &(KsChain->Normal);
- }
+ //
+ // Locking the User Buffer / Allocating a MDL for it
+ //
- /* if the Tsdu is even larger than the biggest Tsdu, we have
- to allocate new buffer and use TSDU_TYOE_BUF to store it */
+ Status = KsLockUserBuffer(
+ ProviderInfo,
+ FALSE,
+ ProviderSize,
+ IoModifyAccess,
+ &Mdl
+ );
- if ( KS_TSDU_STRU_SIZE(BytesAvailable) > ks_data.ksnd_tsdu_size -
- KS_DWORD_ALIGN(sizeof(KS_TSDU))) {
- bNewBuff = TRUE;
+ if (!NT_SUCCESS(Status)) {
+
+ IoFreeIrp(Irp);
+ Irp = NULL;
+ }
}
- /* retrieve the latest Tsdu buffer form TsduMgr
- list if the list is not empty. */
+ if (Irp) {
- if (list_empty(&(KsTsduMgr->TsduList))) {
+ LASSERT(NT_SUCCESS(Status));
- LASSERT(KsTsduMgr->NumOfTsdu == 0);
- KsTsdu = NULL;
+ TdiBuildQueryInformation(
+ Irp,
+ DeviceObject,
+ FileObject,
+ NULL,
+ NULL,
+ TDI_QUERY_PROVIDER_INFO,
+ Mdl
+ );
- } else {
+ Status = KsSubmitTdiIrp(
+ DeviceObject,
+ Irp,
+ TRUE,
+ &ProviderSize
+ );
- LASSERT(KsTsduMgr->NumOfTsdu > 0);
- KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
+ KsReleaseMdl(Mdl, FALSE);
+ }
- /* if this Tsdu does not contain enough space, we need
- allocate a new Tsdu queue. */
+ if (!NT_SUCCESS(Status)) {
- if (bNewBuff) {
- if ( KsTsdu->LastOffset + sizeof(KS_TSDU_BUF) >
- KsTsdu->TotalLength ) {
- KsTsdu = NULL;
- }
- } else {
- if ( KS_TSDU_STRU_SIZE(BytesAvailable) >
- KsTsdu->TotalLength - KsTsdu->LastOffset ) {
- KsTsdu = NULL;
- }
- }
+ cfs_enter_debugger();
+ //TDI_BUFFER_OVERFLOW
}
- /* allocating the buffer for TSDU_TYPE_BUF */
- if (bNewBuff) {
- Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
- if (NULL == Buffer) {
- /* there's no enough memory for us. We just try to
- receive maximum bytes with a new Tsdu */
- bNewBuff = FALSE;
- KsTsdu = NULL;
- }
- }
+ KsCloseControl(Handle, FileObject);
- /* allocate a new Tsdu in case we are not statisfied. */
+ return (Status);
+}
- if (NULL == KsTsdu) {
+/*
+ * KsQueryConnectionInfo
+ * Query the connection info of the FileObject specified
+ * (some statics data of the traffic)
+ *
+ * Arguments:
+ * FileObject: the FileObject to be queried
+ * ConnectionInfo: buffer to contain the connection info
+ * ConnectionSize: length of the ConnectionInfo buffer
+ *
+ * Return Value:
+ * NTSTATUS: kernel status code (STATUS_SUCCESS
+ * or other error code)
+ *
+ * NOTES:
+ * N/A
+ */
- KsTsdu = KsAllocateKsTsdu();
+NTSTATUS
+KsQueryConnectionInfo(
+ PFILE_OBJECT ConnectionObject,
+ PTDI_CONNECTION_INFO ConnectionInfo,
+ PULONG ConnectionSize
+ )
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PIRP Irp = NULL;
+ PMDL Mdl;
+ PDEVICE_OBJECT DeviceObject;
- if (NULL == KsTsdu) {
- goto errorout;
- } else {
- bNewTsdu = TRUE;
- }
- }
+ LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
- KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
- KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
- if (bNewBuff) {
+ RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
- /* setup up the KS_TSDU_BUF record */
+ //
+ // Allocating the Tdi Query Irp ...
+ //
- KsTsduBuf->TsduType = TSDU_TYPE_BUF;
- KsTsduBuf->TsduFlags = 0;
- KsTsduBuf->StartOffset = 0;
- KsTsduBuf->UserBuffer = Buffer;
- KsTsduBuf->DataLength = BytesReceived = BytesAvailable;
+ Irp = KsBuildTdiIrp(DeviceObject);
- KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
+ if (NULL == Irp) {
- } else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
- /* setup the KS_TSDU_DATA to contain all the messages */
+ } else {
- KsTsduDat->TsduType = TSDU_TYPE_DAT;
- KsTsduDat->TsduFlags = 0;
+ //
+ // Locking the User Buffer / Allocating a MDL for it
+ //
- if ( KsTsdu->TotalLength - KsTsdu->LastOffset >=
- KS_TSDU_STRU_SIZE(BytesAvailable) ) {
- BytesReceived = BytesAvailable;
- } else {
- BytesReceived = KsTsdu->TotalLength - KsTsdu->LastOffset -
- FIELD_OFFSET(KS_TSDU_DAT, Data);
- BytesReceived &= (~((ULONG)3));
- }
- KsTsduDat->DataLength = BytesReceived;
- KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(BytesReceived);
- KsTsduDat->StartOffset = 0;
+ Status = KsLockUserBuffer(
+ ConnectionInfo,
+ FALSE,
+ *(ConnectionSize),
+ IoModifyAccess,
+ &Mdl
+ );
- Buffer = &KsTsduDat->Data[0];
+ if (NT_SUCCESS(Status)) {
- KsTsdu->LastOffset += KsTsduDat->TotalLength;
+ IoFreeIrp(Irp);
+ Irp = NULL;
+ }
}
- KsTsduMgr->TotalBytes += BytesReceived;
+ if (Irp) {
- if (bIsCompleteTsdu) {
+ LASSERT(NT_SUCCESS(Status));
- /* It's a complete receive, we just move all
- the data from system to our Tsdu */
+ TdiBuildQueryInformation(
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL,
+ TDI_QUERY_CONNECTION_INFO,
+ Mdl
+ );
- RtlMoveMemory(
- Buffer,
- Tsdu,
- BytesReceived
- );
+ Status = KsSubmitTdiIrp(
+ DeviceObject,
+ Irp,
+ TRUE,
+ ConnectionSize
+ );
- *BytesTaken = BytesReceived;
- Status = STATUS_SUCCESS;
+ KsReleaseMdl(Mdl, FALSE);
+ }
- if (bNewTsdu) {
- list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
- KsTsduMgr->NumOfTsdu++;
- }
+ return (Status);
+}
- KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
- /* re-active the ks connection and wake up the scheduler */
- if (tconn->kstc_conn && tconn->kstc_sched_cb) {
- tconn->kstc_sched_cb( tconn, FALSE, NULL,
- KsTsduMgr->TotalBytes );
- }
+/*
+ * KsInitializeTdiAddress
+ * Initialize the tdi addresss
+ *
+ * Arguments:
+ * pTransportAddress: tdi address to be initialized
+ * IpAddress: the ip address of object
+ * IpPort: the ip port of the object
+ *
+ * Return Value:
+ * ULONG: the total size of the tdi address
+ *
+ * NOTES:
+ * N/A
+ */
- } else {
+ULONG
+KsInitializeTdiAddress(
+ IN OUT PTA_IP_ADDRESS pTransportAddress,
+ IN ULONG IpAddress,
+ IN USHORT IpPort
+ )
+{
+ pTransportAddress->TAAddressCount = 1;
+ pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
+ pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
+ pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
+ pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
- /* there's still data in tdi internal queue, we need issue a new
- Irp to receive all of them. first allocate the tcp context */
+ return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
+}
- context = ExAllocatePoolWithTag(
- NonPagedPool,
- sizeof(KS_TCP_COMPLETION_CONTEXT),
- 'cTsK');
+/*
+ * KsQueryTdiAddressLength
+ * Query the total size of the tdi address
+ *
+ * Arguments:
+ * pTransportAddress: tdi address to be queried
+ *
+ * Return Value:
+ * ULONG: the total size of the tdi address
+ *
+ * NOTES:
+ * N/A
+ */
- if (!context) {
+ULONG
+KsQueryTdiAddressLength(
+ PTRANSPORT_ADDRESS pTransportAddress
+ )
+{
+ ULONG TotalLength = 0;
+ LONG i;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
+ PTA_ADDRESS pTaAddress = NULL;
- /* setup the context */
- RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
+ ASSERT (NULL != pTransportAddress);
- context->tconn = tconn;
- context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
- context->CompletionContext = KsTsdu;
- context->CompletionContext = bNewBuff ? (PVOID)KsTsduBuf : (PVOID)KsTsduDat;
- context->KsTsduMgr = KsTsduMgr;
- context->Event = &(KsTsduMgr->Event);
+ TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
+ FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
- if (tconn->kstc_type == kstt_sender) {
- FileObject = tconn->sender.kstc_info.FileObject;
- } else {
- FileObject = tconn->child.kstc_info.FileObject;
- }
+ pTaAddress = (PTA_ADDRESS)pTransportAddress->Address;
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ for (i = 0; i < pTransportAddress->TAAddressCount; i++)
+ {
+ TotalLength += pTaAddress->AddressLength;
+ pTaAddress = (PTA_ADDRESS)((PCHAR)pTaAddress +
+ FIELD_OFFSET(TA_ADDRESS,Address) +
+ pTaAddress->AddressLength );
+ }
- /* build new tdi Irp and setup it. */
- Irp = KsBuildTdiIrp(DeviceObject);
+ return (TotalLength);
+}
- if (NULL == Irp) {
- goto errorout;
- }
- Status = KsLockUserBuffer(
- Buffer,
- FALSE,
- BytesReceived,
- IoModifyAccess,
- &Mdl
- );
+/*
+ * KsQueryIpAddress
+ * Query the ip address of the tdi object
+ *
+ * Arguments:
+ * FileObject: tdi object to be queried
+ * TdiAddress: TdiAddress buffer, to store the queried
+ * tdi ip address
+ * AddressLength: buffer length of the TdiAddress
+ *
+ * Return Value:
+ * ULONG: the total size of the tdi ip address
+ *
+ * NOTES:
+ * N/A
+ */
- if (!NT_SUCCESS(Status)) {
- goto errorout;
- }
+NTSTATUS
+KsQueryIpAddress(
+ PFILE_OBJECT FileObject,
+ PVOID TdiAddress,
+ ULONG* AddressLength
+ )
+{
+ NTSTATUS Status;
- TdiBuildReceive(
- Irp,
- DeviceObject,
- FileObject,
- KsTcpCompletionRoutine,
- context,
- Mdl,
- ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
- BytesReceived
- );
+ PTDI_ADDRESS_INFO TdiAddressInfo;
+ ULONG Length;
- IoSetNextIrpStackLocation(Irp);
- /* return the newly built Irp to transport driver,
- it will process it to receive all the data */
+ //
+ // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
+ //
- *IoRequestPacket = Irp;
- *BytesTaken = 0;
+ Length = MAX_ADDRESS_LENGTH;
- if (bNewTsdu) {
+ TdiAddressInfo = (PTDI_ADDRESS_INFO)
+ ExAllocatePoolWithTag(
+ NonPagedPool,
+ Length,
+ 'KSAI' );
- list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
- KsTsduMgr->NumOfTsdu++;
- }
+ if (NULL == TdiAddressInfo) {
- if (bNewBuff) {
- cfs_set_flag(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING);
- } else {
- cfs_set_flag(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING);
- }
- ks_get_tconn(tconn);
- Status = STATUS_MORE_PROCESSING_REQUIRED;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
}
- spin_unlock(&(tconn->kstc_lock));
- ks_put_tconn(tconn);
- return (Status);
+ Status = KsQueryAddressInfo(
+ FileObject,
+ TdiAddressInfo,
+ &Length
+ );
errorout:
- spin_unlock(&(tconn->kstc_lock));
-
- if (bNewTsdu && (KsTsdu != NULL)) {
- KsFreeKsTsdu(KsTsdu);
- }
-
- if (Mdl) {
- KsReleaseMdl(Mdl, FALSE);
- }
+ if (NT_SUCCESS(Status)) {
- if (Irp) {
- IoFreeIrp(Irp);
+ if (*AddressLength < Length) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ } else {
+ *AddressLength = Length;
+ RtlCopyMemory(
+ TdiAddress,
+ &(TdiAddressInfo->Address),
+ Length
+ );
+ Status = STATUS_SUCCESS;
+ }
}
- if (context) {
- ExFreePool(context);
+ if (NULL != TdiAddressInfo) {
+ ExFreePool(TdiAddressInfo);
}
- ks_abort_tconn(tconn);
- ks_put_tconn(tconn);
-
- *BytesTaken = BytesAvailable;
- Status = STATUS_SUCCESS;
-
- return (Status);
+ return Status;
}
-/*
- * Expedited receive event handler
- */
-NTSTATUS
-KsTcpReceiveExpeditedEventHandler(
- IN PVOID TdiEventContext,
- IN CONNECTION_CONTEXT ConnectionContext,
- IN ULONG ReceiveFlags,
- IN ULONG BytesIndicated,
- IN ULONG BytesAvailable,
- OUT ULONG * BytesTaken,
- IN PVOID Tsdu,
- OUT PIRP * IoRequestPacket
- )
+/*
+ * KsErrorEventHandler
+ * the common error event handler callback
+ *
+ * Arguments:
+ * TdiEventContext: should be the socket
+ * Status: the error code
+ *
+ * Return Value:
+ * Status: STATS_SUCCESS
+ *
+ * NOTES:
+ * We need not do anything in such a severe
+ * error case. System will process it for us.
+ */
+
+NTSTATUS
+KsErrorEventHandler(
+ IN PVOID TdiEventContext,
+ IN NTSTATUS Status
+ )
{
- return KsTcpReceiveEventHandler(
- TdiEventContext,
- ConnectionContext,
- ReceiveFlags | TDI_RECEIVE_EXPEDITED,
- BytesIndicated,
- BytesAvailable,
- BytesTaken,
- Tsdu,
- IoRequestPacket
- );
-}
+ KsPrint((1, "KsErrorEventHandler called at Irql = %xh ...\n",
+ KeGetCurrentIrql()));
+
+ cfs_enter_debugger();
+ return (STATUS_SUCCESS);
+}
/*
- * Bulk receive event handler
+ * KsAcceptCompletionRoutine
+ * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
*
- * It will queue all the system Tsdus to our TsduList.
- * Then later ks_recv_mdl will release them.
+ * Here system gives us a chance to check the conneciton is built
+ * ready or not.
+ *
+ * Arguments:
+ * DeviceObject: the device object of the transport driver
+ * Irp: the Irp is being completed.
+ * Context: the context we specified when issuing the Irp
+ *
+ * Return Value:
+ * Nt status code
+ *
+ * Notes:
+ * N/A
*/
NTSTATUS
-KsTcpChainedReceiveEventHandler (
- IN PVOID TdiEventContext, // the event context
- IN CONNECTION_CONTEXT ConnectionContext,
- IN ULONG ReceiveFlags,
- IN ULONG ReceiveLength,
- IN ULONG StartingOffset, // offset of start of client data in TSDU
- IN PMDL Tsdu, // TSDU data chain
- IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
+KsAcceptCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
)
{
+ ks_tconn_t * child = (ks_tconn_t *) Context;
+ ks_tconn_t * parent = child->child.kstc_parent;
- NTSTATUS Status;
+ KsPrint((2, "KsAcceptCompletionRoutine at Irql: %xh child: %p status: %p\n",
+ KeGetCurrentIrql(), child, Irp->IoStatus.Status));
- ksock_tconn_t * tconn;
+ LASSERT(child->kstc_type == kstt_child);
- PKS_CHAIN KsChain;
- PKS_TSDUMGR KsTsduMgr;
- PKS_TSDU KsTsdu;
- PKS_TSDU_MDL KsTsduMdl;
+ cfs_spin_lock(&(child->kstc_lock));
- BOOLEAN bIsExpedited;
- BOOLEAN bNewTsdu = FALSE;
+ LASSERT(parent->kstc_state == ksts_listening);
+ LASSERT(child->kstc_state == ksts_connecting);
- tconn = (ksock_tconn_t *) ConnectionContext;
+ if (NT_SUCCESS(Irp->IoStatus.Status)) {
- bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
+ child->child.kstc_accepted = TRUE;
- KsPrint((2, "KsTcpChainedReceive: ReceiveLength = %xh bIsExpedited = %d\n", ReceiveLength, bIsExpedited));
+ child->kstc_state = ksts_connected;
- ks_get_tconn(tconn);
- spin_lock(&(tconn->kstc_lock));
+ /* wake up the daemon thread which waits on this event */
+ KeSetEvent(
+ &(parent->listener.kstc_accept_event),
+ 0,
+ FALSE
+ );
- /* check whether we are conntected or not listener ¡Â*/
- if ( !((tconn->kstc_state == ksts_connected) &&
- (tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child))) {
+ cfs_spin_unlock(&(child->kstc_lock));
- spin_unlock(&(tconn->kstc_lock));
- ks_put_tconn(tconn);
+ KsPrint((2, "KsAcceptCompletionRoutine: singal parent: %p (child: %p)\n",
+ parent, child));
- return (STATUS_SUCCESS);
- }
+ } else {
- /* get the latest Tsdu buffer form TsduMgr list.
- just set NULL if the list is empty. */
+ /* re-use this child connecton */
+ child->child.kstc_accepted = FALSE;
+ child->child.kstc_busy = FALSE;
+ child->kstc_state = ksts_associated;
- if (tconn->kstc_type == kstt_sender) {
- KsChain = &(tconn->sender.kstc_recv);
- } else {
- LASSERT(tconn->kstc_type == kstt_child);
- KsChain = &(tconn->child.kstc_recv);
+ cfs_spin_unlock(&(child->kstc_lock));
}
- if (bIsExpedited) {
- KsTsduMgr = &(KsChain->Expedited);
- } else {
- KsTsduMgr = &(KsChain->Normal);
- }
+ /* now free the Irp */
+ IoFreeIrp(Irp);
- if (list_empty(&(KsTsduMgr->TsduList))) {
+ /* drop the refer count of the child */
+ ks_put_tconn(child);
- LASSERT(KsTsduMgr->NumOfTsdu == 0);
- KsTsdu = NULL;
+ return (STATUS_MORE_PROCESSING_REQUIRED);
+}
- } else {
+ks_addr_slot_t *
+KsSearchIpAddress(PUNICODE_STRING DeviceName)
+{
+ ks_addr_slot_t * slot = NULL;
+ PLIST_ENTRY list = NULL;
- LASSERT(KsTsduMgr->NumOfTsdu > 0);
- KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
- LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
+ cfs_spin_lock(&ks_data.ksnd_addrs_lock);
- if (sizeof(KS_TSDU_MDL) > KsTsdu->TotalLength - KsTsdu->LastOffset) {
- KsTsdu = NULL;
+ list = ks_data.ksnd_addrs_list.Flink;
+ while (list != &ks_data.ksnd_addrs_list) {
+ slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
+ if (RtlCompareUnicodeString(
+ DeviceName,
+ &slot->devname,
+ TRUE) == 0) {
+ break;
}
+ list = list->Flink;
+ slot = NULL;
}
- /* if there's no Tsdu or the free size is not enough for this
- KS_TSDU_MDL structure. We need re-allocate a new Tsdu. */
+ cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
- if (NULL == KsTsdu) {
+ return slot;
+}
- KsTsdu = KsAllocateKsTsdu();
+void
+KsCleanupIpAddresses()
+{
+ cfs_spin_lock(&ks_data.ksnd_addrs_lock);
- if (NULL == KsTsdu) {
- goto errorout;
- } else {
- bNewTsdu = TRUE;
- }
- }
+ while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
- /* just queue the KS_TSDU_MDL to the Tsdu buffer */
+ ks_addr_slot_t * slot = NULL;
+ PLIST_ENTRY list = NULL;
- KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ list = RemoveHeadList(&ks_data.ksnd_addrs_list);
+ slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
+ cfs_free(slot);
+ ks_data.ksnd_naddrs--;
+ }
- KsTsduMdl->TsduType = TSDU_TYPE_MDL;
- KsTsduMdl->DataLength = ReceiveLength;
- KsTsduMdl->StartOffset = StartingOffset;
- KsTsduMdl->Mdl = Tsdu;
- KsTsduMdl->Descriptor = TsduDescriptor;
+ cfs_assert(ks_data.ksnd_naddrs == 0);
+ cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
+}
- KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
- KsTsduMgr->TotalBytes += ReceiveLength;
+VOID
+KsAddAddressHandler(
+ IN PTA_ADDRESS Address,
+ IN PUNICODE_STRING DeviceName,
+ IN PTDI_PNP_CONTEXT Context
+ )
+{
+ PTDI_ADDRESS_IP IpAddress = NULL;
- KsPrint((2, "KsTcpChainedReceiveEventHandler: Total %xh bytes.\n",
- KsTsduMgr->TotalBytes ));
+ if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
+ Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
- Status = STATUS_PENDING;
+ ks_addr_slot_t * slot = NULL;
- /* attach it to the TsduMgr list if the Tsdu is newly created. */
- if (bNewTsdu) {
+ IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
+ KsPrint((2, "KsAddAddressHandle: Device=%wZ Context=%xh "
+ "IpAddress=%xh(%d.%d.%d.%d)\n",
+ DeviceName, Context, IpAddress->in_addr,
+ (IpAddress->in_addr & 0x000000FF) >> 0,
+ (IpAddress->in_addr & 0x0000FF00) >> 8,
+ (IpAddress->in_addr & 0x00FF0000) >> 16,
+ (IpAddress->in_addr & 0xFF000000) >> 24
+ ));
- list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
- KsTsduMgr->NumOfTsdu++;
- }
+ slot = KsSearchIpAddress(DeviceName);
- spin_unlock(&(tconn->kstc_lock));
+ if (slot != NULL) {
+ slot->up = TRUE;
+ slot->ip_addr = ntohl(IpAddress->in_addr);
+ } else {
- /* wake up the threads waiing in ks_recv_mdl */
- KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
+ /* Matt: only add 192.168.10/5/92.xxx for temporary test */
+ if ((IpAddress->in_addr & 0x00FFFFFF) != 0x000aa8c0 &&
+ (IpAddress->in_addr & 0x00FFFFFF) != 0x0092a8c0 &&
+ (IpAddress->in_addr & 0x00FFFFFF) != 0x0005a8c0 ) {
+ return;
+ }
- if (tconn->kstc_conn && tconn->kstc_sched_cb) {
- tconn->kstc_sched_cb( tconn, FALSE, NULL,
- KsTsduMgr->TotalBytes );
+ slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
+ if (slot != NULL) {
+ cfs_spin_lock(&ks_data.ksnd_addrs_lock);
+ InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
+ sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
+ slot->ip_addr = ntohl(IpAddress->in_addr);
+ slot->netmask = 0x00FFFFFF; /* Matt: hardcode*/
+ slot->up = TRUE;
+ RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
+ slot->devname.Length = DeviceName->Length;
+ slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
+ slot->devname.Buffer = slot->buffer;
+ cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
+
+ KsPrint((0, "KsAddAddressHandle: %s added: ip=%xh(%d.%d.%d.%d)\n",
+ slot->iface, IpAddress->in_addr,
+ (IpAddress->in_addr & 0x000000FF) >> 0,
+ (IpAddress->in_addr & 0x0000FF00) >> 8,
+ (IpAddress->in_addr & 0x00FF0000) >> 16,
+ (IpAddress->in_addr & 0xFF000000) >> 24
+ ));
+ }
+ }
}
+}
- ks_put_tconn(tconn);
+VOID
+KsDelAddressHandler(
+ IN PTA_ADDRESS Address,
+ IN PUNICODE_STRING DeviceName,
+ IN PTDI_PNP_CONTEXT Context
+ )
+{
+ PTDI_ADDRESS_IP IpAddress = NULL;
- /* Return STATUS_PENDING to system because we are still
- owning the MDL resources. ks_recv_mdl is expected
- to free the MDL resources. */
+ if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
+ Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
- return (Status);
+ ks_addr_slot_t * slot = NULL;
-errorout:
+ slot = KsSearchIpAddress(DeviceName);
- spin_unlock(&(tconn->kstc_lock));
+ if (slot != NULL) {
+ slot->up = FALSE;
+ }
- if (bNewTsdu && (KsTsdu != NULL)) {
- KsFreeKsTsdu(KsTsdu);
+ IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
+ KsPrint((2, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
+ DeviceName, Context, IpAddress->in_addr,
+ (IpAddress->in_addr & 0xFF000000) >> 24,
+ (IpAddress->in_addr & 0x00FF0000) >> 16,
+ (IpAddress->in_addr & 0x0000FF00) >> 8,
+ (IpAddress->in_addr & 0x000000FF) >> 0 ));
}
+}
- /* abort the tdi connection */
- ks_abort_tconn(tconn);
- ks_put_tconn(tconn);
+NTSTATUS
+KsRegisterPnpHandlers()
+{
+ TDI20_CLIENT_INTERFACE_INFO ClientInfo;
+ /* initialize the global ks_data members */
+ RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
+ cfs_spin_lock_init(&ks_data.ksnd_addrs_lock);
+ InitializeListHead(&ks_data.ksnd_addrs_list);
- Status = STATUS_SUCCESS;
+ /* register the pnp handlers */
+ RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
+ ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
- return (Status);
+ ClientInfo.ClientName = &ks_data.ksnd_client_name;
+ ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
+ ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
+
+ return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
+ &ks_data.ksnd_pnp_handle);
}
+VOID
+KsDeregisterPnpHandlers()
+{
+ if (ks_data.ksnd_pnp_handle) {
-/*
- * Expedited & Bulk receive event handler
- */
+ /* De-register the pnp handlers */
-NTSTATUS
-KsTcpChainedReceiveExpeditedEventHandler (
- IN PVOID TdiEventContext, // the event context
- IN CONNECTION_CONTEXT ConnectionContext,
- IN ULONG ReceiveFlags,
- IN ULONG ReceiveLength,
- IN ULONG StartingOffset, // offset of start of client data in TSDU
- IN PMDL Tsdu, // TSDU data chain
- IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
- )
-{
- return KsTcpChainedReceiveEventHandler(
- TdiEventContext,
- ConnectionContext,
- ReceiveFlags | TDI_RECEIVE_EXPEDITED,
- ReceiveLength,
- StartingOffset,
- Tsdu,
- TsduDescriptor );
-}
-
-
-VOID
-KsPrintProviderInfo(
- PWSTR DeviceName,
- PTDI_PROVIDER_INFO ProviderInfo
- )
-{
- KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
-
- KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
- KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
- KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
- KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
- KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
-
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
- KsPrint((2, " CONNECTION_MODE\n"));
- }
-
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
- KsPrint((2, " ORDERLY_RELEASE\n"));
- }
-
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
- KsPrint((2, " CONNECTIONLESS_MODE\n"));
- }
+ TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
+ ks_data.ksnd_pnp_handle = NULL;
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
- KsPrint((2, " ERROR_FREE_DELIVERY\n"));
+ /* cleanup all the ip address slots */
+ KsCleanupIpAddresses();
}
+}
- if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
- KsPrint((2, " SECURITY_LEVEL\n"));
- }
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
- KsPrint((2, " BROADCAST_SUPPORTED\n"));
- }
+/*
+ * KsGetVacancyBacklog
+ * Get a vacancy listeing child from the backlog list
+ *
+ * Arguments:
+ * parent: the listener daemon connection
+ *
+ * Return Value:
+ * the child listening connection or NULL in failure
+ *
+ * Notes
+ * Parent's lock should be acquired before calling.
+ */
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
- KsPrint((2, " MULTICAST_SUPPORTED\n"));
- }
+ks_tconn_t *
+KsGetVacancyBacklog(
+ ks_tconn_t * parent
+ )
+{
+ ks_tconn_t * child;
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
- KsPrint((2, " DELAYED_ACCEPTANCE\n"));
- }
+ LASSERT(parent->kstc_type == kstt_listener);
+ LASSERT(parent->kstc_state == ksts_listening);
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
- KsPrint((2, " EXPEDITED_DATA\n"));
- }
+ if (cfs_list_empty(&(parent->listener.kstc_listening.list))) {
- if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
- KsPrint((2, " INTERNAL_BUFFERING\n"));
- }
+ child = NULL;
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
- KsPrint((2, " ROUTE_DIRECTED\n"));
- }
+ } else {
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
- KsPrint((2, " NO_ZERO_LENGTH\n"));
- }
+ cfs_list_t * tmp;
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
- KsPrint((2, " POINT_TO_POINT\n"));
- }
+ /* check the listening queue and try to get a free connecton */
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
- KsPrint((2, " MESSAGE_MODE\n"));
- }
+ cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
+ child = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
+ cfs_spin_lock(&(child->kstc_lock));
- if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
- KsPrint((2, " HALF_DUPLEX\n"));
+ if (!child->child.kstc_busy) {
+ LASSERT(child->kstc_state == ksts_associated);
+ child->child.kstc_busy = TRUE;
+ cfs_spin_unlock(&(child->kstc_lock));
+ break;
+ } else {
+ cfs_spin_unlock(&(child->kstc_lock));
+ child = NULL;
+ }
+ }
}
- KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
- KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
- KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
+ return child;
}
-
/*
- * KsAllocateKsTsdu
- * Reuse a Tsdu from the freelist or allocate a new Tsdu
- * from the LookAsideList table or the NonPagedPool
+ * KsConnectEventHandler
+ * Connect event handler event handler, called by the underlying TDI
+ * transport in response to an incoming request to the listening daemon.
+ *
+ * it will grab a vacancy backlog from the children tconn list, and
+ * build an acception Irp with it, then transfer the Irp to TDI driver.
*
* Arguments:
- * N/A
+ * TdiEventContext: the tdi connnection object of the listening daemon
+ * ......
*
* Return Value:
- * PKS_Tsdu: the new Tsdu or NULL if it fails
+ * Nt kernel status code
*
* Notes:
* N/A
*/
-PKS_TSDU
-KsAllocateKsTsdu()
+NTSTATUS
+KsConnectEventHandler(
+ IN PVOID TdiEventContext,
+ IN LONG RemoteAddressLength,
+ IN PVOID RemoteAddress,
+ IN LONG UserDataLength,
+ IN PVOID UserData,
+ IN LONG OptionsLength,
+ IN PVOID Options,
+ OUT CONNECTION_CONTEXT * ConnectionContext,
+ OUT PIRP * AcceptIrp
+ )
{
- PKS_TSDU KsTsdu = NULL;
+ ks_tconn_t * parent;
+ ks_tconn_t * child;
- spin_lock(&(ks_data.ksnd_tsdu_lock));
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
- if (!list_empty (&(ks_data.ksnd_freetsdus))) {
+ PIRP Irp = NULL;
+ PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
- LASSERT(ks_data.ksnd_nfreetsdus > 0);
+ KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
+ parent = (ks_tconn_t *) TdiEventContext;
- KsTsdu = list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
- list_del(&(KsTsdu->Link));
- ks_data.ksnd_nfreetsdus--;
+ LASSERT(parent->kstc_type == kstt_listener);
+
+ cfs_spin_lock(&(parent->kstc_lock));
+
+ if (parent->kstc_state == ksts_listening) {
+
+ /* allocate a new ConnectionInfo to backup the peer's info */
+
+ ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
+ RemoteAddressLength, 'iCsK' );
+
+ if (NULL == ConnectionInfo) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ cfs_enter_debugger();
+ goto errorout;
+ }
+
+ /* initializing ConnectionInfo structure ... */
+
+ ConnectionInfo->UserDataLength = UserDataLength;
+ ConnectionInfo->UserData = UserData;
+ ConnectionInfo->OptionsLength = OptionsLength;
+ ConnectionInfo->Options = Options;
+ ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
+ ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
+
+ RtlCopyMemory(
+ ConnectionInfo->RemoteAddress,
+ RemoteAddress,
+ RemoteAddressLength
+ );
+
+ /* get the vacancy listening child tdi connections */
+
+ child = KsGetVacancyBacklog(parent);
+
+ if (child) {
+
+ cfs_spin_lock(&(child->kstc_lock));
+ child->child.kstc_info.ConnectionInfo = ConnectionInfo;
+ child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
+ child->kstc_state = ksts_connecting;
+ cfs_spin_unlock(&(child->kstc_lock));
+
+ } else {
+
+ KsPrint((1, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ FileObject = child->child.kstc_info.FileObject;
+ DeviceObject = IoGetRelatedDeviceObject (FileObject);
+
+ Irp = KsBuildTdiIrp(DeviceObject);
+
+ TdiBuildAccept(
+ Irp,
+ DeviceObject,
+ FileObject,
+ KsAcceptCompletionRoutine,
+ child,
+ NULL,
+ NULL
+ );
+
+ IoSetNextIrpStackLocation(Irp);
+
+ /* grap the refer of the child tdi connection */
+ ks_get_tconn(child);
+
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ *AcceptIrp = Irp;
+ *ConnectionContext = child;
} else {
- KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
- ks_data.ksnd_tsdu_slab, 0);
+ Status = STATUS_CONNECTION_REFUSED;
+ goto errorout;
}
- spin_unlock(&(ks_data.ksnd_tsdu_lock));
+ cfs_spin_unlock(&(parent->kstc_lock));
- if (NULL != KsTsdu) {
- KsInitializeKsTsdu(KsTsdu, ks_data.ksnd_tsdu_size);
+ return Status;
+
+errorout:
+
+ cfs_spin_unlock(&(parent->kstc_lock));
+
+ *AcceptIrp = NULL;
+ *ConnectionContext = NULL;
+
+ if (ConnectionInfo) {
+ ExFreePool(ConnectionInfo);
}
- return (KsTsdu);
-}
+ if (Irp) {
+ IoFreeIrp (Irp);
+ }
+ return Status;
+}
/*
- * KsPutKsTsdu
- * Move the Tsdu to the free tsdu list in ks_data.
+ * KsDisconnectCompletionRoutine
+ * the Irp completion routine for TdiBuildDisconect
+ *
+ * We just signal the event and return MORE_PRO... to
+ * let the caller take the responsibility of the Irp.
*
* Arguments:
- * KsTsdu: Tsdu to be moved.
+ * DeviceObject: the device object of the transport
+ * Irp: the Irp is being completed.
+ * Context: the event specified by the caller
*
* Return Value:
- * N/A
+ * Nt status code
*
* Notes:
* N/A
*/
-VOID
-KsPutKsTsdu(
- PKS_TSDU KsTsdu
+NTSTATUS
+KsDisconectCompletionRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
)
{
- spin_lock(&(ks_data.ksnd_tsdu_lock));
- list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
- ks_data.ksnd_nfreetsdus++;
+ KeSetEvent((PKEVENT) Context, 0, FALSE);
- spin_unlock(&(ks_data.ksnd_tsdu_lock));
-}
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+}
/*
- * KsFreeKsTsdu
- * Release a Tsdu: uninitialize then free it.
+ * KsDisconnectHelper
+ * the routine to be executed in the WorkItem procedure
+ * this routine is to disconnect a tdi connection
*
* Arguments:
- * KsTsdu: Tsdu to be freed.
+ * Workitem: the context transferred to the workitem
*
* Return Value:
* N/A
*
* Notes:
- * N/A
+ * tconn is already referred in abort_connecton ...
*/
VOID
-KsFreeKsTsdu(
- PKS_TSDU KsTsdu
- )
+KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
{
- cfs_mem_cache_free(
- ks_data.ksnd_tsdu_slab,
- KsTsdu );
-}
+ ks_tconn_t * tconn = WorkItem->tconn;
+ KsPrint((1, "KsDisconnectHelper: disconnecting tconn=%p\n", tconn));
+ ks_disconnect_tconn(tconn, WorkItem->Flags);
-/*
- * KsInitializeKsTsdu
- * Initialize the Tsdu buffer header
- *
- * Arguments:
- * KsTsdu: the Tsdu to be initialized
- * Length: the total length of the Tsdu
- *
- * Return Value:
- * VOID
- *
- * NOTES:
- * N/A
- */
+ KeSetEvent(&(WorkItem->Event), 0, FALSE);
-VOID
-KsInitializeKsTsdu(
- PKS_TSDU KsTsdu,
- ULONG Length
- )
-{
- RtlZeroMemory(KsTsdu, Length);
- KsTsdu->Magic = KS_TSDU_MAGIC;
- KsTsdu->TotalLength = Length;
- KsTsdu->StartOffset = KsTsdu->LastOffset =
- KS_DWORD_ALIGN(sizeof(KS_TSDU));
+ cfs_spin_lock(&(tconn->kstc_lock));
+ cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
+ cfs_spin_unlock(&(tconn->kstc_lock));
+ ks_put_tconn(tconn);
}
/*
- * KsInitializeKsTsduMgr
- * Initialize the management structure of
- * Tsdu buffers
+ * KsDisconnectEventHandler
+ * Disconnect event handler event handler, called by the underlying TDI transport
+ * in response to an incoming disconnection notification from a remote node.
*
* Arguments:
- * TsduMgr: the TsduMgr to be initialized
+ * ConnectionContext: tdi connnection object
+ * DisconnectFlags: specifies the nature of the disconnection
+ * ......
*
* Return Value:
- * VOID
+ * Nt kernel status code
*
- * NOTES:
+ * Notes:
* N/A
*/
-VOID
-KsInitializeKsTsduMgr(
- PKS_TSDUMGR TsduMgr
+
+NTSTATUS
+KsDisconnectEventHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN LONG DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN LONG DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectFlags
)
{
- KeInitializeEvent(
- &(TsduMgr->Event),
- NotificationEvent,
- FALSE
- );
-
- CFS_INIT_LIST_HEAD(
- &(TsduMgr->TsduList)
- );
-
- TsduMgr->NumOfTsdu = 0;
- TsduMgr->TotalBytes = 0;
-}
+ ks_tconn_t * tconn;
+ NTSTATUS Status;
+ PKS_DISCONNECT_WORKITEM WorkItem;
+ tconn = (ks_tconn_t *)ConnectionContext;
-/*
- * KsInitializeKsChain
- * Initialize the China structure for receiving
- * or transmitting
- *
- * Arguments:
- * KsChain: the KsChain to be initialized
- *
- * Return Value:
- * VOID
- *
- * NOTES:
- * N/A
- */
+ KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
+ KeGetCurrentIrql() ));
-VOID
-KsInitializeKsChain(
- PKS_CHAIN KsChain
- )
-{
- KsInitializeKsTsduMgr(&(KsChain->Normal));
- KsInitializeKsTsduMgr(&(KsChain->Expedited));
-}
+ KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
+ tconn, DisconnectFlags));
+ ks_get_tconn(tconn);
+ cfs_spin_lock(&(tconn->kstc_lock));
-/*
- * KsCleanupTsduMgr
- * Clean up all the Tsdus in the TsduMgr list
- *
- * Arguments:
- * KsTsduMgr: the Tsdu list manager
- *
- * Return Value:
- * NTSTATUS: nt status code
- *
- * NOTES:
- * N/A
- */
+ WorkItem = &(tconn->kstc_disconnect);
-NTSTATUS
-KsCleanupTsduMgr(
- PKS_TSDUMGR KsTsduMgr
- )
-{
- PKS_TSDU KsTsdu;
- PKS_TSDU_DAT KsTsduDat;
- PKS_TSDU_BUF KsTsduBuf;
- PKS_TSDU_MDL KsTsduMdl;
+ if (tconn->kstc_state != ksts_connected) {
- LASSERT(NULL != KsTsduMgr);
+ Status = STATUS_SUCCESS;
- KeSetEvent(&(KsTsduMgr->Event), 0, FALSE);
+ } else {
- while (!list_empty(&KsTsduMgr->TsduList)) {
+ if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
- KsTsdu = list_entry(KsTsduMgr->TsduList.next, KS_TSDU, Link);
- LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
+ Status = STATUS_REMOTE_DISCONNECT;
- if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
+ } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
- //
- // KsTsdu is empty now, we need free it ...
- //
+ Status = STATUS_GRACEFUL_DISCONNECT;
+ }
- list_del(&(KsTsdu->Link));
- KsTsduMgr->NumOfTsdu--;
+ if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
- KsFreeKsTsdu(KsTsdu);
+ ks_get_tconn(tconn);
- } else {
+ WorkItem->Flags = DisconnectFlags;
+ WorkItem->tconn = tconn;
- KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
- KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
- KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
+ cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
- if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
+ /* queue the workitem to call */
+ ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
+ }
+ }
- KsTsdu->StartOffset += KsTsduDat->TotalLength;
+ cfs_spin_unlock(&(tconn->kstc_lock));
+ ks_put_tconn(tconn);
- } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
+ return (Status);
+}
- ASSERT(KsTsduBuf->UserBuffer != NULL);
+NTSTATUS
+KsTcpReceiveCompletionRoutine(
+ IN PIRP Irp,
+ IN PKS_TCP_COMPLETION_CONTEXT Context
+ )
+{
+ ks_tconn_t *tconn = Context->tconn;
+ NTSTATUS status = Irp->IoStatus.Status;
+ ULONG length = (ULONG)Irp->IoStatus.Information;
- if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
- ExFreePool(KsTsduBuf->UserBuffer);
- } else {
- cfs_enter_debugger();
- }
+ LASSERT(Context != NULL);
- KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
+ if (NT_SUCCESS(status)) {
- } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
+ PKS_TSDUMGR TsduMgr = Context->TsduMgr;
+ PCHAR Buffer = Context->Buffer;
- //
- // MDL Tsdu Unit ...
- //
+ KsPrint((4, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
+ TsduMgr->TotalBytes ));
- TdiReturnChainedReceives(
- &(KsTsduMdl->Descriptor),
- 1 );
+ ks_lock_tsdumgr(TsduMgr);
+ KsWriteTsduBuf(TsduMgr, Context->Buffer, length, 0);
+ /* signal TsduMgr event */
+ KeSetEvent(&(Context->TsduMgr->Event), 0, FALSE);
+ ks_unlock_tsdumgr(TsduMgr);
- KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
+ /* re-active the ks connection and wake up the scheduler */
+ if (KS_CAN_SCHED(TsduMgr)) {
+ if (tconn->kstc_conn && tconn->kstc_sched_cb) {
+ tconn->kstc_sched_cb(tconn, FALSE);
}
}
- }
-
- return STATUS_SUCCESS;
-}
+ ks_put_tconn(tconn);
-/*
- * KsCleanupKsChain
- * Clean up the TsduMgrs of the KsChain
- *
- * Arguments:
- * KsChain: the chain managing TsduMgr
- *
- * Return Value:
- * NTSTATUS: nt status code
- *
- * NOTES:
- * N/A
- */
+ } else {
-NTSTATUS
-KsCleanupKsChain(
- PKS_CHAIN KsChain
- )
-{
- NTSTATUS Status;
+ /* un-expected errors occur, we must abort the connection */
+ ks_put_tconn(tconn);
+ ks_abort_tconn(tconn);
+ }
- LASSERT(NULL != KsChain);
- Status = KsCleanupTsduMgr(
- &(KsChain->Normal)
- );
+ if (Context) {
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
+ /* free the Context structure... */
+ ASSERT(Context->Magic == KS_TCP_CONTEXT_MAGIC);
+ Context->Magic = 'CDAB';
+ cfs_free(Context);
}
- Status = KsCleanupTsduMgr(
- &(KsChain->Expedited)
- );
+ /* free the Irp */
+ if (Irp) {
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
- }
+ /* release mdl chain */
+ if (Irp->MdlAddress) {
+ KsReleaseMdl(Irp->MdlAddress, FALSE);
+ }
-errorout:
+ /* free irp packet */
+ IoFreeIrp(Irp);
+ }
- return Status;
+ return (status);
}
/*
- * KsCleanupTsdu
- * Clean up all the Tsdus of a tdi connected object
+ * KsTcpCompletionRoutine
+ * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
+ * We need call the use's own CompletionRoutine if specified. Or
+ * it's a synchronous case, we need signal the event.
*
* Arguments:
- * tconn: the tdi connection which is connected already.
+ * DeviceObject: the device object of the transport
+ * Irp: the Irp is being completed.
+ * Context: the context we specified when issuing the Irp
*
* Return Value:
* Nt status code
*
- * NOTES:
+ * Notes:
* N/A
*/
NTSTATUS
-KsCleanupTsdu(
- ksock_tconn_t * tconn
- )
+KsTcpCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
{
- NTSTATUS Status = STATUS_SUCCESS;
+ if (Context) {
+ PKS_TCP_COMPLETION_CONTEXT context = NULL;
+ ks_tconn_t * tconn = NULL;
- if (tconn->kstc_type != kstt_sender &&
- tconn->kstc_type != kstt_child ) {
+ context = (PKS_TCP_COMPLETION_CONTEXT) Context;
+ ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
+ tconn = context->tconn;
- goto errorout;
- }
+ if (context->CompletionRoutine) {
- if (tconn->kstc_type == kstt_sender) {
+ //
+ // Giving control to user specified CompletionRoutine ...
+ //
- Status = KsCleanupKsChain(
- &(tconn->sender.kstc_recv)
- );
+ context->CompletionRoutine(Irp, context);
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
- }
+ } else {
- Status = KsCleanupKsChain(
- &(tconn->sender.kstc_send)
- );
+ //
+ // Signaling the Event ...
+ //
+ LASSERT(NULL != context->Event);
+ KeSetEvent(context->Event, 0, FALSE);
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
+ /* drop the reference count of the tconn object */
+ ks_put_tconn(tconn);
}
} else {
- Status = KsCleanupKsChain(
- &(tconn->child.kstc_recv)
- );
-
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
- }
-
- Status = KsCleanupKsChain(
- &(tconn->child.kstc_send)
- );
-
- if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
- }
-
+ /* cfs_enter_debugger(); */
}
-errorout:
-
- return (Status);
+ return STATUS_MORE_PROCESSING_REQUIRED;
}
-
/*
- * KsCopyMdlChainToMdlChain
- * Copy data from a [chained] Mdl to anther [chained] Mdl.
- * Tdi library does not provide this function. We have to
- * realize it ourselives.
+ * KsTcpSendCompletionRoutine
+ * the user specified Irp completion routine for asynchronous
+ * data transmission requests.
+ *
+ * It will do th cleanup job of the ks_tx_t and wake up the
+ * ks scheduler thread
*
* Arguments:
- * SourceMdlChain: the source mdl
- * SourceOffset: start offset of the source
- * DestinationMdlChain: the dst mdl
- * DestinationOffset: the offset where data are to be copied.
- * BytesTobecopied: the expteced bytes to be copied
- * BytesCopied: to store the really copied data length
+ * Irp: the Irp is being completed.
+ * Context: the context we specified when issuing the Irp
*
* Return Value:
- * NTSTATUS: STATUS_SUCCESS or other error code
+ * Nt status code
*
- * NOTES:
- * The length of source mdl must be >= SourceOffset + BytesTobecopied
+ * Notes:
+ * N/A
*/
NTSTATUS
-KsCopyMdlChainToMdlChain(
- IN PMDL SourceMdlChain,
- IN ULONG SourceOffset,
- IN PMDL DestinationMdlChain,
- IN ULONG DestinationOffset,
- IN ULONG BytesTobecopied,
- OUT PULONG BytesCopied
+KsTcpSendCompletionRoutine(
+ IN PIRP Irp,
+ IN PKS_TCP_COMPLETION_CONTEXT context
)
{
- PMDL SrcMdl = SourceMdlChain;
- PMDL DstMdl = DestinationMdlChain;
-
- PUCHAR SrcBuf = NULL;
- PUCHAR DstBuf = NULL;
-
- ULONG dwBytes = 0;
-
- NTSTATUS Status = STATUS_SUCCESS;
-
-
- while (dwBytes < BytesTobecopied) {
-
- ULONG Length = 0;
-
- while (MmGetMdlByteCount(SrcMdl) <= SourceOffset) {
-
- SourceOffset -= MmGetMdlByteCount(SrcMdl);
+ NTSTATUS status = Irp->IoStatus.Status;
+ ULONG rc = (ULONG)(ULONG_PTR)Irp->IoStatus.Information;
+ ks_tconn_t * tconn = context->tconn;
- SrcMdl = SrcMdl->Next;
+ PKS_TSDUMGR TsduMgr = context->TsduMgr;
+ PKEVENT Event = context->Event;
- if (NULL == SrcMdl) {
+ LASSERT(tconn != NULL && tconn->kstc_magic == KS_TCONN_MAGIC);
+ LASSERT(context && context->Magic == KS_TCP_CONTEXT_MAGIC);
- Status = STATUS_INVALID_PARAMETER;
- goto errorout;
- }
- }
-
- while (MmGetMdlByteCount(DstMdl) <= DestinationOffset) {
+ KsPrint((4, "KsTcpSendCompltionRoutine: tconn = %p TsduMgr = %p "
+ "status = %xh bytes = %xh/%x\n", tconn, TsduMgr, status,
+ Irp->IoStatus.Information, TsduMgr->TotalBytes));
- DestinationOffset -= MmGetMdlByteCount(DstMdl);
+ ks_lock_tsdumgr(TsduMgr);
- DstMdl = DstMdl->Next;
+ if (NT_SUCCESS(status)) {
- if (NULL == DstMdl) {
+ /* cleanup processed TsduMgr queue */
+ KsReleaseTsdus(tconn, TsduMgr, rc);
- Status = STATUS_INVALID_PARAMETER;
- goto errorout;
- }
+ /* queue to delivery engine if there's still remained data */
+ TsduMgr->Busy = FALSE;
+ if (TsduMgr->TotalBytes > 0) {
+ KsQueueTdiEngine(tconn, TsduMgr);
}
+ /* signal TsduMgr event */
+ KeSetEvent(&(TsduMgr->Event), 0, FALSE);
+ ks_unlock_tsdumgr(TsduMgr);
- DstBuf = (PUCHAR)KsMapMdlBuffer(DstMdl);
+ /*
+ * now it's time to re-queue the conns into the
+ * scheduler queue and wake the scheduler thread.
+ */
- if ((NULL == DstBuf)) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ if (tconn->kstc_conn && tconn->kstc_sched_cb) {
+ tconn->kstc_sched_cb(tconn, TRUE);
}
- //
- // Here we need skip the OVERFLOW case via RtlCopyMemory :-(
- //
-
- if ( KsQueryMdlsSize(SrcMdl) - SourceOffset >
- MmGetMdlByteCount(DstMdl) - DestinationOffset ) {
-
- Length = BytesTobecopied - dwBytes;
-
- if (Length > KsQueryMdlsSize(SrcMdl) - SourceOffset) {
- Length = KsQueryMdlsSize(SrcMdl) - SourceOffset;
- }
-
- if (Length > MmGetMdlByteCount(DstMdl) - DestinationOffset) {
- Length = MmGetMdlByteCount(DstMdl) - DestinationOffset;
- }
+ } else {
- SrcBuf = (PUCHAR)KsMapMdlBuffer(SrcMdl);
+ ks_unlock_tsdumgr(TsduMgr);
- if ((NULL == DstBuf)) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
+ KsPrint((1, "KsTcpSendCompltionRoutine: failed tconn: %p "
+ "TsduMgr: %p status: %xh\n", tconn, TsduMgr, status));
- RtlCopyMemory(
- DstBuf + DestinationOffset,
- SrcBuf + SourceOffset,
- Length
- );
+ /* cfs_enter_debugger(); */
- } else {
+ /*
+ * for the case that the transmission is unsuccessful,
+ * we need abort the tdi connection, but not destroy it.
+ * the socknal conn will drop the refer count, then the
+ * tdi connection will be freed.
+ */
- Status = TdiCopyMdlToBuffer(
- SrcMdl,
- SourceOffset,
- DstBuf,
- DestinationOffset,
- MmGetMdlByteCount(DstMdl),
- &Length
- );
+ ks_abort_tconn(tconn);
+ }
- if (STATUS_BUFFER_OVERFLOW == Status) {
- cfs_enter_debugger();
- } else if (!NT_SUCCESS(Status)) {
- cfs_enter_debugger();
- goto errorout;
- }
- }
+ /* drop tconn reference */
+ ks_put_tconn(tconn);
- SourceOffset += Length;
- DestinationOffset += Length;
- dwBytes += Length;
+ /* freeing the context structure */
+ if (context) {
+ ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
+ context->Magic = 'CDAB';
+ cfs_free(context);
}
-errorout:
-
- if (NT_SUCCESS(Status)) {
- *BytesCopied = dwBytes;
- } else {
- *BytesCopied = 0;
+ /* free the Irp structure */
+ if (Irp) {
+ /* mdl chain was released by KsReleaseTsdus*/
+ Irp->MdlAddress = NULL;
+ IoFreeIrp(Irp);
+ Irp = NULL;
}
- return Status;
+ return status;
}
-
-
/*
- * KsQueryMdlSize
- * Query the whole size of a MDL (may be chained)
- *
- * Arguments:
- * Mdl: the Mdl to be queried
- *
- * Return Value:
- * ULONG: the total size of the mdl
+ * Normal receive event handler
*
- * NOTES:
- * N/A
+ * It will move data from system Tsdu to our TsduList
*/
-ULONG
-KsQueryMdlsSize (PMDL Mdl)
+NTSTATUS
+KsTcpReceiveEventHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG * BytesTaken,
+ IN PVOID Tsdu,
+ OUT PIRP * IoRequestPacket
+ )
{
- PMDL Next = Mdl;
- ULONG Length = 0;
+ NTSTATUS status;
+ ks_tconn_t * tconn;
- //
- // Walking the MDL Chain ...
- //
+ BOOLEAN bIsExpedited;
+ BOOLEAN bIsCompleteTsdu;
- while (Next) {
- Length += MmGetMdlByteCount(Next);
- Next = Next->Next;
- }
+ PCHAR Buffer = NULL;
+ PIRP Irp = NULL;
+ PMDL Mdl = NULL;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PKS_TSDUMGR TsduMgr;
- return (Length);
-}
+ PKS_TCP_COMPLETION_CONTEXT context = NULL;
+ tconn = (ks_tconn_t *) ConnectionContext;
+ ks_get_tconn(tconn);
-/*
- * KsLockUserBuffer
- * Allocate MDL for the buffer and lock the pages into
- * nonpaged pool
- *
- * Arguments:
- * UserBuffer: the user buffer to be locked
- * Length: length in bytes of the buffer
- * Operation: read or write access
- * pMdl: the result of the created mdl
- *
- * Return Value:
- * NTSTATUS: kernel status code (STATUS_SUCCESS
- * or other error code)
- *
- * NOTES:
- * N/A
- */
+ /* check expedited flag */
+ bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
-NTSTATUS
-KsLockUserBuffer (
- IN PVOID UserBuffer,
- IN BOOLEAN bPaged,
- IN ULONG Length,
- IN LOCK_OPERATION Operation,
- OUT PMDL * pMdl
- )
-{
- NTSTATUS Status;
- PMDL Mdl = NULL;
+ /* check whether the whole body of payload is received or not */
+ if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
+ (BytesIndicated == BytesAvailable) ) {
+ bIsCompleteTsdu = TRUE;
+ } else {
+ bIsCompleteTsdu = FALSE;
+ }
- LASSERT(UserBuffer != NULL);
+ KsPrint((4, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n",
+ BytesIndicated, BytesAvailable));
+ KsPrint((4, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
- *pMdl = NULL;
+ /* check whether we are conntected or not listener */
+ if ( !((tconn->kstc_state == ksts_connected) &&
+ (tconn->kstc_type == kstt_sender ||
+ tconn->kstc_type == kstt_child))) {
- Mdl = IoAllocateMdl(
- UserBuffer,
- Length,
- FALSE,
- FALSE,
- NULL
- );
+ *BytesTaken = BytesIndicated;
+ ks_put_tconn(tconn);
+ return (STATUS_SUCCESS);
+ }
- if (Mdl == NULL) {
+ /* query tsdu mgr */
+ TsduMgr = KsQueryTsduMgr(tconn, bIsExpedited, FALSE);
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ ks_lock_tsdumgr(TsduMgr);
+ if (bIsCompleteTsdu) {
- } else {
+ *BytesTaken = KsWriteTsduDat(TsduMgr, Tsdu, BytesAvailable, 0);
+ status = STATUS_SUCCESS;
- __try {
+ /* signal TsduMgr event */
+ KeSetEvent(&(TsduMgr->Event), 0, FALSE);
+ ks_unlock_tsdumgr(TsduMgr);
- if (bPaged) {
- MmProbeAndLockPages(
- Mdl,
- KernelMode,
- Operation
- );
- } else {
- MmBuildMdlForNonPagedPool(
- Mdl
- );
+ /* re-active the ks connection and wake up the scheduler */
+ if (KS_CAN_SCHED(TsduMgr)) {
+ if (tconn->kstc_conn && tconn->kstc_sched_cb) {
+ tconn->kstc_sched_cb(tconn, FALSE);
}
+ }
- Status = STATUS_SUCCESS;
+ } else {
- *pMdl = Mdl;
+ ks_unlock_tsdumgr(TsduMgr);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
-
- IoFreeMdl(Mdl);
-
- Mdl = NULL;
-
- cfs_enter_debugger();
-
- Status = STATUS_INVALID_USER_BUFFER;
+ /* allocate buffer for further data in tsdu queue */
+ Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
+ if (NULL == Buffer) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
}
- }
-
- return Status;
-}
-
-/*
- * KsMapMdlBuffer
- * Map the mdl into a buffer in kernel space
- *
- * Arguments:
- * Mdl: the mdl to be mapped
- *
- * Return Value:
- * PVOID: the buffer mapped or NULL in failure
- *
- * NOTES:
- * N/A
- */
-
-PVOID
-KsMapMdlBuffer (PMDL Mdl)
-{
- LASSERT(Mdl != NULL);
-
- return MmGetSystemAddressForMdlSafe(
- Mdl,
- NormalPagePriority
- );
-}
-
-
-/*
- * KsReleaseMdl
- * Unlock all the pages in the mdl
- *
- * Arguments:
- * Mdl: memory description list to be released
- *
- * Return Value:
- * N/A
- *
- * NOTES:
- * N/A
- */
-
-VOID
-KsReleaseMdl (IN PMDL Mdl,
- IN int Paged )
-{
- LASSERT(Mdl != NULL);
-
- while (Mdl) {
- PMDL Next;
-
- Next = Mdl->Next;
-
- if (Paged) {
- MmUnlockPages(Mdl);
+ /* there's still data in tdi internal queue, we need issue a new
+ Irp to receive all of them. first allocate the tcp context */
+ context = cfs_alloc(sizeof(KS_TCP_COMPLETION_CONTEXT), 0);
+ if (!context) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
}
- IoFreeMdl(Mdl);
-
- Mdl = Next;
- }
-}
-
+ /* setup the context */
+ RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
+ context->Magic = KS_TCP_CONTEXT_MAGIC;
+ context->tconn = tconn;
+ context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
+ context->CompletionContext = Buffer;
+ context->TsduMgr = TsduMgr;
+ context->Buffer = Buffer;
+ context->Event = &(TsduMgr->Event);
-/*
- * ks_lock_buffer
- * allocate MDL for the user spepcified buffer and lock (paging-in)
- * all the pages of the buffer into system memory
- *
- * Arguments:
- * buffer: the user buffer to be locked
- * length: length in bytes of the buffer
- * access: read or write access
- * mdl: the result of the created mdl
- *
- * Return Value:
- * int: the ks error code: 0: success / -x: failture
- *
- * Notes:
- * N/A
- */
+ if (tconn->kstc_type == kstt_sender) {
+ FileObject = tconn->sender.kstc_info.FileObject;
+ } else {
+ FileObject = tconn->child.kstc_info.FileObject;
+ }
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
-int
-ks_lock_buffer (
- void * buffer,
- int paged,
- int length,
- LOCK_OPERATION access,
- ksock_mdl_t ** kmdl
- )
-{
- NTSTATUS status;
+ /* build new tdi Irp and setup it. */
+ Irp = KsBuildTdiIrp(DeviceObject);
+ if (NULL == Irp) {
+ goto errorout;
+ }
- status = KsLockUserBuffer(
- buffer,
- paged !=0,
- length,
- access,
- kmdl
+ status = KsLockUserBuffer(
+ Buffer,
+ FALSE,
+ BytesAvailable,
+ IoModifyAccess,
+ &Mdl
);
- return cfs_error_code(status);
-}
-
-
-/*
- * ks_map_mdl
- * Map the mdl pages into kernel space
- *
- * Arguments:
- * mdl: the mdl to be mapped
- *
- * Return Value:
- * void *: the buffer mapped or NULL in failure
- *
- * Notes:
- * N/A
- */
-
-void *
-ks_map_mdl (ksock_mdl_t * mdl)
-{
- LASSERT(mdl != NULL);
-
- return KsMapMdlBuffer(mdl);
-}
-
-/*
- * ks_release_mdl
- * Unlock all the pages in the mdl and release the mdl
- *
- * Arguments:
- * mdl: memory description list to be released
- *
- * Return Value:
- * N/A
- *
- * Notes:
- * N/A
- */
-
-void
-ks_release_mdl (ksock_mdl_t *mdl, int paged)
-{
- LASSERT(mdl != NULL);
-
- KsReleaseMdl(mdl, paged);
-}
-
-
-/*
- * ks_create_tconn
- * allocate a new tconn structure from the SLAB cache or
- * NonPaged sysetm pool
- *
- * Arguments:
- * N/A
- *
- * Return Value:
- * ksock_tconn_t *: the address of tconn or NULL if it fails
- *
- * NOTES:
- * N/A
- */
-
-ksock_tconn_t *
-ks_create_tconn()
-{
- ksock_tconn_t * tconn = NULL;
-
- /* allocate ksoc_tconn_t from the slab cache memory */
-
- tconn = (ksock_tconn_t *)cfs_mem_cache_alloc(
- ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
-
- if (tconn) {
-
- /* zero tconn elements */
- memset(tconn, 0, sizeof(ksock_tconn_t));
-
- /* initialize the tconn ... */
- tconn->kstc_magic = KS_TCONN_MAGIC;
+ if (!NT_SUCCESS(status)) {
+ goto errorout;
+ }
- ExInitializeWorkItem(
- &(tconn->kstc_disconnect.WorkItem),
- KsDisconnectHelper,
- &(tconn->kstc_disconnect)
- );
+ TdiBuildReceive(
+ Irp,
+ DeviceObject,
+ FileObject,
+ KsTcpCompletionRoutine,
+ context,
+ Mdl,
+ ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
+ BytesAvailable
+ );
- KeInitializeEvent(
- &(tconn->kstc_disconnect.Event),
- SynchronizationEvent,
- FALSE );
+ IoSetNextIrpStackLocation(Irp);
- ExInitializeWorkItem(
- &(tconn->kstc_destroy),
- ks_destroy_tconn,
- tconn
- );
+ /* return the newly built Irp to transport driver,
+ it will process it to receive all the data */
- spin_lock_init(&(tconn->kstc_lock));
+ *IoRequestPacket = Irp;
+ *BytesTaken = 0;
ks_get_tconn(tconn);
-
- spin_lock(&(ks_data.ksnd_tconn_lock));
-
- /* attach it into global list in ks_data */
-
- list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
- ks_data.ksnd_ntconns++;
- spin_unlock(&(ks_data.ksnd_tconn_lock));
-
- tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
}
- return (tconn);
-}
-
-
-/*
- * ks_free_tconn
- * free the tconn structure to the SLAB cache or NonPaged
- * sysetm pool
- *
- * Arguments:
- * tconn: the tcon is to be freed
- *
- * Return Value:
- * N/A
- *
- * Notes:
- * N/A
- */
-
-void
-ks_free_tconn(ksock_tconn_t * tconn)
-{
- LASSERT(atomic_read(&(tconn->kstc_refcount)) == 0);
+ ks_put_tconn(tconn);
- spin_lock(&(ks_data.ksnd_tconn_lock));
+ return (status);
- /* remove it from the global list */
- list_del(&tconn->kstc_list);
- ks_data.ksnd_ntconns--;
+errorout:
- /* if this is the last tconn, it would be safe for
- ks_tdi_fini_data to quit ... */
- if (ks_data.ksnd_ntconns == 0) {
- cfs_wake_event(&ks_data.ksnd_tconn_exit);
+ if (Mdl) {
+ KsReleaseMdl(Mdl, FALSE);
}
- spin_unlock(&(ks_data.ksnd_tconn_lock));
- /* free the structure memory */
- cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
-}
-
-
-/*
- * ks_init_listener
- * Initialize the tconn as a listener (daemon)
- *
- * Arguments:
- * tconn: the listener tconn
- *
- * Return Value:
- * N/A
- *
- * Notes:
- * N/A
- */
-
-void
-ks_init_listener(
- ksock_tconn_t * tconn
- )
-{
- /* preparation: intialize the tconn members */
-
- tconn->kstc_type = kstt_listener;
-
- RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
-
- CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
- CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
-
- cfs_init_event( &(tconn->listener.kstc_accept_event),
- TRUE,
- FALSE );
-
- cfs_init_event( &(tconn->listener.kstc_destroy_event),
- TRUE,
- FALSE );
-
- tconn->kstc_state = ksts_inited;
-}
-
-
-/*
- * ks_init_sender
- * Initialize the tconn as a sender
- *
- * Arguments:
- * tconn: the sender tconn
- *
- * Return Value:
- * N/A
- *
- * Notes:
- * N/A
- */
-
-void
-ks_init_sender(
- ksock_tconn_t * tconn
- )
-{
- tconn->kstc_type = kstt_sender;
- RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
-
- KsInitializeKsChain(&(tconn->sender.kstc_recv));
- KsInitializeKsChain(&(tconn->sender.kstc_send));
-
- tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
- tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
-
- tconn->kstc_state = ksts_inited;
-}
-
-/*
- * ks_init_child
- * Initialize the tconn as a child
- *
- * Arguments:
- * tconn: the child tconn
- *
- * Return Value:
- * N/A
- *
- * NOTES:
- * N/A
- */
-
-void
-ks_init_child(
- ksock_tconn_t * tconn
- )
-{
- tconn->kstc_type = kstt_child;
- RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
+ if (Buffer) {
+ ExFreePool(Buffer);
+ }
- KsInitializeKsChain(&(tconn->child.kstc_recv));
- KsInitializeKsChain(&(tconn->child.kstc_send));
+ if (Irp) {
+ IoFreeIrp(Irp);
+ }
- tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
- tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
+ if (context) {
+ ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
+ context->Magic = 'CDAB';
+ cfs_free(context);
+ }
- tconn->kstc_state = ksts_inited;
-}
+ ks_abort_tconn(tconn);
+ ks_put_tconn(tconn);
-/*
- * ks_get_tconn
- * increase the reference count of the tconn with 1
- *
- * Arguments:
- * tconn: the tdi connection to be referred
- *
- * Return Value:
- * N/A
- *
- * NOTES:
- * N/A
- */
+ *BytesTaken = BytesAvailable;
-void
-ks_get_tconn(
- ksock_tconn_t * tconn
- )
-{
- atomic_inc(&(tconn->kstc_refcount));
+ return STATUS_SUCCESS;
}
/*
- * ks_put_tconn
- * decrease the reference count of the tconn and destroy
- * it if the refercount becomes 0.
- *
- * Arguments:
- * tconn: the tdi connection to be dereferred
- *
- * Return Value:
- * N/A
- *
- * NOTES:
- * N/A
+ * Expedited receive event handler
*/
-void
-ks_put_tconn(
- ksock_tconn_t *tconn
+NTSTATUS
+KsTcpReceiveExpeditedEventHandler(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG * BytesTaken,
+ IN PVOID Tsdu,
+ OUT PIRP * IoRequestPacket
)
{
- if (atomic_dec_and_test(&(tconn->kstc_refcount))) {
-
- spin_lock(&(tconn->kstc_lock));
-
- if ( ( tconn->kstc_type == kstt_child ||
- tconn->kstc_type == kstt_sender ) &&
- ( tconn->kstc_state == ksts_connected ) ) {
-
- spin_unlock(&(tconn->kstc_lock));
-
- ks_abort_tconn(tconn);
-
- } else {
-
- if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
- cfs_enter_debugger();
- } else {
- ExQueueWorkItem(
- &(tconn->kstc_destroy),
- DelayedWorkQueue
- );
-
- cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
- }
-
- spin_unlock(&(tconn->kstc_lock));
- }
- }
+ return KsTcpReceiveEventHandler(
+ TdiEventContext,
+ ConnectionContext,
+ ReceiveFlags | TDI_RECEIVE_EXPEDITED,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ Tsdu,
+ IoRequestPacket
+ );
}
/*
- * ks_destroy_tconn
- * cleanup the tdi connection and free it
- *
- * Arguments:
- * tconn: the tdi connection to be cleaned.
- *
- * Return Value:
- * N/A
+ * Bulk receive event handler
*
- * NOTES:
- * N/A
+ * It will queue all the system Tsdus to our TsduList.
+ * Then later ks_recv_mdl will release them.
*/
-void
-ks_destroy_tconn(
- ksock_tconn_t * tconn
+NTSTATUS
+KsTcpChainedReceiveEventHandler (
+ IN PVOID TdiEventContext, // the event context
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG ReceiveLength,
+ IN ULONG StartingOffset, // offset of start of client data in TSDU
+ IN PMDL Tsdu, // TSDU data chain
+ IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
)
{
- LASSERT(tconn->kstc_refcount.counter == 0);
-
- if (tconn->kstc_type == kstt_listener) {
-
- ks_reset_handlers(tconn);
-
- /* for listener, we just need to close the address object */
- KsCloseAddress(
- tconn->kstc_addr.Handle,
- tconn->kstc_addr.FileObject
- );
-
- tconn->kstc_state = ksts_inited;
-
- } else if (tconn->kstc_type == kstt_child) {
-
- /* for child tdi conections */
-
- /* disassociate the relation between it's connection object
- and the address object */
-
- if (tconn->kstc_state == ksts_associated) {
- KsDisassociateAddress(
- tconn->child.kstc_info.FileObject
- );
- }
-
- /* release the connection object */
- KsCloseConnection(
- tconn->child.kstc_info.Handle,
- tconn->child.kstc_info.FileObject
- );
-
- /* release it's refer of it's parent's address object */
- KsCloseAddress(
- NULL,
- tconn->kstc_addr.FileObject
- );
-
- spin_lock(&tconn->child.kstc_parent->kstc_lock);
- spin_lock(&tconn->kstc_lock);
-
- tconn->kstc_state = ksts_inited;
-
- /* remove it frome it's parent's queues */
-
- if (tconn->child.kstc_queued) {
-
- list_del(&(tconn->child.kstc_link));
-
- if (tconn->child.kstc_queueno) {
-
- LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
- tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
-
- } else {
+ NTSTATUS status;
+ ks_tconn_t * tconn;
- LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
- tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
- }
+ PKS_TSDUMGR TsduMgr;
- tconn->child.kstc_queued = FALSE;
- }
+ BOOLEAN expedited;
- spin_unlock(&tconn->kstc_lock);
- spin_unlock(&tconn->child.kstc_parent->kstc_lock);
+ tconn = (ks_tconn_t *) ConnectionContext;
+ expedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
- /* drop the reference of the parent tconn */
- ks_put_tconn(tconn->child.kstc_parent);
+ KsPrint((4, "KsTcpChainedReceive: sock: %p conn: %p ReceiveLength: %xh "
+ "bIsExpedited: %d Tsdu=%p TsduDesc=%p data=%xh\n",
+ tconn, tconn->kstc_conn, ReceiveLength, expedited,
+ Tsdu, TsduDescriptor, *((PULONG)KsMapMdlBuffer(Tsdu))));
- } else if (tconn->kstc_type == kstt_sender) {
+ ks_get_tconn(tconn);
- ks_reset_handlers(tconn);
+ /* check whether we are conntected or not listener */
+ if ( !((tconn->kstc_state == ksts_connected) &&
+ (tconn->kstc_type == kstt_sender ||
+ tconn->kstc_type == kstt_child))) {
- /* release the connection object */
+ ks_put_tconn(tconn);
+ return (STATUS_SUCCESS);
+ }
- KsCloseConnection(
- tconn->sender.kstc_info.Handle,
- tconn->sender.kstc_info.FileObject
- );
+ if (Tsdu) {
- /* release it's refer of it's parent's address object */
- KsCloseAddress(
- tconn->kstc_addr.Handle,
- tconn->kstc_addr.FileObject
- );
+ TsduMgr = KsQueryTsduMgr(tconn, expedited, FALSE);
+ ks_lock_tsdumgr(TsduMgr);
+#if FALSE
+ KsWriteTsduMdl(TsduMgr, Tsdu, TsduDescriptor,
+ StartingOffset, ReceiveLength, 0);
+ status = STATUS_PENDING;
+#else
+ KsWriteTsduDat(TsduMgr, (PCHAR)KsMapMdlBuffer(Tsdu) +
+ StartingOffset, ReceiveLength, 0);
+ status = STATUS_SUCCESS;
+#endif
+ KeSetEvent(&(TsduMgr->Event), 0, FALSE);
+ ks_unlock_tsdumgr(TsduMgr);
- tconn->kstc_state = ksts_inited;
+ /* re-active the ks connection and wake up the scheduler */
+ if (KS_CAN_SCHED(TsduMgr)) {
+ if (tconn->kstc_conn && tconn->kstc_sched_cb) {
+ tconn->kstc_sched_cb(tconn, FALSE);
+ }
+ }
} else {
- cfs_enter_debugger();
+
+ ks_abort_tconn(tconn);
+ status = STATUS_CONNECTION_ABORTED;
}
- /* free the tconn structure ... */
+ ks_put_tconn(tconn);
- ks_free_tconn(tconn);
+ /* Return STATUS_PENDING to system because we are still
+ owning the MDL resources. ks_recv_mdl is expected
+ to free the MDL resources. */
+
+ return (status);
}
-int
-ks_query_data(
- ksock_tconn_t * tconn,
- size_t * size,
- int bIsExpedited )
+
+/*
+ * Expedited & Bulk receive event handler
+ */
+
+NTSTATUS
+KsTcpChainedReceiveExpeditedEventHandler (
+ IN PVOID TdiEventContext, // the event context
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN ULONG ReceiveFlags,
+ IN ULONG ReceiveLength,
+ IN ULONG StartingOffset, // offset of start of client data in TSDU
+ IN PMDL Tsdu, // TSDU data chain
+ IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
+ )
{
- int rc = 0;
+ return KsTcpChainedReceiveEventHandler(
+ TdiEventContext,
+ ConnectionContext,
+ ReceiveFlags | TDI_RECEIVE_EXPEDITED,
+ ReceiveLength,
+ StartingOffset,
+ Tsdu,
+ TsduDescriptor );
+}
- PKS_CHAIN KsChain;
- PKS_TSDUMGR KsTsduMgr;
- *size = 0;
+/*
+ * KsSetHandlers
+ * setup all the event handler callbacks
+ *
+ * Arguments:
+ * tconn: the tdi connecton object
+ *
+ * Return Value:
+ * int: ks error code
+ *
+ * NOTES:
+ * N/A
+ */
- ks_get_tconn(tconn);
- spin_lock(&(tconn->kstc_lock));
+int
+KsSetHandlers(
+ ks_tconn_t * tconn
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ KS_EVENT_HANDLERS handlers;
- if ( tconn->kstc_type != kstt_sender &&
- tconn->kstc_type != kstt_child) {
- rc = -EINVAL;
- spin_unlock(&(tconn->kstc_lock));
+ /* to make sure the address object is opened already */
+ if (tconn->kstc_addr.FileObject == NULL) {
goto errorout;
}
- if (tconn->kstc_state != ksts_connected) {
- rc = -ENOTCONN;
- spin_unlock(&(tconn->kstc_lock));
- goto errorout;
- }
+ /* initialize the handlers indictor array. for sender and listenr,
+ there are different set of callbacks. for child, we just return. */
- if (tconn->kstc_type == kstt_sender) {
- KsChain = &(tconn->sender.kstc_recv);
- } else {
- LASSERT(tconn->kstc_type == kstt_child);
- KsChain = &(tconn->child.kstc_recv);
- }
+ memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
- if (bIsExpedited) {
- KsTsduMgr = &(KsChain->Expedited);
- } else {
- KsTsduMgr = &(KsChain->Normal);
+ SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
+ SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
+ SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
+ SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
+ SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
+
+ // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
+
+ if (tconn->kstc_type == kstt_listener) {
+ SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
+ } else if (tconn->kstc_type == kstt_child) {
+ goto errorout;
}
- *size = KsTsduMgr->TotalBytes;
- spin_unlock(&(tconn->kstc_lock));
+ /* set all the event callbacks */
+ status = KsSetEventHandlers(
+ tconn->kstc_addr.FileObject, /* Address File Object */
+ tconn, /* Event Context */
+ &handlers /* Event callback handlers */
+ );
errorout:
- ks_put_tconn(tconn);
-
- return (rc);
+ return cfs_error_code(status);
}
+
/*
- * ks_get_tcp_option
- * Query the the options of the tcp stream connnection
+ * KsResetHandlers
+ * disable all the event handler callbacks (set to NULL)
*
* Arguments:
- * tconn: the tdi connection
- * ID: option id
- * OptionValue: buffer to store the option value
- * Length: the length of the value, to be returned
+ * tconn: the tdi connecton object
*
* Return Value:
- * int: ks return code
+ * int: ks error code
*
* NOTES:
* N/A
*/
int
-ks_get_tcp_option (
- ksock_tconn_t * tconn,
- ULONG ID,
- PVOID OptionValue,
- PULONG Length
+KsResetHandlers(
+ ks_tconn_t * tconn
)
{
- NTSTATUS Status = STATUS_SUCCESS;
-
- IO_STATUS_BLOCK IoStatus;
-
- TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
-
- PFILE_OBJECT ConnectionObject;
- PDEVICE_OBJECT DeviceObject = NULL;
+ NTSTATUS status = STATUS_SUCCESS;
+ KS_EVENT_HANDLERS handlers;
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp = NULL;
+ /* to make sure the address object is opened already */
+ if (tconn->kstc_addr.FileObject == NULL) {
+ goto errorout;
+ }
- KEVENT Event;
+ /* initialize the handlers indictor array. for sender and listenr,
+ there are different set of callbacks. for child, we just return. */
- /* make sure the tdi connection is connected ? */
+ memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
- ks_get_tconn(tconn);
+ SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
+ SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
+ SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
+ SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
+ SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
+ // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
- if (tconn->kstc_state != ksts_connected) {
- Status = STATUS_INVALID_PARAMETER;
+ if (tconn->kstc_type == kstt_listener) {
+ SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
+ } else if (tconn->kstc_type == kstt_child) {
goto errorout;
}
- LASSERT(tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child);
+ /* set all the event callbacks */
+ status = KsSetEventHandlers(
+ tconn->kstc_addr.FileObject, /* Address File Object */
+ tconn, /* Event Context */
+ &handlers /* Event callback handlers */
+ );
- if (tconn->kstc_type == kstt_sender) {
- ConnectionObject = tconn->sender.kstc_info.FileObject;
- } else {
- ConnectionObject = tconn->child.kstc_info.FileObject;
- }
+errorout:
- QueryInfoEx.ID.toi_id = ID;
- QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
- QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
- QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
- QueryInfoEx.ID.toi_entity.tei_instance = 0;
+ return cfs_error_code(status);
+}
- RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
+VOID
+KsPrintProviderInfo(
+ PWSTR DeviceName,
+ PTDI_PROVIDER_INFO ProviderInfo
+ )
+{
+ KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
+ KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
+ KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
+ KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
+ KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
- Irp = IoBuildDeviceIoControlRequest(
- IOCTL_TCP_QUERY_INFORMATION_EX,
- DeviceObject,
- &QueryInfoEx,
- sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
- OptionValue,
- *Length,
- FALSE,
- &Event,
- &IoStatus
- );
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
+ KsPrint((2, " CONNECTION_MODE\n"));
+ }
- if (Irp == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
+ KsPrint((2, " ORDERLY_RELEASE\n"));
}
- IrpSp = IoGetNextIrpStackLocation(Irp);
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
+ KsPrint((2, " CONNECTIONLESS_MODE\n"));
+ }
- if (IrpSp == NULL) {
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
+ KsPrint((2, " ERROR_FREE_DELIVERY\n"));
+ }
- IoFreeIrp(Irp);
- Irp = NULL;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
+ KsPrint((2, " SECURITY_LEVEL\n"));
}
- IrpSp->FileObject = ConnectionObject;
- IrpSp->DeviceObject = DeviceObject;
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
+ KsPrint((2, " BROADCAST_SUPPORTED\n"));
+ }
- Status = IoCallDriver(DeviceObject, Irp);
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
+ KsPrint((2, " MULTICAST_SUPPORTED\n"));
+ }
- if (Status == STATUS_PENDING) {
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
+ KsPrint((2, " DELAYED_ACCEPTANCE\n"));
+ }
- KeWaitForSingleObject(
- &Event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
+ KsPrint((2, " EXPEDITED_DATA\n"));
+ }
- Status = IoStatus.Status;
+ if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
+ KsPrint((2, " INTERNAL_BUFFERING\n"));
}
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
+ KsPrint((2, " ROUTE_DIRECTED\n"));
+ }
- if (NT_SUCCESS(Status)) {
- *Length = IoStatus.Information;
- } else {
- cfs_enter_debugger();
- memset(OptionValue, 0, *Length);
- Status = STATUS_SUCCESS;
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
+ KsPrint((2, " NO_ZERO_LENGTH\n"));
}
-errorout:
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
+ KsPrint((2, " POINT_TO_POINT\n"));
+ }
- ks_put_tconn(tconn);
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
+ KsPrint((2, " MESSAGE_MODE\n"));
+ }
- return cfs_error_code(Status);
+ if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
+ KsPrint((2, " HALF_DUPLEX\n"));
+ }
+
+ KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
+ KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
+ KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
}
+
/*
- * ks_set_tcp_option
- * Set the the options for the tcp stream connnection
+ * ks_create_tconn
+ * allocate a new tconn structure from the SLAB cache or
+ * NonPaged sysetm pool
*
* Arguments:
- * tconn: the tdi connection
- * ID: option id
- * OptionValue: buffer containing the new option value
- * Length: the length of the value
+ * N/A
*
* Return Value:
- * int: ks return code
+ * ks_tconn_t *: the address of tconn or NULL if it fails
*
* NOTES:
* N/A
*/
-NTSTATUS
-ks_set_tcp_option (
- ksock_tconn_t * tconn,
- ULONG ID,
- PVOID OptionValue,
- ULONG Length
- )
+ks_tconn_t *
+ks_create_tconn()
{
- NTSTATUS Status = STATUS_SUCCESS;
+ ks_tconn_t * tconn = NULL;
- IO_STATUS_BLOCK IoStatus;
+ /* allocate ksoc_tconn_t from the slab cache memory */
+ tconn = (ks_tconn_t *)cfs_mem_cache_alloc(
+ ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
- ULONG SetInfoExLength;
- PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
+ if (tconn) {
- PFILE_OBJECT ConnectionObject;
- PDEVICE_OBJECT DeviceObject = NULL;
+ /* zero tconn elements */
+ memset(tconn, 0, sizeof(ks_tconn_t));
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp = NULL;
+ /* initialize the tconn ... */
+ tconn->kstc_magic = KS_TCONN_MAGIC;
- PKEVENT Event;
+ ExInitializeWorkItem(
+ &(tconn->kstc_disconnect.WorkItem),
+ KsDisconnectHelper,
+ &(tconn->kstc_disconnect)
+ );
- /* make sure the tdi connection is connected ? */
+ KeInitializeEvent(
+ &(tconn->kstc_disconnect.Event),
+ SynchronizationEvent,
+ FALSE );
- ks_get_tconn(tconn);
+ ExInitializeWorkItem(
+ &(tconn->kstc_destroy),
+ ks_destroy_tconn,
+ tconn
+ );
- if (tconn->kstc_state != ksts_connected) {
- Status = STATUS_INVALID_PARAMETER;
- goto errorout;
- }
+ cfs_spin_lock_init(&(tconn->kstc_lock));
- LASSERT(tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child);
+ ks_get_tconn(tconn);
+ cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
- if (tconn->kstc_type == kstt_sender) {
- ConnectionObject = tconn->sender.kstc_info.FileObject;
- } else {
- ConnectionObject = tconn->child.kstc_info.FileObject;
+ /* attach it into global list in ks_data */
+
+ cfs_list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
+ ks_data.ksnd_ntconns++;
+ cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
+
+ tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
}
+ KsPrint((3, "ks_create_tconn: new connection: %p\n", tconn));
+ return (tconn);
+}
- SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
+/*
+ * ks_free_tconn
+ * free the tconn structure to the SLAB cache or NonPaged
+ * sysetm pool
+ *
+ * Arguments:
+ * tconn: the tcon is to be freed
+ *
+ * Return Value:
+ * N/A
+ *
+ * Notes:
+ * N/A
+ */
- SetInfoEx = ExAllocatePoolWithTag(
- NonPagedPool,
- SetInfoExLength,
- 'TSSK'
- );
+void
+ks_free_tconn(ks_tconn_t * tconn)
+{
+ LASSERT(cfs_atomic_read(&(tconn->kstc_refcount)) == 0);
- if (SetInfoEx == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
+
+ /* remove it from the global list */
+ cfs_list_del(&tconn->kstc_list);
+ ks_data.ksnd_ntconns--;
+
+ /* if this is the last tconn, it would be safe for
+ ks_tdi_fini_data to quit ... */
+ if (ks_data.ksnd_ntconns == 0) {
+ cfs_wake_event(&ks_data.ksnd_tconn_exit);
}
+ cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
- SetInfoEx->ID.toi_id = ID;
+ /* free the structure memory */
+ cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
- SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
- SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
- SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
- SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
+ KsPrint((3, "ks_free_tconn: tconn %p is freed.\n", tconn));
+}
- SetInfoEx->BufferSize = Length;
- RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
- Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
- KeInitializeEvent(Event, NotificationEvent, FALSE);
+/*
+ * ks_init_listener
+ * Initialize the tconn as a listener (daemon)
+ *
+ * Arguments:
+ * tconn: the listener tconn
+ *
+ * Return Value:
+ * N/A
+ *
+ * Notes:
+ * N/A
+ */
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+void
+ks_init_listener(
+ ks_tconn_t * tconn
+ )
+{
+ /* preparation: intialize the tconn members */
- Irp = IoBuildDeviceIoControlRequest(
- IOCTL_TCP_SET_INFORMATION_EX,
- DeviceObject,
- SetInfoEx,
- SetInfoExLength,
- NULL,
- 0,
- FALSE,
- Event,
- &IoStatus
- );
+ tconn->kstc_type = kstt_listener;
- if (Irp == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
+ RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
- IrpSp = IoGetNextIrpStackLocation(Irp);
+ CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
+ CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
- if (IrpSp == NULL) {
- IoFreeIrp(Irp);
- Irp = NULL;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
+ cfs_init_event( &(tconn->listener.kstc_accept_event),
+ TRUE,
+ FALSE );
- IrpSp->FileObject = ConnectionObject;
- IrpSp->DeviceObject = DeviceObject;
+ cfs_init_event( &(tconn->listener.kstc_destroy_event),
+ TRUE,
+ FALSE );
- Status = IoCallDriver(DeviceObject, Irp);
+ tconn->kstc_state = ksts_inited;
+}
- if (Status == STATUS_PENDING) {
- KeWaitForSingleObject(
- Event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
+/*
+ * ks_init_sender
+ * Initialize the tconn as a sender
+ *
+ * Arguments:
+ * tconn: the sender tconn
+ *
+ * Return Value:
+ * N/A
+ *
+ * Notes:
+ * N/A
+ */
- Status = IoStatus.Status;
- }
+void
+ks_init_sender(
+ ks_tconn_t * tconn
+ )
+{
+ tconn->kstc_type = kstt_sender;
+ RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
-errorout:
+ KsInitializeKsChain(&(tconn->sender.kstc_recv));
+ KsInitializeKsChain(&(tconn->sender.kstc_send));
- if (SetInfoEx) {
- ExFreePool(SetInfoEx);
- }
+ tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
+ tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
- if (!NT_SUCCESS(Status)) {
- printk("ks_set_tcp_option: error setup tcp option: ID (%d), Status = %xh\n",
- ID, Status);
- Status = STATUS_SUCCESS;
- }
+ tconn->kstc_state = ksts_inited;
+}
+
+/*
+ * ks_init_child
+ * Initialize the tconn as a child
+ *
+ * Arguments:
+ * tconn: the child tconn
+ *
+ * Return Value:
+ * N/A
+ *
+ * NOTES:
+ * N/A
+ */
+
+void
+ks_init_child(
+ ks_tconn_t * tconn
+ )
+{
+ tconn->kstc_type = kstt_child;
+ RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
- ks_put_tconn(tconn);
+ KsInitializeKsChain(&(tconn->child.kstc_recv));
+ KsInitializeKsChain(&(tconn->child.kstc_send));
- return cfs_error_code(Status);
+ tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
+ tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
+
+ tconn->kstc_state = ksts_inited;
}
/*
- * ks_bind_tconn
- * bind the tdi connection object with an address
+ * ks_get_tconn
+ * increase the reference count of the tconn with 1
*
* Arguments:
- * tconn: tconn to be bound
- * parent: the parent tconn object
- * ipaddr: the ip address
- * port: the port number
+ * tconn: the tdi connection to be referred
*
* Return Value:
- * int: 0 for success or ks error codes.
+ * N/A
*
* NOTES:
* N/A
*/
-int
-ks_bind_tconn (
- ksock_tconn_t * tconn,
- ksock_tconn_t * parent,
- ulong_ptr addr,
- unsigned short port
+void
+ks_get_tconn(
+ ks_tconn_t * tconn
)
{
- NTSTATUS status;
- int rc = 0;
-
- ksock_tdi_addr_t taddr;
-
- memset(&taddr, 0, sizeof(ksock_tdi_addr_t));
-
- if (tconn->kstc_state != ksts_inited) {
-
- status = STATUS_INVALID_PARAMETER;
- rc = cfs_error_code(status);
-
- goto errorout;
-
- } else if (tconn->kstc_type == kstt_child) {
-
- if (NULL == parent) {
- status = STATUS_INVALID_PARAMETER;
- rc = cfs_error_code(status);
-
- goto errorout;
- }
-
- /* refer it's parent's address object */
-
- taddr = parent->kstc_addr;
- ObReferenceObject(taddr.FileObject);
-
- ks_get_tconn(parent);
-
- } else {
-
- PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
- ULONG AddrLen = 0;
+ cfs_atomic_inc(&(tconn->kstc_refcount));
+}
- /* intialize the tdi address*/
+/*
+ * ks_put_tconn
+ * decrease the reference count of the tconn and destroy
+ * it if the refercount becomes 0.
+ *
+ * Arguments:
+ * tconn: the tdi connection to be dereferred
+ *
+ * Return Value:
+ * N/A
+ *
+ * NOTES:
+ * N/A
+ */
- TdiAddress->TAAddressCount = 1;
- TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
- TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+void
+ks_put_tconn(
+ ks_tconn_t *tconn
+ )
+{
+ if (cfs_atomic_dec_and_test(&(tconn->kstc_refcount))) {
- ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
- ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = htonl(addr);
+ cfs_spin_lock(&(tconn->kstc_lock));
- memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
+ if ( ( tconn->kstc_type == kstt_child ||
+ tconn->kstc_type == kstt_sender ) &&
+ ( tconn->kstc_state == ksts_connected ) ) {
+ cfs_spin_unlock(&(tconn->kstc_lock));
- /* open the transport address object */
+ ks_abort_tconn(tconn);
- AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
- TDI_ADDRESS_LENGTH_IP;
+ } else {
- status = KsOpenAddress(
- &(tconn->kstc_dev),
- &(taddr.Tdi),
- AddrLen,
- &(taddr.Handle),
- &(taddr.FileObject)
- );
+ if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
+ cfs_enter_debugger();
+ } else {
+ ExQueueWorkItem(
+ &(tconn->kstc_destroy),
+ DelayedWorkQueue
+ );
- if (!NT_SUCCESS(status)) {
+ cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
+ }
- KsPrint((0, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
- addr, port, status ));
- rc = cfs_error_code(status);
- goto errorout;
+ cfs_spin_unlock(&(tconn->kstc_lock));
}
}
-
- if (tconn->kstc_type == kstt_child) {
- tconn->child.kstc_parent = parent;
- }
-
- tconn->kstc_state = ksts_bind;
- tconn->kstc_addr = taddr;
-
-errorout:
-
- return (rc);
}
/*
- * ks_build_tconn
- * build tcp/streaming connection to remote peer
+ * ks_destroy_tconn
+ * cleanup the tdi connection and free it
*
* Arguments:
- * tconn: tconn to be connected to the peer
- * addr: the peer's ip address
- * port: the peer's port number
+ * tconn: the tdi connection to be cleaned.
*
* Return Value:
- * int: 0 for success or ks error codes.
+ * N/A
*
- * Notes:
+ * NOTES:
* N/A
*/
-int
-ks_build_tconn(
- ksock_tconn_t * tconn,
- ulong_ptr addr,
- unsigned short port
+void
+ks_destroy_tconn(
+ ks_tconn_t * tconn
)
{
- int rc = 0;
- NTSTATUS status = STATUS_SUCCESS;
-
+ LASSERT(tconn->kstc_refcount.counter == 0);
- PFILE_OBJECT ConnectionObject = NULL;
- PDEVICE_OBJECT DeviceObject = NULL;
+ if (tconn->kstc_type == kstt_listener) {
- PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
- ULONG AddrLength;
+ KsResetHandlers(tconn);
- PIRP Irp = NULL;
+ /* for listener, we just need to close the address object */
+ KsCloseAddress(
+ tconn->kstc_addr.Handle,
+ tconn->kstc_addr.FileObject
+ );
- LASSERT(tconn->kstc_type == kstt_sender);
- LASSERT(tconn->kstc_state == ksts_bind);
+ tconn->kstc_state = ksts_inited;
- ks_get_tconn(tconn);
+ } else if (tconn->kstc_type == kstt_child) {
- {
- /* set the event callbacks */
- rc = ks_set_handlers(tconn);
+ /* for child tdi conections */
- if (rc < 0) {
- cfs_enter_debugger();
- goto errorout;
- }
- }
+ /* disassociate the relation between it's connection object
+ and the address object */
- /* create the connection file handle / object */
- status = KsOpenConnection(
- &(tconn->kstc_dev),
- (CONNECTION_CONTEXT)tconn,
- &(tconn->sender.kstc_info.Handle),
- &(tconn->sender.kstc_info.FileObject)
+ if (tconn->kstc_state == ksts_associated) {
+ KsDisassociateAddress(
+ tconn->child.kstc_info.FileObject
);
+ }
- if (!NT_SUCCESS(status)) {
- rc = cfs_error_code(status);
- cfs_enter_debugger();
- goto errorout;
- }
-
- /* associdate the the connection with the adress object of the tconn */
+ /* release the connection object */
- status = KsAssociateAddress(
- tconn->kstc_addr.Handle,
- tconn->sender.kstc_info.FileObject
+ KsCloseConnection(
+ tconn->child.kstc_info.Handle,
+ tconn->child.kstc_info.FileObject
);
- if (!NT_SUCCESS(status)) {
- rc = cfs_error_code(status);
- cfs_enter_debugger();
- goto errorout;
- }
-
- tconn->kstc_state = ksts_associated;
+ /* release it's refer of it's parent's address object */
+ KsCloseAddress(
+ NULL,
+ tconn->kstc_addr.FileObject
+ );
- /* Allocating Connection Info Together with the Address */
- AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
- + TDI_ADDRESS_LENGTH_IP;
+ cfs_spin_lock(&tconn->child.kstc_parent->kstc_lock);
+ cfs_spin_lock(&tconn->kstc_lock);
- ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
- NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
+ tconn->kstc_state = ksts_inited;
- if (NULL == ConnectionInfo) {
+ /* remove it frome it's parent's queues */
- status = STATUS_INSUFFICIENT_RESOURCES;
- rc = cfs_error_code(status);
- cfs_enter_debugger();
- goto errorout;
- }
+ if (tconn->child.kstc_queued) {
- /* Initializing ConnectionInfo ... */
- {
- PTRANSPORT_ADDRESS TdiAddress;
+ cfs_list_del(&(tconn->child.kstc_link));
- /* ConnectionInfo settings */
+ if (tconn->child.kstc_queueno) {
- ConnectionInfo->UserDataLength = 0;
- ConnectionInfo->UserData = NULL;
- ConnectionInfo->OptionsLength = 0;
- ConnectionInfo->Options = NULL;
- ConnectionInfo->RemoteAddressLength = AddrLength;
- ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
+ LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
+ tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
+ } else {
- /* intialize the tdi address*/
+ LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
+ tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
+ }
- TdiAddress = ConnectionInfo->RemoteAddress;
+ tconn->child.kstc_queued = FALSE;
+ }
- TdiAddress->TAAddressCount = 1;
- TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
- TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ cfs_spin_unlock(&tconn->kstc_lock);
+ cfs_spin_unlock(&tconn->child.kstc_parent->kstc_lock);
- ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
- ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = htonl(addr);
+ /* drop the reference of the parent tconn */
+ ks_put_tconn(tconn->child.kstc_parent);
- memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
- }
+ } else if (tconn->kstc_type == kstt_sender) {
- /* Now prepare to connect the remote peer ... */
+ KsResetHandlers(tconn);
- ConnectionObject = tconn->sender.kstc_info.FileObject;
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ /* release the connection object */
- /* allocate a new Irp */
+ KsCloseConnection(
+ tconn->sender.kstc_info.Handle,
+ tconn->sender.kstc_info.FileObject
+ );
- Irp = KsBuildTdiIrp(DeviceObject);
+ /* release it's refer of it's parent's address object */
+ KsCloseAddress(
+ tconn->kstc_addr.Handle,
+ tconn->kstc_addr.FileObject
+ );
- if (NULL == Irp) {
+ tconn->kstc_state = ksts_inited;
- status = STATUS_INSUFFICIENT_RESOURCES;
- rc = cfs_error_code(status);
+ } else {
cfs_enter_debugger();
- goto errorout;
}
- /* setup the Irp */
+ /* free the tconn structure ... */
- TdiBuildConnect(
- Irp,
- DeviceObject,
- ConnectionObject,
- NULL,
- NULL,
- NULL,
- ConnectionInfo,
- NULL
- );
+ ks_free_tconn(tconn);
+}
+/*
+ * ks_get_tcp_option
+ * Query the the options of the tcp stream connnection
+ *
+ * Arguments:
+ * tconn: the tdi connection
+ * ID: option id
+ * OptionValue: buffer to store the option value
+ * Length: the length of the value, to be returned
+ *
+ * Return Value:
+ * int: ks return code
+ *
+ * NOTES:
+ * N/A
+ */
- /* sumbit the Irp to the underlying transport driver */
- status = KsSubmitTdiIrp(
- DeviceObject,
- Irp,
- TRUE,
- NULL
- );
+int
+ks_get_tcp_option (
+ ks_tconn_t * tconn,
+ ULONG ID,
+ PVOID OptionValue,
+ PULONG Length
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
- spin_lock(&(tconn->kstc_lock));
+ IO_STATUS_BLOCK IoStatus;
- if (NT_SUCCESS(status)) {
+ TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
- /* Connected! the conneciton is built successfully. */
+ PFILE_OBJECT ConnectionObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
- tconn->kstc_state = ksts_connected;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp = NULL;
- tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
- tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
+ KEVENT Event;
+
+ /* make sure the tdi connection is connected ? */
- spin_unlock(&(tconn->kstc_lock));
+ ks_get_tconn(tconn);
+
+ if (tconn->kstc_state != ksts_connected) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto errorout;
+ }
+
+ LASSERT(tconn->kstc_type == kstt_sender ||
+ tconn->kstc_type == kstt_child);
+ if (tconn->kstc_type == kstt_sender) {
+ ConnectionObject = tconn->sender.kstc_info.FileObject;
} else {
+ ConnectionObject = tconn->child.kstc_info.FileObject;
+ }
- /* Not connected! Abort it ... */
+ QueryInfoEx.ID.toi_id = ID;
+ QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
+ QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
+ QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
+ QueryInfoEx.ID.toi_entity.tei_instance = 0;
- if (rc != 0) {
- cfs_enter_debugger();
- }
+ RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
- Irp = NULL;
- rc = cfs_error_code(status);
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
- tconn->kstc_state = ksts_associated;
- spin_unlock(&(tconn->kstc_lock));
+ Irp = IoBuildDeviceIoControlRequest(
+ IOCTL_TCP_QUERY_INFORMATION_EX,
+ DeviceObject,
+ &QueryInfoEx,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+ OptionValue,
+ *Length,
+ FALSE,
+ &Event,
+ &IoStatus
+ );
- /* disassocidate the connection and the address object,
- after cleanup, it's safe to set the state to abort ... */
+ if (Irp == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
- if ( NT_SUCCESS(KsDisassociateAddress(
- tconn->sender.kstc_info.FileObject))) {
- tconn->kstc_state = ksts_aborted;
- }
+ IrpSp = IoGetNextIrpStackLocation(Irp);
- /* reset the event callbacks */
- rc = ks_reset_handlers(tconn);
+ if (IrpSp == NULL) {
+ IoFreeIrp(Irp);
+ Irp = NULL;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
-errorout:
+ IrpSp->FileObject = ConnectionObject;
+ IrpSp->DeviceObject = DeviceObject;
- if (NT_SUCCESS(status)) {
+ Status = IoCallDriver(DeviceObject, Irp);
- ks_query_local_ipaddr(tconn);
+ if (Status == STATUS_PENDING) {
- } else {
+ KeWaitForSingleObject(
+ &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
- if (ConnectionInfo) {
- ExFreePool(ConnectionInfo);
- }
- if (Irp) {
- IoFreeIrp(Irp);
- }
+ Status = IoStatus.Status;
+ }
+
+
+ if (NT_SUCCESS(Status)) {
+ *Length = (ULONG)(ULONG_PTR)IoStatus.Information;
+ } else {
+ cfs_enter_debugger();
+ memset(OptionValue, 0, *Length);
+ Status = STATUS_SUCCESS;
}
+errorout:
+
ks_put_tconn(tconn);
- return (rc);
+ return cfs_error_code(Status);
}
-
/*
- * ks_disconnect_tconn
- * disconnect the tconn from a connection
+ * ks_set_tcp_option
+ * Set the the options for the tcp stream connnection
*
* Arguments:
- * tconn: the tdi connecton object connected already
- * flags: flags & options for disconnecting
+ * tconn: the tdi connection
+ * ID: option id
+ * OptionValue: buffer containing the new option value
+ * Length: the length of the value
*
* Return Value:
- * int: ks error code
+ * int: ks return code
*
- * Notes:
+ * NOTES:
* N/A
*/
-int
-ks_disconnect_tconn(
- ksock_tconn_t * tconn,
- ulong_ptr flags
+NTSTATUS
+ks_set_tcp_option (
+ ks_tconn_t * tconn,
+ ULONG ID,
+ PVOID OptionValue,
+ ULONG Length
)
{
- NTSTATUS status = STATUS_SUCCESS;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ IO_STATUS_BLOCK IoStatus;
- ksock_tconn_info_t * info;
+ ULONG SetInfoExLength;
+ PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
PFILE_OBJECT ConnectionObject;
PDEVICE_OBJECT DeviceObject = NULL;
PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp = NULL;
- KEVENT Event;
-
- ks_get_tconn(tconn);
-
- /* make sure tt's connected already and it
- must be a sender or a child ... */
+ PKEVENT Event;
- LASSERT(tconn->kstc_state == ksts_connected);
- LASSERT( tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child);
+ /* make sure the tdi connection is connected ? */
- /* reset all the event handlers to NULL */
+ ks_get_tconn(tconn);
- if (tconn->kstc_type != kstt_child) {
- ks_reset_handlers (tconn);
+ if (tconn->kstc_state != ksts_connected) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto errorout;
}
- /* Disconnecting to the remote peer ... */
+ LASSERT(tconn->kstc_type == kstt_sender ||
+ tconn->kstc_type == kstt_child);
if (tconn->kstc_type == kstt_sender) {
- info = &(tconn->sender.kstc_info);
+ ConnectionObject = tconn->sender.kstc_info.FileObject;
} else {
- info = &(tconn->child.kstc_info);
+ ConnectionObject = tconn->child.kstc_info.FileObject;
}
- ConnectionObject = info->FileObject;
- DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
-
- /* allocate an Irp and setup it */
-
- Irp = KsBuildTdiIrp(DeviceObject);
+ SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
- if (NULL == Irp) {
+ SetInfoEx = ExAllocatePoolWithTag(
+ NonPagedPool,
+ SetInfoExLength,
+ 'TSSK'
+ );
- status = STATUS_INSUFFICIENT_RESOURCES;
- cfs_enter_debugger();
+ if (SetInfoEx == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- KeInitializeEvent(
- &Event,
- SynchronizationEvent,
- FALSE
- );
-
- TdiBuildDisconnect(
- Irp,
- DeviceObject,
- ConnectionObject,
- KsDisconectCompletionRoutine,
- &Event,
- NULL,
- flags,
- NULL,
- NULL
- );
-
- /* issue the Irp to the underlying transport
- driver to disconnect the connection */
+ SetInfoEx->ID.toi_id = ID;
- status = IoCallDriver(DeviceObject, Irp);
+ SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
+ SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
+ SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
+ SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
- if (STATUS_PENDING == status) {
+ SetInfoEx->BufferSize = Length;
+ RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
- status = KeWaitForSingleObject(
- &Event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
+ Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
+ KeInitializeEvent(Event, NotificationEvent, FALSE);
- status = Irp->IoStatus.Status;
- }
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
- KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
- status, KsNtStatusToString(status)));
+ Irp = IoBuildDeviceIoControlRequest(
+ IOCTL_TCP_SET_INFORMATION_EX,
+ DeviceObject,
+ SetInfoEx,
+ SetInfoExLength,
+ NULL,
+ 0,
+ FALSE,
+ Event,
+ &IoStatus
+ );
- IoFreeIrp(Irp);
+ if (Irp == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
- if (info->ConnectionInfo) {
+ IrpSp = IoGetNextIrpStackLocation(Irp);
- /* disassociate the association between connection/address objects */
+ if (IrpSp == NULL) {
+ IoFreeIrp(Irp);
+ Irp = NULL;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
- status = KsDisassociateAddress(ConnectionObject);
+ IrpSp->FileObject = ConnectionObject;
+ IrpSp->DeviceObject = DeviceObject;
- if (!NT_SUCCESS(status)) {
- cfs_enter_debugger();
- }
+ Status = IoCallDriver(DeviceObject, Irp);
- spin_lock(&(tconn->kstc_lock));
+ if (Status == STATUS_PENDING) {
- /* cleanup the tsdumgr Lists */
- KsCleanupTsdu (tconn);
+ KeWaitForSingleObject(
+ Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
- /* set the state of the tconn */
- if (NT_SUCCESS(status)) {
- tconn->kstc_state = ksts_disconnected;
- } else {
- tconn->kstc_state = ksts_associated;
- }
+ Status = IoStatus.Status;
+ }
- /* free the connection info to system pool*/
- ExFreePool(info->ConnectionInfo);
- info->ConnectionInfo = NULL;
- info->Remote = NULL;
+errorout:
- spin_unlock(&(tconn->kstc_lock));
+ if (SetInfoEx) {
+ ExFreePool(SetInfoEx);
}
- status = STATUS_SUCCESS;
-
-errorout:
+ if (!NT_SUCCESS(Status)) {
+ KsPrint((0, "ks_set_tcp_option: error setup tcp option: "
+ "ID (%d) Status = %xh\n", ID, Status));
+ Status = STATUS_SUCCESS;
+ }
ks_put_tconn(tconn);
- return cfs_error_code(status);
+ return cfs_error_code(Status);
}
-
/*
- * ks_abort_tconn
- * The connection is broken un-expectedly. We need do
- * some cleanup.
+ * ks_bind_tconn
+ * bind the tdi connection object with an address
*
* Arguments:
- * tconn: the tdi connection
+ * tconn: tconn to be bound
+ * parent: the parent tconn object
+ * ipaddr: the ip address
+ * port: the port number
*
* Return Value:
- * N/A
+ * int: 0 for success or ks error codes.
*
- * Notes:
+ * NOTES:
* N/A
*/
-void
-ks_abort_tconn(
- ksock_tconn_t * tconn
+int
+ks_bind_tconn (
+ ks_tconn_t * tconn,
+ ks_tconn_t * parent,
+ ulong addr,
+ unsigned short port
)
{
- PKS_DISCONNECT_WORKITEM WorkItem = NULL;
+ NTSTATUS status;
+ int rc = 0;
- WorkItem = &(tconn->kstc_disconnect);
+ ks_tdi_addr_t taddr;
- ks_get_tconn(tconn);
- spin_lock(&(tconn->kstc_lock));
+ memset(&taddr, 0, sizeof(ks_tdi_addr_t));
- if (tconn->kstc_state != ksts_connected) {
- ks_put_tconn(tconn);
- } else {
+ if (tconn->kstc_state != ksts_inited) {
- if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
+ status = STATUS_INVALID_PARAMETER;
+ rc = cfs_error_code(status);
+ goto errorout;
- WorkItem->Flags = TDI_DISCONNECT_ABORT;
- WorkItem->tconn = tconn;
+ } else if (tconn->kstc_type == kstt_child) {
- cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
+ if (NULL == parent) {
+ status = STATUS_INVALID_PARAMETER;
+ rc = cfs_error_code(status);
- ExQueueWorkItem(
- &(WorkItem->WorkItem),
- DelayedWorkQueue
- );
+ goto errorout;
}
- }
- spin_unlock(&(tconn->kstc_lock));
-}
+ /* refer it's parent's address object */
+ taddr = parent->kstc_addr;
+ ObReferenceObject(taddr.FileObject);
-/*
- * ks_query_local_ipaddr
- * query the local connection ip address
- *
- * Arguments:
- * tconn: the tconn which is connected
- *
- * Return Value:
- * int: ks error code
- *
- * Notes:
- * N/A
- */
+ ks_get_tconn(parent);
-int
-ks_query_local_ipaddr(
- ksock_tconn_t * tconn
- )
-{
- PFILE_OBJECT FileObject = NULL;
- NTSTATUS status;
+ } else {
- PTRANSPORT_ADDRESS TdiAddress;
- ULONG AddressLength;
+ PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
+ ULONG AddrLen = 0;
- if (tconn->kstc_type == kstt_sender) {
- FileObject = tconn->sender.kstc_info.FileObject;
- } else if (tconn->kstc_type == kstt_child) {
- FileObject = tconn->child.kstc_info.FileObject;
- } else {
- status = STATUS_INVALID_PARAMETER;
- goto errorout;
- }
+ /* intialize the tdi address*/
- TdiAddress = &(tconn->kstc_addr.Tdi);
- AddressLength = MAX_ADDRESS_LENGTH;
+ TdiAddress->TAAddressCount = 1;
+ TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+ TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
- status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
+ ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
+ ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
- if (NT_SUCCESS(status)) {
+ memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
- KsPrint((0, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
- ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
- ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
- } else {
- KsPrint((0, "KsQueryonnectionIpAddress: Failed to query the connection local ip address.\n"));
+
+ /* open the transport address object */
+
+ AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
+ TDI_ADDRESS_LENGTH_IP;
+
+ status = KsOpenAddress(
+ &(tconn->kstc_dev),
+ &(taddr.Tdi),
+ AddrLen,
+ &(taddr.Handle),
+ &(taddr.FileObject)
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ KsPrint((1, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
+ addr, port, status ));
+ rc = cfs_error_code(status);
+ goto errorout;
+ }
+ }
+
+ if (tconn->kstc_type == kstt_child) {
+ tconn->child.kstc_parent = parent;
}
+ tconn->kstc_state = ksts_bind;
+ tconn->kstc_addr = taddr;
+
errorout:
- return cfs_error_code(status);
+ return (rc);
}
/*
- * ks_send_mdl
- * send MDL chain to the peer for a stream connection
+ * ks_build_tconn
+ * build tcp/streaming connection to remote peer
*
* Arguments:
- * tconn: tdi connection object
- * tx: the transmit context
- * mdl: the mdl chain containing the data
- * len: length of the data
- * flags: flags of the transmission
+ * tconn: tconn to be connected to the peer
+ * addr: the peer's ip address
+ * port: the peer's port number
*
* Return Value:
- * ks return code
+ * int: 0 for success or ks error codes.
*
* Notes:
* N/A
*/
int
-ks_send_mdl(
- ksock_tconn_t * tconn,
- void * tx,
- ksock_mdl_t * mdl,
- int len,
- int flags
+ks_build_tconn(
+ ks_tconn_t * tconn,
+ ulong addr,
+ unsigned short port
)
{
- NTSTATUS Status;
- int rc = 0;
- ulong_ptr length;
- ulong_ptr tflags;
- ksock_tdi_tx_t * context;
+ int rc = 0;
+ NTSTATUS status = STATUS_SUCCESS;
- PKS_CHAIN KsChain;
- PKS_TSDUMGR KsTsduMgr;
- PKS_TSDU KsTsdu;
- PKS_TSDU_BUF KsTsduBuf;
- PKS_TSDU_DAT KsTsduDat;
- BOOLEAN bNewTsdu = FALSE; /* newly allocated */
- BOOLEAN bNewBuff = FALSE; /* newly allocated */
+ PFILE_OBJECT ConnectionObject = NULL;
+ PDEVICE_OBJECT DeviceObject = NULL;
+
+ PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
+ ULONG AddrLength;
+
+ PIRP Irp = NULL;
+
+ LASSERT(tconn->kstc_type == kstt_sender);
+ LASSERT(tconn->kstc_state == ksts_bind);
+
+ ks_get_tconn(tconn);
+
+ {
+ /* set the event callbacks */
+ rc = KsSetHandlers(tconn);
+
+ if (rc < 0) {
+ cfs_enter_debugger();
+ goto errorout;
+ }
+ }
+
+ /* create the connection file handle / object */
+ status = KsOpenConnection(
+ &(tconn->kstc_dev),
+ (CONNECTION_CONTEXT)tconn,
+ &(tconn->sender.kstc_info.Handle),
+ &(tconn->sender.kstc_info.FileObject)
+ );
- BOOLEAN bBuffed; /* bufferred sending */
+ if (!NT_SUCCESS(status)) {
+ rc = cfs_error_code(status);
+ cfs_enter_debugger();
+ goto errorout;
+ }
- PUCHAR Buffer = NULL;
- ksock_mdl_t * NewMdl = NULL;
+ /* associdate the the connection with the adress object of the tconn */
- PIRP Irp = NULL;
- PFILE_OBJECT ConnObject;
- PDEVICE_OBJECT DeviceObject;
+ status = KsAssociateAddress(
+ tconn->kstc_addr.Handle,
+ tconn->sender.kstc_info.FileObject
+ );
- BOOLEAN bIsNonBlock;
+ if (!NT_SUCCESS(status)) {
+ rc = cfs_error_code(status);
+ cfs_enter_debugger();
+ goto errorout;
+ }
- ks_get_tconn(tconn);
+ tconn->kstc_state = ksts_associated;
- tflags = ks_tdi_send_flags(flags);
- bIsNonBlock = cfs_is_flag_set(flags, MSG_DONTWAIT);
+ /* Allocating Connection Info Together with the Address */
+ AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
+ + TDI_ADDRESS_LENGTH_IP;
- spin_lock(&tconn->kstc_lock);
+ ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
- LASSERT( tconn->kstc_type == kstt_sender ||
- tconn->kstc_type == kstt_child );
+ if (NULL == ConnectionInfo) {
- if (tconn->kstc_state != ksts_connected) {
- spin_unlock(&tconn->kstc_lock);
- ks_put_tconn(tconn);
- return -ENOTCONN;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ rc = cfs_error_code(status);
+ cfs_enter_debugger();
+ goto errorout;
}
- /* get the latest Tsdu buffer form TsduMgr list.
- just set NULL if the list is empty. */
-
- if (tconn->kstc_type == kstt_sender) {
- KsChain = &(tconn->sender.kstc_send);
- } else {
- LASSERT(tconn->kstc_type == kstt_child);
- KsChain = &(tconn->child.kstc_send);
- }
+ /* Initializing ConnectionInfo ... */
+ {
+ PTRANSPORT_ADDRESS TdiAddress;
- if (cfs_is_flag_set(tflags, TDI_SEND_EXPEDITED)) {
- KsTsduMgr = &(KsChain->Expedited);
- } else {
- KsTsduMgr = &(KsChain->Normal);
- }
+ /* ConnectionInfo settings */
- if (KsTsduMgr->TotalBytes + len <= tconn->kstc_snd_wnd) {
- bBuffed = TRUE;
- } else {
- bBuffed = FALSE;
- }
+ ConnectionInfo->UserDataLength = 0;
+ ConnectionInfo->UserData = NULL;
+ ConnectionInfo->OptionsLength = 0;
+ ConnectionInfo->Options = NULL;
+ ConnectionInfo->RemoteAddressLength = AddrLength;
+ ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
- /* do the preparation work for bufferred sending */
- if (bBuffed) {
+ /* intialize the tdi address*/
- /* if the data is even larger than the biggest Tsdu, we have
- to allocate new buffer and use TSDU_TYOE_BUF to store it */
+ TdiAddress = ConnectionInfo->RemoteAddress;
- if ( KS_TSDU_STRU_SIZE((ULONG)len) > ks_data.ksnd_tsdu_size
- - KS_DWORD_ALIGN(sizeof(KS_TSDU))) {
- bNewBuff = TRUE;
- }
+ TdiAddress->TAAddressCount = 1;
+ TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+ TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
- if (list_empty(&(KsTsduMgr->TsduList))) {
+ ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
+ ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
- LASSERT(KsTsduMgr->NumOfTsdu == 0);
- KsTsdu = NULL;
+ memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
+ }
- } else {
+ /* Now prepare to connect the remote peer ... */
- LASSERT(KsTsduMgr->NumOfTsdu > 0);
- KsTsdu = list_entry(KsTsduMgr->TsduList.prev, KS_TSDU, Link);
- LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
+ ConnectionObject = tconn->sender.kstc_info.FileObject;
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+ /* allocate a new Irp */
- /* check whether KsTsdu free space is enough, or we need alloc new Tsdu */
- if (bNewBuff) {
- if (sizeof(KS_TSDU_BUF) + KsTsdu->LastOffset > KsTsdu->TotalLength) {
- KsTsdu = NULL;
- }
- } else {
- if ( KS_TSDU_STRU_SIZE((ULONG)len) >
- KsTsdu->TotalLength - KsTsdu->LastOffset ) {
- KsTsdu = NULL;
- }
- }
- }
+ Irp = KsBuildTdiIrp(DeviceObject);
- /* if there's no Tsdu or the free size is not enough for the
- KS_TSDU_BUF or KS_TSDU_DAT. We need re-allocate a new Tsdu. */
+ if (NULL == Irp) {
- if (NULL == KsTsdu) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ rc = cfs_error_code(status);
+ cfs_enter_debugger();
+ goto errorout;
+ }
- KsTsdu = KsAllocateKsTsdu();
+ /* setup the Irp */
- if (NULL == KsTsdu) {
- bBuffed = FALSE;
- bNewBuff = FALSE;
- } else {
- bNewTsdu = TRUE;
- }
- }
+ TdiBuildConnect(
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL,
+ NULL,
+ ConnectionInfo,
+ NULL
+ );
- /* process the case that a new buffer is to be allocated from system memory */
- if (bNewBuff) {
- /* now allocating internal buffer to contain the payload */
- Buffer = ExAllocatePool(NonPagedPool, len);
+ /* sumbit the Irp to the underlying transport driver */
+ status = KsSubmitTdiIrp(
+ DeviceObject,
+ Irp,
+ TRUE,
+ NULL
+ );
- if (NULL == Buffer) {
- bBuffed = FALSE;
- }
- }
- }
+ cfs_spin_lock(&(tconn->kstc_lock));
- if (bBuffed) {
+ if (NT_SUCCESS(status)) {
- if (bNewBuff) {
+ /* Connected! the conneciton is built successfully. */
- /* queue a new KS_TSDU_BUF to the Tsdu buffer */
- KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ tconn->kstc_state = ksts_connected;
- KsTsduBuf->TsduFlags = 0;
- KsTsduBuf->DataLength = (ULONG)len;
- KsTsduBuf->StartOffset = 0;
- KsTsduBuf->UserBuffer = Buffer;
- } else {
- /* queue a new KS_TSDU_BUF to the Tsdu buffer */
- KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
+ tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
+ tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
- KsTsduDat->TsduFlags = 0;
- KsTsduDat->DataLength = (ULONG)len;
- KsTsduDat->StartOffset = 0;
- KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE((ULONG)len);
+ cfs_spin_unlock(&(tconn->kstc_lock));
- Buffer = &KsTsduDat->Data[0];
- }
+ } else {
- /* now locking the Buffer and copy user payload into the buffer */
- ASSERT(Buffer != NULL);
+ /* Not connected! Abort it ... */
- rc = ks_lock_buffer(Buffer, FALSE, len, IoReadAccess, &NewMdl);
if (rc != 0) {
- printk("ks_send_mdl: bufferred: error allocating mdl.\n");
- bBuffed = FALSE;
- } else {
- ULONG BytesCopied = 0;
- TdiCopyMdlToBuffer(mdl, 0, Buffer, 0, (ULONG)len, &BytesCopied);
- if (BytesCopied != (ULONG) len) {
- bBuffed = FALSE;
- }
+ cfs_enter_debugger();
}
- /* Do the finializing job if we succeed to to lock the buffer and move
- user data. Or we need do cleaning up ... */
- if (bBuffed) {
+ Irp = NULL;
+ rc = cfs_error_code(status);
- if (bNewBuff) {
- KsTsduBuf->TsduType = TSDU_TYPE_BUF;
- KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
+ tconn->kstc_state = ksts_associated;
+ cfs_spin_unlock(&(tconn->kstc_lock));
- } else {
- KsTsduDat->TsduType = TSDU_TYPE_DAT;
- KsTsdu->LastOffset += KsTsduDat->TotalLength;
- }
+ /* disassocidate the connection and the address object,
+ after cleanup, it's safe to set the state to abort ... */
- /* attach it to the TsduMgr list if the Tsdu is newly created. */
- if (bNewTsdu) {
+ if ( NT_SUCCESS(KsDisassociateAddress(
+ tconn->sender.kstc_info.FileObject))) {
+ tconn->kstc_state = ksts_aborted;
+ }
- list_add_tail(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
- KsTsduMgr->NumOfTsdu++;
- }
+ /* reset the event callbacks */
+ rc = KsResetHandlers(tconn);
- } else {
+ goto errorout;
+ }
- if (NewMdl) {
- ks_release_mdl(NewMdl, FALSE);
- NewMdl = NULL;
- }
+errorout:
- if (bNewBuff) {
- ExFreePool(Buffer);
- Buffer = NULL;
- bNewBuff = FALSE;
- }
- }
- }
+ if (NT_SUCCESS(status)) {
- /* update the TotalBytes being in sending */
- KsTsduMgr->TotalBytes += (ULONG)len;
+ ks_query_local_ipaddr(tconn);
- spin_unlock(&tconn->kstc_lock);
+ } else {
- /* cleanup the Tsdu if not successful */
- if (!bBuffed && bNewTsdu) {
- KsPutKsTsdu(KsTsdu);
- bNewTsdu = FALSE;
- KsTsdu = NULL;
+ if (ConnectionInfo) {
+ ExFreePool(ConnectionInfo);
+ }
+ if (Irp) {
+ IoFreeIrp(Irp);
+ }
}
- /* we need allocate the ksock_tx_t structure from memory pool. */
+ ks_put_tconn(tconn);
- context = cfs_alloc(sizeof(ksock_tdi_tx_t) + sizeof(KEVENT),0);
- if (!context) {
- /* release the chained mdl */
- ks_release_mdl(mdl, FALSE);
+ return (rc);
+}
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- /* intialize the TcpContext */
+/*
+ * ks_disconnect_tconn
+ * disconnect the tconn from a connection
+ *
+ * Arguments:
+ * tconn: the tdi connecton object connected already
+ * flags: flags & options for disconnecting
+ *
+ * Return Value:
+ * int: ks error code
+ *
+ * Notes:
+ * N/A
+ */
- memset(context,0, sizeof(ksock_tdi_tx_t) + sizeof(KEVENT));
+int
+ks_disconnect_tconn(
+ ks_tconn_t * tconn,
+ ulong flags
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
- context->tconn = tconn;
- context->Event = (PKEVENT) ((PUCHAR)context + sizeof(ksock_tdi_tx_t));
+ ks_tconn_info_t * info;
+
+ PFILE_OBJECT ConnectionObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
- KeInitializeEvent(context->Event, SynchronizationEvent, FALSE);
+ PIRP Irp = NULL;
- if (bBuffed) {
+ KEVENT Event;
- /* for bufferred transmission, we need set
- the internal completion routine. */
+ ks_get_tconn(tconn);
- context->CompletionRoutine = KsTcpSendCompletionRoutine;
- context->KsTsduMgr = KsTsduMgr;
- context->CompletionContext = KsTsdu;
- context->CompletionContext2 = (bNewBuff ? (PVOID)KsTsduBuf : (PVOID)KsTsduDat);
- context->bCounted = FALSE;
+ /* make sure tt's connected already and it
+ must be a sender or a child ... */
- } else if (bIsNonBlock) {
+ LASSERT(tconn->kstc_state == ksts_connected);
+ LASSERT( tconn->kstc_type == kstt_sender ||
+ tconn->kstc_type == kstt_child);
- /* for non-blocking transmission, we need set
- the internal completion routine too. */
+ /* reset all the event handlers to NULL */
- context->CompletionRoutine = KsTcpSendCompletionRoutine;
- context->CompletionContext = tx;
- context->KsTsduMgr = KsTsduMgr;
- context->bCounted = TRUE;
- context->ReferCount = 2;
+ if (tconn->kstc_type != kstt_child) {
+ KsResetHandlers (tconn);
}
+ /* Disconnecting to the remote peer ... */
+
if (tconn->kstc_type == kstt_sender) {
- ConnObject = tconn->sender.kstc_info.FileObject;
+ info = &(tconn->sender.kstc_info);
} else {
- LASSERT(tconn->kstc_type == kstt_child);
- ConnObject = tconn->child.kstc_info.FileObject;
+ info = &(tconn->child.kstc_info);
}
- DeviceObject = IoGetRelatedDeviceObject(ConnObject);
+ ConnectionObject = info->FileObject;
+ DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
+
+ /* allocate an Irp and setup it */
Irp = KsBuildTdiIrp(DeviceObject);
if (NULL == Irp) {
- /* release the chained mdl */
- ks_release_mdl(mdl, FALSE);
-
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- length = KsQueryMdlsSize(mdl);
-
- LASSERT((ULONG)len <= length);
-
- ks_get_tconn(tconn);
-
- TdiBuildSend(
- Irp,
- DeviceObject,
- ConnObject,
- KsTcpCompletionRoutine,
- context,
- (bBuffed ? NewMdl : mdl),
- (bBuffed ? (tflags | TDI_SEND_NON_BLOCKING) : tflags),
- (ULONG)len;
- );
-
- Status = IoCallDriver(DeviceObject, Irp);
-
- if (bBuffed) {
- ks_release_mdl(mdl, FALSE);
- NewMdl = NULL;
- }
-
- if (!NT_SUCCESS(Status)) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
cfs_enter_debugger();
- rc = cfs_error_code(Status);
goto errorout;
}
- if (bBuffed) {
- Status = STATUS_SUCCESS;
- rc = len;
- context = NULL;
- } else {
- if (bIsNonBlock) {
- if (InterlockedDecrement(&context->ReferCount) == 0) {
- Status = Irp->IoStatus.Status;
- } else {
- Status = STATUS_PENDING;
- context = NULL;
- }
- } else {
- if (STATUS_PENDING == Status) {
- Status = KeWaitForSingleObject(
- context->Event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
-
- if (NT_SUCCESS(Status)) {
- Status = Irp->IoStatus.Status;
- }
- }
- }
-
- if (Status == STATUS_SUCCESS) {
- rc = (int)(Irp->IoStatus.Information);
-
- spin_lock(&tconn->kstc_lock);
- KsTsduMgr->TotalBytes -= rc;
- spin_unlock(&tconn->kstc_lock);
-
- } else {
- rc = cfs_error_code(Status);
- }
- }
-
-errorout:
-
- if (bBuffed) {
-
- if (NewMdl) {
- ks_release_mdl(NewMdl, FALSE);
- NewMdl = NULL;
- }
+ KeInitializeEvent(
+ &Event,
+ SynchronizationEvent,
+ FALSE
+ );
- if (bNewBuff) {
- if (!NT_SUCCESS(Status)) {
- ExFreePool(Buffer);
- Buffer = NULL;
- }
- }
+ TdiBuildDisconnect(
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ KsDisconectCompletionRoutine,
+ &Event,
+ NULL,
+ flags,
+ NULL,
+ NULL
+ );
- } else {
+ /* issue the Irp to the underlying transport
+ driver to disconnect the connection */
- if (Status != STATUS_PENDING) {
+ status = IoCallDriver(DeviceObject, Irp);
- if (Irp) {
+ if (STATUS_PENDING == status) {
- /* Freeing the Irp ... */
+ status = KeWaitForSingleObject(
+ &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
- IoFreeIrp(Irp);
- Irp = NULL;
- }
- }
+ status = Irp->IoStatus.Status;
}
- if (!NT_SUCCESS(Status)) {
+ KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
+ status, KsNtStatusToString(status)));
- spin_lock(&tconn->kstc_lock);
+ IoFreeIrp(Irp);
- KsTsduMgr->TotalBytes -= (ULONG)len;
+ if (info->ConnectionInfo) {
- if (bBuffed) {
+ /* disassociate the association between connection/address objects */
- /* attach it to the TsduMgr list if the Tsdu is newly created. */
- if (bNewTsdu) {
+ status = KsDisassociateAddress(ConnectionObject);
- list_del(&(KsTsdu->Link));
- KsTsduMgr->NumOfTsdu--;
+ if (!NT_SUCCESS(status)) {
+ cfs_enter_debugger();
+ }
- KsPutKsTsdu(KsTsdu);
- } else {
- if (bNewBuff) {
- if ( (ulong_ptr)KsTsduBuf + sizeof(KS_TSDU_BUF) ==
- (ulong_ptr)KsTsdu + KsTsdu->LastOffset) {
- KsTsdu->LastOffset -= sizeof(KS_TSDU_BUF);
- KsTsduBuf->TsduType = 0;
- } else {
- cfs_enter_debugger();
- KsTsduBuf->StartOffset = KsTsduBuf->DataLength;
- }
- } else {
- if ( (ulong_ptr)KsTsduDat + KsTsduDat->TotalLength ==
- (ulong_ptr)KsTsdu + KsTsdu->LastOffset) {
- KsTsdu->LastOffset -= KsTsduDat->TotalLength;
- KsTsduDat->TsduType = 0;
- } else {
- cfs_enter_debugger();
- KsTsduDat->StartOffset = KsTsduDat->DataLength;
- }
- }
- }
+ cfs_spin_lock(&(tconn->kstc_lock));
+
+ /* cleanup the tsdumgr Lists */
+ KsCleanupTsdu (tconn);
+
+ /* set the state of the tconn */
+ if (NT_SUCCESS(status)) {
+ tconn->kstc_state = ksts_disconnected;
+ } else {
+ tconn->kstc_state = ksts_associated;
}
- spin_unlock(&tconn->kstc_lock);
- }
+ /* free the connection info to system pool*/
+ ExFreePool(info->ConnectionInfo);
+ info->ConnectionInfo = NULL;
+ info->Remote = NULL;
- /* free the context if is not used at all */
- if (context) {
- cfs_free(context);
+ cfs_spin_unlock(&(tconn->kstc_lock));
}
+ status = STATUS_SUCCESS;
+
+errorout:
+
ks_put_tconn(tconn);
- return rc;
+ return cfs_error_code(status);
}
+
/*
- * ks_recv_mdl
- * Receive data from the peer for a stream connection
+ * ks_abort_tconn
+ * The connection is broken un-expectedly. We need do
+ * some cleanup.
*
* Arguments:
- * tconn: tdi connection object
- * mdl: the mdl chain to contain the incoming data
- * len: length of the data
- * flags: flags of the receiving
+ * tconn: the tdi connection
*
* Return Value:
- * ks return code
+ * N/A
*
* Notes:
* N/A
*/
-int
-ks_recv_mdl(
- ksock_tconn_t * tconn,
- ksock_mdl_t * mdl,
- int size,
- int flags
+void
+ks_abort_tconn(
+ ks_tconn_t * tconn
)
{
- NTSTATUS Status = STATUS_SUCCESS;
- int rc = 0;
-
- BOOLEAN bIsNonBlock;
- BOOLEAN bIsExpedited;
-
- PKS_CHAIN KsChain;
- PKS_TSDUMGR KsTsduMgr;
- PKS_TSDU KsTsdu;
- PKS_TSDU_DAT KsTsduDat;
- PKS_TSDU_BUF KsTsduBuf;
- PKS_TSDU_MDL KsTsduMdl;
-
- PUCHAR Buffer;
-
- ULONG BytesRecved = 0;
- ULONG RecvedOnce;
+ PKS_DISCONNECT_WORKITEM WorkItem = NULL;
- bIsNonBlock = cfs_is_flag_set(flags, MSG_DONTWAIT);
- bIsExpedited = cfs_is_flag_set(flags, MSG_OOB);
+ WorkItem = &(tconn->kstc_disconnect);
ks_get_tconn(tconn);
+ cfs_spin_lock(&(tconn->kstc_lock));
-Again:
-
- RecvedOnce = 0;
+ if (tconn->kstc_state != ksts_connected) {
+ ks_put_tconn(tconn);
+ } else {
- spin_lock(&(tconn->kstc_lock));
+ if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
- if ( tconn->kstc_type != kstt_sender &&
- tconn->kstc_type != kstt_child) {
+ WorkItem->Flags = TDI_DISCONNECT_ABORT;
+ WorkItem->tconn = tconn;
- rc = -EINVAL;
- spin_unlock(&(tconn->kstc_lock));
+ cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
- goto errorout;
+ ExQueueWorkItem(
+ &(WorkItem->WorkItem),
+ DelayedWorkQueue
+ );
+ }
}
- if (tconn->kstc_state != ksts_connected) {
+ cfs_spin_unlock(&(tconn->kstc_lock));
+}
- rc = -ENOTCONN;
- spin_unlock(&(tconn->kstc_lock));
- goto errorout;
- }
+/*
+ * ks_query_local_ipaddr
+ * query the local connection ip address
+ *
+ * Arguments:
+ * tconn: the tconn which is connected
+ *
+ * Return Value:
+ * int: ks error code
+ *
+ * Notes:
+ * N/A
+ */
- if (tconn->kstc_type == kstt_sender) {
- KsChain = &(tconn->sender.kstc_recv);
- } else {
- LASSERT(tconn->kstc_type == kstt_child);
- KsChain = &(tconn->child.kstc_recv);
- }
+int
+ks_query_local_ipaddr(
+ ks_tconn_t * tconn
+ )
+{
+ PFILE_OBJECT FileObject = NULL;
+ NTSTATUS status;
- if (bIsExpedited) {
- KsTsduMgr = &(KsChain->Expedited);
+ PTRANSPORT_ADDRESS TdiAddress;
+ ULONG AddressLength;
+
+ if (tconn->kstc_type == kstt_sender) {
+ FileObject = tconn->sender.kstc_info.FileObject;
+ } else if (tconn->kstc_type == kstt_child) {
+ FileObject = tconn->child.kstc_info.FileObject;
} else {
- KsTsduMgr = &(KsChain->Normal);
+ status = STATUS_INVALID_PARAMETER;
+ goto errorout;
}
-NextTsdu:
-
- if (list_empty(&(KsTsduMgr->TsduList))) {
-
- //
- // It's a notification event. We need reset it to
- // un-signaled state in case there no any tsdus.
- //
+ TdiAddress = &(tconn->kstc_addr.Tdi);
+ AddressLength = MAX_ADDRESS_LENGTH;
- KeResetEvent(&(KsTsduMgr->Event));
+ status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
+ if (NT_SUCCESS(status)) {
+ KsPrint((2, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
+ ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
+ ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
} else {
+ KsPrint((2, "ks_query_local_ipaddr: Failed to query the connection local ip address.\n"));
+ }
- KsTsdu = list_entry(KsTsduMgr->TsduList.next, KS_TSDU, Link);
- LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
-
- /* remove the KsTsdu from TsduMgr list to release the lock */
- list_del(&(KsTsdu->Link));
- KsTsduMgr->NumOfTsdu--;
-
- spin_unlock(&(tconn->kstc_lock));
-
- while ((ULONG)size > BytesRecved) {
-
- ULONG BytesCopied = 0;
- ULONG BytesToCopy = 0;
- ULONG StartOffset = 0;
-
- KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
- KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
- KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
-
- if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
- TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
-
-
- //
- // Data Tsdu Unit ...
- //
-
- if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
-
- if (cfs_is_flag_set(KsTsduDat->TsduFlags, KS_TSDU_DAT_RECEIVING)) {
- /* data is not ready yet*/
- KeResetEvent(&(KsTsduMgr->Event));
- printk("ks_recv_mdl: KsTsduDat (%xh) is not ready yet !!!!!!!\n", KsTsduDat);
- break;
- }
-
- Buffer = &KsTsduDat->Data[0];
- StartOffset = KsTsduDat->StartOffset;
- if (KsTsduDat->DataLength - KsTsduDat->StartOffset > size - BytesRecved) {
- /* Recvmsg requst could be statisfied ... */
- BytesToCopy = size - BytesRecved;
- } else {
- BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
- }
-
- } else {
-
- if (cfs_is_flag_set(KsTsduBuf->TsduFlags, KS_TSDU_BUF_RECEIVING)) {
- /* data is not ready yet*/
- KeResetEvent(&(KsTsduMgr->Event));
- DbgPrint("ks_recv_mdl: KsTsduBuf (%xh) is not ready yet !!!!!!!\n", KsTsduBuf);
- break;
- }
-
- ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
- Buffer = KsTsduBuf->UserBuffer;
- StartOffset = KsTsduBuf->StartOffset;
-
- if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > size - BytesRecved) {
- /* Recvmsg requst could be statisfied ... */
- BytesToCopy = size - BytesRecved;
- } else {
- BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
- }
- }
-
- if (BytesToCopy > 0) {
- Status = TdiCopyBufferToMdl(
- Buffer,
- StartOffset,
- BytesToCopy,
- mdl,
- BytesRecved,
- &BytesCopied
- );
-
- if (NT_SUCCESS(Status)) {
-
- if (BytesToCopy != BytesCopied) {
- cfs_enter_debugger();
- }
+errorout:
- BytesRecved += BytesCopied;
- RecvedOnce += BytesCopied;
+ return cfs_error_code(status);
+}
- } else {
+int
+KsCalcWhichEngine(ks_tconn_t * tconn)
+{
+ PTRANSPORT_ADDRESS TdiAddress = &(tconn->kstc_addr.Tdi);
+ ULONG addr = ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr;
+ ULONG sum = (addr & 0xFF) + ((addr & 0xFF00) >> 8) + ((addr & 0xFF0000) >> 16);
- cfs_enter_debugger();
+ return (int)(sum % ks_data.ksnd_engine_nums);
+}
- if (STATUS_BUFFER_OVERFLOW == Status) {
- }
- }
- }
+void
+KsQueueTdiEngine(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
+{
+ ks_engine_mgr_t * engm;
+ ks_engine_slot_t * engs;
+
+ engm = &ks_data.ksnd_engine_mgr[KsCalcWhichEngine(tconn)];
+ engs = &TsduMgr->Slot;
+
+ if (!engs->queued) {
+ cfs_spin_lock(&engm->lock);
+ if (!engs->queued) {
+ cfs_list_add_tail(&engs->link, &engm->list);
+ engs->queued = TRUE;
+ engs->tconn = tconn;
+ engs->emgr = engm;
+ engs->tsdumgr = TsduMgr;
+ KeSetEvent(&(engm->start),0, FALSE);
+ }
+ cfs_spin_unlock(&engm->lock);
+ KsPrint((4, "KsQueueTdiEngine: TsduMgr=%p is queued to engine %p\n",
+ TsduMgr, engm));
+ }
+ KeSetEvent(&(engm->start),0, FALSE);
+}
- if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
+void
+KsRemoveTdiEngine(PKS_TSDUMGR TsduMgr)
+{
+ ks_engine_mgr_t * engm;
+ ks_engine_slot_t * engs;
+
+ engs = &TsduMgr->Slot;
+ if (engs->queued) {
+ engm = engs->emgr;
+ LASSERT(engm != NULL);
+ cfs_spin_lock(&engm->lock);
+ if (engs->queued) {
+ cfs_list_del(&engs->link);
+ engs->queued = FALSE;
+ engs->tconn = NULL;
+ engs->emgr = NULL;
+ engs->tsdumgr = NULL;
+ }
+ cfs_spin_unlock(&engm->lock);
+ KsPrint((4, "KsQueueTdiEngine: TsduMgr %p is removed from engine %p\n",
+ TsduMgr, engm));
+ }
+}
- KsTsduDat->StartOffset += BytesCopied;
+int
+KsDeliveryIrp(ks_tconn_t * tconn, PIRP irp)
+{
+ PFILE_OBJECT connobj;
+ PDEVICE_OBJECT devobj;
+ NTSTATUS status;
+ int rc = 0;
- if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
- KsTsdu->StartOffset += KsTsduDat->TotalLength;
- }
+ /* construct Irp */
+ if (tconn->kstc_type == kstt_sender) {
+ connobj = tconn->sender.kstc_info.FileObject;
+ } else {
+ LASSERT(tconn->kstc_type == kstt_child);
+ connobj = tconn->child.kstc_info.FileObject;
+ }
+ devobj = IoGetRelatedDeviceObject(connobj);
+
+ /* send irp to transport layer */
+ status = IoCallDriver(devobj, irp);
- } else {
+ /* convert status to linux error code */
+ if (!NT_SUCCESS(status)) {
+ rc = cfs_error_code(status);
+ }
- ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
- KsTsduBuf->StartOffset += BytesCopied;
- if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
- KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
- /* now we need release the buf to system pool */
- ExFreePool(KsTsduBuf->UserBuffer);
- }
- }
+ KsPrint((4, "KsDeliveryIrp: tconn=%p irp=%p status=%xh rc=%d.\n",
+ tconn, irp, status, rc));
+ return rc;
+}
- } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
+PIRP
+KsBuildSend(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr,
+ ks_mdl_t * mdl, ulong flags )
+{
+ ks_tdi_tx_t * context;
+ PIRP irp = NULL;
+ PFILE_OBJECT connobj;
+ PDEVICE_OBJECT devobj;
+ NTSTATUS status;
+ ULONG length;
- //
- // MDL Tsdu Unit ...
- //
+ int rc = 0;
- if (KsTsduMdl->DataLength > size - BytesRecved) {
+ /* query mdl chain total length */
+ length = KsQueryMdlsSize(mdl);
- /* Recvmsg requst could be statisfied ... */
+ /* we need allocate the ks_tx_t structure from memory pool. */
+ context = cfs_alloc(sizeof(ks_tdi_tx_t), 0);
+ if (!context) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
- BytesToCopy = size - BytesRecved;
+ /* intialize the TcpContext */
+ memset(context,0, sizeof(ks_tdi_tx_t));
+ context->Magic = KS_TCP_CONTEXT_MAGIC;
+ context->tconn = tconn;
+ context->CompletionRoutine = KsTcpSendCompletionRoutine;
+ context->TsduMgr = TsduMgr;
+ context->Length = length;
- } else {
+ /* construct Irp */
+ if (tconn->kstc_type == kstt_sender) {
+ connobj = tconn->sender.kstc_info.FileObject;
+ } else {
+ LASSERT(tconn->kstc_type == kstt_child);
+ connobj = tconn->child.kstc_info.FileObject;
+ }
+ devobj = IoGetRelatedDeviceObject(connobj);
+ irp = KsBuildTdiIrp(devobj);
+ if (NULL == irp) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
- BytesToCopy = KsTsduMdl->DataLength;
- }
+ /* grab tconn reference */
+ ks_get_tconn(tconn);
- Status = KsCopyMdlChainToMdlChain(
- KsTsduMdl->Mdl,
- KsTsduMdl->StartOffset,
- mdl,
- BytesRecved,
- BytesToCopy,
- &BytesCopied
- );
+ /* delivery the sending request */
+ TdiBuildSend(
+ irp,
+ devobj,
+ connobj,
+ KsTcpCompletionRoutine,
+ context,
+ mdl,
+ flags,
+ length
+ );
- if (NT_SUCCESS(Status)) {
+ return irp;
- if (BytesToCopy != BytesCopied) {
- cfs_enter_debugger();
- }
+errorout:
- KsTsduMdl->StartOffset += BytesCopied;
- KsTsduMdl->DataLength -= BytesCopied;
+ /* free the context if is not used at all */
+ if (context) {
+ ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
+ context->Magic = 'CDAB';
+ cfs_free(context);
+ }
- BytesRecved += BytesCopied;
- RecvedOnce += BytesCopied;
- } else {
- cfs_enter_debugger();
- }
+ /* here need free the Irp. */
+ if (irp) {
+ IoFreeIrp(irp);
+ irp = NULL;
+ }
- if (0 == KsTsduMdl->DataLength) {
+ return NULL;
+}
- //
- // Call TdiReturnChainedReceives to release the Tsdu memory
- //
+int
+KsDeliveryTsdus(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
+{
+ int rc = 0;
+ ulong length = 0;
+ ulong tflags = 0;
+ ks_mdl_t * mdl = NULL;
+ PIRP irp = NULL;
+ BOOLEAN expedited;
- TdiReturnChainedReceives(
- &(KsTsduMdl->Descriptor),
- 1 );
+ LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
- KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
- }
+ ks_get_tconn(tconn);
+ ks_lock_tsdumgr(TsduMgr);
- } else {
- printk("ks_recv_mdl: unknown tsdu slot: slot = %x type = %x Start= %x\n",
- KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength);
- printk(" Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x",
- KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength);
- cfs_enter_debugger();
- }
+ if ( tconn->kstc_type != kstt_sender &&
+ tconn->kstc_type != kstt_child) {
+ rc = -EINVAL;
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
+ }
- if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
+ if (tconn->kstc_state != ksts_connected) {
+ rc = -ENOTCONN;
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
+ }
- //
- // KsTsdu is empty now, we need free it ...
- //
+ if (TsduMgr->OOB) {
+ tflags = TDI_SEND_NON_BLOCKING | TDI_SEND_EXPEDITED;
+ } else {
+ tflags = TDI_SEND_NON_BLOCKING;
+ }
+
+ if (cfs_list_empty(&TsduMgr->TsduList)) {
+ LASSERT(TsduMgr->TotalBytes == 0);
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
+ }
- KsPutKsTsdu(KsTsdu);
- KsTsdu = NULL;
+ /* check whether there's outstanding sending requests */
+ if (TsduMgr->Busy) {
+ rc = -EAGAIN;
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
+ }
- break;
- }
+ /* probe all Tsdus and merge buffers together */
+ mdl = KsLockTsdus(tconn, TsduMgr, &tflags, &length);
+ if (NULL == mdl) {
+ if (length == 0) {
+ LASSERT(TsduMgr->TotalBytes == 0);
+ rc = -EAGAIN;
+ } else {
+ rc = -ENOMEM;
}
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
+ }
- spin_lock(&(tconn->kstc_lock));
+ KsPrint((4, "KsDeliveryTsdus: tconn=%p TsudMgr=%p, length=%xh/%xh\n",
+ tconn, TsduMgr, length, TsduMgr->TotalBytes));
- /* we need attach the KsTsdu to the list header */
- if (KsTsdu) {
- KsTsduMgr->NumOfTsdu++;
- list_add(&(KsTsdu->Link), &(KsTsduMgr->TsduList));
- } else if ((ULONG)size > BytesRecved) {
- goto NextTsdu;
- }
+ /* build send irp request */
+ irp = KsBuildSend(tconn, TsduMgr, mdl, tflags);
+ if (NULL == irp) {
+ rc = -ENOMEM;
+ ks_unlock_tsdumgr(TsduMgr);
+ goto errorout;
}
+ TsduMgr->Busy = TRUE;
+ ks_unlock_tsdumgr(TsduMgr);
- if (KsTsduMgr->TotalBytes < RecvedOnce) {
- cfs_enter_debugger();
- KsTsduMgr->TotalBytes = 0;
- } else {
- KsTsduMgr->TotalBytes -= RecvedOnce;
+ /* delivery mdl chain */
+ LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ rc = KsDeliveryIrp(tconn, irp);
+ if (rc < 0) {
+ goto errorout;
}
- spin_unlock(&(tconn->kstc_lock));
+errorout:
- if (NT_SUCCESS(Status)) {
+ LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ ks_put_tconn(tconn);
+ return rc;
+}
- if ((BytesRecved < (ulong_ptr)size) && (!bIsNonBlock)) {
+int
+KsDeliveryEngineThread(void * context)
+{
+ ks_engine_mgr_t * engm = context;
+ ks_engine_slot_t * engs;
+ cfs_list_t * list;
+ ks_tconn_t * tconn;
- KeWaitForSingleObject(
- &(KsTsduMgr->Event),
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
+ cfs_set_thread_priority(31);
- goto Again;
- }
+ while (!engm->stop) {
- if (bIsNonBlock && (BytesRecved == 0)) {
- rc = -EAGAIN;
- } else {
- rc = BytesRecved;
+ cfs_wait_event_internal(&engm->start, 0);
+
+ cfs_spin_lock(&engm->lock);
+ if (cfs_list_empty(&engm->list)) {
+ cfs_spin_unlock(&engm->lock);
+ continue;
}
- }
-errorout:
+ list = engm->list.next;
+ cfs_list_del(list);
+ engs = cfs_list_entry(list, ks_engine_slot_t, link);
+ LASSERT(engs->emgr == engm);
+ LASSERT(engs->queued);
+ engs->emgr = NULL;
+ engs->queued = FALSE;
+ cfs_spin_unlock(&engm->lock);
- ks_put_tconn(tconn);
+ tconn = engs->tconn;
+ LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
- if (rc > 0) {
- KsPrint((1, "ks_recv_mdl: recvieving %d bytes ...\n", rc));
- } else {
- KsPrint((0, "ks_recv_mdl: recvieving error code = %d Stauts = %xh ...\n", rc, Status));
+ KsPrint((4, "KsDeliveryEngineThread: %p active: tconn=%p "
+ "TsduMgr=%p\n", engm, tconn, engs->tsdumgr));
+ KsDeliveryTsdus(tconn, engs->tsdumgr);
+
+ LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
}
- /* release the chained mdl */
- ks_release_mdl(mdl, FALSE);
+ KeSetEvent(&engm->exit, 0, FALSE);
- return (rc);
+ return 0;
}
-
/*
* ks_init_tdi_data
* initialize the global data in ksockal_data
int
ks_init_tdi_data()
{
- int rc = 0;
+ int rc = 0, i;
/* initialize tconn related globals */
- RtlZeroMemory(&ks_data, sizeof(ks_data_t));
+ RtlZeroMemory(&ks_data, sizeof(ks_tdi_data_t));
- spin_lock_init(&ks_data.ksnd_tconn_lock);
+ cfs_spin_lock_init(&ks_data.ksnd_tconn_lock);
CFS_INIT_LIST_HEAD(&ks_data.ksnd_tconns);
cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
ks_data.ksnd_tconn_slab = cfs_mem_cache_create(
- "tcon", sizeof(ksock_tconn_t) , 0, 0);
+ "tcon", sizeof(ks_tconn_t) , 0, 0);
if (!ks_data.ksnd_tconn_slab) {
rc = -ENOMEM;
}
/* initialize tsdu related globals */
-
- spin_lock_init(&ks_data.ksnd_tsdu_lock);
+ cfs_spin_lock_init(&ks_data.ksnd_tsdu_lock);
CFS_INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
ks_data.ksnd_tsdu_slab = cfs_mem_cache_create(
if (!ks_data.ksnd_tsdu_slab) {
rc = -ENOMEM;
- cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
- ks_data.ksnd_tconn_slab = NULL;
goto errorout;
}
- /* initialize daemon related globals */
-
- spin_lock_init(&ks_data.ksnd_daemon_lock);
- CFS_INIT_LIST_HEAD(&ks_data.ksnd_daemons);
- cfs_init_event(&ks_data.ksnd_daemon_exit, TRUE, FALSE);
+ /* initialize engine threads list */
+ ks_data.ksnd_engine_nums = cfs_num_online_cpus();
+ if (ks_data.ksnd_engine_nums < 4) {
+ ks_data.ksnd_engine_nums = 4;
+ }
+ ks_data.ksnd_engine_mgr = cfs_alloc(sizeof(ks_engine_mgr_t) *
+ ks_data.ksnd_engine_nums,CFS_ALLOC_ZERO);
+ if (ks_data.ksnd_engine_mgr == NULL) {
+ rc = -ENOMEM;
+ goto errorout;
+ }
+ for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
+ cfs_spin_lock_init(&ks_data.ksnd_engine_mgr[i].lock);
+ cfs_init_event(&ks_data.ksnd_engine_mgr[i].start, TRUE, FALSE);
+ cfs_init_event(&ks_data.ksnd_engine_mgr[i].exit, TRUE, FALSE);
+ CFS_INIT_LIST_HEAD(&ks_data.ksnd_engine_mgr[i].list);
+ cfs_create_thread(KsDeliveryEngineThread, &ks_data.ksnd_engine_mgr[i], 0);
+ }
+ /* register pnp handlers to watch network condition */
KsRegisterPnpHandlers();
errorout:
+ /* do cleanup in case we get failures */
+ if (rc < 0) {
+ if (ks_data.ksnd_tconn_slab) {
+ cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
+ ks_data.ksnd_tconn_slab = NULL;
+ }
+ }
+
return rc;
}
ks_fini_tdi_data()
{
PKS_TSDU KsTsdu = NULL;
- struct list_head * list = NULL;
+ cfs_list_t * list = NULL;
+ int i;
/* clean up the pnp handler and address slots */
KsDeregisterPnpHandlers();
+ /* stop all tcp sending engines */
+ for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
+ ks_data.ksnd_engine_mgr[i].stop = TRUE;
+ KeSetEvent(&ks_data.ksnd_engine_mgr[i].start, 0, FALSE);
+ }
+
+ for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
+ cfs_wait_event_internal(&ks_data.ksnd_engine_mgr[i].exit, 0);
+ }
+
/* we need wait until all the tconn are freed */
- spin_lock(&(ks_data.ksnd_tconn_lock));
+ cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
- if (list_empty(&(ks_data.ksnd_tconns))) {
+ if (cfs_list_empty(&(ks_data.ksnd_tconns))) {
cfs_wake_event(&ks_data.ksnd_tconn_exit);
}
- spin_unlock(&(ks_data.ksnd_tconn_lock));
+ cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
/* now wait on the tconn exit event */
- cfs_wait_event(&ks_data.ksnd_tconn_exit, 0);
+ cfs_wait_event_internal(&ks_data.ksnd_tconn_exit, 0);
/* it's safe to delete the tconn slab ... */
cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
ks_data.ksnd_tconn_slab = NULL;
/* clean up all the tsud buffers in the free list */
- spin_lock(&(ks_data.ksnd_tsdu_lock));
- list_for_each (list, &ks_data.ksnd_freetsdus) {
- KsTsdu = list_entry (list, KS_TSDU, Link);
+ cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
+ cfs_list_for_each (list, &ks_data.ksnd_freetsdus) {
+ KsTsdu = cfs_list_entry (list, KS_TSDU, Link);
cfs_mem_cache_free(
ks_data.ksnd_tsdu_slab,
KsTsdu );
}
- spin_unlock(&(ks_data.ksnd_tsdu_lock));
+ cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
/* it's safe to delete the tsdu slab ... */
cfs_mem_cache_destroy(ks_data.ksnd_tsdu_slab);
* N/A
*/
-ksock_tconn_t *
+ks_tconn_t *
ks_create_child_tconn(
- ksock_tconn_t * parent
+ ks_tconn_t * parent
)
{
NTSTATUS status;
- ksock_tconn_t * backlog;
+ ks_tconn_t * backlog;
/* allocate the tdi connecton object */
backlog = ks_create_tconn();
void
ks_replenish_backlogs(
- ksock_tconn_t * parent,
- int nbacklog
+ ks_tconn_t * parent,
+ int nbacklog
)
{
- ksock_tconn_t * backlog;
- int n = 0;
+ ks_tconn_t * backlog;
+ int n = 0;
/* calculate how many backlogs needed */
if ( ( parent->listener.kstc_listening.num +
/* create the backlog child tconn */
backlog = ks_create_child_tconn(parent);
- spin_lock(&(parent->kstc_lock));
+ cfs_spin_lock(&(parent->kstc_lock));
if (backlog) {
- spin_lock(&backlog->kstc_lock);
+ cfs_spin_lock(&backlog->kstc_lock);
/* attch it into the listing list of daemon */
- list_add( &backlog->child.kstc_link,
+ cfs_list_add( &backlog->child.kstc_link,
&parent->listener.kstc_listening.list );
parent->listener.kstc_listening.num++;
backlog->child.kstc_queued = TRUE;
- spin_unlock(&backlog->kstc_lock);
+ cfs_spin_unlock(&backlog->kstc_lock);
} else {
cfs_enter_debugger();
}
- spin_unlock(&(parent->kstc_lock));
+ cfs_spin_unlock(&(parent->kstc_lock));
}
}
*/
int
-ks_start_listen(ksock_tconn_t *tconn, int nbacklog)
+ks_start_listen(ks_tconn_t *tconn, int nbacklog)
{
int rc = 0;
ks_replenish_backlogs(tconn, nbacklog);
/* set the event callback handlers */
- rc = ks_set_handlers(tconn);
+ rc = KsSetHandlers(tconn);
if (rc < 0) {
return rc;
}
- spin_lock(&(tconn->kstc_lock));
+ cfs_spin_lock(&(tconn->kstc_lock));
tconn->listener.nbacklog = nbacklog;
tconn->kstc_state = ksts_listening;
cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
- spin_unlock(&(tconn->kstc_lock));
+ cfs_spin_unlock(&(tconn->kstc_lock));
return rc;
}
void
-ks_stop_listen(ksock_tconn_t *tconn)
+ks_stop_listen(ks_tconn_t *tconn)
{
- struct list_head * list;
- ksock_tconn_t * backlog;
+ cfs_list_t * list;
+ ks_tconn_t * backlog;
/* reset all tdi event callbacks to NULL */
- ks_reset_handlers (tconn);
+ KsResetHandlers (tconn);
- spin_lock(&tconn->kstc_lock);
+ cfs_spin_lock(&tconn->kstc_lock);
cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
/* cleanup all the listening backlog child connections */
- list_for_each (list, &(tconn->listener.kstc_listening.list)) {
- backlog = list_entry(list, ksock_tconn_t, child.kstc_link);
+ cfs_list_for_each (list, &(tconn->listener.kstc_listening.list)) {
+ backlog = cfs_list_entry(list, ks_tconn_t, child.kstc_link);
/* destory and free it */
ks_put_tconn(backlog);
}
- spin_unlock(&tconn->kstc_lock);
+ cfs_spin_unlock(&tconn->kstc_lock);
/* wake up it from the waiting on new incoming connections */
KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
int
ks_wait_child_tconn(
- ksock_tconn_t * parent,
- ksock_tconn_t ** child
+ ks_tconn_t * parent,
+ ks_tconn_t ** child
)
{
- struct list_head * tmp;
- ksock_tconn_t * backlog = NULL;
+ cfs_list_t * tmp;
+ ks_tconn_t * backlog = NULL;
ks_replenish_backlogs(parent, parent->listener.nbacklog);
- spin_lock(&(parent->kstc_lock));
+ cfs_spin_lock(&(parent->kstc_lock));
if (parent->listener.kstc_listening.num <= 0) {
- spin_unlock(&(parent->kstc_lock));
+ cfs_spin_unlock(&(parent->kstc_lock));
return -1;
}
/* check the listening queue and try to search the accepted connecton */
- list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
- backlog = list_entry (tmp, ksock_tconn_t, child.kstc_link);
+ cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
+ backlog = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
- spin_lock(&(backlog->kstc_lock));
+ cfs_spin_lock(&(backlog->kstc_lock));
if (backlog->child.kstc_accepted) {
LASSERT(backlog->kstc_state == ksts_connected);
LASSERT(backlog->child.kstc_busy);
- list_del(&(backlog->child.kstc_link));
- list_add(&(backlog->child.kstc_link),
- &(parent->listener.kstc_accepted.list));
+ cfs_list_del(&(backlog->child.kstc_link));
+ cfs_list_add(&(backlog->child.kstc_link),
+ &(parent->listener.kstc_accepted.list));
parent->listener.kstc_accepted.num++;
parent->listener.kstc_listening.num--;
backlog->child.kstc_queueno = 1;
- spin_unlock(&(backlog->kstc_lock));
+ cfs_spin_unlock(&(backlog->kstc_lock));
break;
} else {
- spin_unlock(&(backlog->kstc_lock));
+ cfs_spin_unlock(&(backlog->kstc_lock));
backlog = NULL;
}
}
- spin_unlock(&(parent->kstc_lock));
+ cfs_spin_unlock(&(parent->kstc_lock));
/* we need wait until new incoming connections are requested
or the case of shuting down the listenig daemon thread */
NULL
);
- spin_lock(&(parent->kstc_lock));
+ cfs_spin_lock(&(parent->kstc_lock));
/* check whether it's exptected to exit ? */
if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
- spin_unlock(&(parent->kstc_lock));
+ cfs_spin_unlock(&(parent->kstc_lock));
} else {
goto again;
}
}
+ KsPrint((2, "ks_wait_child_tconn: connection %p accepted.\n", backlog));
+
if (backlog) {
/* query the local ip address of the connection */
ks_query_local_ipaddr(backlog);
+ } else {
+ return -EINTR;
}
-
*child = backlog;
return 0;
}
+int
+ks_query_iovs_length(struct iovec *iov, int niov)
+{
+ int i;
+ int total = 0;
+
+ LASSERT(iov != NULL);
+ LASSERT(niov > 0);
+
+ for (i=0; i < niov; i++) {
+ total += iov[i].iov_len;
+ }
+
+ return total;
+}
+
+int
+ks_query_kiovs_length(lnet_kiov_t *kiov, int nkiov)
+{
+ int i;
+ int total = 0;
+
+ LASSERT(kiov != NULL);
+ LASSERT(nkiov > 0);
+
+ for (i=0; i < nkiov; i++) {
+ total += kiov[i].kiov_len;
+ }
+
+ return total;
+}
+
+int
+ks_sock_buf_cb(void *tsdu, int ns, int off, char **buf)
+{
+ int rc = 0;
+
+ if (off < ns) {
+ *buf = (char *)tsdu + off;
+ rc = ns - off;
+ }
+ return rc;
+}
+
+int
+ks_sock_iov_cb(void *tsdu, int ns, int off, char **buf)
+{
+ int rc = 0, i;
+ struct iovec *iov = tsdu;
+
+ for (i=0; i < ns; i++) {
+ if ((size_t)off >= iov[i].iov_len) {
+ off -= iov[i].iov_len;
+ } else {
+ *buf = (char *)iov[i].iov_base + off;
+ rc = iov[i].iov_len - off;
+ break;
+ }
+ }
+ return rc;
+}
+
+int
+ks_sock_kiov_cb(void *tsdu, int ns, int off, char **buf)
+{
+ int rc = 0, i;
+ lnet_kiov_t *kiov = tsdu;
+
+ for (i=0; i < ns; i++) {
+ if ((size_t)off >= kiov[i].kiov_len) {
+ off -= kiov[i].kiov_len;
+ } else {
+ *buf = (char *)kiov[i].kiov_page->addr +
+ kiov[i].kiov_offset + off;
+ rc = kiov[i].kiov_len - off;
+ break;
+ }
+ }
+ return rc;
+}
+
+typedef int (*ks_tsdu_cb_t)(void *tsdu, int ns, int off, char **buf);
+
+int
+ks_sock_io(ks_tconn_t *tconn, void *tsdu, int ns, int reqlen,
+ int flags, int timeout, int out, ks_tsdu_cb_t callback)
+{
+ ULONG tflags;
+ BOOLEAN expedited;
+ PKS_TSDUMGR TsduMgr;
+
+ int rc;
+ int length;
+ int total = 0;
+ int64_t remained;
+ PCHAR buffer;
+ BOOLEAN async;
+
+ LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ remained = (int64_t)cfs_time_seconds(timeout);
+
+ /* query tsdu manager */
+ expedited = cfs_is_flag_set(flags, MSG_OOB);
+ TsduMgr = KsQueryTsduMgr(tconn, expedited, (BOOLEAN)out);
+
+ /* check whether equest is nonblocking */
+ if (async = cfs_is_flag_set(flags, MSG_DONTWAIT)) {
+ timeout = 0;
+ }
+
+ ks_get_tconn(tconn);
+ ks_lock_tsdumgr(TsduMgr);
+ if ( tconn->kstc_type != kstt_sender &&
+ tconn->kstc_type != kstt_child) {
+ rc = -EINVAL;
+ goto errorout;
+ }
+
+ while (length = callback(tsdu, ns, total, &buffer)) {
+
+ /* check whether socket is stil valid */
+ if (tconn->kstc_state != ksts_connected) {
+ rc = -ENOTCONN;
+ goto errorout;
+ }
+
+ if (out) {
+ tflags = KsTdiSendFlags(flags);
+ rc = KsWriteTsdus(TsduMgr, buffer, length, tflags);
+ } else {
+ tflags = KsTdiRecvFlags(flags);
+ rc = KsReadTsdus(TsduMgr, buffer, length, tflags);
+ }
+
+ if (rc > 0) {
+ total += rc;
+ } else if (!async && rc == -EAGAIN) {
+ if (timeout) {
+ if (remained) {
+ ks_unlock_tsdumgr(TsduMgr);
+ remained = cfs_wait_event_internal(
+ &TsduMgr->Event,
+ remained );
+ } else {
+ goto errorout;
+ }
+ } else {
+ ks_unlock_tsdumgr(TsduMgr);
+ cfs_wait_event_internal(&TsduMgr->Event, 0);
+ }
+ ks_lock_tsdumgr(TsduMgr);
+ } else {
+ break;
+ }
+ }
+
+errorout:
+
+ if (!out) {
+ TsduMgr->Payload = reqlen - total;
+ }
+ ks_unlock_tsdumgr(TsduMgr);
+
+ KsPrint((4, "ks_sock_io: tconn=%p tsdumgr=%p %c total=%xh/%xh rc=%d\n",
+ tconn, TsduMgr, out?'W':'R', total, TsduMgr->TotalBytes, rc));
+
+ if (total) {
+ if (out) {
+ /* signal Tdi sending engine */
+ KsQueueTdiEngine(tconn, TsduMgr);
+ }
+ rc = total;
+ }
+
+ ks_put_tconn(tconn);
+
+ LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ return rc;
+}
+
+int ks_send_buf(ks_tconn_t * tconn, char *buf,
+ int len, int flags, int timeout)
+{
+ return ks_sock_io(tconn, buf, len, len, flags,
+ timeout, 1, ks_sock_buf_cb);
+}
+
+int ks_recv_buf(ks_tconn_t * tconn, char *buf,
+ int len, int flags, int timeout)
+{
+ return ks_sock_io(tconn, buf, len, len, flags,
+ timeout, 0, ks_sock_buf_cb);
+}
+
+int ks_send_iovs(ks_tconn_t * tconn, struct iovec *iov,
+ int niov, int flags, int timeout)
+{
+ int reqlen = ks_query_iovs_length(iov, niov);
+ return ks_sock_io(tconn, iov, niov, reqlen, flags,
+ timeout, TRUE, ks_sock_iov_cb);
+}
+
+int ks_recv_iovs(ks_tconn_t * tconn, struct iovec *iov,
+ int niov, int flags, int timeout)
+{
+ int reqlen = ks_query_iovs_length(iov, niov);
+ return ks_sock_io(tconn, iov, niov, reqlen, flags,
+ timeout, FALSE, ks_sock_iov_cb);
+}
+
+int ks_send_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
+ int nkiov, int flags, int timeout)
+{
+ int reqlen = ks_query_kiovs_length(kiov, nkiov);
+ return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
+ timeout, TRUE, ks_sock_kiov_cb);
+}
+
+int ks_recv_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
+ int nkiov, int flags, int timeout)
+{
+ int reqlen = ks_query_kiovs_length(kiov, nkiov);
+ return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
+ timeout, FALSE, ks_sock_kiov_cb);
+}
+
int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
{
ks_addr_slot_t * slot = NULL;
PLIST_ENTRY list = NULL;
- spin_lock(&ks_data.ksnd_addrs_lock);
+ cfs_spin_lock(&ks_data.ksnd_addrs_lock);
list = ks_data.ksnd_addrs_list.Flink;
while (list != &ks_data.ksnd_addrs_list) {
slot = NULL;
}
- spin_unlock(&ks_data.ksnd_addrs_lock);
+ cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
return (int)(slot == NULL);
}
PLIST_ENTRY list = NULL;
int nips = 0;
- spin_lock(&ks_data.ksnd_addrs_lock);
+ cfs_spin_lock(&ks_data.ksnd_addrs_lock);
*names = cfs_alloc(sizeof(char *) * ks_data.ksnd_naddrs, CFS_ALLOC_ZERO);
if (*names == NULL) {
errorout:
- spin_unlock(&ks_data.ksnd_addrs_lock);
+ cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
return nips;
}
int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
{
- int rc = 0;
- ksock_tconn_t * parent;
+ int rc = 0;
+ ks_tconn_t * parent;
parent = ks_create_tconn();
if (!parent) {
{
LASSERT(sock->kstc_type == kstt_listener);
- spin_lock(&(sock->kstc_lock));
+ cfs_spin_lock(&(sock->kstc_lock));
/* clear the daemon flag */
cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
/* wake up it from the waiting on new incoming connections */
KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
- spin_unlock(&(sock->kstc_lock));
+ cfs_spin_unlock(&(sock->kstc_lock));
}
/*
__u32 local_ip, int local_port,
__u32 peer_ip, int peer_port)
{
- ksock_tconn_t * tconn = NULL;
+ ks_tconn_t * tconn = NULL;
int rc = 0;
*sockp = NULL;
+ if (fatal) *fatal = 0;
- KsPrint((1, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
+ KsPrint((2, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
peer_ip, peer_port, local_ip, local_port ));
/* create the tdi connecion structure */
/* bind the local ip address with the tconn */
rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
if (rc < 0) {
- KsPrint((0, "libcfs_sock_connect: failed to bind address %x:%d...\n",
+ KsPrint((1, "libcfs_sock_connect: failed to bind address %x:%d...\n",
local_ip, local_port ));
ks_free_tconn(tconn);
goto errorout;
/* connect to the remote peer */
rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
if (rc < 0) {
- KsPrint((0, "libcfs_sock_connect: failed to connect %x:%d ...\n",
+ KsPrint((1, "libcfs_sock_connect: failed to connect %x:%d ...\n",
peer_ip, peer_port ));
ks_put_tconn(tconn);
{
PTRANSPORT_ADDRESS taddr = NULL;
- spin_lock(&socket->kstc_lock);
+ cfs_spin_lock(&socket->kstc_lock);
if (remote) {
if (socket->kstc_type == kstt_sender) {
taddr = socket->sender.kstc_info.Remote;
if (port != NULL)
*port = ntohs (addr->sin_port);
} else {
- spin_unlock(&socket->kstc_lock);
+ cfs_spin_unlock(&socket->kstc_lock);
return -ENOTCONN;
}
- spin_unlock(&socket->kstc_lock);
+ cfs_spin_unlock(&socket->kstc_lock);
return 0;
}
int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
{
int rc;
- ksock_mdl_t * mdl;
-
int offset = 0;
while (nob > offset) {
- /* lock the user buffer */
- rc = ks_lock_buffer( (char *)buffer + offset,
- FALSE, nob - offset, IoReadAccess, &mdl );
+ rc = ks_send_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
- if (rc < 0) {
- return (rc);
- }
-
- /* send out the whole mdl */
- rc = ks_send_mdl( sock, NULL, mdl, nob - offset, 0 );
-
- if (rc > 0) {
- offset += rc;
+ if (rc <= 0) {
+ goto errorout;
} else {
- return (rc);
+ offset += rc;
+ rc = 0;
}
}
- return (0);
+errorout:
+
+ KsPrint((4, "libcfs_sock_write: sock: %p %d bytes rc: %d\n", sock, offset, rc));
+ return rc;
}
int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
{
- int rc;
- ksock_mdl_t * mdl;
-
+ int rc = 0;
int offset = 0;
while (nob > offset) {
- /* lock the user buffer */
- rc = ks_lock_buffer( (char *)buffer + offset,
- FALSE, nob - offset, IoWriteAccess, &mdl );
-
- if (rc < 0) {
- return (rc);
- }
-
- /* recv the requested buffer */
- rc = ks_recv_mdl( sock, mdl, nob - offset, 0 );
+ rc = ks_recv_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
- if (rc > 0) {
- offset += rc;
+ if (rc <= 0) {
+ goto errorout;
} else {
- return (rc);
+ offset += rc;
+ rc = 0;
}
}
- return (0);
+errorout:
+
+ KsPrint((4, "libcfs_sock_read: sock: %p %d bytes rc: %d\n", sock, offset, rc));
+ return rc;
}
void libcfs_sock_release(struct socket *sock)