4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
35 #define DEBUG_SUBSYSTEM S_LNET
37 #include <libcfs/libcfs.h>
38 #include <lnet/lnet.h>
40 #define TDILND_MODULE_NAME L"tdilnd"
42 ks_tdi_data_t ks_data;
45 KsDumpPrint(PCHAR buffer, ULONG length)
48 for (i=0; i < length; i++) {
49 if (((i+1) % 31) == 0)
51 printk("%2.2x ", (UCHAR)buffer[i]);
57 KsMapMdlBuffer (PMDL Mdl);
60 KsDumpMdlChain(PMDL Mdl, ULONG length)
68 printk("mdl %d:\n", i);
69 buffer = KsMapMdlBuffer(mdl);
70 KsDumpPrint(buffer, mdl->ByteCount);
71 len += mdl->ByteCount;
74 ASSERT(len == length);
79 * Allocate MDL for the buffer and lock the pages into
83 * UserBuffer: the user buffer to be locked
84 * Length: length in bytes of the buffer
85 * Operation: read or write access
86 * pMdl: the result of the created mdl
89 * NTSTATUS: kernel status code (STATUS_SUCCESS
90 * or other error code)
101 IN LOCK_OPERATION Operation,
108 LASSERT(UserBuffer != NULL);
122 Status = STATUS_INSUFFICIENT_RESOURCES;
135 MmBuildMdlForNonPagedPool(
140 Status = STATUS_SUCCESS;
144 } __except (EXCEPTION_EXECUTE_HANDLER) {
150 cfs_enter_debugger();
152 Status = STATUS_INVALID_USER_BUFFER;
161 * Map the mdl into a buffer in kernel space
164 * Mdl: the mdl to be mapped
167 * PVOID: the buffer mapped or NULL in failure
174 KsMapMdlBuffer (PMDL Mdl)
176 LASSERT(Mdl != NULL);
178 return MmGetSystemAddressForMdlSafe(
187 * Unlock all the pages in the mdl
190 * Mdl: memory description list to be released
200 KsReleaseMdl (IN PMDL Mdl,
203 LASSERT(Mdl != NULL);
223 * Query the whole size of a MDL (may be chained)
226 * Mdl: the Mdl to be queried
229 * ULONG: the total size of the mdl
236 KsQueryMdlsSize (PMDL Mdl)
243 // Walking the MDL Chain ...
247 Length += MmGetMdlByteCount(Next);
256 * Copy payload from Mdl to buffer
259 * SourceMdl: the source mdl
260 * SourceOffset: start offset of the source
261 * DestinationBuffer: the dst buffer
262 * DestinationOffset: the offset where data are to be copied.
263 * BytesTobecopied: the expteced bytes to be copied
266 * Length of data copied from MDL to user buffer
275 IN ULONG SourceOffset,
276 IN PVOID DestinationBuffer,
277 IN ULONG DestinationOffset,
278 IN ULONG BytesTobeCopied
281 PUCHAR SourceBuffer = NULL;
282 PUCHAR TargetBuffer = DestinationBuffer;
283 ULONG BytesCopied = 0;
285 if (MmGetMdlByteCount(SourceMdl) <= SourceOffset) {
289 BytesCopied = MmGetMdlByteCount(SourceMdl) - SourceOffset;
290 if (BytesCopied > BytesTobeCopied) {
291 BytesCopied = BytesTobeCopied;
294 SourceBuffer = (PUCHAR)KsMapMdlBuffer(SourceMdl);
296 RtlMoveMemory(TargetBuffer + DestinationOffset,
297 SourceBuffer + SourceOffset, BytesCopied);
304 * Initialize the Tsdu buffer header
307 * KsTsdu: the Tsdu to be initialized
308 * Length: the total length of the Tsdu
323 KsTsdu->Magic = KS_TSDU_MAGIC;
324 KsTsdu->TotalLength = Length;
325 KsTsdu->StartOffset = KsTsdu->LastOffset =
326 KS_QWORD_ALIGN(sizeof(KS_TSDU));
331 * Reuse a Tsdu from the freelist or allocate a new Tsdu
332 * from the LookAsideList table or the NonPagedPool
338 * PKS_Tsdu: the new Tsdu or NULL if it fails
347 PKS_TSDU KsTsdu = NULL;
349 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
351 if (!cfs_list_empty (&(ks_data.ksnd_freetsdus))) {
353 LASSERT(ks_data.ksnd_nfreetsdus > 0);
355 KsTsdu = cfs_list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
356 cfs_list_del(&(KsTsdu->Link));
357 ks_data.ksnd_nfreetsdus--;
361 KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
362 ks_data.ksnd_tsdu_slab, 0);
365 cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
367 if (NULL != KsTsdu) {
368 RtlZeroMemory(KsTsdu, ks_data.ksnd_tsdu_size);
369 KsInitializeKsTsdu(KsTsdu, (ULONG)ks_data.ksnd_tsdu_size);
377 * Release a Tsdu: uninitialize then free it.
380 * KsTsdu: Tsdu to be freed.
395 ks_data.ksnd_tsdu_slab,
401 * Move the Tsdu to the free tsdu list in ks_data.
404 * KsTsdu: Tsdu to be moved.
418 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
419 if (ks_data.ksnd_nfreetsdus > 128) {
420 KsFreeKsTsdu(KsTsdu);
422 cfs_list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
423 ks_data.ksnd_nfreetsdus++;
425 cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
428 /* with tconn lock acquired */
438 ks_mdl_t * mdl = NULL;
439 ks_mdl_t * tail = NULL;
442 PKS_TSDU_DAT KsTsduDat;
443 PKS_TSDU_BUF KsTsduBuf;
444 PKS_TSDU_MDL KsTsduMdl;
448 cfs_list_for_each_entry_typed(KsTsdu,
449 &TsduMgr->TsduList,KS_TSDU, Link) {
453 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
454 start = KsTsdu->StartOffset;
456 while (start < KsTsdu->LastOffset) {
458 ks_mdl_t * iov = NULL;
460 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
461 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
462 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
463 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
464 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
465 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
467 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
469 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->TotalLength);
470 if (KsTsduDat->Mdl) {
471 iov = KsTsduDat->Mdl;
474 &KsTsduDat->Data[KsTsduDat->StartOffset],
476 KsTsduDat->DataLength,
479 KsTsduDat->Mdl = iov;
482 printk("KsLockTsdus: %u\n", KsTsduDat->DataLength);
484 &KsTsduDat->Data[KsTsduDat->StartOffset],
485 KsTsduDat->DataLength);
487 *Length += KsTsduDat->DataLength;
488 start += KsTsduDat->TotalLength;
490 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
492 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
493 if (KsTsduBuf->Mdl) {
494 iov = KsTsduBuf->Mdl;
497 (PUCHAR)KsTsduBuf->UserBuffer +
498 KsTsduBuf->StartOffset,
500 KsTsduBuf->DataLength,
503 KsTsduBuf->Mdl = iov;
506 *Length += KsTsduBuf->DataLength;
507 start += sizeof(KS_TSDU_BUF);
511 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
512 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
513 iov = KsTsduMdl->Mdl;
514 *Length += KsTsduMdl->DataLength;
515 start += sizeof(KS_TSDU_MDL);
519 cfs_enter_debugger();
531 printk("KsLockTsdus: mdl %d\n", tail->ByteCount);
532 KsDumpMdlChain(tail, tail->ByteCount);
551 IN ks_mdl_t * master,
556 ks_mdl_t * mdl = NULL;
559 /* calculate the start virtual address */
560 ptr = (char *)KsMapMdlBuffer(master) + offset;
562 /* allocate new mdl for new memory range */
563 mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
569 /* initialize the mdl */
570 IoBuildPartialMdl(master, mdl, (PVOID)ptr, length);
575 /* with tconn lock acquired */
584 PKS_TSDU_DAT KsTsduDat;
585 PKS_TSDU_BUF KsTsduBuf;
586 PKS_TSDU_MDL KsTsduMdl;
588 ULONG total = TsduMgr->TotalBytes;
592 LASSERT(TsduMgr->TotalBytes >= length);
594 while (!cfs_list_empty(&TsduMgr->TsduList)) {
598 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
599 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
600 start = KsTsdu->StartOffset;
602 while (length > 0 && start < KsTsdu->LastOffset) {
605 ks_mdl_t * mdl = NULL;
607 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
608 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
609 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
610 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
611 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
612 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
614 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
616 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->DataLength);
617 if (length >= KsTsduDat->DataLength) {
618 /* whole tsdu is sent out */
619 size = KsTsduDat->DataLength;
620 start += KsTsduDat->TotalLength;
623 KsTsduDat->StartOffset += size;
626 if (KsTsduDat->Mdl) {
627 mdl = KsTsduDat->Mdl;
628 KsTsduDat->Mdl = NULL;
631 KsTsduDat->DataLength -= size;
633 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
635 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
636 if (length >= KsTsduBuf->DataLength) {
637 /* whole tsdu is sent out */
638 size = KsTsduBuf->DataLength;
639 start += sizeof(KS_TSDU_BUF);
640 LASSERT(KsTsduBuf->UserBuffer);
641 ExFreePool(KsTsduBuf->UserBuffer);
642 KsTsduBuf->UserBuffer = NULL;
644 KsTsduBuf->StartOffset += length;
648 if (KsTsduBuf->Mdl) {
649 mdl = KsTsduBuf->Mdl;
650 KsTsduBuf->Mdl = NULL;
653 KsTsduBuf->DataLength -= size;
657 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
658 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
659 mdl = KsTsduMdl->Mdl;
660 if (length >= KsTsduMdl->DataLength) {
661 /* whole mdl is sent out */
662 size = KsTsduMdl->DataLength;
663 start += sizeof(KS_TSDU_MDL);
664 KsTsduMdl->Mdl = NULL;
666 /* now split the remained data out */
667 ks_mdl_t * mdl1 = KsSplitMdl(mdl, length,
668 KsTsduMdl->DataLength - length);
670 mdl->ByteOffset += length;
673 KsTsduMdl->Mdl = mdl1;
676 KsTsduMdl->StartOffset += size;
679 KsTsduMdl->DataLength -= size;
683 TsduMgr->TotalBytes -= size;
687 KsReleaseMdl(mdl, FALSE);
690 KsTsdu->StartOffset = start;
693 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
695 /* remove KsTsdu from list */
696 cfs_list_del(&KsTsdu->Link);
697 TsduMgr->NumOfTsdu--;
706 LASSERT(length == 0);
708 LASSERT(total - size == TsduMgr->TotalBytes);
709 KsPrint((4, "KsReleaseTsdus: TsduMgr=%p Remained=%xh (%xh)\n",
710 TsduMgr, TsduMgr->TotalBytes, size ));
725 /* get the latest Tsdu buffer form TsduMgr list.
726 just set NULL if the list is empty. */
729 if (tconn->kstc_type == kstt_sender) {
730 KsChain = &(tconn->sender.kstc_send);
732 LASSERT(tconn->kstc_type == kstt_child);
733 KsChain = &(tconn->child.kstc_send);
736 if (tconn->kstc_type == kstt_sender) {
737 KsChain = &(tconn->sender.kstc_recv);
739 LASSERT(tconn->kstc_type == kstt_child);
740 KsChain = &(tconn->child.kstc_recv);
745 TsduMgr = &(KsChain->Expedited);
747 TsduMgr = &(KsChain->Normal);
754 KsGetTsdu(PKS_TSDUMGR TsduMgr, ULONG Length)
756 PKS_TSDU KsTsdu = NULL;
758 /* retrieve the latest Tsdu buffer form TsduMgr
759 list if the list is not empty. */
761 if (cfs_list_empty(&(TsduMgr->TsduList))) {
763 LASSERT(TsduMgr->NumOfTsdu == 0);
768 LASSERT(TsduMgr->NumOfTsdu > 0);
769 KsTsdu = cfs_list_entry(TsduMgr->TsduList.prev, KS_TSDU, Link);
771 /* if this Tsdu does not contain enough space, we need
772 allocate a new Tsdu queue. */
774 if (KsTsdu->LastOffset + Length > KsTsdu->TotalLength) {
779 /* allocate a new Tsdu in case we are not statisfied. */
780 if (NULL == KsTsdu) {
781 KsTsdu = KsAllocateKsTsdu();
782 if (NULL != KsTsdu) {
783 cfs_list_add_tail(&(KsTsdu->Link), &(TsduMgr->TsduList));
784 TsduMgr->NumOfTsdu++;
800 PKS_TSDU_DAT KsTsduDat;
801 PKS_TSDU_BUF KsTsduBuf;
803 BOOLEAN bNewBuff = FALSE;
807 printk("KsWriteTsduDat: %u\n", length);
808 KsDumpPrint(buffer, length);
810 /* if the Tsdu is even larger than the biggest Tsdu, we have
811 to allocate new buffer and use TSDU_TYPE_BUF to store it */
813 if ( KS_TSDU_STRU_SIZE(length) > ks_data.ksnd_tsdu_size -
814 KS_QWORD_ALIGN(sizeof(KS_TSDU))) {
818 /* allocating the buffer for TSDU_TYPE_BUF */
820 Buffer = ExAllocatePool(NonPagedPool, length);
821 if (NULL == Buffer) {
822 /* there's no enough memory for us. We just try to
823 receive maximum bytes with a new Tsdu */
825 length = ks_data.ksnd_tsdu_size - KS_TSDU_STRU_SIZE(0) -
826 KS_QWORD_ALIGN(sizeof(KS_TSDU));
830 /* get empty Tsdu from TsduMgr */
831 KsTsdu = KsGetTsdu(TsduMgr, bNewBuff ? sizeof(KS_TSDU_BUF) :
832 KS_TSDU_STRU_SIZE(length) );
834 /* allocate a new Tsdu in case we are not statisfied. */
835 if (NULL == KsTsdu) {
839 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
840 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
844 /* setup up the KS_TSDU_BUF record */
845 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
846 KsTsduBuf->TsduFlags = 0;
847 KsTsduBuf->StartOffset = 0;
848 KsTsduBuf->UserBuffer = Buffer;
849 KsTsduBuf->DataLength = length;
850 KsTsduBuf->Mdl = NULL;
851 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
852 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
855 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
859 /* setup the KS_TSDU_DATA to contain all the messages */
861 KsTsduDat->TsduType = TSDU_TYPE_DAT;
862 KsTsduDat->TsduFlags = 0;
864 if ( KsTsdu->TotalLength - KsTsdu->LastOffset <
865 KS_TSDU_STRU_SIZE(length) ) {
866 length = KsTsdu->TotalLength - KsTsdu->LastOffset -
867 FIELD_OFFSET(KS_TSDU_DAT, Data);
869 KsTsduDat->DataLength = length;
870 KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(length);
871 KsTsduDat->StartOffset = 0;
872 KsTsduDat->Mdl = NULL;
873 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
874 KsTsduDat->TsduFlags |= KS_TSDU_COMM_PARTIAL;
877 Buffer = &KsTsduDat->Data[0];
878 KsTsdu->LastOffset += KsTsduDat->TotalLength;
881 RtlMoveMemory(Buffer, buffer, length);
882 TsduMgr->TotalBytes += length;
884 KsPrint((4, "KsWriteTsduDat: TsduMgr=%p bytes in queue:%xh (%xh)\n",
885 TsduMgr, TsduMgr->TotalBytes, length));
902 PKS_TSDU_BUF KsTsduBuf;
904 /* get empty Tsdu from TsduMgr */
905 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_BUF));
907 /* allocate a new Tsdu in case we are not statisfied. */
908 if (NULL == KsTsdu) {
912 /* setup up the KS_TSDU_BUF record */
913 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
914 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
915 KsTsduBuf->TsduFlags = 0;
916 KsTsduBuf->StartOffset = 0;
917 KsTsduBuf->UserBuffer = buffer;
918 KsTsduBuf->DataLength = length;
919 KsTsduBuf->Mdl = NULL;
920 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
921 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
922 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
925 TsduMgr->TotalBytes += length;
926 KsPrint((4, "KsWriteTsduBuf: TsduMgr=%p bytes in queue:%xh (%xh)\n",
927 TsduMgr, TsduMgr->TotalBytes, length));
946 PKS_TSDU_MDL KsTsduMdl;
948 /* get empty Tsdu from TsduMgr */
949 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_MDL));
951 /* allocate a new Tsdu in case we are not statisfied. */
952 if (NULL == KsTsdu) {
956 /* setup up the KS_TSDU_MDL record */
957 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
958 KsTsduMdl->TsduType = TSDU_TYPE_MDL;
959 KsTsduMdl->TsduFlags = 0;
960 KsTsduMdl->StartOffset = 0;
961 KsTsduMdl->BaseOffset = offset;
962 KsTsduMdl->DataLength = length;
963 KsTsduMdl->Mdl = mdl;
964 KsTsduMdl->Descriptor = desc;
965 KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
966 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
967 KsTsduMdl->TsduFlags |= KS_TSDU_COMM_PARTIAL;
970 TsduMgr->TotalBytes += length;
971 KsPrint((4, "KsWriteTsduMdl: TsduMgr=%p bytes in queue:%xh (%xh)\n",
972 TsduMgr, TsduMgr->TotalBytes, length));
989 PKS_TSDU_DAT KsTsduDat;
990 PKS_TSDU_BUF KsTsduBuf;
991 PKS_TSDU_MDL KsTsduMdl;
994 ULONG BytesRecved = 0;
996 ULONG TotalBytes = TsduMgr->TotalBytes;
999 KsPrint((4, "KsReadTsdu: TsduMgr=%p request=%xh total=%xh\n",
1000 TsduMgr, length, TsduMgr->TotalBytes ));
1003 if (TsduMgr->TotalBytes == 0) {
1005 /* It's a notification event. We need reset it to
1006 un-signaled state in case there no any tsdus. */
1008 KeResetEvent(&(TsduMgr->Event));
1012 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1013 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1015 /* remove the KsTsdu from TsduMgr list to release the lock */
1016 cfs_list_del(&(KsTsdu->Link));
1017 TsduMgr->NumOfTsdu--;
1019 while (length > BytesRecved) {
1021 ULONG BytesToCopy = 0;
1022 ULONG StartOffset = 0;
1023 ULONG BytesCopied = 0;
1025 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1026 /* KsTsdu is empty now, we need free it ... */
1027 KsPutKsTsdu(KsTsdu);
1032 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1033 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1034 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1036 if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
1037 TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
1039 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1041 /* Data Tsdu Unit ... */
1042 Buffer = &KsTsduDat->Data[0];
1043 StartOffset = KsTsduDat->StartOffset;
1044 if (KsTsduDat->DataLength - KsTsduDat->StartOffset > length - BytesRecved) {
1045 /* Recvmsg requst could be statisfied ... */
1046 BytesToCopy = length - BytesRecved;
1048 BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
1053 /* Buffer Tsdu Unit */
1054 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1055 Buffer = KsTsduBuf->UserBuffer;
1056 StartOffset = KsTsduBuf->StartOffset;
1058 if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > length - BytesRecved) {
1059 /* Recvmsg requst could be statisfied ... */
1060 BytesToCopy = length - BytesRecved;
1062 BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
1066 if (BytesToCopy > 0) {
1067 RtlMoveMemory(buffer + BytesRecved, Buffer + StartOffset, BytesToCopy);
1069 BytesCopied = BytesToCopy;
1070 BytesRecved += BytesCopied;
1071 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1072 TsduMgr->TotalBytes -= BytesCopied;
1073 KsPrint((4, "KsReadTsdu: TsduMgr=%p copied=%xh recved=%xh\n",
1074 TsduMgr, BytesCopied, BytesRecved ));
1076 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1078 KsTsduDat->StartOffset += BytesCopied;
1079 if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
1080 if (KsTsduDat->Mdl) {
1081 KsTsduDat->Mdl->Next = NULL;
1082 KsReleaseMdl(KsTsduDat->Mdl, FALSE);
1084 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1089 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1090 KsTsduBuf->StartOffset += BytesCopied;
1091 if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
1092 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1093 /* now we need release the buf to system pool */
1094 if (KsTsduBuf->Mdl) {
1095 KsTsduBuf->Mdl->Next = NULL;
1096 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1098 ExFreePool(KsTsduBuf->UserBuffer);
1102 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1104 /* MDL Tsdu Unit ... */
1105 if (KsTsduMdl->DataLength > length - BytesRecved) {
1106 /* Recvmsg requst could be statisfied ... */
1107 BytesToCopy = length - BytesRecved;
1109 BytesToCopy = KsTsduMdl->DataLength;
1115 KsTsduMdl->StartOffset +
1116 KsTsduMdl->BaseOffset,
1121 KsPrint((4, "KsReadTsdu: TsduMgr=%p mdl=%p dec=%p copied=%xh "
1123 TsduMgr, KsTsduMdl->Mdl, KsTsduMdl->Descriptor,
1124 BytesCopied, BytesRecved + BytesCopied));
1125 if (BytesCopied == 0) {
1126 cfs_enter_debugger();
1130 KsTsduMdl->StartOffset += BytesCopied;
1131 KsTsduMdl->DataLength -= BytesCopied;
1132 BytesRecved += BytesCopied;
1133 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1134 TsduMgr->TotalBytes -= BytesCopied;
1136 if (0 == KsTsduMdl->DataLength) {
1138 /* Call TdiReturnChainedReceives to release the Tsdu memory */
1139 LASSERT(KsTsduMdl->Descriptor != NULL);
1140 if (KsTsduMdl->Descriptor) {
1141 TdiReturnChainedReceives(
1142 &(KsTsduMdl->Descriptor),
1146 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1150 KsPrint((1, "KsReadTsdu: unknown tsdu slot: slot = %x type = %x Start= %x Length=%x\n",
1151 KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength));
1152 KsPrint((1, " Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x\n",
1153 KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength));
1154 cfs_enter_debugger();
1158 /* we need attach the KsTsdu to the list header */
1160 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1161 KsPutKsTsdu(KsTsdu);
1164 TsduMgr->NumOfTsdu++;
1165 cfs_list_add(&(KsTsdu->Link), &(TsduMgr->TsduList));
1169 if (length > BytesRecved) {
1175 LASSERT(TotalBytes == TsduMgr->TotalBytes + BytesRecved);
1177 KsPrint((4, "KsReadTsdu: TsduMgr=%p recved=%xh (%xh) remained=%xh\n",
1178 TsduMgr, BytesRecved, length, TsduMgr->TotalBytes ));
1185 KsTdiSendFlags(int SockFlags)
1189 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1190 cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
1193 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1194 cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
1197 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1198 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1205 KsTdiRecvFlags(int SockFlags)
1209 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1210 cfs_set_flag(TdiFlags, TDI_RECEIVE_EXPEDITED);
1213 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1214 cfs_set_flag(TdiFlags, TDI_RECEIVE_PARTIAL);
1217 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1218 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1225 KsWriteTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1229 if (TsduMgr->TotalBytes <= TDINAL_MAX_TSDU_QUEUE_SIZE) {
1230 rc = KsWriteTsduDat(TsduMgr, buffer, length, flags);
1241 KsReadTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1243 int rc = KsReadTsdu(TsduMgr, buffer, length, flags);
1253 * KsInitializeKsTsduMgr
1254 * Initialize the management structure of
1258 * TsduMgr: the TsduMgr to be initialized
1268 KsInitializeKsTsduMgr(
1279 &(TsduMgr->TsduList)
1282 TsduMgr->NumOfTsdu = 0;
1283 TsduMgr->TotalBytes = 0;
1285 cfs_spin_lock_init(&TsduMgr->Lock);
1290 * KsInitializeKsChain
1291 * Initialize the China structure for receiving
1295 * KsChain: the KsChain to be initialized
1305 KsInitializeKsChain(
1309 KsInitializeKsTsduMgr(&(KsChain->Normal));
1310 KsInitializeKsTsduMgr(&(KsChain->Expedited));
1311 KsChain->Expedited.OOB = TRUE;
1317 * Clean up all the Tsdus in the TsduMgr list
1320 * TsduMgr: the Tsdu list manager
1323 * NTSTATUS: nt status code
1335 PKS_TSDU_DAT KsTsduDat;
1336 PKS_TSDU_BUF KsTsduBuf;
1337 PKS_TSDU_MDL KsTsduMdl;
1339 LASSERT(NULL != TsduMgr);
1341 KsRemoveTdiEngine(TsduMgr);
1342 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
1344 while (!cfs_list_empty(&TsduMgr->TsduList)) {
1346 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1347 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1349 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
1352 // KsTsdu is empty now, we need free it ...
1355 cfs_list_del(&(KsTsdu->Link));
1356 TsduMgr->NumOfTsdu--;
1358 KsFreeKsTsdu(KsTsdu);
1362 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1363 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1364 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1366 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1368 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1370 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
1372 ASSERT(KsTsduBuf->UserBuffer != NULL);
1374 if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
1375 if (KsTsduBuf->Mdl) {
1376 KsTsduBuf->Mdl->Next = NULL;
1377 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1379 ExFreePool(KsTsduBuf->UserBuffer);
1381 cfs_enter_debugger();
1384 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1386 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1389 // MDL Tsdu Unit ...
1391 if (KsTsduMdl->Descriptor) {
1392 TdiReturnChainedReceives(
1393 &(KsTsduMdl->Descriptor),
1395 } else if (KsTsduMdl->Mdl) {
1396 KsTsduMdl->Mdl->Next = NULL;
1397 KsReleaseMdl(KsTsduMdl->Mdl, FALSE);
1400 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1405 return STATUS_SUCCESS;
1411 * Clean up the TsduMgrs of the KsChain
1414 * KsChain: the chain managing TsduMgr
1417 * NTSTATUS: nt status code
1430 LASSERT(NULL != KsChain);
1432 Status = KsCleanupTsduMgr(
1436 if (!NT_SUCCESS(Status)) {
1437 cfs_enter_debugger();
1441 Status = KsCleanupTsduMgr(
1442 &(KsChain->Expedited)
1445 if (!NT_SUCCESS(Status)) {
1446 cfs_enter_debugger();
1458 * Clean up all the Tsdus of a tdi connected object
1461 * tconn: the tdi connection which is connected already.
1475 NTSTATUS Status = STATUS_SUCCESS;
1478 if (tconn->kstc_type != kstt_sender &&
1479 tconn->kstc_type != kstt_child ) {
1484 if (tconn->kstc_type == kstt_sender) {
1486 Status = KsCleanupKsChain(
1487 &(tconn->sender.kstc_recv)
1490 if (!NT_SUCCESS(Status)) {
1491 cfs_enter_debugger();
1495 Status = KsCleanupKsChain(
1496 &(tconn->sender.kstc_send)
1499 if (!NT_SUCCESS(Status)) {
1500 cfs_enter_debugger();
1506 Status = KsCleanupKsChain(
1507 &(tconn->child.kstc_recv)
1510 if (!NT_SUCCESS(Status)) {
1511 cfs_enter_debugger();
1515 Status = KsCleanupKsChain(
1516 &(tconn->child.kstc_send)
1519 if (!NT_SUCCESS(Status)) {
1520 cfs_enter_debugger();
1532 KsIrpCompletionRoutine(
1533 IN PDEVICE_OBJECT DeviceObject,
1538 if (NULL != Context) {
1539 KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
1542 return STATUS_MORE_PROCESSING_REQUIRED;
1544 UNREFERENCED_PARAMETER(DeviceObject);
1545 UNREFERENCED_PARAMETER(Irp);
1551 * Allocate a new IRP and initialize it to be issued to tdi
1554 * DeviceObject: device object created by the underlying
1555 * TDI transport driver
1558 * PRIP: the allocated Irp in success or NULL in failure.
1566 IN PDEVICE_OBJECT DeviceObject
1570 PIO_STACK_LOCATION IrpSp;
1573 // Allocating the IRP ...
1576 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1581 // Getting the Next Stack Location ...
1584 IrpSp = IoGetNextIrpStackLocation(Irp);
1587 // Initializing Irp ...
1590 IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1591 IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
1599 * Issue the Irp to the underlying tdi driver
1602 * DeviceObject: the device object created by TDI driver
1603 * Irp: the I/O request packet to be processed
1604 * bSynchronous: synchronous or not. If true, we need wait
1605 * until the process is finished.
1606 * Information: returned info
1609 * NTSTATUS: kernel status code
1617 IN PDEVICE_OBJECT DeviceObject,
1619 IN BOOLEAN bSynchronous,
1620 OUT PULONG Information
1630 SynchronizationEvent,
1635 IoSetCompletionRoutine(
1637 KsIrpCompletionRoutine,
1645 Status = IoCallDriver(DeviceObject, Irp);
1649 if (STATUS_PENDING == Status) {
1651 Status = KeWaitForSingleObject(
1660 Status = Irp->IoStatus.Status;
1663 *Information = (ULONG)(Irp->IoStatus.Information);
1669 if (!NT_SUCCESS(Status)) {
1671 KsPrint((1, "KsSubmitTdiIrp: Error when submitting the Irp: "
1672 "Status = %xh (%s)\n", Status, KsNtStatusToString(Status)));
1682 * Open the Control Channel Object ...
1685 * DeviceName: the device name to be opened
1686 * Handle: opened handle in success case
1687 * FileObject: the fileobject of the device
1690 * NTSTATUS: kernel status code (STATUS_SUCCESS
1691 * or other error code)
1699 IN PUNICODE_STRING DeviceName,
1700 OUT HANDLE * Handle,
1701 OUT PFILE_OBJECT * FileObject
1704 NTSTATUS Status = STATUS_SUCCESS;
1706 OBJECT_ATTRIBUTES ObjectAttributes;
1707 IO_STATUS_BLOCK IoStatus;
1710 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1716 InitializeObjectAttributes(
1719 OBJ_CASE_INSENSITIVE |
1725 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL );
1728 // Creating the Transport Address Object ...
1731 Status = ZwCreateFile(
1733 FILE_READ_DATA | FILE_WRITE_DATA,
1737 FILE_ATTRIBUTE_NORMAL,
1738 FILE_SHARE_READ | FILE_SHARE_WRITE,
1746 if (NT_SUCCESS(Status)) {
1749 // Now Obtaining the FileObject of the Transport Address ...
1752 Status = ObReferenceObjectByHandle(
1761 if (!NT_SUCCESS(Status)) {
1763 cfs_enter_debugger();
1769 cfs_enter_debugger();
1778 * Release the Control Channel Handle and FileObject
1781 * Handle: the channel handle to be released
1782 * FileObject: the fileobject to be released
1785 * NTSTATUS: kernel status code (STATUS_SUCCESS
1786 * or other error code)
1795 IN PFILE_OBJECT FileObject
1798 NTSTATUS Status = STATUS_SUCCESS;
1800 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1804 ObDereferenceObject(FileObject);
1809 Status = ZwClose(Handle);
1812 ASSERT(NT_SUCCESS(Status));
1820 * Open the tdi address object
1823 * DeviceName: device name of the address object
1824 * pAddress: tdi address of the address object
1825 * AddressLength: length in bytes of the tdi address
1826 * Handle: the newly opened handle
1827 * FileObject: the newly opened fileobject
1830 * NTSTATUS: kernel status code (STATUS_SUCCESS
1831 * or other error code)
1839 IN PUNICODE_STRING DeviceName,
1840 IN PTRANSPORT_ADDRESS pAddress,
1841 IN ULONG AddressLength,
1842 OUT HANDLE * Handle,
1843 OUT PFILE_OBJECT * FileObject
1846 NTSTATUS Status = STATUS_SUCCESS;
1848 PFILE_FULL_EA_INFORMATION Ea = NULL;
1850 UCHAR EaBuffer[EA_MAX_LENGTH];
1852 OBJECT_ATTRIBUTES ObjectAttributes;
1853 IO_STATUS_BLOCK IoStatus;
1856 // Building EA for the Address Object to be Opened ...
1859 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1860 Ea->NextEntryOffset = 0;
1862 Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
1863 Ea->EaValueLength = (USHORT)AddressLength;
1866 TdiTransportAddress,
1867 Ea->EaNameLength + 1
1870 &(Ea->EaName[Ea->EaNameLength + 1]),
1874 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
1875 Ea->EaNameLength + AddressLength;
1877 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1884 InitializeObjectAttributes(
1887 OBJ_CASE_INSENSITIVE |
1893 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1896 // Creating the Transport Address Object ...
1899 Status = ZwCreateFile(
1901 FILE_READ_DATA | FILE_WRITE_DATA,
1905 FILE_ATTRIBUTE_NORMAL,
1906 FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
1914 if (NT_SUCCESS(Status)) {
1917 // Now Obtaining the FileObject of the Transport Address ...
1920 Status = ObReferenceObjectByHandle(
1929 if (!NT_SUCCESS(Status)) {
1931 cfs_enter_debugger();
1937 cfs_enter_debugger();
1945 * Release the Hanlde and FileObject of an opened tdi
1949 * Handle: the handle to be released
1950 * FileObject: the fileobject to be released
1953 * NTSTATUS: kernel status code (STATUS_SUCCESS
1954 * or other error code)
1963 IN PFILE_OBJECT FileObject
1966 NTSTATUS Status = STATUS_SUCCESS;
1970 ObDereferenceObject(FileObject);
1975 Status = ZwClose(Handle);
1978 ASSERT(NT_SUCCESS(Status));
1986 * Open a tdi connection object
1989 * DeviceName: device name of the connection object
1990 * ConnectionContext: the connection context
1991 * Handle: the newly opened handle
1992 * FileObject: the newly opened fileobject
1995 * NTSTATUS: kernel status code (STATUS_SUCCESS
1996 * or other error code)
2004 IN PUNICODE_STRING DeviceName,
2005 IN CONNECTION_CONTEXT ConnectionContext,
2006 OUT HANDLE * Handle,
2007 OUT PFILE_OBJECT * FileObject
2010 NTSTATUS Status = STATUS_SUCCESS;
2012 PFILE_FULL_EA_INFORMATION Ea = NULL;
2014 UCHAR EaBuffer[EA_MAX_LENGTH];
2016 OBJECT_ATTRIBUTES ObjectAttributes;
2017 IO_STATUS_BLOCK IoStatus;
2020 // Building EA for the Address Object to be Opened ...
2023 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
2024 Ea->NextEntryOffset = 0;
2026 Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
2027 Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
2030 TdiConnectionContext,
2031 Ea->EaNameLength + 1
2034 &(Ea->EaName[Ea->EaNameLength + 1]),
2036 sizeof(CONNECTION_CONTEXT)
2038 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
2039 Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
2041 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2048 InitializeObjectAttributes(
2051 OBJ_CASE_INSENSITIVE |
2057 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2060 // Creating the Connection Object ...
2063 Status = ZwCreateFile(
2065 FILE_READ_DATA | FILE_WRITE_DATA,
2069 FILE_ATTRIBUTE_NORMAL,
2070 FILE_SHARE_READ | FILE_SHARE_WRITE,
2078 if (NT_SUCCESS(Status)) {
2081 // Now Obtaining the FileObject of the Transport Address ...
2084 Status = ObReferenceObjectByHandle(
2093 if (!NT_SUCCESS(Status)) {
2095 cfs_enter_debugger();
2101 cfs_enter_debugger();
2109 * Release the Hanlde and FileObject of an opened tdi
2113 * Handle: the handle to be released
2114 * FileObject: the fileobject to be released
2117 * NTSTATUS: kernel status code (STATUS_SUCCESS
2118 * or other error code)
2127 IN PFILE_OBJECT FileObject
2130 NTSTATUS Status = STATUS_SUCCESS;
2134 ObDereferenceObject(FileObject);
2139 Status = ZwClose(Handle);
2142 ASSERT(NT_SUCCESS(Status));
2149 * KsAssociateAddress
2150 * Associate an address object with a connection object
2153 * AddressHandle: the handle of the address object
2154 * ConnectionObject: the FileObject of the connection
2157 * NTSTATUS: kernel status code (STATUS_SUCCESS
2158 * or other error code)
2166 IN HANDLE AddressHandle,
2167 IN PFILE_OBJECT ConnectionObject
2171 PDEVICE_OBJECT DeviceObject;
2175 // Getting the DeviceObject from Connection FileObject
2178 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2181 // Building Tdi Internal Irp ...
2184 Irp = KsBuildTdiIrp(DeviceObject);
2188 Status = STATUS_INSUFFICIENT_RESOURCES;
2193 // Assocating the Address Object with the Connection Object
2196 TdiBuildAssociateAddress(
2206 // Calling the Transprot Driver with the Prepared Irp
2209 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2217 * KsDisassociateAddress
2218 * Disassociate the connection object (the relationship will
2219 * the corresponding address object will be dismissed. )
2222 * ConnectionObject: the FileObject of the connection
2225 * NTSTATUS: kernel status code (STATUS_SUCCESS
2226 * or other error code)
2233 KsDisassociateAddress(
2234 IN PFILE_OBJECT ConnectionObject
2238 PDEVICE_OBJECT DeviceObject;
2242 // Getting the DeviceObject from Connection FileObject
2245 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2248 // Building Tdi Internal Irp ...
2251 Irp = KsBuildTdiIrp(DeviceObject);
2255 Status = STATUS_INSUFFICIENT_RESOURCES;
2260 // Disassocating the Address Object with the Connection Object
2263 TdiBuildDisassociateAddress(
2272 // Calling the Transprot Driver with the Prepared Irp
2275 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2285 // Connection Control Event Callbacks
2289 TDI_EVENT_DISCONNECT
2293 // Tcp Event Callbacks
2297 TDI_EVENT_RECEIVE_EXPEDITED
2298 TDI_EVENT_CHAINED_RECEIVE
2299 TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
2302 // Udp Event Callbacks
2305 TDI_EVENT_RECEIVE_DATAGRAM
2306 TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
2312 * KsSetEventHandlers
2313 * Set the tdi event callbacks with an address object
2316 * AddressObject: the FileObject of the address object
2317 * EventContext: the parameter for the callbacks
2318 * Handlers: the handlers indictor array
2321 * NTSTATUS: kernel status code (STATUS_SUCCESS
2322 * or other error code)
2330 IN PFILE_OBJECT AddressObject, // Address File Object
2331 IN PVOID EventContext, // Context for Handlers
2332 IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
2335 NTSTATUS Status = STATUS_SUCCESS;
2336 PDEVICE_OBJECT DeviceObject;
2339 DeviceObject = IoGetRelatedDeviceObject(AddressObject);
2341 for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
2344 // Setup the tdi event callback handler if requested.
2347 if (Handlers->IsActive[i]) {
2352 // Building Tdi Internal Irp ...
2355 Irp = KsBuildTdiIrp(DeviceObject);
2359 Status = STATUS_INSUFFICIENT_RESOURCES;
2364 // Building the Irp to set the Event Handler ...
2367 TdiBuildSetEventHandler(
2373 i, /* tdi event type */
2374 Handlers->Handler[i], /* tdi event handler */
2375 EventContext /* context for the handler */
2379 // Calling the Transprot Driver with the Prepared Irp
2382 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2385 // tcp/ip tdi does not support these two event callbacks
2388 if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
2389 i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
2390 cfs_enter_debugger();
2391 Status = STATUS_SUCCESS;
2395 if (!NT_SUCCESS(Status)) {
2396 cfs_enter_debugger();
2405 if (!NT_SUCCESS(Status)) {
2407 KsPrint((1, "KsSetEventHandlers: Error Status = %xh (%s)\n",
2408 Status, KsNtStatusToString(Status) ));
2417 * KsQueryAddressInfo
2418 * Query the address of the FileObject specified
2421 * FileObject: the FileObject to be queried
2422 * AddressInfo: buffer to contain the address info
2423 * AddressSize: length of the AddressInfo buffer
2426 * NTSTATUS: kernel status code (STATUS_SUCCESS
2427 * or other error code)
2435 PFILE_OBJECT FileObject,
2436 PTDI_ADDRESS_INFO AddressInfo,
2440 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2443 PDEVICE_OBJECT DeviceObject;
2445 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2447 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2449 RtlZeroMemory(AddressInfo, *(AddressSize));
2452 // Allocating the Tdi Setting Irp ...
2455 Irp = KsBuildTdiIrp(DeviceObject);
2459 Status = STATUS_INSUFFICIENT_RESOURCES;
2464 // Locking the User Buffer / Allocating a MDL for it
2467 Status = KsLockUserBuffer(
2475 if (!NT_SUCCESS(Status)) {
2484 LASSERT(NT_SUCCESS(Status));
2486 TdiBuildQueryInformation(
2492 TDI_QUERY_ADDRESS_INFO,
2496 Status = KsSubmitTdiIrp(
2503 KsReleaseMdl(Mdl, FALSE);
2506 if (!NT_SUCCESS(Status)) {
2508 cfs_enter_debugger();
2509 //TDI_BUFFER_OVERFLOW
2516 * KsQueryProviderInfo
2517 * Query the underlying transport device's information
2520 * TdiDeviceName: the transport device's name string
2521 * ProviderInfo: TDI_PROVIDER_INFO struncture
2524 * NTSTATUS: Nt system status code
2531 KsQueryProviderInfo(
2532 PWSTR TdiDeviceName,
2533 PTDI_PROVIDER_INFO ProviderInfo
2536 NTSTATUS Status = STATUS_SUCCESS;
2541 UNICODE_STRING ControlName;
2544 PFILE_OBJECT FileObject;
2545 PDEVICE_OBJECT DeviceObject;
2547 ULONG ProviderSize = 0;
2549 RtlInitUnicodeString(&ControlName, TdiDeviceName);
2552 // Open the Tdi Control Channel
2555 Status = KsOpenControl(
2561 if (!NT_SUCCESS(Status)) {
2563 KsPrint((1, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
2568 // Obtain The Related Device Object
2571 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2573 ProviderSize = sizeof(TDI_PROVIDER_INFO);
2574 RtlZeroMemory(ProviderInfo, ProviderSize);
2577 // Allocating the Tdi Setting Irp ...
2580 Irp = KsBuildTdiIrp(DeviceObject);
2584 Status = STATUS_INSUFFICIENT_RESOURCES;
2589 // Locking the User Buffer / Allocating a MDL for it
2592 Status = KsLockUserBuffer(
2600 if (!NT_SUCCESS(Status)) {
2609 LASSERT(NT_SUCCESS(Status));
2611 TdiBuildQueryInformation(
2617 TDI_QUERY_PROVIDER_INFO,
2621 Status = KsSubmitTdiIrp(
2628 KsReleaseMdl(Mdl, FALSE);
2631 if (!NT_SUCCESS(Status)) {
2633 cfs_enter_debugger();
2634 //TDI_BUFFER_OVERFLOW
2637 KsCloseControl(Handle, FileObject);
2643 * KsQueryConnectionInfo
2644 * Query the connection info of the FileObject specified
2645 * (some statics data of the traffic)
2648 * FileObject: the FileObject to be queried
2649 * ConnectionInfo: buffer to contain the connection info
2650 * ConnectionSize: length of the ConnectionInfo buffer
2653 * NTSTATUS: kernel status code (STATUS_SUCCESS
2654 * or other error code)
2661 KsQueryConnectionInfo(
2662 PFILE_OBJECT ConnectionObject,
2663 PTDI_CONNECTION_INFO ConnectionInfo,
2664 PULONG ConnectionSize
2667 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2670 PDEVICE_OBJECT DeviceObject;
2672 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2674 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2676 RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
2679 // Allocating the Tdi Query Irp ...
2682 Irp = KsBuildTdiIrp(DeviceObject);
2686 Status = STATUS_INSUFFICIENT_RESOURCES;
2691 // Locking the User Buffer / Allocating a MDL for it
2694 Status = KsLockUserBuffer(
2702 if (NT_SUCCESS(Status)) {
2711 LASSERT(NT_SUCCESS(Status));
2713 TdiBuildQueryInformation(
2719 TDI_QUERY_CONNECTION_INFO,
2723 Status = KsSubmitTdiIrp(
2730 KsReleaseMdl(Mdl, FALSE);
2738 * KsInitializeTdiAddress
2739 * Initialize the tdi addresss
2742 * pTransportAddress: tdi address to be initialized
2743 * IpAddress: the ip address of object
2744 * IpPort: the ip port of the object
2747 * ULONG: the total size of the tdi address
2754 KsInitializeTdiAddress(
2755 IN OUT PTA_IP_ADDRESS pTransportAddress,
2760 pTransportAddress->TAAddressCount = 1;
2761 pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
2762 pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
2763 pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
2764 pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
2766 return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
2770 * KsQueryTdiAddressLength
2771 * Query the total size of the tdi address
2774 * pTransportAddress: tdi address to be queried
2777 * ULONG: the total size of the tdi address
2784 KsQueryTdiAddressLength(
2785 PTRANSPORT_ADDRESS pTransportAddress
2788 ULONG TotalLength = 0;
2791 PTA_ADDRESS pTaAddress = NULL;
2793 ASSERT (NULL != pTransportAddress);
2795 TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
2796 FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
2798 pTaAddress = (PTA_ADDRESS)pTransportAddress->Address;
2800 for (i = 0; i < pTransportAddress->TAAddressCount; i++)
2802 TotalLength += pTaAddress->AddressLength;
2803 pTaAddress = (PTA_ADDRESS)((PCHAR)pTaAddress +
2804 FIELD_OFFSET(TA_ADDRESS,Address) +
2805 pTaAddress->AddressLength );
2808 return (TotalLength);
2814 * Query the ip address of the tdi object
2817 * FileObject: tdi object to be queried
2818 * TdiAddress: TdiAddress buffer, to store the queried
2820 * AddressLength: buffer length of the TdiAddress
2823 * ULONG: the total size of the tdi ip address
2831 PFILE_OBJECT FileObject,
2833 ULONG* AddressLength
2838 PTDI_ADDRESS_INFO TdiAddressInfo;
2843 // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
2846 Length = MAX_ADDRESS_LENGTH;
2848 TdiAddressInfo = (PTDI_ADDRESS_INFO)
2849 ExAllocatePoolWithTag(
2854 if (NULL == TdiAddressInfo) {
2856 Status = STATUS_INSUFFICIENT_RESOURCES;
2861 Status = KsQueryAddressInfo(
2869 if (NT_SUCCESS(Status)) {
2871 if (*AddressLength < Length) {
2872 Status = STATUS_BUFFER_TOO_SMALL;
2874 *AddressLength = Length;
2877 &(TdiAddressInfo->Address),
2880 Status = STATUS_SUCCESS;
2884 if (NULL != TdiAddressInfo) {
2885 ExFreePool(TdiAddressInfo);
2893 * KsErrorEventHandler
2894 * the common error event handler callback
2897 * TdiEventContext: should be the socket
2898 * Status: the error code
2901 * Status: STATS_SUCCESS
2904 * We need not do anything in such a severe
2905 * error case. System will process it for us.
2909 KsErrorEventHandler(
2910 IN PVOID TdiEventContext,
2914 KsPrint((1, "KsErrorEventHandler called at Irql = %xh ...\n",
2915 KeGetCurrentIrql()));
2917 cfs_enter_debugger();
2919 return (STATUS_SUCCESS);
2923 * KsAcceptCompletionRoutine
2924 * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
2926 * Here system gives us a chance to check the conneciton is built
2930 * DeviceObject: the device object of the transport driver
2931 * Irp: the Irp is being completed.
2932 * Context: the context we specified when issuing the Irp
2942 KsAcceptCompletionRoutine(
2943 IN PDEVICE_OBJECT DeviceObject,
2948 ks_tconn_t * child = (ks_tconn_t *) Context;
2949 ks_tconn_t * parent = child->child.kstc_parent;
2951 KsPrint((2, "KsAcceptCompletionRoutine at Irql: %xh child: %p status: %p\n",
2952 KeGetCurrentIrql(), child, Irp->IoStatus.Status));
2954 LASSERT(child->kstc_type == kstt_child);
2956 cfs_spin_lock(&(child->kstc_lock));
2958 LASSERT(parent->kstc_state == ksts_listening);
2959 LASSERT(child->kstc_state == ksts_connecting);
2961 if (NT_SUCCESS(Irp->IoStatus.Status)) {
2963 child->child.kstc_accepted = TRUE;
2965 child->kstc_state = ksts_connected;
2967 /* wake up the daemon thread which waits on this event */
2969 &(parent->listener.kstc_accept_event),
2974 cfs_spin_unlock(&(child->kstc_lock));
2976 KsPrint((2, "KsAcceptCompletionRoutine: singal parent: %p (child: %p)\n",
2981 /* re-use this child connecton */
2982 child->child.kstc_accepted = FALSE;
2983 child->child.kstc_busy = FALSE;
2984 child->kstc_state = ksts_associated;
2986 cfs_spin_unlock(&(child->kstc_lock));
2989 /* now free the Irp */
2992 /* drop the refer count of the child */
2993 ks_put_tconn(child);
2995 return (STATUS_MORE_PROCESSING_REQUIRED);
2999 KsSearchIpAddress(PUNICODE_STRING DeviceName)
3001 ks_addr_slot_t * slot = NULL;
3002 PLIST_ENTRY list = NULL;
3004 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3006 list = ks_data.ksnd_addrs_list.Flink;
3007 while (list != &ks_data.ksnd_addrs_list) {
3008 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3009 if (RtlCompareUnicodeString(
3019 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3025 KsCleanupIpAddresses()
3027 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3029 while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
3031 ks_addr_slot_t * slot = NULL;
3032 PLIST_ENTRY list = NULL;
3034 list = RemoveHeadList(&ks_data.ksnd_addrs_list);
3035 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3037 ks_data.ksnd_naddrs--;
3040 cfs_assert(ks_data.ksnd_naddrs == 0);
3041 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3045 KsAddAddressHandler(
3046 IN PTA_ADDRESS Address,
3047 IN PUNICODE_STRING DeviceName,
3048 IN PTDI_PNP_CONTEXT Context
3051 PTDI_ADDRESS_IP IpAddress = NULL;
3053 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3054 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3056 ks_addr_slot_t * slot = NULL;
3058 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3059 KsPrint((2, "KsAddAddressHandle: Device=%wZ Context=%xh "
3060 "IpAddress=%xh(%d.%d.%d.%d)\n",
3061 DeviceName, Context, IpAddress->in_addr,
3062 (IpAddress->in_addr & 0x000000FF) >> 0,
3063 (IpAddress->in_addr & 0x0000FF00) >> 8,
3064 (IpAddress->in_addr & 0x00FF0000) >> 16,
3065 (IpAddress->in_addr & 0xFF000000) >> 24
3068 slot = KsSearchIpAddress(DeviceName);
3072 slot->ip_addr = ntohl(IpAddress->in_addr);
3075 /* Matt: only add 192.168.10/5/92.xxx for temporary test */
3076 if ((IpAddress->in_addr & 0x00FFFFFF) != 0x000aa8c0 &&
3077 (IpAddress->in_addr & 0x00FFFFFF) != 0x0092a8c0 &&
3078 (IpAddress->in_addr & 0x00FFFFFF) != 0x0005a8c0 ) {
3082 slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
3084 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3085 InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
3086 sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
3087 slot->ip_addr = ntohl(IpAddress->in_addr);
3088 slot->netmask = 0x00FFFFFF; /* Matt: hardcode*/
3090 RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
3091 slot->devname.Length = DeviceName->Length;
3092 slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
3093 slot->devname.Buffer = slot->buffer;
3094 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3096 KsPrint((0, "KsAddAddressHandle: %s added: ip=%xh(%d.%d.%d.%d)\n",
3097 slot->iface, IpAddress->in_addr,
3098 (IpAddress->in_addr & 0x000000FF) >> 0,
3099 (IpAddress->in_addr & 0x0000FF00) >> 8,
3100 (IpAddress->in_addr & 0x00FF0000) >> 16,
3101 (IpAddress->in_addr & 0xFF000000) >> 24
3109 KsDelAddressHandler(
3110 IN PTA_ADDRESS Address,
3111 IN PUNICODE_STRING DeviceName,
3112 IN PTDI_PNP_CONTEXT Context
3115 PTDI_ADDRESS_IP IpAddress = NULL;
3117 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3118 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3120 ks_addr_slot_t * slot = NULL;
3122 slot = KsSearchIpAddress(DeviceName);
3128 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3129 KsPrint((2, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
3130 DeviceName, Context, IpAddress->in_addr,
3131 (IpAddress->in_addr & 0xFF000000) >> 24,
3132 (IpAddress->in_addr & 0x00FF0000) >> 16,
3133 (IpAddress->in_addr & 0x0000FF00) >> 8,
3134 (IpAddress->in_addr & 0x000000FF) >> 0 ));
3139 KsRegisterPnpHandlers()
3141 TDI20_CLIENT_INTERFACE_INFO ClientInfo;
3143 /* initialize the global ks_data members */
3144 RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
3145 cfs_spin_lock_init(&ks_data.ksnd_addrs_lock);
3146 InitializeListHead(&ks_data.ksnd_addrs_list);
3148 /* register the pnp handlers */
3149 RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
3150 ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
3152 ClientInfo.ClientName = &ks_data.ksnd_client_name;
3153 ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
3154 ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
3156 return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
3157 &ks_data.ksnd_pnp_handle);
3161 KsDeregisterPnpHandlers()
3163 if (ks_data.ksnd_pnp_handle) {
3165 /* De-register the pnp handlers */
3167 TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
3168 ks_data.ksnd_pnp_handle = NULL;
3170 /* cleanup all the ip address slots */
3171 KsCleanupIpAddresses();
3177 * KsGetVacancyBacklog
3178 * Get a vacancy listeing child from the backlog list
3181 * parent: the listener daemon connection
3184 * the child listening connection or NULL in failure
3187 * Parent's lock should be acquired before calling.
3191 KsGetVacancyBacklog(
3197 LASSERT(parent->kstc_type == kstt_listener);
3198 LASSERT(parent->kstc_state == ksts_listening);
3200 if (cfs_list_empty(&(parent->listener.kstc_listening.list))) {
3208 /* check the listening queue and try to get a free connecton */
3210 cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
3211 child = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
3212 cfs_spin_lock(&(child->kstc_lock));
3214 if (!child->child.kstc_busy) {
3215 LASSERT(child->kstc_state == ksts_associated);
3216 child->child.kstc_busy = TRUE;
3217 cfs_spin_unlock(&(child->kstc_lock));
3220 cfs_spin_unlock(&(child->kstc_lock));
3230 * KsConnectEventHandler
3231 * Connect event handler event handler, called by the underlying TDI
3232 * transport in response to an incoming request to the listening daemon.
3234 * it will grab a vacancy backlog from the children tconn list, and
3235 * build an acception Irp with it, then transfer the Irp to TDI driver.
3238 * TdiEventContext: the tdi connnection object of the listening daemon
3242 * Nt kernel status code
3249 KsConnectEventHandler(
3250 IN PVOID TdiEventContext,
3251 IN LONG RemoteAddressLength,
3252 IN PVOID RemoteAddress,
3253 IN LONG UserDataLength,
3255 IN LONG OptionsLength,
3257 OUT CONNECTION_CONTEXT * ConnectionContext,
3258 OUT PIRP * AcceptIrp
3261 ks_tconn_t * parent;
3264 PFILE_OBJECT FileObject;
3265 PDEVICE_OBJECT DeviceObject;
3269 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
3271 KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
3272 parent = (ks_tconn_t *) TdiEventContext;
3274 LASSERT(parent->kstc_type == kstt_listener);
3276 cfs_spin_lock(&(parent->kstc_lock));
3278 if (parent->kstc_state == ksts_listening) {
3280 /* allocate a new ConnectionInfo to backup the peer's info */
3282 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
3283 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
3284 RemoteAddressLength, 'iCsK' );
3286 if (NULL == ConnectionInfo) {
3288 Status = STATUS_INSUFFICIENT_RESOURCES;
3289 cfs_enter_debugger();
3293 /* initializing ConnectionInfo structure ... */
3295 ConnectionInfo->UserDataLength = UserDataLength;
3296 ConnectionInfo->UserData = UserData;
3297 ConnectionInfo->OptionsLength = OptionsLength;
3298 ConnectionInfo->Options = Options;
3299 ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
3300 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
3303 ConnectionInfo->RemoteAddress,
3308 /* get the vacancy listening child tdi connections */
3310 child = KsGetVacancyBacklog(parent);
3314 cfs_spin_lock(&(child->kstc_lock));
3315 child->child.kstc_info.ConnectionInfo = ConnectionInfo;
3316 child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
3317 child->kstc_state = ksts_connecting;
3318 cfs_spin_unlock(&(child->kstc_lock));
3322 KsPrint((1, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
3323 Status = STATUS_INSUFFICIENT_RESOURCES;
3327 FileObject = child->child.kstc_info.FileObject;
3328 DeviceObject = IoGetRelatedDeviceObject (FileObject);
3330 Irp = KsBuildTdiIrp(DeviceObject);
3336 KsAcceptCompletionRoutine,
3342 IoSetNextIrpStackLocation(Irp);
3344 /* grap the refer of the child tdi connection */
3345 ks_get_tconn(child);
3347 Status = STATUS_MORE_PROCESSING_REQUIRED;
3349 *ConnectionContext = child;
3353 Status = STATUS_CONNECTION_REFUSED;
3357 cfs_spin_unlock(&(parent->kstc_lock));
3363 cfs_spin_unlock(&(parent->kstc_lock));
3366 *ConnectionContext = NULL;
3368 if (ConnectionInfo) {
3369 ExFreePool(ConnectionInfo);
3380 * KsDisconnectCompletionRoutine
3381 * the Irp completion routine for TdiBuildDisconect
3383 * We just signal the event and return MORE_PRO... to
3384 * let the caller take the responsibility of the Irp.
3387 * DeviceObject: the device object of the transport
3388 * Irp: the Irp is being completed.
3389 * Context: the event specified by the caller
3399 KsDisconectCompletionRoutine (
3400 IN PDEVICE_OBJECT DeviceObject,
3406 KeSetEvent((PKEVENT) Context, 0, FALSE);
3408 return STATUS_MORE_PROCESSING_REQUIRED;
3410 UNREFERENCED_PARAMETER(DeviceObject);
3415 * KsDisconnectHelper
3416 * the routine to be executed in the WorkItem procedure
3417 * this routine is to disconnect a tdi connection
3420 * Workitem: the context transferred to the workitem
3426 * tconn is already referred in abort_connecton ...
3430 KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
3432 ks_tconn_t * tconn = WorkItem->tconn;
3434 KsPrint((1, "KsDisconnectHelper: disconnecting tconn=%p\n", tconn));
3435 ks_disconnect_tconn(tconn, WorkItem->Flags);
3437 KeSetEvent(&(WorkItem->Event), 0, FALSE);
3439 cfs_spin_lock(&(tconn->kstc_lock));
3440 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3441 cfs_spin_unlock(&(tconn->kstc_lock));
3442 ks_put_tconn(tconn);
3447 * KsDisconnectEventHandler
3448 * Disconnect event handler event handler, called by the underlying TDI transport
3449 * in response to an incoming disconnection notification from a remote node.
3452 * ConnectionContext: tdi connnection object
3453 * DisconnectFlags: specifies the nature of the disconnection
3457 * Nt kernel status code
3465 KsDisconnectEventHandler(
3466 IN PVOID TdiEventContext,
3467 IN CONNECTION_CONTEXT ConnectionContext,
3468 IN LONG DisconnectDataLength,
3469 IN PVOID DisconnectData,
3470 IN LONG DisconnectInformationLength,
3471 IN PVOID DisconnectInformation,
3472 IN ULONG DisconnectFlags
3477 PKS_DISCONNECT_WORKITEM WorkItem;
3479 tconn = (ks_tconn_t *)ConnectionContext;
3481 KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
3482 KeGetCurrentIrql() ));
3484 KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
3485 tconn, DisconnectFlags));
3487 ks_get_tconn(tconn);
3488 cfs_spin_lock(&(tconn->kstc_lock));
3490 WorkItem = &(tconn->kstc_disconnect);
3492 if (tconn->kstc_state != ksts_connected) {
3494 Status = STATUS_SUCCESS;
3498 if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
3500 Status = STATUS_REMOTE_DISCONNECT;
3502 } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
3504 Status = STATUS_GRACEFUL_DISCONNECT;
3507 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
3509 ks_get_tconn(tconn);
3511 WorkItem->Flags = DisconnectFlags;
3512 WorkItem->tconn = tconn;
3514 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3516 /* queue the workitem to call */
3517 ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
3521 cfs_spin_unlock(&(tconn->kstc_lock));
3522 ks_put_tconn(tconn);
3528 KsTcpReceiveCompletionRoutine(
3530 IN PKS_TCP_COMPLETION_CONTEXT Context
3533 ks_tconn_t *tconn = Context->tconn;
3534 NTSTATUS status = Irp->IoStatus.Status;
3535 ULONG length = (ULONG)Irp->IoStatus.Information;
3537 LASSERT(Context != NULL);
3539 if (NT_SUCCESS(status)) {
3541 PKS_TSDUMGR TsduMgr = Context->TsduMgr;
3542 PCHAR Buffer = Context->Buffer;
3544 KsPrint((4, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
3545 TsduMgr->TotalBytes ));
3547 ks_lock_tsdumgr(TsduMgr);
3548 KsWriteTsduBuf(TsduMgr, Context->Buffer, length, 0);
3549 /* signal TsduMgr event */
3550 KeSetEvent(&(Context->TsduMgr->Event), 0, FALSE);
3551 ks_unlock_tsdumgr(TsduMgr);
3553 /* re-active the ks connection and wake up the scheduler */
3554 if (KS_CAN_SCHED(TsduMgr)) {
3555 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3556 tconn->kstc_sched_cb(tconn, FALSE);
3560 ks_put_tconn(tconn);
3564 /* un-expected errors occur, we must abort the connection */
3565 ks_put_tconn(tconn);
3566 ks_abort_tconn(tconn);
3572 /* free the Context structure... */
3573 ASSERT(Context->Magic == KS_TCP_CONTEXT_MAGIC);
3574 Context->Magic = 'CDAB';
3581 /* release mdl chain */
3582 if (Irp->MdlAddress) {
3583 KsReleaseMdl(Irp->MdlAddress, FALSE);
3586 /* free irp packet */
3595 * KsTcpCompletionRoutine
3596 * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
3597 * We need call the use's own CompletionRoutine if specified. Or
3598 * it's a synchronous case, we need signal the event.
3601 * DeviceObject: the device object of the transport
3602 * Irp: the Irp is being completed.
3603 * Context: the context we specified when issuing the Irp
3613 KsTcpCompletionRoutine(
3614 IN PDEVICE_OBJECT DeviceObject,
3621 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3622 ks_tconn_t * tconn = NULL;
3624 context = (PKS_TCP_COMPLETION_CONTEXT) Context;
3625 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3626 tconn = context->tconn;
3628 if (context->CompletionRoutine) {
3631 // Giving control to user specified CompletionRoutine ...
3634 context->CompletionRoutine(Irp, context);
3639 // Signaling the Event ...
3641 LASSERT(NULL != context->Event);
3642 KeSetEvent(context->Event, 0, FALSE);
3644 /* drop the reference count of the tconn object */
3645 ks_put_tconn(tconn);
3650 /* cfs_enter_debugger(); */
3653 return STATUS_MORE_PROCESSING_REQUIRED;
3657 * KsTcpSendCompletionRoutine
3658 * the user specified Irp completion routine for asynchronous
3659 * data transmission requests.
3661 * It will do th cleanup job of the ks_tx_t and wake up the
3662 * ks scheduler thread
3665 * Irp: the Irp is being completed.
3666 * Context: the context we specified when issuing the Irp
3676 KsTcpSendCompletionRoutine(
3678 IN PKS_TCP_COMPLETION_CONTEXT context
3681 NTSTATUS status = Irp->IoStatus.Status;
3682 ULONG rc = (ULONG)(ULONG_PTR)Irp->IoStatus.Information;
3683 ks_tconn_t * tconn = context->tconn;
3685 PKS_TSDUMGR TsduMgr = context->TsduMgr;
3686 PKEVENT Event = context->Event;
3688 LASSERT(tconn != NULL && tconn->kstc_magic == KS_TCONN_MAGIC);
3689 LASSERT(context && context->Magic == KS_TCP_CONTEXT_MAGIC);
3691 KsPrint((4, "KsTcpSendCompltionRoutine: tconn = %p TsduMgr = %p "
3692 "status = %xh bytes = %xh/%x\n", tconn, TsduMgr, status,
3693 Irp->IoStatus.Information, TsduMgr->TotalBytes));
3695 ks_lock_tsdumgr(TsduMgr);
3697 if (NT_SUCCESS(status)) {
3699 /* cleanup processed TsduMgr queue */
3700 KsReleaseTsdus(tconn, TsduMgr, rc);
3702 /* queue to delivery engine if there's still remained data */
3703 TsduMgr->Busy = FALSE;
3704 if (TsduMgr->TotalBytes > 0) {
3705 KsQueueTdiEngine(tconn, TsduMgr);
3707 /* signal TsduMgr event */
3708 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3709 ks_unlock_tsdumgr(TsduMgr);
3712 * now it's time to re-queue the conns into the
3713 * scheduler queue and wake the scheduler thread.
3716 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3717 tconn->kstc_sched_cb(tconn, TRUE);
3722 ks_unlock_tsdumgr(TsduMgr);
3724 KsPrint((1, "KsTcpSendCompltionRoutine: failed tconn: %p "
3725 "TsduMgr: %p status: %xh\n", tconn, TsduMgr, status));
3727 /* cfs_enter_debugger(); */
3730 * for the case that the transmission is unsuccessful,
3731 * we need abort the tdi connection, but not destroy it.
3732 * the socknal conn will drop the refer count, then the
3733 * tdi connection will be freed.
3736 ks_abort_tconn(tconn);
3739 /* drop tconn reference */
3740 ks_put_tconn(tconn);
3742 /* freeing the context structure */
3744 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3745 context->Magic = 'CDAB';
3749 /* free the Irp structure */
3751 /* mdl chain was released by KsReleaseTsdus*/
3752 Irp->MdlAddress = NULL;
3761 * Normal receive event handler
3763 * It will move data from system Tsdu to our TsduList
3767 KsTcpReceiveEventHandler(
3768 IN PVOID TdiEventContext,
3769 IN CONNECTION_CONTEXT ConnectionContext,
3770 IN ULONG ReceiveFlags,
3771 IN ULONG BytesIndicated,
3772 IN ULONG BytesAvailable,
3773 OUT ULONG * BytesTaken,
3775 OUT PIRP * IoRequestPacket
3782 BOOLEAN bIsExpedited;
3783 BOOLEAN bIsCompleteTsdu;
3785 PCHAR Buffer = NULL;
3788 PFILE_OBJECT FileObject;
3789 PDEVICE_OBJECT DeviceObject;
3790 PKS_TSDUMGR TsduMgr;
3792 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3794 tconn = (ks_tconn_t *) ConnectionContext;
3795 ks_get_tconn(tconn);
3797 /* check expedited flag */
3798 bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
3800 /* check whether the whole body of payload is received or not */
3801 if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
3802 (BytesIndicated == BytesAvailable) ) {
3803 bIsCompleteTsdu = TRUE;
3805 bIsCompleteTsdu = FALSE;
3808 KsPrint((4, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n",
3809 BytesIndicated, BytesAvailable));
3810 KsPrint((4, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
3812 /* check whether we are conntected or not listener */
3813 if ( !((tconn->kstc_state == ksts_connected) &&
3814 (tconn->kstc_type == kstt_sender ||
3815 tconn->kstc_type == kstt_child))) {
3817 *BytesTaken = BytesIndicated;
3818 ks_put_tconn(tconn);
3819 return (STATUS_SUCCESS);
3822 /* query tsdu mgr */
3823 TsduMgr = KsQueryTsduMgr(tconn, bIsExpedited, FALSE);
3825 ks_lock_tsdumgr(TsduMgr);
3826 if (bIsCompleteTsdu) {
3828 *BytesTaken = KsWriteTsduDat(TsduMgr, Tsdu, BytesAvailable, 0);
3829 status = STATUS_SUCCESS;
3831 /* signal TsduMgr event */
3832 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3833 ks_unlock_tsdumgr(TsduMgr);
3835 /* re-active the ks connection and wake up the scheduler */
3836 if (KS_CAN_SCHED(TsduMgr)) {
3837 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3838 tconn->kstc_sched_cb(tconn, FALSE);
3844 ks_unlock_tsdumgr(TsduMgr);
3846 /* allocate buffer for further data in tsdu queue */
3847 Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
3848 if (NULL == Buffer) {
3849 status = STATUS_INSUFFICIENT_RESOURCES;
3853 /* there's still data in tdi internal queue, we need issue a new
3854 Irp to receive all of them. first allocate the tcp context */
3855 context = cfs_alloc(sizeof(KS_TCP_COMPLETION_CONTEXT), 0);
3857 status = STATUS_INSUFFICIENT_RESOURCES;
3861 /* setup the context */
3862 RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
3863 context->Magic = KS_TCP_CONTEXT_MAGIC;
3864 context->tconn = tconn;
3865 context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
3866 context->CompletionContext = Buffer;
3867 context->TsduMgr = TsduMgr;
3868 context->Buffer = Buffer;
3869 context->Event = &(TsduMgr->Event);
3871 if (tconn->kstc_type == kstt_sender) {
3872 FileObject = tconn->sender.kstc_info.FileObject;
3874 FileObject = tconn->child.kstc_info.FileObject;
3876 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3878 /* build new tdi Irp and setup it. */
3879 Irp = KsBuildTdiIrp(DeviceObject);
3884 status = KsLockUserBuffer(
3892 if (!NT_SUCCESS(status)) {
3900 KsTcpCompletionRoutine,
3903 ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
3907 IoSetNextIrpStackLocation(Irp);
3909 /* return the newly built Irp to transport driver,
3910 it will process it to receive all the data */
3912 *IoRequestPacket = Irp;
3915 ks_get_tconn(tconn);
3916 status = STATUS_MORE_PROCESSING_REQUIRED;
3919 ks_put_tconn(tconn);
3926 KsReleaseMdl(Mdl, FALSE);
3938 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3939 context->Magic = 'CDAB';
3943 ks_abort_tconn(tconn);
3944 ks_put_tconn(tconn);
3946 *BytesTaken = BytesAvailable;
3948 return STATUS_SUCCESS;
3952 * Expedited receive event handler
3956 KsTcpReceiveExpeditedEventHandler(
3957 IN PVOID TdiEventContext,
3958 IN CONNECTION_CONTEXT ConnectionContext,
3959 IN ULONG ReceiveFlags,
3960 IN ULONG BytesIndicated,
3961 IN ULONG BytesAvailable,
3962 OUT ULONG * BytesTaken,
3964 OUT PIRP * IoRequestPacket
3967 return KsTcpReceiveEventHandler(
3970 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
3980 * Bulk receive event handler
3982 * It will queue all the system Tsdus to our TsduList.
3983 * Then later ks_recv_mdl will release them.
3987 KsTcpChainedReceiveEventHandler (
3988 IN PVOID TdiEventContext, // the event context
3989 IN CONNECTION_CONTEXT ConnectionContext,
3990 IN ULONG ReceiveFlags,
3991 IN ULONG ReceiveLength,
3992 IN ULONG StartingOffset, // offset of start of client data in TSDU
3993 IN PMDL Tsdu, // TSDU data chain
3994 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4001 PKS_TSDUMGR TsduMgr;
4005 tconn = (ks_tconn_t *) ConnectionContext;
4006 expedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
4008 KsPrint((4, "KsTcpChainedReceive: sock: %p conn: %p ReceiveLength: %xh "
4009 "bIsExpedited: %d Tsdu=%p TsduDesc=%p data=%xh\n",
4010 tconn, tconn->kstc_conn, ReceiveLength, expedited,
4011 Tsdu, TsduDescriptor, *((PULONG)KsMapMdlBuffer(Tsdu))));
4013 ks_get_tconn(tconn);
4015 /* check whether we are conntected or not listener */
4016 if ( !((tconn->kstc_state == ksts_connected) &&
4017 (tconn->kstc_type == kstt_sender ||
4018 tconn->kstc_type == kstt_child))) {
4020 ks_put_tconn(tconn);
4021 return (STATUS_SUCCESS);
4026 TsduMgr = KsQueryTsduMgr(tconn, expedited, FALSE);
4027 ks_lock_tsdumgr(TsduMgr);
4029 KsWriteTsduMdl(TsduMgr, Tsdu, TsduDescriptor,
4030 StartingOffset, ReceiveLength, 0);
4031 status = STATUS_PENDING;
4033 KsWriteTsduDat(TsduMgr, (PCHAR)KsMapMdlBuffer(Tsdu) +
4034 StartingOffset, ReceiveLength, 0);
4035 status = STATUS_SUCCESS;
4037 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
4038 ks_unlock_tsdumgr(TsduMgr);
4040 /* re-active the ks connection and wake up the scheduler */
4041 if (KS_CAN_SCHED(TsduMgr)) {
4042 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
4043 tconn->kstc_sched_cb(tconn, FALSE);
4049 ks_abort_tconn(tconn);
4050 status = STATUS_CONNECTION_ABORTED;
4053 ks_put_tconn(tconn);
4055 /* Return STATUS_PENDING to system because we are still
4056 owning the MDL resources. ks_recv_mdl is expected
4057 to free the MDL resources. */
4064 * Expedited & Bulk receive event handler
4068 KsTcpChainedReceiveExpeditedEventHandler (
4069 IN PVOID TdiEventContext, // the event context
4070 IN CONNECTION_CONTEXT ConnectionContext,
4071 IN ULONG ReceiveFlags,
4072 IN ULONG ReceiveLength,
4073 IN ULONG StartingOffset, // offset of start of client data in TSDU
4074 IN PMDL Tsdu, // TSDU data chain
4075 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4078 return KsTcpChainedReceiveEventHandler(
4081 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
4091 * setup all the event handler callbacks
4094 * tconn: the tdi connecton object
4097 * int: ks error code
4108 NTSTATUS status = STATUS_SUCCESS;
4109 KS_EVENT_HANDLERS handlers;
4111 /* to make sure the address object is opened already */
4112 if (tconn->kstc_addr.FileObject == NULL) {
4116 /* initialize the handlers indictor array. for sender and listenr,
4117 there are different set of callbacks. for child, we just return. */
4119 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4121 SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
4122 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
4123 SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
4124 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
4125 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
4127 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
4129 if (tconn->kstc_type == kstt_listener) {
4130 SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
4131 } else if (tconn->kstc_type == kstt_child) {
4135 /* set all the event callbacks */
4136 status = KsSetEventHandlers(
4137 tconn->kstc_addr.FileObject, /* Address File Object */
4138 tconn, /* Event Context */
4139 &handlers /* Event callback handlers */
4144 return cfs_error_code(status);
4150 * disable all the event handler callbacks (set to NULL)
4153 * tconn: the tdi connecton object
4156 * int: ks error code
4167 NTSTATUS status = STATUS_SUCCESS;
4168 KS_EVENT_HANDLERS handlers;
4170 /* to make sure the address object is opened already */
4171 if (tconn->kstc_addr.FileObject == NULL) {
4175 /* initialize the handlers indictor array. for sender and listenr,
4176 there are different set of callbacks. for child, we just return. */
4178 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4180 SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
4181 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
4182 SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
4183 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
4184 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
4185 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
4187 if (tconn->kstc_type == kstt_listener) {
4188 SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
4189 } else if (tconn->kstc_type == kstt_child) {
4193 /* set all the event callbacks */
4194 status = KsSetEventHandlers(
4195 tconn->kstc_addr.FileObject, /* Address File Object */
4196 tconn, /* Event Context */
4197 &handlers /* Event callback handlers */
4202 return cfs_error_code(status);
4206 KsPrintProviderInfo(
4208 PTDI_PROVIDER_INFO ProviderInfo
4211 KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
4213 KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
4214 KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
4215 KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
4216 KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
4217 KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
4219 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
4220 KsPrint((2, " CONNECTION_MODE\n"));
4223 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
4224 KsPrint((2, " ORDERLY_RELEASE\n"));
4227 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
4228 KsPrint((2, " CONNECTIONLESS_MODE\n"));
4231 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
4232 KsPrint((2, " ERROR_FREE_DELIVERY\n"));
4235 if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
4236 KsPrint((2, " SECURITY_LEVEL\n"));
4239 if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
4240 KsPrint((2, " BROADCAST_SUPPORTED\n"));
4243 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
4244 KsPrint((2, " MULTICAST_SUPPORTED\n"));
4247 if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
4248 KsPrint((2, " DELAYED_ACCEPTANCE\n"));
4251 if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
4252 KsPrint((2, " EXPEDITED_DATA\n"));
4255 if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
4256 KsPrint((2, " INTERNAL_BUFFERING\n"));
4259 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
4260 KsPrint((2, " ROUTE_DIRECTED\n"));
4263 if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
4264 KsPrint((2, " NO_ZERO_LENGTH\n"));
4267 if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
4268 KsPrint((2, " POINT_TO_POINT\n"));
4271 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
4272 KsPrint((2, " MESSAGE_MODE\n"));
4275 if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
4276 KsPrint((2, " HALF_DUPLEX\n"));
4279 KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
4280 KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
4281 KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
4287 * allocate a new tconn structure from the SLAB cache or
4288 * NonPaged sysetm pool
4294 * ks_tconn_t *: the address of tconn or NULL if it fails
4303 ks_tconn_t * tconn = NULL;
4305 /* allocate ksoc_tconn_t from the slab cache memory */
4306 tconn = (ks_tconn_t *)cfs_mem_cache_alloc(
4307 ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
4311 /* zero tconn elements */
4312 memset(tconn, 0, sizeof(ks_tconn_t));
4314 /* initialize the tconn ... */
4315 tconn->kstc_magic = KS_TCONN_MAGIC;
4317 ExInitializeWorkItem(
4318 &(tconn->kstc_disconnect.WorkItem),
4320 &(tconn->kstc_disconnect)
4324 &(tconn->kstc_disconnect.Event),
4325 SynchronizationEvent,
4328 ExInitializeWorkItem(
4329 &(tconn->kstc_destroy),
4334 cfs_spin_lock_init(&(tconn->kstc_lock));
4336 ks_get_tconn(tconn);
4337 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
4339 /* attach it into global list in ks_data */
4341 cfs_list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
4342 ks_data.ksnd_ntconns++;
4343 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
4345 tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
4347 KsPrint((3, "ks_create_tconn: new connection: %p\n", tconn));
4353 * free the tconn structure to the SLAB cache or NonPaged
4357 * tconn: the tcon is to be freed
4367 ks_free_tconn(ks_tconn_t * tconn)
4369 LASSERT(cfs_atomic_read(&(tconn->kstc_refcount)) == 0);
4371 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
4373 /* remove it from the global list */
4374 cfs_list_del(&tconn->kstc_list);
4375 ks_data.ksnd_ntconns--;
4377 /* if this is the last tconn, it would be safe for
4378 ks_tdi_fini_data to quit ... */
4379 if (ks_data.ksnd_ntconns == 0) {
4380 cfs_wake_event(&ks_data.ksnd_tconn_exit);
4382 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
4384 /* free the structure memory */
4385 cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
4387 KsPrint((3, "ks_free_tconn: tconn %p is freed.\n", tconn));
4393 * Initialize the tconn as a listener (daemon)
4396 * tconn: the listener tconn
4410 /* preparation: intialize the tconn members */
4412 tconn->kstc_type = kstt_listener;
4414 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4416 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
4417 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
4419 cfs_init_event( &(tconn->listener.kstc_accept_event),
4423 cfs_init_event( &(tconn->listener.kstc_destroy_event),
4427 tconn->kstc_state = ksts_inited;
4433 * Initialize the tconn as a sender
4436 * tconn: the sender tconn
4450 tconn->kstc_type = kstt_sender;
4451 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4453 KsInitializeKsChain(&(tconn->sender.kstc_recv));
4454 KsInitializeKsChain(&(tconn->sender.kstc_send));
4456 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4457 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4459 tconn->kstc_state = ksts_inited;
4464 * Initialize the tconn as a child
4467 * tconn: the child tconn
4481 tconn->kstc_type = kstt_child;
4482 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4484 KsInitializeKsChain(&(tconn->child.kstc_recv));
4485 KsInitializeKsChain(&(tconn->child.kstc_send));
4487 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4488 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4490 tconn->kstc_state = ksts_inited;
4495 * increase the reference count of the tconn with 1
4498 * tconn: the tdi connection to be referred
4512 cfs_atomic_inc(&(tconn->kstc_refcount));
4517 * decrease the reference count of the tconn and destroy
4518 * it if the refercount becomes 0.
4521 * tconn: the tdi connection to be dereferred
4535 if (cfs_atomic_dec_and_test(&(tconn->kstc_refcount))) {
4537 cfs_spin_lock(&(tconn->kstc_lock));
4539 if ( ( tconn->kstc_type == kstt_child ||
4540 tconn->kstc_type == kstt_sender ) &&
4541 ( tconn->kstc_state == ksts_connected ) ) {
4543 cfs_spin_unlock(&(tconn->kstc_lock));
4545 ks_abort_tconn(tconn);
4549 if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
4550 cfs_enter_debugger();
4553 &(tconn->kstc_destroy),
4557 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
4560 cfs_spin_unlock(&(tconn->kstc_lock));
4567 * cleanup the tdi connection and free it
4570 * tconn: the tdi connection to be cleaned.
4584 LASSERT(tconn->kstc_refcount.counter == 0);
4586 if (tconn->kstc_type == kstt_listener) {
4588 KsResetHandlers(tconn);
4590 /* for listener, we just need to close the address object */
4592 tconn->kstc_addr.Handle,
4593 tconn->kstc_addr.FileObject
4596 tconn->kstc_state = ksts_inited;
4598 } else if (tconn->kstc_type == kstt_child) {
4600 /* for child tdi conections */
4602 /* disassociate the relation between it's connection object
4603 and the address object */
4605 if (tconn->kstc_state == ksts_associated) {
4606 KsDisassociateAddress(
4607 tconn->child.kstc_info.FileObject
4611 /* release the connection object */
4614 tconn->child.kstc_info.Handle,
4615 tconn->child.kstc_info.FileObject
4618 /* release it's refer of it's parent's address object */
4621 tconn->kstc_addr.FileObject
4624 cfs_spin_lock(&tconn->child.kstc_parent->kstc_lock);
4625 cfs_spin_lock(&tconn->kstc_lock);
4627 tconn->kstc_state = ksts_inited;
4629 /* remove it frome it's parent's queues */
4631 if (tconn->child.kstc_queued) {
4633 cfs_list_del(&(tconn->child.kstc_link));
4635 if (tconn->child.kstc_queueno) {
4637 LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
4638 tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
4642 LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
4643 tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
4646 tconn->child.kstc_queued = FALSE;
4649 cfs_spin_unlock(&tconn->kstc_lock);
4650 cfs_spin_unlock(&tconn->child.kstc_parent->kstc_lock);
4652 /* drop the reference of the parent tconn */
4653 ks_put_tconn(tconn->child.kstc_parent);
4655 } else if (tconn->kstc_type == kstt_sender) {
4657 KsResetHandlers(tconn);
4659 /* release the connection object */
4662 tconn->sender.kstc_info.Handle,
4663 tconn->sender.kstc_info.FileObject
4666 /* release it's refer of it's parent's address object */
4668 tconn->kstc_addr.Handle,
4669 tconn->kstc_addr.FileObject
4672 tconn->kstc_state = ksts_inited;
4675 cfs_enter_debugger();
4678 /* free the tconn structure ... */
4680 ks_free_tconn(tconn);
4685 * Query the the options of the tcp stream connnection
4688 * tconn: the tdi connection
4690 * OptionValue: buffer to store the option value
4691 * Length: the length of the value, to be returned
4694 * int: ks return code
4708 NTSTATUS Status = STATUS_SUCCESS;
4710 IO_STATUS_BLOCK IoStatus;
4712 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
4714 PFILE_OBJECT ConnectionObject;
4715 PDEVICE_OBJECT DeviceObject = NULL;
4718 PIO_STACK_LOCATION IrpSp = NULL;
4722 /* make sure the tdi connection is connected ? */
4724 ks_get_tconn(tconn);
4726 if (tconn->kstc_state != ksts_connected) {
4727 Status = STATUS_INVALID_PARAMETER;
4731 LASSERT(tconn->kstc_type == kstt_sender ||
4732 tconn->kstc_type == kstt_child);
4734 if (tconn->kstc_type == kstt_sender) {
4735 ConnectionObject = tconn->sender.kstc_info.FileObject;
4737 ConnectionObject = tconn->child.kstc_info.FileObject;
4740 QueryInfoEx.ID.toi_id = ID;
4741 QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
4742 QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
4743 QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
4744 QueryInfoEx.ID.toi_entity.tei_instance = 0;
4746 RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
4748 KeInitializeEvent(&Event, NotificationEvent, FALSE);
4749 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4751 Irp = IoBuildDeviceIoControlRequest(
4752 IOCTL_TCP_QUERY_INFORMATION_EX,
4755 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
4764 Status = STATUS_INSUFFICIENT_RESOURCES;
4768 IrpSp = IoGetNextIrpStackLocation(Irp);
4770 if (IrpSp == NULL) {
4774 Status = STATUS_INSUFFICIENT_RESOURCES;
4778 IrpSp->FileObject = ConnectionObject;
4779 IrpSp->DeviceObject = DeviceObject;
4781 Status = IoCallDriver(DeviceObject, Irp);
4783 if (Status == STATUS_PENDING) {
4785 KeWaitForSingleObject(
4793 Status = IoStatus.Status;
4797 if (NT_SUCCESS(Status)) {
4798 *Length = (ULONG)(ULONG_PTR)IoStatus.Information;
4800 cfs_enter_debugger();
4801 memset(OptionValue, 0, *Length);
4802 Status = STATUS_SUCCESS;
4807 ks_put_tconn(tconn);
4809 return cfs_error_code(Status);
4814 * Set the the options for the tcp stream connnection
4817 * tconn: the tdi connection
4819 * OptionValue: buffer containing the new option value
4820 * Length: the length of the value
4823 * int: ks return code
4837 NTSTATUS Status = STATUS_SUCCESS;
4839 IO_STATUS_BLOCK IoStatus;
4841 ULONG SetInfoExLength;
4842 PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
4844 PFILE_OBJECT ConnectionObject;
4845 PDEVICE_OBJECT DeviceObject = NULL;
4848 PIO_STACK_LOCATION IrpSp = NULL;
4852 /* make sure the tdi connection is connected ? */
4854 ks_get_tconn(tconn);
4856 if (tconn->kstc_state != ksts_connected) {
4857 Status = STATUS_INVALID_PARAMETER;
4861 LASSERT(tconn->kstc_type == kstt_sender ||
4862 tconn->kstc_type == kstt_child);
4864 if (tconn->kstc_type == kstt_sender) {
4865 ConnectionObject = tconn->sender.kstc_info.FileObject;
4867 ConnectionObject = tconn->child.kstc_info.FileObject;
4870 SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
4872 SetInfoEx = ExAllocatePoolWithTag(
4878 if (SetInfoEx == NULL) {
4879 Status = STATUS_INSUFFICIENT_RESOURCES;
4883 SetInfoEx->ID.toi_id = ID;
4885 SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
4886 SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
4887 SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
4888 SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
4890 SetInfoEx->BufferSize = Length;
4891 RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
4893 Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
4894 KeInitializeEvent(Event, NotificationEvent, FALSE);
4896 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4898 Irp = IoBuildDeviceIoControlRequest(
4899 IOCTL_TCP_SET_INFORMATION_EX,
4911 Status = STATUS_INSUFFICIENT_RESOURCES;
4915 IrpSp = IoGetNextIrpStackLocation(Irp);
4917 if (IrpSp == NULL) {
4920 Status = STATUS_INSUFFICIENT_RESOURCES;
4924 IrpSp->FileObject = ConnectionObject;
4925 IrpSp->DeviceObject = DeviceObject;
4927 Status = IoCallDriver(DeviceObject, Irp);
4929 if (Status == STATUS_PENDING) {
4931 KeWaitForSingleObject(
4939 Status = IoStatus.Status;
4945 ExFreePool(SetInfoEx);
4948 if (!NT_SUCCESS(Status)) {
4949 KsPrint((0, "ks_set_tcp_option: error setup tcp option: "
4950 "ID (%d) Status = %xh\n", ID, Status));
4951 Status = STATUS_SUCCESS;
4954 ks_put_tconn(tconn);
4956 return cfs_error_code(Status);
4961 * bind the tdi connection object with an address
4964 * tconn: tconn to be bound
4965 * parent: the parent tconn object
4966 * ipaddr: the ip address
4967 * port: the port number
4970 * int: 0 for success or ks error codes.
4979 ks_tconn_t * parent,
4987 ks_tdi_addr_t taddr;
4989 memset(&taddr, 0, sizeof(ks_tdi_addr_t));
4991 if (tconn->kstc_state != ksts_inited) {
4993 status = STATUS_INVALID_PARAMETER;
4994 rc = cfs_error_code(status);
4997 } else if (tconn->kstc_type == kstt_child) {
4999 if (NULL == parent) {
5000 status = STATUS_INVALID_PARAMETER;
5001 rc = cfs_error_code(status);
5006 /* refer it's parent's address object */
5008 taddr = parent->kstc_addr;
5009 ObReferenceObject(taddr.FileObject);
5011 ks_get_tconn(parent);
5015 PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
5018 /* intialize the tdi address*/
5020 TdiAddress->TAAddressCount = 1;
5021 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5022 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5024 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5025 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5027 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5030 /* open the transport address object */
5032 AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
5033 TDI_ADDRESS_LENGTH_IP;
5035 status = KsOpenAddress(
5043 if (!NT_SUCCESS(status)) {
5045 KsPrint((1, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
5046 addr, port, status ));
5047 rc = cfs_error_code(status);
5052 if (tconn->kstc_type == kstt_child) {
5053 tconn->child.kstc_parent = parent;
5056 tconn->kstc_state = ksts_bind;
5057 tconn->kstc_addr = taddr;
5066 * build tcp/streaming connection to remote peer
5069 * tconn: tconn to be connected to the peer
5070 * addr: the peer's ip address
5071 * port: the peer's port number
5074 * int: 0 for success or ks error codes.
5088 NTSTATUS status = STATUS_SUCCESS;
5091 PFILE_OBJECT ConnectionObject = NULL;
5092 PDEVICE_OBJECT DeviceObject = NULL;
5094 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
5099 LASSERT(tconn->kstc_type == kstt_sender);
5100 LASSERT(tconn->kstc_state == ksts_bind);
5102 ks_get_tconn(tconn);
5105 /* set the event callbacks */
5106 rc = KsSetHandlers(tconn);
5109 cfs_enter_debugger();
5114 /* create the connection file handle / object */
5115 status = KsOpenConnection(
5117 (CONNECTION_CONTEXT)tconn,
5118 &(tconn->sender.kstc_info.Handle),
5119 &(tconn->sender.kstc_info.FileObject)
5122 if (!NT_SUCCESS(status)) {
5123 rc = cfs_error_code(status);
5124 cfs_enter_debugger();
5128 /* associdate the the connection with the adress object of the tconn */
5130 status = KsAssociateAddress(
5131 tconn->kstc_addr.Handle,
5132 tconn->sender.kstc_info.FileObject
5135 if (!NT_SUCCESS(status)) {
5136 rc = cfs_error_code(status);
5137 cfs_enter_debugger();
5141 tconn->kstc_state = ksts_associated;
5143 /* Allocating Connection Info Together with the Address */
5144 AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
5145 + TDI_ADDRESS_LENGTH_IP;
5147 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
5148 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
5150 if (NULL == ConnectionInfo) {
5152 status = STATUS_INSUFFICIENT_RESOURCES;
5153 rc = cfs_error_code(status);
5154 cfs_enter_debugger();
5158 /* Initializing ConnectionInfo ... */
5160 PTRANSPORT_ADDRESS TdiAddress;
5162 /* ConnectionInfo settings */
5164 ConnectionInfo->UserDataLength = 0;
5165 ConnectionInfo->UserData = NULL;
5166 ConnectionInfo->OptionsLength = 0;
5167 ConnectionInfo->Options = NULL;
5168 ConnectionInfo->RemoteAddressLength = AddrLength;
5169 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
5172 /* intialize the tdi address*/
5174 TdiAddress = ConnectionInfo->RemoteAddress;
5176 TdiAddress->TAAddressCount = 1;
5177 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5178 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5180 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5181 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5183 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5186 /* Now prepare to connect the remote peer ... */
5188 ConnectionObject = tconn->sender.kstc_info.FileObject;
5189 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5191 /* allocate a new Irp */
5193 Irp = KsBuildTdiIrp(DeviceObject);
5197 status = STATUS_INSUFFICIENT_RESOURCES;
5198 rc = cfs_error_code(status);
5199 cfs_enter_debugger();
5217 /* sumbit the Irp to the underlying transport driver */
5218 status = KsSubmitTdiIrp(
5225 cfs_spin_lock(&(tconn->kstc_lock));
5227 if (NT_SUCCESS(status)) {
5229 /* Connected! the conneciton is built successfully. */
5231 tconn->kstc_state = ksts_connected;
5233 tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
5234 tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
5236 cfs_spin_unlock(&(tconn->kstc_lock));
5240 /* Not connected! Abort it ... */
5243 cfs_enter_debugger();
5247 rc = cfs_error_code(status);
5249 tconn->kstc_state = ksts_associated;
5250 cfs_spin_unlock(&(tconn->kstc_lock));
5252 /* disassocidate the connection and the address object,
5253 after cleanup, it's safe to set the state to abort ... */
5255 if ( NT_SUCCESS(KsDisassociateAddress(
5256 tconn->sender.kstc_info.FileObject))) {
5257 tconn->kstc_state = ksts_aborted;
5260 /* reset the event callbacks */
5261 rc = KsResetHandlers(tconn);
5268 if (NT_SUCCESS(status)) {
5270 ks_query_local_ipaddr(tconn);
5274 if (ConnectionInfo) {
5275 ExFreePool(ConnectionInfo);
5282 ks_put_tconn(tconn);
5289 * ks_disconnect_tconn
5290 * disconnect the tconn from a connection
5293 * tconn: the tdi connecton object connected already
5294 * flags: flags & options for disconnecting
5297 * int: ks error code
5304 ks_disconnect_tconn(
5309 NTSTATUS status = STATUS_SUCCESS;
5311 ks_tconn_info_t * info;
5313 PFILE_OBJECT ConnectionObject;
5314 PDEVICE_OBJECT DeviceObject = NULL;
5320 ks_get_tconn(tconn);
5322 /* make sure tt's connected already and it
5323 must be a sender or a child ... */
5325 LASSERT(tconn->kstc_state == ksts_connected);
5326 LASSERT( tconn->kstc_type == kstt_sender ||
5327 tconn->kstc_type == kstt_child);
5329 /* reset all the event handlers to NULL */
5331 if (tconn->kstc_type != kstt_child) {
5332 KsResetHandlers (tconn);
5335 /* Disconnecting to the remote peer ... */
5337 if (tconn->kstc_type == kstt_sender) {
5338 info = &(tconn->sender.kstc_info);
5340 info = &(tconn->child.kstc_info);
5343 ConnectionObject = info->FileObject;
5344 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5346 /* allocate an Irp and setup it */
5348 Irp = KsBuildTdiIrp(DeviceObject);
5352 status = STATUS_INSUFFICIENT_RESOURCES;
5353 cfs_enter_debugger();
5359 SynchronizationEvent,
5367 KsDisconectCompletionRoutine,
5375 /* issue the Irp to the underlying transport
5376 driver to disconnect the connection */
5378 status = IoCallDriver(DeviceObject, Irp);
5380 if (STATUS_PENDING == status) {
5382 status = KeWaitForSingleObject(
5390 status = Irp->IoStatus.Status;
5393 KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
5394 status, KsNtStatusToString(status)));
5398 if (info->ConnectionInfo) {
5400 /* disassociate the association between connection/address objects */
5402 status = KsDisassociateAddress(ConnectionObject);
5404 if (!NT_SUCCESS(status)) {
5405 cfs_enter_debugger();
5408 cfs_spin_lock(&(tconn->kstc_lock));
5410 /* cleanup the tsdumgr Lists */
5411 KsCleanupTsdu (tconn);
5413 /* set the state of the tconn */
5414 if (NT_SUCCESS(status)) {
5415 tconn->kstc_state = ksts_disconnected;
5417 tconn->kstc_state = ksts_associated;
5420 /* free the connection info to system pool*/
5421 ExFreePool(info->ConnectionInfo);
5422 info->ConnectionInfo = NULL;
5423 info->Remote = NULL;
5425 cfs_spin_unlock(&(tconn->kstc_lock));
5428 status = STATUS_SUCCESS;
5432 ks_put_tconn(tconn);
5434 return cfs_error_code(status);
5440 * The connection is broken un-expectedly. We need do
5444 * tconn: the tdi connection
5458 PKS_DISCONNECT_WORKITEM WorkItem = NULL;
5460 WorkItem = &(tconn->kstc_disconnect);
5462 ks_get_tconn(tconn);
5463 cfs_spin_lock(&(tconn->kstc_lock));
5465 if (tconn->kstc_state != ksts_connected) {
5466 ks_put_tconn(tconn);
5469 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
5471 WorkItem->Flags = TDI_DISCONNECT_ABORT;
5472 WorkItem->tconn = tconn;
5474 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
5477 &(WorkItem->WorkItem),
5483 cfs_spin_unlock(&(tconn->kstc_lock));
5488 * ks_query_local_ipaddr
5489 * query the local connection ip address
5492 * tconn: the tconn which is connected
5495 * int: ks error code
5502 ks_query_local_ipaddr(
5506 PFILE_OBJECT FileObject = NULL;
5509 PTRANSPORT_ADDRESS TdiAddress;
5510 ULONG AddressLength;
5512 if (tconn->kstc_type == kstt_sender) {
5513 FileObject = tconn->sender.kstc_info.FileObject;
5514 } else if (tconn->kstc_type == kstt_child) {
5515 FileObject = tconn->child.kstc_info.FileObject;
5517 status = STATUS_INVALID_PARAMETER;
5521 TdiAddress = &(tconn->kstc_addr.Tdi);
5522 AddressLength = MAX_ADDRESS_LENGTH;
5524 status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
5526 if (NT_SUCCESS(status)) {
5527 KsPrint((2, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
5528 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
5529 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
5531 KsPrint((2, "ks_query_local_ipaddr: Failed to query the connection local ip address.\n"));
5536 return cfs_error_code(status);
5540 KsCalcWhichEngine(ks_tconn_t * tconn)
5542 PTRANSPORT_ADDRESS TdiAddress = &(tconn->kstc_addr.Tdi);
5543 ULONG addr = ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr;
5544 ULONG sum = (addr & 0xFF) + ((addr & 0xFF00) >> 8) + ((addr & 0xFF0000) >> 16);
5546 return (int)(sum % ks_data.ksnd_engine_nums);
5550 KsQueueTdiEngine(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5552 ks_engine_mgr_t * engm;
5553 ks_engine_slot_t * engs;
5555 engm = &ks_data.ksnd_engine_mgr[KsCalcWhichEngine(tconn)];
5556 engs = &TsduMgr->Slot;
5558 if (!engs->queued) {
5559 cfs_spin_lock(&engm->lock);
5560 if (!engs->queued) {
5561 cfs_list_add_tail(&engs->link, &engm->list);
5562 engs->queued = TRUE;
5563 engs->tconn = tconn;
5565 engs->tsdumgr = TsduMgr;
5566 KeSetEvent(&(engm->start),0, FALSE);
5568 cfs_spin_unlock(&engm->lock);
5569 KsPrint((4, "KsQueueTdiEngine: TsduMgr=%p is queued to engine %p\n",
5572 KeSetEvent(&(engm->start),0, FALSE);
5576 KsRemoveTdiEngine(PKS_TSDUMGR TsduMgr)
5578 ks_engine_mgr_t * engm;
5579 ks_engine_slot_t * engs;
5581 engs = &TsduMgr->Slot;
5584 LASSERT(engm != NULL);
5585 cfs_spin_lock(&engm->lock);
5587 cfs_list_del(&engs->link);
5588 engs->queued = FALSE;
5591 engs->tsdumgr = NULL;
5593 cfs_spin_unlock(&engm->lock);
5594 KsPrint((4, "KsQueueTdiEngine: TsduMgr %p is removed from engine %p\n",
5600 KsDeliveryIrp(ks_tconn_t * tconn, PIRP irp)
5602 PFILE_OBJECT connobj;
5603 PDEVICE_OBJECT devobj;
5608 if (tconn->kstc_type == kstt_sender) {
5609 connobj = tconn->sender.kstc_info.FileObject;
5611 LASSERT(tconn->kstc_type == kstt_child);
5612 connobj = tconn->child.kstc_info.FileObject;
5614 devobj = IoGetRelatedDeviceObject(connobj);
5616 /* send irp to transport layer */
5617 status = IoCallDriver(devobj, irp);
5619 /* convert status to linux error code */
5620 if (!NT_SUCCESS(status)) {
5621 rc = cfs_error_code(status);
5624 KsPrint((4, "KsDeliveryIrp: tconn=%p irp=%p status=%xh rc=%d.\n",
5625 tconn, irp, status, rc));
5630 KsBuildSend(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr,
5631 ks_mdl_t * mdl, ulong flags )
5633 ks_tdi_tx_t * context;
5635 PFILE_OBJECT connobj;
5636 PDEVICE_OBJECT devobj;
5642 /* query mdl chain total length */
5643 length = KsQueryMdlsSize(mdl);
5645 /* we need allocate the ks_tx_t structure from memory pool. */
5646 context = cfs_alloc(sizeof(ks_tdi_tx_t), 0);
5648 status = STATUS_INSUFFICIENT_RESOURCES;
5652 /* intialize the TcpContext */
5653 memset(context,0, sizeof(ks_tdi_tx_t));
5654 context->Magic = KS_TCP_CONTEXT_MAGIC;
5655 context->tconn = tconn;
5656 context->CompletionRoutine = KsTcpSendCompletionRoutine;
5657 context->TsduMgr = TsduMgr;
5658 context->Length = length;
5661 if (tconn->kstc_type == kstt_sender) {
5662 connobj = tconn->sender.kstc_info.FileObject;
5664 LASSERT(tconn->kstc_type == kstt_child);
5665 connobj = tconn->child.kstc_info.FileObject;
5667 devobj = IoGetRelatedDeviceObject(connobj);
5668 irp = KsBuildTdiIrp(devobj);
5670 status = STATUS_INSUFFICIENT_RESOURCES;
5674 /* grab tconn reference */
5675 ks_get_tconn(tconn);
5677 /* delivery the sending request */
5682 KsTcpCompletionRoutine,
5693 /* free the context if is not used at all */
5695 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
5696 context->Magic = 'CDAB';
5700 /* here need free the Irp. */
5710 KsDeliveryTsdus(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5715 ks_mdl_t * mdl = NULL;
5719 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5721 ks_get_tconn(tconn);
5722 ks_lock_tsdumgr(TsduMgr);
5724 if ( tconn->kstc_type != kstt_sender &&
5725 tconn->kstc_type != kstt_child) {
5727 ks_unlock_tsdumgr(TsduMgr);
5731 if (tconn->kstc_state != ksts_connected) {
5733 ks_unlock_tsdumgr(TsduMgr);
5738 tflags = TDI_SEND_NON_BLOCKING | TDI_SEND_EXPEDITED;
5740 tflags = TDI_SEND_NON_BLOCKING;
5743 if (cfs_list_empty(&TsduMgr->TsduList)) {
5744 LASSERT(TsduMgr->TotalBytes == 0);
5745 ks_unlock_tsdumgr(TsduMgr);
5749 /* check whether there's outstanding sending requests */
5750 if (TsduMgr->Busy) {
5752 ks_unlock_tsdumgr(TsduMgr);
5756 /* probe all Tsdus and merge buffers together */
5757 mdl = KsLockTsdus(tconn, TsduMgr, &tflags, &length);
5760 LASSERT(TsduMgr->TotalBytes == 0);
5765 ks_unlock_tsdumgr(TsduMgr);
5769 KsPrint((4, "KsDeliveryTsdus: tconn=%p TsudMgr=%p, length=%xh/%xh\n",
5770 tconn, TsduMgr, length, TsduMgr->TotalBytes));
5772 /* build send irp request */
5773 irp = KsBuildSend(tconn, TsduMgr, mdl, tflags);
5776 ks_unlock_tsdumgr(TsduMgr);
5779 TsduMgr->Busy = TRUE;
5780 ks_unlock_tsdumgr(TsduMgr);
5782 /* delivery mdl chain */
5783 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5784 rc = KsDeliveryIrp(tconn, irp);
5791 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5792 ks_put_tconn(tconn);
5797 KsDeliveryEngineThread(void * context)
5799 ks_engine_mgr_t * engm = context;
5800 ks_engine_slot_t * engs;
5804 cfs_set_thread_priority(31);
5806 while (!engm->stop) {
5808 cfs_wait_event_internal(&engm->start, 0);
5810 cfs_spin_lock(&engm->lock);
5811 if (cfs_list_empty(&engm->list)) {
5812 cfs_spin_unlock(&engm->lock);
5816 list = engm->list.next;
5818 engs = cfs_list_entry(list, ks_engine_slot_t, link);
5819 LASSERT(engs->emgr == engm);
5820 LASSERT(engs->queued);
5822 engs->queued = FALSE;
5823 cfs_spin_unlock(&engm->lock);
5825 tconn = engs->tconn;
5826 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5828 KsPrint((4, "KsDeliveryEngineThread: %p active: tconn=%p "
5829 "TsduMgr=%p\n", engm, tconn, engs->tsdumgr));
5830 KsDeliveryTsdus(tconn, engs->tsdumgr);
5832 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5835 KeSetEvent(&engm->exit, 0, FALSE);
5842 * initialize the global data in ksockal_data
5848 * int: ks error code
5859 /* initialize tconn related globals */
5860 RtlZeroMemory(&ks_data, sizeof(ks_tdi_data_t));
5862 cfs_spin_lock_init(&ks_data.ksnd_tconn_lock);
5863 CFS_INIT_LIST_HEAD(&ks_data.ksnd_tconns);
5864 cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
5866 ks_data.ksnd_tconn_slab = cfs_mem_cache_create(
5867 "tcon", sizeof(ks_tconn_t) , 0, 0);
5869 if (!ks_data.ksnd_tconn_slab) {
5874 /* initialize tsdu related globals */
5875 cfs_spin_lock_init(&ks_data.ksnd_tsdu_lock);
5876 CFS_INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
5877 ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
5878 ks_data.ksnd_tsdu_slab = cfs_mem_cache_create(
5879 "tsdu", ks_data.ksnd_tsdu_size, 0, 0);
5881 if (!ks_data.ksnd_tsdu_slab) {
5886 /* initialize engine threads list */
5887 ks_data.ksnd_engine_nums = cfs_num_online_cpus();
5888 if (ks_data.ksnd_engine_nums < 4) {
5889 ks_data.ksnd_engine_nums = 4;
5891 ks_data.ksnd_engine_mgr = cfs_alloc(sizeof(ks_engine_mgr_t) *
5892 ks_data.ksnd_engine_nums,CFS_ALLOC_ZERO);
5893 if (ks_data.ksnd_engine_mgr == NULL) {
5897 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5898 cfs_spin_lock_init(&ks_data.ksnd_engine_mgr[i].lock);
5899 cfs_init_event(&ks_data.ksnd_engine_mgr[i].start, TRUE, FALSE);
5900 cfs_init_event(&ks_data.ksnd_engine_mgr[i].exit, TRUE, FALSE);
5901 CFS_INIT_LIST_HEAD(&ks_data.ksnd_engine_mgr[i].list);
5902 cfs_create_thread(KsDeliveryEngineThread, &ks_data.ksnd_engine_mgr[i], 0);
5905 /* register pnp handlers to watch network condition */
5906 KsRegisterPnpHandlers();
5910 /* do cleanup in case we get failures */
5912 if (ks_data.ksnd_tconn_slab) {
5913 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5914 ks_data.ksnd_tconn_slab = NULL;
5924 * finalize the global data in ksockal_data
5930 * int: ks error code
5939 PKS_TSDU KsTsdu = NULL;
5940 cfs_list_t * list = NULL;
5943 /* clean up the pnp handler and address slots */
5944 KsDeregisterPnpHandlers();
5946 /* stop all tcp sending engines */
5947 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5948 ks_data.ksnd_engine_mgr[i].stop = TRUE;
5949 KeSetEvent(&ks_data.ksnd_engine_mgr[i].start, 0, FALSE);
5952 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5953 cfs_wait_event_internal(&ks_data.ksnd_engine_mgr[i].exit, 0);
5956 /* we need wait until all the tconn are freed */
5957 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
5959 if (cfs_list_empty(&(ks_data.ksnd_tconns))) {
5960 cfs_wake_event(&ks_data.ksnd_tconn_exit);
5962 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
5964 /* now wait on the tconn exit event */
5965 cfs_wait_event_internal(&ks_data.ksnd_tconn_exit, 0);
5967 /* it's safe to delete the tconn slab ... */
5968 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5969 ks_data.ksnd_tconn_slab = NULL;
5971 /* clean up all the tsud buffers in the free list */
5972 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
5973 cfs_list_for_each (list, &ks_data.ksnd_freetsdus) {
5974 KsTsdu = cfs_list_entry (list, KS_TSDU, Link);
5977 ks_data.ksnd_tsdu_slab,
5980 cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
5982 /* it's safe to delete the tsdu slab ... */
5983 cfs_mem_cache_destroy(ks_data.ksnd_tsdu_slab);
5984 ks_data.ksnd_tsdu_slab = NULL;
5986 /* good! it's smooth to do the cleaning up...*/
5990 * ks_create_child_tconn
5991 * Create the backlog child connection for a listener
5994 * parent: the listener daemon connection
5997 * the child connection or NULL in failure
6004 ks_create_child_tconn(
6009 ks_tconn_t * backlog;
6011 /* allocate the tdi connecton object */
6012 backlog = ks_create_tconn();
6018 /* initialize the tconn as a child */
6019 ks_init_child(backlog);
6023 if (ks_bind_tconn(backlog, parent, 0, 0) < 0) {
6024 ks_free_tconn(backlog);
6029 /* open the connection object */
6030 status = KsOpenConnection(
6031 &(backlog->kstc_dev),
6033 &(backlog->child.kstc_info.Handle),
6034 &(backlog->child.kstc_info.FileObject)
6037 if (!NT_SUCCESS(status)) {
6039 ks_put_tconn(backlog);
6041 cfs_enter_debugger();
6045 /* associate it now ... */
6046 status = KsAssociateAddress(
6047 backlog->kstc_addr.Handle,
6048 backlog->child.kstc_info.FileObject
6051 if (!NT_SUCCESS(status)) {
6053 ks_put_tconn(backlog);
6055 cfs_enter_debugger();
6059 backlog->kstc_state = ksts_associated;
6067 * ks_replenish_backlogs(
6068 * to replenish the backlogs listening...
6071 * tconn: the parent listen tdi connect
6072 * nbacklog: number fo child connections in queue
6082 ks_replenish_backlogs(
6083 ks_tconn_t * parent,
6087 ks_tconn_t * backlog;
6090 /* calculate how many backlogs needed */
6091 if ( ( parent->listener.kstc_listening.num +
6092 parent->listener.kstc_accepted.num ) < nbacklog ) {
6093 n = nbacklog - ( parent->listener.kstc_listening.num +
6094 parent->listener.kstc_accepted.num );
6101 /* create the backlog child tconn */
6102 backlog = ks_create_child_tconn(parent);
6104 cfs_spin_lock(&(parent->kstc_lock));
6107 cfs_spin_lock(&backlog->kstc_lock);
6108 /* attch it into the listing list of daemon */
6109 cfs_list_add( &backlog->child.kstc_link,
6110 &parent->listener.kstc_listening.list );
6111 parent->listener.kstc_listening.num++;
6113 backlog->child.kstc_queued = TRUE;
6114 cfs_spin_unlock(&backlog->kstc_lock);
6116 cfs_enter_debugger();
6119 cfs_spin_unlock(&(parent->kstc_lock));
6125 * setup the listener tdi connection and make it listen
6126 * on the user specified ip address and port.
6129 * tconn: the parent listen tdi connect
6130 * nbacklog: number fo child connections in queue
6133 * ks error code >=: success; otherwise error.
6140 ks_start_listen(ks_tconn_t *tconn, int nbacklog)
6144 /* now replenish the backlogs */
6145 ks_replenish_backlogs(tconn, nbacklog);
6147 /* set the event callback handlers */
6148 rc = KsSetHandlers(tconn);
6154 cfs_spin_lock(&(tconn->kstc_lock));
6155 tconn->listener.nbacklog = nbacklog;
6156 tconn->kstc_state = ksts_listening;
6157 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6158 cfs_spin_unlock(&(tconn->kstc_lock));
6164 ks_stop_listen(ks_tconn_t *tconn)
6167 ks_tconn_t * backlog;
6169 /* reset all tdi event callbacks to NULL */
6170 KsResetHandlers (tconn);
6172 cfs_spin_lock(&tconn->kstc_lock);
6174 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6176 /* cleanup all the listening backlog child connections */
6177 cfs_list_for_each (list, &(tconn->listener.kstc_listening.list)) {
6178 backlog = cfs_list_entry(list, ks_tconn_t, child.kstc_link);
6180 /* destory and free it */
6181 ks_put_tconn(backlog);
6184 cfs_spin_unlock(&tconn->kstc_lock);
6186 /* wake up it from the waiting on new incoming connections */
6187 KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
6189 /* free the listening daemon tconn */
6190 ks_put_tconn(tconn);
6195 * ks_wait_child_tconn
6196 * accept a child connection from peer
6199 * parent: the daemon tdi connection listening
6200 * child: to contain the accepted connection
6210 ks_wait_child_tconn(
6211 ks_tconn_t * parent,
6216 ks_tconn_t * backlog = NULL;
6218 ks_replenish_backlogs(parent, parent->listener.nbacklog);
6220 cfs_spin_lock(&(parent->kstc_lock));
6222 if (parent->listener.kstc_listening.num <= 0) {
6223 cfs_spin_unlock(&(parent->kstc_lock));
6229 /* check the listening queue and try to search the accepted connecton */
6231 cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
6232 backlog = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
6234 cfs_spin_lock(&(backlog->kstc_lock));
6236 if (backlog->child.kstc_accepted) {
6238 LASSERT(backlog->kstc_state == ksts_connected);
6239 LASSERT(backlog->child.kstc_busy);
6241 cfs_list_del(&(backlog->child.kstc_link));
6242 cfs_list_add(&(backlog->child.kstc_link),
6243 &(parent->listener.kstc_accepted.list));
6244 parent->listener.kstc_accepted.num++;
6245 parent->listener.kstc_listening.num--;
6246 backlog->child.kstc_queueno = 1;
6248 cfs_spin_unlock(&(backlog->kstc_lock));
6252 cfs_spin_unlock(&(backlog->kstc_lock));
6257 cfs_spin_unlock(&(parent->kstc_lock));
6259 /* we need wait until new incoming connections are requested
6260 or the case of shuting down the listenig daemon thread */
6261 if (backlog == NULL) {
6265 Status = KeWaitForSingleObject(
6266 &(parent->listener.kstc_accept_event),
6273 cfs_spin_lock(&(parent->kstc_lock));
6275 /* check whether it's exptected to exit ? */
6276 if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
6277 cfs_spin_unlock(&(parent->kstc_lock));
6283 KsPrint((2, "ks_wait_child_tconn: connection %p accepted.\n", backlog));
6286 /* query the local ip address of the connection */
6287 ks_query_local_ipaddr(backlog);
6297 ks_query_iovs_length(struct iovec *iov, int niov)
6302 LASSERT(iov != NULL);
6305 for (i=0; i < niov; i++) {
6306 total += iov[i].iov_len;
6313 ks_query_kiovs_length(lnet_kiov_t *kiov, int nkiov)
6318 LASSERT(kiov != NULL);
6321 for (i=0; i < nkiov; i++) {
6322 total += kiov[i].kiov_len;
6329 ks_sock_buf_cb(void *tsdu, int ns, int off, char **buf)
6334 *buf = (char *)tsdu + off;
6341 ks_sock_iov_cb(void *tsdu, int ns, int off, char **buf)
6344 struct iovec *iov = tsdu;
6346 for (i=0; i < ns; i++) {
6347 if ((size_t)off >= iov[i].iov_len) {
6348 off -= iov[i].iov_len;
6350 *buf = (char *)iov[i].iov_base + off;
6351 rc = iov[i].iov_len - off;
6359 ks_sock_kiov_cb(void *tsdu, int ns, int off, char **buf)
6362 lnet_kiov_t *kiov = tsdu;
6364 for (i=0; i < ns; i++) {
6365 if ((size_t)off >= kiov[i].kiov_len) {
6366 off -= kiov[i].kiov_len;
6368 *buf = (char *)kiov[i].kiov_page->addr +
6369 kiov[i].kiov_offset + off;
6370 rc = kiov[i].kiov_len - off;
6377 typedef int (*ks_tsdu_cb_t)(void *tsdu, int ns, int off, char **buf);
6380 ks_sock_io(ks_tconn_t *tconn, void *tsdu, int ns, int reqlen,
6381 int flags, int timeout, int out, ks_tsdu_cb_t callback)
6385 PKS_TSDUMGR TsduMgr;
6394 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6395 remained = (int64_t)cfs_time_seconds(timeout);
6397 /* query tsdu manager */
6398 expedited = cfs_is_flag_set(flags, MSG_OOB);
6399 TsduMgr = KsQueryTsduMgr(tconn, expedited, (BOOLEAN)out);
6401 /* check whether equest is nonblocking */
6402 if (async = cfs_is_flag_set(flags, MSG_DONTWAIT)) {
6406 ks_get_tconn(tconn);
6407 ks_lock_tsdumgr(TsduMgr);
6408 if ( tconn->kstc_type != kstt_sender &&
6409 tconn->kstc_type != kstt_child) {
6414 while (length = callback(tsdu, ns, total, &buffer)) {
6416 /* check whether socket is stil valid */
6417 if (tconn->kstc_state != ksts_connected) {
6423 tflags = KsTdiSendFlags(flags);
6424 rc = KsWriteTsdus(TsduMgr, buffer, length, tflags);
6426 tflags = KsTdiRecvFlags(flags);
6427 rc = KsReadTsdus(TsduMgr, buffer, length, tflags);
6432 } else if (!async && rc == -EAGAIN) {
6435 ks_unlock_tsdumgr(TsduMgr);
6436 remained = cfs_wait_event_internal(
6443 ks_unlock_tsdumgr(TsduMgr);
6444 cfs_wait_event_internal(&TsduMgr->Event, 0);
6446 ks_lock_tsdumgr(TsduMgr);
6455 TsduMgr->Payload = reqlen - total;
6457 ks_unlock_tsdumgr(TsduMgr);
6459 KsPrint((4, "ks_sock_io: tconn=%p tsdumgr=%p %c total=%xh/%xh rc=%d\n",
6460 tconn, TsduMgr, out?'W':'R', total, TsduMgr->TotalBytes, rc));
6464 /* signal Tdi sending engine */
6465 KsQueueTdiEngine(tconn, TsduMgr);
6470 ks_put_tconn(tconn);
6472 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6476 int ks_send_buf(ks_tconn_t * tconn, char *buf,
6477 int len, int flags, int timeout)
6479 return ks_sock_io(tconn, buf, len, len, flags,
6480 timeout, 1, ks_sock_buf_cb);
6483 int ks_recv_buf(ks_tconn_t * tconn, char *buf,
6484 int len, int flags, int timeout)
6486 return ks_sock_io(tconn, buf, len, len, flags,
6487 timeout, 0, ks_sock_buf_cb);
6490 int ks_send_iovs(ks_tconn_t * tconn, struct iovec *iov,
6491 int niov, int flags, int timeout)
6493 int reqlen = ks_query_iovs_length(iov, niov);
6494 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6495 timeout, TRUE, ks_sock_iov_cb);
6498 int ks_recv_iovs(ks_tconn_t * tconn, struct iovec *iov,
6499 int niov, int flags, int timeout)
6501 int reqlen = ks_query_iovs_length(iov, niov);
6502 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6503 timeout, FALSE, ks_sock_iov_cb);
6506 int ks_send_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6507 int nkiov, int flags, int timeout)
6509 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6510 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6511 timeout, TRUE, ks_sock_kiov_cb);
6514 int ks_recv_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6515 int nkiov, int flags, int timeout)
6517 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6518 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6519 timeout, FALSE, ks_sock_kiov_cb);
6522 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
6524 ks_addr_slot_t * slot = NULL;
6525 PLIST_ENTRY list = NULL;
6527 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
6529 list = ks_data.ksnd_addrs_list.Flink;
6530 while (list != &ks_data.ksnd_addrs_list) {
6531 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6532 if (_stricmp(name, &slot->iface[0]) == 0) {
6534 *ip = slot->ip_addr;
6535 *mask = slot->netmask;
6542 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
6544 return (int)(slot == NULL);
6547 int libcfs_ipif_enumerate(char ***names)
6549 ks_addr_slot_t * slot = NULL;
6550 PLIST_ENTRY list = NULL;
6553 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
6555 *names = cfs_alloc(sizeof(char *) * ks_data.ksnd_naddrs, CFS_ALLOC_ZERO);
6556 if (*names == NULL) {
6560 list = ks_data.ksnd_addrs_list.Flink;
6561 while (list != &ks_data.ksnd_addrs_list) {
6562 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6564 (*names)[nips++] = slot->iface;
6565 cfs_assert(nips <= ks_data.ksnd_naddrs);
6568 cfs_assert(nips == ks_data.ksnd_naddrs);
6572 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
6576 void libcfs_ipif_free_enumeration(char **names, int n)
6583 int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
6586 ks_tconn_t * parent;
6588 parent = ks_create_tconn();
6594 /* initialize the tconn as a listener */
6595 ks_init_listener(parent);
6597 /* bind the daemon->tconn */
6598 rc = ks_bind_tconn(parent, NULL, ip, (unsigned short)port);
6601 ks_free_tconn(parent);
6605 /* create listening children and make it to listen state*/
6606 rc = ks_start_listen(parent, backlog);
6608 ks_stop_listen(parent);
6619 int libcfs_sock_accept(struct socket **newsockp, struct socket *sock)
6621 /* wait for incoming connecitons */
6622 return ks_wait_child_tconn(sock, newsockp);
6625 void libcfs_sock_abort_accept(struct socket *sock)
6627 LASSERT(sock->kstc_type == kstt_listener);
6629 cfs_spin_lock(&(sock->kstc_lock));
6631 /* clear the daemon flag */
6632 cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
6634 /* wake up it from the waiting on new incoming connections */
6635 KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
6637 cfs_spin_unlock(&(sock->kstc_lock));
6641 * libcfs_sock_connect
6642 * build a conntion between local ip/port and the peer ip/port.
6645 * laddr: local ip address
6646 * lport: local port number
6647 * paddr: peer's ip address
6648 * pport: peer's port number
6651 * int: return code ...
6658 int libcfs_sock_connect(struct socket **sockp, int *fatal,
6659 __u32 local_ip, int local_port,
6660 __u32 peer_ip, int peer_port)
6662 ks_tconn_t * tconn = NULL;
6666 if (fatal) *fatal = 0;
6668 KsPrint((2, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
6669 peer_ip, peer_port, local_ip, local_port ));
6671 /* create the tdi connecion structure */
6672 tconn = ks_create_tconn();
6678 /* initialize the tdi sender connection */
6679 ks_init_sender(tconn);
6681 /* bind the local ip address with the tconn */
6682 rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
6684 KsPrint((1, "libcfs_sock_connect: failed to bind address %x:%d...\n",
6685 local_ip, local_port ));
6686 ks_free_tconn(tconn);
6690 /* connect to the remote peer */
6691 rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
6693 KsPrint((1, "libcfs_sock_connect: failed to connect %x:%d ...\n",
6694 peer_ip, peer_port ));
6696 ks_put_tconn(tconn);
6707 int libcfs_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize)
6712 int libcfs_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize)
6717 int libcfs_sock_getaddr(struct socket *socket, int remote, __u32 *ip, int *port)
6719 PTRANSPORT_ADDRESS taddr = NULL;
6721 cfs_spin_lock(&socket->kstc_lock);
6723 if (socket->kstc_type == kstt_sender) {
6724 taddr = socket->sender.kstc_info.Remote;
6725 } else if (socket->kstc_type == kstt_child) {
6726 taddr = socket->child.kstc_info.Remote;
6729 taddr = &(socket->kstc_addr.Tdi);
6733 PTDI_ADDRESS_IP addr = (PTDI_ADDRESS_IP)(&(taddr->Address[0].Address));
6735 *ip = ntohl (addr->in_addr);
6737 *port = ntohs (addr->sin_port);
6739 cfs_spin_unlock(&socket->kstc_lock);
6743 cfs_spin_unlock(&socket->kstc_lock);
6747 int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
6752 while (nob > offset) {
6754 rc = ks_send_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6766 KsPrint((4, "libcfs_sock_write: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6770 int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
6775 while (nob > offset) {
6777 rc = ks_recv_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6789 KsPrint((4, "libcfs_sock_read: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6793 void libcfs_sock_release(struct socket *sock)
6795 if (sock->kstc_type == kstt_listener &&
6796 sock->kstc_state == ksts_listening) {
6797 ks_stop_listen(sock);