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.
30 * Copyright (c) 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_LNET
39 #include <libcfs/libcfs.h>
40 #include <lnet/lnet.h>
42 #define TDILND_MODULE_NAME L"tdilnd"
44 ks_tdi_data_t ks_data;
47 KsDumpPrint(PCHAR buffer, ULONG length)
50 for (i=0; i < length; i++) {
51 if (((i+1) % 31) == 0)
53 printk("%2.2x ", (UCHAR)buffer[i]);
59 KsMapMdlBuffer (PMDL Mdl);
62 KsDumpMdlChain(PMDL Mdl, ULONG length)
70 printk("mdl %d:\n", i);
71 buffer = KsMapMdlBuffer(mdl);
72 KsDumpPrint(buffer, mdl->ByteCount);
73 len += mdl->ByteCount;
76 ASSERT(len == length);
81 * Allocate MDL for the buffer and lock the pages into
85 * UserBuffer: the user buffer to be locked
86 * Length: length in bytes of the buffer
87 * Operation: read or write access
88 * pMdl: the result of the created mdl
91 * NTSTATUS: kernel status code (STATUS_SUCCESS
92 * or other error code)
103 IN LOCK_OPERATION Operation,
110 LASSERT(UserBuffer != NULL);
124 Status = STATUS_INSUFFICIENT_RESOURCES;
137 MmBuildMdlForNonPagedPool(
142 Status = STATUS_SUCCESS;
146 } __except (EXCEPTION_EXECUTE_HANDLER) {
152 cfs_enter_debugger();
154 Status = STATUS_INVALID_USER_BUFFER;
163 * Map the mdl into a buffer in kernel space
166 * Mdl: the mdl to be mapped
169 * PVOID: the buffer mapped or NULL in failure
176 KsMapMdlBuffer (PMDL Mdl)
178 LASSERT(Mdl != NULL);
180 return MmGetSystemAddressForMdlSafe(
189 * Unlock all the pages in the mdl
192 * Mdl: memory description list to be released
202 KsReleaseMdl (IN PMDL Mdl,
205 LASSERT(Mdl != NULL);
225 * Query the whole size of a MDL (may be chained)
228 * Mdl: the Mdl to be queried
231 * ULONG: the total size of the mdl
238 KsQueryMdlsSize (PMDL Mdl)
245 // Walking the MDL Chain ...
249 Length += MmGetMdlByteCount(Next);
258 * Copy payload from Mdl to buffer
261 * SourceMdl: the source mdl
262 * SourceOffset: start offset of the source
263 * DestinationBuffer: the dst buffer
264 * DestinationOffset: the offset where data are to be copied.
265 * BytesTobecopied: the expteced bytes to be copied
268 * Length of data copied from MDL to user buffer
277 IN ULONG SourceOffset,
278 IN PVOID DestinationBuffer,
279 IN ULONG DestinationOffset,
280 IN ULONG BytesTobeCopied
283 PUCHAR SourceBuffer = NULL;
284 PUCHAR TargetBuffer = DestinationBuffer;
285 ULONG BytesCopied = 0;
287 if (MmGetMdlByteCount(SourceMdl) <= SourceOffset) {
291 BytesCopied = MmGetMdlByteCount(SourceMdl) - SourceOffset;
292 if (BytesCopied > BytesTobeCopied) {
293 BytesCopied = BytesTobeCopied;
296 SourceBuffer = (PUCHAR)KsMapMdlBuffer(SourceMdl);
298 RtlMoveMemory(TargetBuffer + DestinationOffset,
299 SourceBuffer + SourceOffset, BytesCopied);
306 * Initialize the Tsdu buffer header
309 * KsTsdu: the Tsdu to be initialized
310 * Length: the total length of the Tsdu
325 KsTsdu->Magic = KS_TSDU_MAGIC;
326 KsTsdu->TotalLength = Length;
327 KsTsdu->StartOffset = KsTsdu->LastOffset =
328 KS_QWORD_ALIGN(sizeof(KS_TSDU));
333 * Reuse a Tsdu from the freelist or allocate a new Tsdu
334 * from the LookAsideList table or the NonPagedPool
340 * PKS_Tsdu: the new Tsdu or NULL if it fails
349 PKS_TSDU KsTsdu = NULL;
351 spin_lock(&(ks_data.ksnd_tsdu_lock));
353 if (!list_empty (&(ks_data.ksnd_freetsdus))) {
355 LASSERT(ks_data.ksnd_nfreetsdus > 0);
357 KsTsdu = list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
358 list_del(&(KsTsdu->Link));
359 ks_data.ksnd_nfreetsdus--;
363 KsTsdu = (PKS_TSDU) kmem_cache_alloc(
364 ks_data.ksnd_tsdu_slab, 0);
367 spin_unlock(&(ks_data.ksnd_tsdu_lock));
369 if (NULL != KsTsdu) {
370 RtlZeroMemory(KsTsdu, ks_data.ksnd_tsdu_size);
371 KsInitializeKsTsdu(KsTsdu, (ULONG)ks_data.ksnd_tsdu_size);
379 * Release a Tsdu: uninitialize then free it.
382 * KsTsdu: Tsdu to be freed.
397 ks_data.ksnd_tsdu_slab,
403 * Move the Tsdu to the free tsdu list in ks_data.
406 * KsTsdu: Tsdu to be moved.
420 spin_lock(&(ks_data.ksnd_tsdu_lock));
421 if (ks_data.ksnd_nfreetsdus > 128) {
422 KsFreeKsTsdu(KsTsdu);
424 list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
425 ks_data.ksnd_nfreetsdus++;
427 spin_unlock(&(ks_data.ksnd_tsdu_lock));
430 /* with tconn lock acquired */
440 ks_mdl_t * mdl = NULL;
441 ks_mdl_t * tail = NULL;
444 PKS_TSDU_DAT KsTsduDat;
445 PKS_TSDU_BUF KsTsduBuf;
446 PKS_TSDU_MDL KsTsduMdl;
450 list_for_each_entry(KsTsdu, &TsduMgr->TsduList, Link) {
454 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
455 start = KsTsdu->StartOffset;
457 while (start < KsTsdu->LastOffset) {
459 ks_mdl_t * iov = NULL;
461 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
462 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
463 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
464 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
465 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
466 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
468 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
470 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->TotalLength);
471 if (KsTsduDat->Mdl) {
472 iov = KsTsduDat->Mdl;
475 &KsTsduDat->Data[KsTsduDat->StartOffset],
477 KsTsduDat->DataLength,
480 KsTsduDat->Mdl = iov;
483 printk("KsLockTsdus: %u\n", KsTsduDat->DataLength);
485 &KsTsduDat->Data[KsTsduDat->StartOffset],
486 KsTsduDat->DataLength);
488 *Length += KsTsduDat->DataLength;
489 start += KsTsduDat->TotalLength;
491 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
493 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
494 if (KsTsduBuf->Mdl) {
495 iov = KsTsduBuf->Mdl;
498 (PUCHAR)KsTsduBuf->UserBuffer +
499 KsTsduBuf->StartOffset,
501 KsTsduBuf->DataLength,
504 KsTsduBuf->Mdl = iov;
507 *Length += KsTsduBuf->DataLength;
508 start += sizeof(KS_TSDU_BUF);
512 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
513 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
514 iov = KsTsduMdl->Mdl;
515 *Length += KsTsduMdl->DataLength;
516 start += sizeof(KS_TSDU_MDL);
520 cfs_enter_debugger();
532 printk("KsLockTsdus: mdl %d\n", tail->ByteCount);
533 KsDumpMdlChain(tail, tail->ByteCount);
552 IN ks_mdl_t * master,
557 ks_mdl_t * mdl = NULL;
560 /* calculate the start virtual address */
561 ptr = (char *)KsMapMdlBuffer(master) + offset;
563 /* allocate new mdl for new memory range */
564 mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
570 /* initialize the mdl */
571 IoBuildPartialMdl(master, mdl, (PVOID)ptr, length);
576 /* with tconn lock acquired */
585 PKS_TSDU_DAT KsTsduDat;
586 PKS_TSDU_BUF KsTsduBuf;
587 PKS_TSDU_MDL KsTsduMdl;
589 ULONG total = TsduMgr->TotalBytes;
593 LASSERT(TsduMgr->TotalBytes >= length);
595 while (!list_empty(&TsduMgr->TsduList)) {
599 KsTsdu = list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
600 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
601 start = KsTsdu->StartOffset;
603 while (length > 0 && start < KsTsdu->LastOffset) {
606 ks_mdl_t * mdl = NULL;
608 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
609 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
610 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
611 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
612 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
613 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
615 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
617 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->DataLength);
618 if (length >= KsTsduDat->DataLength) {
619 /* whole tsdu is sent out */
620 size = KsTsduDat->DataLength;
621 start += KsTsduDat->TotalLength;
624 KsTsduDat->StartOffset += size;
627 if (KsTsduDat->Mdl) {
628 mdl = KsTsduDat->Mdl;
629 KsTsduDat->Mdl = NULL;
632 KsTsduDat->DataLength -= size;
634 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
636 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
637 if (length >= KsTsduBuf->DataLength) {
638 /* whole tsdu is sent out */
639 size = KsTsduBuf->DataLength;
640 start += sizeof(KS_TSDU_BUF);
641 LASSERT(KsTsduBuf->UserBuffer);
642 ExFreePool(KsTsduBuf->UserBuffer);
643 KsTsduBuf->UserBuffer = NULL;
645 KsTsduBuf->StartOffset += length;
649 if (KsTsduBuf->Mdl) {
650 mdl = KsTsduBuf->Mdl;
651 KsTsduBuf->Mdl = NULL;
654 KsTsduBuf->DataLength -= size;
658 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
659 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
660 mdl = KsTsduMdl->Mdl;
661 if (length >= KsTsduMdl->DataLength) {
662 /* whole mdl is sent out */
663 size = KsTsduMdl->DataLength;
664 start += sizeof(KS_TSDU_MDL);
665 KsTsduMdl->Mdl = NULL;
667 /* now split the remained data out */
668 ks_mdl_t * mdl1 = KsSplitMdl(mdl, length,
669 KsTsduMdl->DataLength - length);
671 mdl->ByteOffset += length;
674 KsTsduMdl->Mdl = mdl1;
677 KsTsduMdl->StartOffset += size;
680 KsTsduMdl->DataLength -= size;
684 TsduMgr->TotalBytes -= size;
688 KsReleaseMdl(mdl, FALSE);
691 KsTsdu->StartOffset = start;
694 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
696 /* remove KsTsdu from list */
697 list_del(&KsTsdu->Link);
698 TsduMgr->NumOfTsdu--;
707 LASSERT(length == 0);
709 LASSERT(total - size == TsduMgr->TotalBytes);
710 KsPrint((4, "KsReleaseTsdus: TsduMgr=%p Remained=%xh (%xh)\n",
711 TsduMgr, TsduMgr->TotalBytes, size ));
726 /* get the latest Tsdu buffer form TsduMgr list.
727 just set NULL if the list is empty. */
730 if (tconn->kstc_type == kstt_sender) {
731 KsChain = &(tconn->sender.kstc_send);
733 LASSERT(tconn->kstc_type == kstt_child);
734 KsChain = &(tconn->child.kstc_send);
737 if (tconn->kstc_type == kstt_sender) {
738 KsChain = &(tconn->sender.kstc_recv);
740 LASSERT(tconn->kstc_type == kstt_child);
741 KsChain = &(tconn->child.kstc_recv);
746 TsduMgr = &(KsChain->Expedited);
748 TsduMgr = &(KsChain->Normal);
755 KsGetTsdu(PKS_TSDUMGR TsduMgr, ULONG Length)
757 PKS_TSDU KsTsdu = NULL;
759 /* retrieve the latest Tsdu buffer form TsduMgr
760 list if the list is not empty. */
762 if (list_empty(&(TsduMgr->TsduList))) {
764 LASSERT(TsduMgr->NumOfTsdu == 0);
769 LASSERT(TsduMgr->NumOfTsdu > 0);
770 KsTsdu = list_entry(TsduMgr->TsduList.prev, KS_TSDU, Link);
772 /* if this Tsdu does not contain enough space, we need
773 allocate a new Tsdu queue. */
775 if (KsTsdu->LastOffset + Length > KsTsdu->TotalLength) {
780 /* allocate a new Tsdu in case we are not statisfied. */
781 if (NULL == KsTsdu) {
782 KsTsdu = KsAllocateKsTsdu();
783 if (NULL != KsTsdu) {
784 list_add_tail(&(KsTsdu->Link), &(TsduMgr->TsduList));
785 TsduMgr->NumOfTsdu++;
801 PKS_TSDU_DAT KsTsduDat;
802 PKS_TSDU_BUF KsTsduBuf;
804 BOOLEAN bNewBuff = FALSE;
808 printk("KsWriteTsduDat: %u\n", length);
809 KsDumpPrint(buffer, length);
811 /* if the Tsdu is even larger than the biggest Tsdu, we have
812 to allocate new buffer and use TSDU_TYPE_BUF to store it */
814 if ( KS_TSDU_STRU_SIZE(length) > ks_data.ksnd_tsdu_size -
815 KS_QWORD_ALIGN(sizeof(KS_TSDU))) {
819 /* allocating the buffer for TSDU_TYPE_BUF */
821 Buffer = ExAllocatePool(NonPagedPool, length);
822 if (NULL == Buffer) {
823 /* there's no enough memory for us. We just try to
824 receive maximum bytes with a new Tsdu */
826 length = ks_data.ksnd_tsdu_size - KS_TSDU_STRU_SIZE(0) -
827 KS_QWORD_ALIGN(sizeof(KS_TSDU));
831 /* get empty Tsdu from TsduMgr */
832 KsTsdu = KsGetTsdu(TsduMgr, bNewBuff ? sizeof(KS_TSDU_BUF) :
833 KS_TSDU_STRU_SIZE(length) );
835 /* allocate a new Tsdu in case we are not statisfied. */
836 if (NULL == KsTsdu) {
840 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
841 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
845 /* setup up the KS_TSDU_BUF record */
846 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
847 KsTsduBuf->TsduFlags = 0;
848 KsTsduBuf->StartOffset = 0;
849 KsTsduBuf->UserBuffer = Buffer;
850 KsTsduBuf->DataLength = length;
851 KsTsduBuf->Mdl = NULL;
852 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
853 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
856 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
860 /* setup the KS_TSDU_DATA to contain all the messages */
862 KsTsduDat->TsduType = TSDU_TYPE_DAT;
863 KsTsduDat->TsduFlags = 0;
865 if ( KsTsdu->TotalLength - KsTsdu->LastOffset <
866 KS_TSDU_STRU_SIZE(length) ) {
867 length = KsTsdu->TotalLength - KsTsdu->LastOffset -
868 FIELD_OFFSET(KS_TSDU_DAT, Data);
870 KsTsduDat->DataLength = length;
871 KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(length);
872 KsTsduDat->StartOffset = 0;
873 KsTsduDat->Mdl = NULL;
874 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
875 KsTsduDat->TsduFlags |= KS_TSDU_COMM_PARTIAL;
878 Buffer = &KsTsduDat->Data[0];
879 KsTsdu->LastOffset += KsTsduDat->TotalLength;
882 RtlMoveMemory(Buffer, buffer, length);
883 TsduMgr->TotalBytes += length;
885 KsPrint((4, "KsWriteTsduDat: TsduMgr=%p bytes in queue:%xh (%xh)\n",
886 TsduMgr, TsduMgr->TotalBytes, length));
903 PKS_TSDU_BUF KsTsduBuf;
905 /* get empty Tsdu from TsduMgr */
906 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_BUF));
908 /* allocate a new Tsdu in case we are not statisfied. */
909 if (NULL == KsTsdu) {
913 /* setup up the KS_TSDU_BUF record */
914 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
915 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
916 KsTsduBuf->TsduFlags = 0;
917 KsTsduBuf->StartOffset = 0;
918 KsTsduBuf->UserBuffer = buffer;
919 KsTsduBuf->DataLength = length;
920 KsTsduBuf->Mdl = NULL;
921 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
922 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
923 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
926 TsduMgr->TotalBytes += length;
927 KsPrint((4, "KsWriteTsduBuf: TsduMgr=%p bytes in queue:%xh (%xh)\n",
928 TsduMgr, TsduMgr->TotalBytes, length));
947 PKS_TSDU_MDL KsTsduMdl;
949 /* get empty Tsdu from TsduMgr */
950 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_MDL));
952 /* allocate a new Tsdu in case we are not statisfied. */
953 if (NULL == KsTsdu) {
957 /* setup up the KS_TSDU_MDL record */
958 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
959 KsTsduMdl->TsduType = TSDU_TYPE_MDL;
960 KsTsduMdl->TsduFlags = 0;
961 KsTsduMdl->StartOffset = 0;
962 KsTsduMdl->BaseOffset = offset;
963 KsTsduMdl->DataLength = length;
964 KsTsduMdl->Mdl = mdl;
965 KsTsduMdl->Descriptor = desc;
966 KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
967 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
968 KsTsduMdl->TsduFlags |= KS_TSDU_COMM_PARTIAL;
971 TsduMgr->TotalBytes += length;
972 KsPrint((4, "KsWriteTsduMdl: TsduMgr=%p bytes in queue:%xh (%xh)\n",
973 TsduMgr, TsduMgr->TotalBytes, length));
990 PKS_TSDU_DAT KsTsduDat;
991 PKS_TSDU_BUF KsTsduBuf;
992 PKS_TSDU_MDL KsTsduMdl;
995 ULONG BytesRecved = 0;
997 ULONG TotalBytes = TsduMgr->TotalBytes;
1000 KsPrint((4, "KsReadTsdu: TsduMgr=%p request=%xh total=%xh\n",
1001 TsduMgr, length, TsduMgr->TotalBytes ));
1004 if (TsduMgr->TotalBytes == 0) {
1006 /* It's a notification event. We need reset it to
1007 un-signaled state in case there no any tsdus. */
1009 KeResetEvent(&(TsduMgr->Event));
1013 KsTsdu = list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1014 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1016 /* remove the KsTsdu from TsduMgr list to release the lock */
1017 list_del(&(KsTsdu->Link));
1018 TsduMgr->NumOfTsdu--;
1020 while (length > BytesRecved) {
1022 ULONG BytesToCopy = 0;
1023 ULONG StartOffset = 0;
1024 ULONG BytesCopied = 0;
1026 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1027 /* KsTsdu is empty now, we need free it ... */
1028 KsPutKsTsdu(KsTsdu);
1033 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1034 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1035 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1037 if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
1038 TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
1040 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1042 /* Data Tsdu Unit ... */
1043 Buffer = &KsTsduDat->Data[0];
1044 StartOffset = KsTsduDat->StartOffset;
1045 if (KsTsduDat->DataLength - KsTsduDat->StartOffset > length - BytesRecved) {
1046 /* Recvmsg requst could be statisfied ... */
1047 BytesToCopy = length - BytesRecved;
1049 BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
1054 /* Buffer Tsdu Unit */
1055 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1056 Buffer = KsTsduBuf->UserBuffer;
1057 StartOffset = KsTsduBuf->StartOffset;
1059 if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > length - BytesRecved) {
1060 /* Recvmsg requst could be statisfied ... */
1061 BytesToCopy = length - BytesRecved;
1063 BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
1067 if (BytesToCopy > 0) {
1068 RtlMoveMemory(buffer + BytesRecved, Buffer + StartOffset, BytesToCopy);
1070 BytesCopied = BytesToCopy;
1071 BytesRecved += BytesCopied;
1072 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1073 TsduMgr->TotalBytes -= BytesCopied;
1074 KsPrint((4, "KsReadTsdu: TsduMgr=%p copied=%xh recved=%xh\n",
1075 TsduMgr, BytesCopied, BytesRecved ));
1077 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1079 KsTsduDat->StartOffset += BytesCopied;
1080 if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
1081 if (KsTsduDat->Mdl) {
1082 KsTsduDat->Mdl->Next = NULL;
1083 KsReleaseMdl(KsTsduDat->Mdl, FALSE);
1085 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1090 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1091 KsTsduBuf->StartOffset += BytesCopied;
1092 if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
1093 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1094 /* now we need release the buf to system pool */
1095 if (KsTsduBuf->Mdl) {
1096 KsTsduBuf->Mdl->Next = NULL;
1097 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1099 ExFreePool(KsTsduBuf->UserBuffer);
1103 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1105 /* MDL Tsdu Unit ... */
1106 if (KsTsduMdl->DataLength > length - BytesRecved) {
1107 /* Recvmsg requst could be statisfied ... */
1108 BytesToCopy = length - BytesRecved;
1110 BytesToCopy = KsTsduMdl->DataLength;
1116 KsTsduMdl->StartOffset +
1117 KsTsduMdl->BaseOffset,
1122 KsPrint((4, "KsReadTsdu: TsduMgr=%p mdl=%p dec=%p copied=%xh "
1124 TsduMgr, KsTsduMdl->Mdl, KsTsduMdl->Descriptor,
1125 BytesCopied, BytesRecved + BytesCopied));
1126 if (BytesCopied == 0) {
1127 cfs_enter_debugger();
1131 KsTsduMdl->StartOffset += BytesCopied;
1132 KsTsduMdl->DataLength -= BytesCopied;
1133 BytesRecved += BytesCopied;
1134 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1135 TsduMgr->TotalBytes -= BytesCopied;
1137 if (0 == KsTsduMdl->DataLength) {
1139 /* Call TdiReturnChainedReceives to release the Tsdu memory */
1140 LASSERT(KsTsduMdl->Descriptor != NULL);
1141 if (KsTsduMdl->Descriptor) {
1142 TdiReturnChainedReceives(
1143 &(KsTsduMdl->Descriptor),
1147 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1151 KsPrint((1, "KsReadTsdu: unknown tsdu slot: slot = %x type = %x Start= %x Length=%x\n",
1152 KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength));
1153 KsPrint((1, " Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x\n",
1154 KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength));
1155 cfs_enter_debugger();
1159 /* we need attach the KsTsdu to the list header */
1161 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1162 KsPutKsTsdu(KsTsdu);
1165 TsduMgr->NumOfTsdu++;
1166 list_add(&(KsTsdu->Link), &(TsduMgr->TsduList));
1170 if (length > BytesRecved) {
1176 LASSERT(TotalBytes == TsduMgr->TotalBytes + BytesRecved);
1178 KsPrint((4, "KsReadTsdu: TsduMgr=%p recved=%xh (%xh) remained=%xh\n",
1179 TsduMgr, BytesRecved, length, TsduMgr->TotalBytes ));
1186 KsTdiSendFlags(int SockFlags)
1190 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1191 cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
1194 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1195 cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
1198 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1199 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1206 KsTdiRecvFlags(int SockFlags)
1210 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1211 cfs_set_flag(TdiFlags, TDI_RECEIVE_EXPEDITED);
1214 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1215 cfs_set_flag(TdiFlags, TDI_RECEIVE_PARTIAL);
1218 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1219 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1226 KsWriteTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1230 if (TsduMgr->TotalBytes <= TDINAL_MAX_TSDU_QUEUE_SIZE) {
1231 rc = KsWriteTsduDat(TsduMgr, buffer, length, flags);
1242 KsReadTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1244 int rc = KsReadTsdu(TsduMgr, buffer, length, flags);
1254 * KsInitializeKsTsduMgr
1255 * Initialize the management structure of
1259 * TsduMgr: the TsduMgr to be initialized
1269 KsInitializeKsTsduMgr(
1280 &(TsduMgr->TsduList)
1283 TsduMgr->NumOfTsdu = 0;
1284 TsduMgr->TotalBytes = 0;
1286 spin_lock_init(&TsduMgr->Lock);
1291 * KsInitializeKsChain
1292 * Initialize the China structure for receiving
1296 * KsChain: the KsChain to be initialized
1306 KsInitializeKsChain(
1310 KsInitializeKsTsduMgr(&(KsChain->Normal));
1311 KsInitializeKsTsduMgr(&(KsChain->Expedited));
1312 KsChain->Expedited.OOB = TRUE;
1318 * Clean up all the Tsdus in the TsduMgr list
1321 * TsduMgr: the Tsdu list manager
1324 * NTSTATUS: nt status code
1336 PKS_TSDU_DAT KsTsduDat;
1337 PKS_TSDU_BUF KsTsduBuf;
1338 PKS_TSDU_MDL KsTsduMdl;
1340 LASSERT(NULL != TsduMgr);
1342 KsRemoveTdiEngine(TsduMgr);
1343 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
1345 while (!list_empty(&TsduMgr->TsduList)) {
1347 KsTsdu = list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1348 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1350 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
1353 // KsTsdu is empty now, we need free it ...
1356 list_del(&(KsTsdu->Link));
1357 TsduMgr->NumOfTsdu--;
1359 KsFreeKsTsdu(KsTsdu);
1363 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1364 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1365 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1367 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1369 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1371 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
1373 ASSERT(KsTsduBuf->UserBuffer != NULL);
1375 if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
1376 if (KsTsduBuf->Mdl) {
1377 KsTsduBuf->Mdl->Next = NULL;
1378 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1380 ExFreePool(KsTsduBuf->UserBuffer);
1382 cfs_enter_debugger();
1385 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1387 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1390 // MDL Tsdu Unit ...
1392 if (KsTsduMdl->Descriptor) {
1393 TdiReturnChainedReceives(
1394 &(KsTsduMdl->Descriptor),
1396 } else if (KsTsduMdl->Mdl) {
1397 KsTsduMdl->Mdl->Next = NULL;
1398 KsReleaseMdl(KsTsduMdl->Mdl, FALSE);
1401 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1406 return STATUS_SUCCESS;
1412 * Clean up the TsduMgrs of the KsChain
1415 * KsChain: the chain managing TsduMgr
1418 * NTSTATUS: nt status code
1431 LASSERT(NULL != KsChain);
1433 Status = KsCleanupTsduMgr(
1437 if (!NT_SUCCESS(Status)) {
1438 cfs_enter_debugger();
1442 Status = KsCleanupTsduMgr(
1443 &(KsChain->Expedited)
1446 if (!NT_SUCCESS(Status)) {
1447 cfs_enter_debugger();
1459 * Clean up all the Tsdus of a tdi connected object
1462 * tconn: the tdi connection which is connected already.
1476 NTSTATUS Status = STATUS_SUCCESS;
1479 if (tconn->kstc_type != kstt_sender &&
1480 tconn->kstc_type != kstt_child ) {
1485 if (tconn->kstc_type == kstt_sender) {
1487 Status = KsCleanupKsChain(
1488 &(tconn->sender.kstc_recv)
1491 if (!NT_SUCCESS(Status)) {
1492 cfs_enter_debugger();
1496 Status = KsCleanupKsChain(
1497 &(tconn->sender.kstc_send)
1500 if (!NT_SUCCESS(Status)) {
1501 cfs_enter_debugger();
1507 Status = KsCleanupKsChain(
1508 &(tconn->child.kstc_recv)
1511 if (!NT_SUCCESS(Status)) {
1512 cfs_enter_debugger();
1516 Status = KsCleanupKsChain(
1517 &(tconn->child.kstc_send)
1520 if (!NT_SUCCESS(Status)) {
1521 cfs_enter_debugger();
1533 KsIrpCompletionRoutine(
1534 IN PDEVICE_OBJECT DeviceObject,
1539 if (NULL != Context) {
1540 KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
1543 return STATUS_MORE_PROCESSING_REQUIRED;
1545 UNREFERENCED_PARAMETER(DeviceObject);
1546 UNREFERENCED_PARAMETER(Irp);
1552 * Allocate a new IRP and initialize it to be issued to tdi
1555 * DeviceObject: device object created by the underlying
1556 * TDI transport driver
1559 * PRIP: the allocated Irp in success or NULL in failure.
1567 IN PDEVICE_OBJECT DeviceObject
1571 PIO_STACK_LOCATION IrpSp;
1574 // Allocating the IRP ...
1577 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1582 // Getting the Next Stack Location ...
1585 IrpSp = IoGetNextIrpStackLocation(Irp);
1588 // Initializing Irp ...
1591 IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1592 IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
1600 * Issue the Irp to the underlying tdi driver
1603 * DeviceObject: the device object created by TDI driver
1604 * Irp: the I/O request packet to be processed
1605 * bSynchronous: synchronous or not. If true, we need wait
1606 * until the process is finished.
1607 * Information: returned info
1610 * NTSTATUS: kernel status code
1618 IN PDEVICE_OBJECT DeviceObject,
1620 IN BOOLEAN bSynchronous,
1621 OUT PULONG Information
1631 SynchronizationEvent,
1636 IoSetCompletionRoutine(
1638 KsIrpCompletionRoutine,
1646 Status = IoCallDriver(DeviceObject, Irp);
1650 if (STATUS_PENDING == Status) {
1652 Status = KeWaitForSingleObject(
1661 Status = Irp->IoStatus.Status;
1664 *Information = (ULONG)(Irp->IoStatus.Information);
1670 if (!NT_SUCCESS(Status)) {
1672 KsPrint((1, "KsSubmitTdiIrp: Error when submitting the Irp: "
1673 "Status = %xh (%s)\n", Status, KsNtStatusToString(Status)));
1683 * Open the Control Channel Object ...
1686 * DeviceName: the device name to be opened
1687 * Handle: opened handle in success case
1688 * FileObject: the fileobject of the device
1691 * NTSTATUS: kernel status code (STATUS_SUCCESS
1692 * or other error code)
1700 IN PUNICODE_STRING DeviceName,
1701 OUT HANDLE * Handle,
1702 OUT PFILE_OBJECT * FileObject
1705 NTSTATUS Status = STATUS_SUCCESS;
1707 OBJECT_ATTRIBUTES ObjectAttributes;
1708 IO_STATUS_BLOCK IoStatus;
1711 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1717 InitializeObjectAttributes(
1720 OBJ_CASE_INSENSITIVE |
1726 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL );
1729 // Creating the Transport Address Object ...
1732 Status = ZwCreateFile(
1734 FILE_READ_DATA | FILE_WRITE_DATA,
1738 FILE_ATTRIBUTE_NORMAL,
1739 FILE_SHARE_READ | FILE_SHARE_WRITE,
1747 if (NT_SUCCESS(Status)) {
1750 // Now Obtaining the FileObject of the Transport Address ...
1753 Status = ObReferenceObjectByHandle(
1762 if (!NT_SUCCESS(Status)) {
1764 cfs_enter_debugger();
1770 cfs_enter_debugger();
1779 * Release the Control Channel Handle and FileObject
1782 * Handle: the channel handle to be released
1783 * FileObject: the fileobject to be released
1786 * NTSTATUS: kernel status code (STATUS_SUCCESS
1787 * or other error code)
1796 IN PFILE_OBJECT FileObject
1799 NTSTATUS Status = STATUS_SUCCESS;
1801 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1805 ObDereferenceObject(FileObject);
1810 Status = ZwClose(Handle);
1813 ASSERT(NT_SUCCESS(Status));
1821 * Open the tdi address object
1824 * DeviceName: device name of the address object
1825 * pAddress: tdi address of the address object
1826 * AddressLength: length in bytes of the tdi address
1827 * Handle: the newly opened handle
1828 * FileObject: the newly opened fileobject
1831 * NTSTATUS: kernel status code (STATUS_SUCCESS
1832 * or other error code)
1840 IN PUNICODE_STRING DeviceName,
1841 IN PTRANSPORT_ADDRESS pAddress,
1842 IN ULONG AddressLength,
1843 OUT HANDLE * Handle,
1844 OUT PFILE_OBJECT * FileObject
1847 NTSTATUS Status = STATUS_SUCCESS;
1849 PFILE_FULL_EA_INFORMATION Ea = NULL;
1851 UCHAR EaBuffer[EA_MAX_LENGTH];
1853 OBJECT_ATTRIBUTES ObjectAttributes;
1854 IO_STATUS_BLOCK IoStatus;
1857 // Building EA for the Address Object to be Opened ...
1860 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1861 Ea->NextEntryOffset = 0;
1863 Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
1864 Ea->EaValueLength = (USHORT)AddressLength;
1867 TdiTransportAddress,
1868 Ea->EaNameLength + 1
1871 &(Ea->EaName[Ea->EaNameLength + 1]),
1875 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
1876 Ea->EaNameLength + AddressLength;
1878 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1885 InitializeObjectAttributes(
1888 OBJ_CASE_INSENSITIVE |
1894 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1897 // Creating the Transport Address Object ...
1900 Status = ZwCreateFile(
1902 FILE_READ_DATA | FILE_WRITE_DATA,
1906 FILE_ATTRIBUTE_NORMAL,
1907 FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
1915 if (NT_SUCCESS(Status)) {
1918 // Now Obtaining the FileObject of the Transport Address ...
1921 Status = ObReferenceObjectByHandle(
1930 if (!NT_SUCCESS(Status)) {
1932 cfs_enter_debugger();
1938 cfs_enter_debugger();
1946 * Release the Hanlde and FileObject of an opened tdi
1950 * Handle: the handle to be released
1951 * FileObject: the fileobject to be released
1954 * NTSTATUS: kernel status code (STATUS_SUCCESS
1955 * or other error code)
1964 IN PFILE_OBJECT FileObject
1967 NTSTATUS Status = STATUS_SUCCESS;
1971 ObDereferenceObject(FileObject);
1976 Status = ZwClose(Handle);
1979 ASSERT(NT_SUCCESS(Status));
1987 * Open a tdi connection object
1990 * DeviceName: device name of the connection object
1991 * ConnectionContext: the connection context
1992 * Handle: the newly opened handle
1993 * FileObject: the newly opened fileobject
1996 * NTSTATUS: kernel status code (STATUS_SUCCESS
1997 * or other error code)
2005 IN PUNICODE_STRING DeviceName,
2006 IN CONNECTION_CONTEXT ConnectionContext,
2007 OUT HANDLE * Handle,
2008 OUT PFILE_OBJECT * FileObject
2011 NTSTATUS Status = STATUS_SUCCESS;
2013 PFILE_FULL_EA_INFORMATION Ea = NULL;
2015 UCHAR EaBuffer[EA_MAX_LENGTH];
2017 OBJECT_ATTRIBUTES ObjectAttributes;
2018 IO_STATUS_BLOCK IoStatus;
2021 // Building EA for the Address Object to be Opened ...
2024 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
2025 Ea->NextEntryOffset = 0;
2027 Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
2028 Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
2031 TdiConnectionContext,
2032 Ea->EaNameLength + 1
2035 &(Ea->EaName[Ea->EaNameLength + 1]),
2037 sizeof(CONNECTION_CONTEXT)
2039 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
2040 Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
2042 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2049 InitializeObjectAttributes(
2052 OBJ_CASE_INSENSITIVE |
2058 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2061 // Creating the Connection Object ...
2064 Status = ZwCreateFile(
2066 FILE_READ_DATA | FILE_WRITE_DATA,
2070 FILE_ATTRIBUTE_NORMAL,
2071 FILE_SHARE_READ | FILE_SHARE_WRITE,
2079 if (NT_SUCCESS(Status)) {
2082 // Now Obtaining the FileObject of the Transport Address ...
2085 Status = ObReferenceObjectByHandle(
2094 if (!NT_SUCCESS(Status)) {
2096 cfs_enter_debugger();
2102 cfs_enter_debugger();
2110 * Release the Hanlde and FileObject of an opened tdi
2114 * Handle: the handle to be released
2115 * FileObject: the fileobject to be released
2118 * NTSTATUS: kernel status code (STATUS_SUCCESS
2119 * or other error code)
2128 IN PFILE_OBJECT FileObject
2131 NTSTATUS Status = STATUS_SUCCESS;
2135 ObDereferenceObject(FileObject);
2140 Status = ZwClose(Handle);
2143 ASSERT(NT_SUCCESS(Status));
2150 * KsAssociateAddress
2151 * Associate an address object with a connection object
2154 * AddressHandle: the handle of the address object
2155 * ConnectionObject: the FileObject of the connection
2158 * NTSTATUS: kernel status code (STATUS_SUCCESS
2159 * or other error code)
2167 IN HANDLE AddressHandle,
2168 IN PFILE_OBJECT ConnectionObject
2172 PDEVICE_OBJECT DeviceObject;
2176 // Getting the DeviceObject from Connection FileObject
2179 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2182 // Building Tdi Internal Irp ...
2185 Irp = KsBuildTdiIrp(DeviceObject);
2189 Status = STATUS_INSUFFICIENT_RESOURCES;
2194 // Assocating the Address Object with the Connection Object
2197 TdiBuildAssociateAddress(
2207 // Calling the Transprot Driver with the Prepared Irp
2210 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2218 * KsDisassociateAddress
2219 * Disassociate the connection object (the relationship will
2220 * the corresponding address object will be dismissed. )
2223 * ConnectionObject: the FileObject of the connection
2226 * NTSTATUS: kernel status code (STATUS_SUCCESS
2227 * or other error code)
2234 KsDisassociateAddress(
2235 IN PFILE_OBJECT ConnectionObject
2239 PDEVICE_OBJECT DeviceObject;
2243 // Getting the DeviceObject from Connection FileObject
2246 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2249 // Building Tdi Internal Irp ...
2252 Irp = KsBuildTdiIrp(DeviceObject);
2256 Status = STATUS_INSUFFICIENT_RESOURCES;
2261 // Disassocating the Address Object with the Connection Object
2264 TdiBuildDisassociateAddress(
2273 // Calling the Transprot Driver with the Prepared Irp
2276 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2286 // Connection Control Event Callbacks
2290 TDI_EVENT_DISCONNECT
2294 // Tcp Event Callbacks
2298 TDI_EVENT_RECEIVE_EXPEDITED
2299 TDI_EVENT_CHAINED_RECEIVE
2300 TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
2303 // Udp Event Callbacks
2306 TDI_EVENT_RECEIVE_DATAGRAM
2307 TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
2313 * KsSetEventHandlers
2314 * Set the tdi event callbacks with an address object
2317 * AddressObject: the FileObject of the address object
2318 * EventContext: the parameter for the callbacks
2319 * Handlers: the handlers indictor array
2322 * NTSTATUS: kernel status code (STATUS_SUCCESS
2323 * or other error code)
2331 IN PFILE_OBJECT AddressObject, // Address File Object
2332 IN PVOID EventContext, // Context for Handlers
2333 IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
2336 NTSTATUS Status = STATUS_SUCCESS;
2337 PDEVICE_OBJECT DeviceObject;
2340 DeviceObject = IoGetRelatedDeviceObject(AddressObject);
2342 for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
2345 // Setup the tdi event callback handler if requested.
2348 if (Handlers->IsActive[i]) {
2353 // Building Tdi Internal Irp ...
2356 Irp = KsBuildTdiIrp(DeviceObject);
2360 Status = STATUS_INSUFFICIENT_RESOURCES;
2365 // Building the Irp to set the Event Handler ...
2368 TdiBuildSetEventHandler(
2374 i, /* tdi event type */
2375 Handlers->Handler[i], /* tdi event handler */
2376 EventContext /* context for the handler */
2380 // Calling the Transprot Driver with the Prepared Irp
2383 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2386 // tcp/ip tdi does not support these two event callbacks
2389 if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
2390 i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
2391 cfs_enter_debugger();
2392 Status = STATUS_SUCCESS;
2396 if (!NT_SUCCESS(Status)) {
2397 cfs_enter_debugger();
2406 if (!NT_SUCCESS(Status)) {
2408 KsPrint((1, "KsSetEventHandlers: Error Status = %xh (%s)\n",
2409 Status, KsNtStatusToString(Status) ));
2418 * KsQueryAddressInfo
2419 * Query the address of the FileObject specified
2422 * FileObject: the FileObject to be queried
2423 * AddressInfo: buffer to contain the address info
2424 * AddressSize: length of the AddressInfo buffer
2427 * NTSTATUS: kernel status code (STATUS_SUCCESS
2428 * or other error code)
2436 PFILE_OBJECT FileObject,
2437 PTDI_ADDRESS_INFO AddressInfo,
2441 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2444 PDEVICE_OBJECT DeviceObject;
2446 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2448 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2450 RtlZeroMemory(AddressInfo, *(AddressSize));
2453 // Allocating the Tdi Setting Irp ...
2456 Irp = KsBuildTdiIrp(DeviceObject);
2460 Status = STATUS_INSUFFICIENT_RESOURCES;
2465 // Locking the User Buffer / Allocating a MDL for it
2468 Status = KsLockUserBuffer(
2476 if (!NT_SUCCESS(Status)) {
2485 LASSERT(NT_SUCCESS(Status));
2487 TdiBuildQueryInformation(
2493 TDI_QUERY_ADDRESS_INFO,
2497 Status = KsSubmitTdiIrp(
2504 KsReleaseMdl(Mdl, FALSE);
2507 if (!NT_SUCCESS(Status)) {
2509 cfs_enter_debugger();
2510 //TDI_BUFFER_OVERFLOW
2517 * KsQueryProviderInfo
2518 * Query the underlying transport device's information
2521 * TdiDeviceName: the transport device's name string
2522 * ProviderInfo: TDI_PROVIDER_INFO struncture
2525 * NTSTATUS: Nt system status code
2532 KsQueryProviderInfo(
2533 PWSTR TdiDeviceName,
2534 PTDI_PROVIDER_INFO ProviderInfo
2537 NTSTATUS Status = STATUS_SUCCESS;
2542 UNICODE_STRING ControlName;
2545 PFILE_OBJECT FileObject;
2546 PDEVICE_OBJECT DeviceObject;
2548 ULONG ProviderSize = 0;
2550 RtlInitUnicodeString(&ControlName, TdiDeviceName);
2553 // Open the Tdi Control Channel
2556 Status = KsOpenControl(
2562 if (!NT_SUCCESS(Status)) {
2564 KsPrint((1, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
2569 // Obtain The Related Device Object
2572 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2574 ProviderSize = sizeof(TDI_PROVIDER_INFO);
2575 RtlZeroMemory(ProviderInfo, ProviderSize);
2578 // Allocating the Tdi Setting Irp ...
2581 Irp = KsBuildTdiIrp(DeviceObject);
2585 Status = STATUS_INSUFFICIENT_RESOURCES;
2590 // Locking the User Buffer / Allocating a MDL for it
2593 Status = KsLockUserBuffer(
2601 if (!NT_SUCCESS(Status)) {
2610 LASSERT(NT_SUCCESS(Status));
2612 TdiBuildQueryInformation(
2618 TDI_QUERY_PROVIDER_INFO,
2622 Status = KsSubmitTdiIrp(
2629 KsReleaseMdl(Mdl, FALSE);
2632 if (!NT_SUCCESS(Status)) {
2634 cfs_enter_debugger();
2635 //TDI_BUFFER_OVERFLOW
2638 KsCloseControl(Handle, FileObject);
2644 * KsQueryConnectionInfo
2645 * Query the connection info of the FileObject specified
2646 * (some statics data of the traffic)
2649 * FileObject: the FileObject to be queried
2650 * ConnectionInfo: buffer to contain the connection info
2651 * ConnectionSize: length of the ConnectionInfo buffer
2654 * NTSTATUS: kernel status code (STATUS_SUCCESS
2655 * or other error code)
2662 KsQueryConnectionInfo(
2663 PFILE_OBJECT ConnectionObject,
2664 PTDI_CONNECTION_INFO ConnectionInfo,
2665 PULONG ConnectionSize
2668 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2671 PDEVICE_OBJECT DeviceObject;
2673 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2675 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2677 RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
2680 // Allocating the Tdi Query Irp ...
2683 Irp = KsBuildTdiIrp(DeviceObject);
2687 Status = STATUS_INSUFFICIENT_RESOURCES;
2692 // Locking the User Buffer / Allocating a MDL for it
2695 Status = KsLockUserBuffer(
2703 if (NT_SUCCESS(Status)) {
2712 LASSERT(NT_SUCCESS(Status));
2714 TdiBuildQueryInformation(
2720 TDI_QUERY_CONNECTION_INFO,
2724 Status = KsSubmitTdiIrp(
2731 KsReleaseMdl(Mdl, FALSE);
2739 * KsInitializeTdiAddress
2740 * Initialize the tdi addresss
2743 * pTransportAddress: tdi address to be initialized
2744 * IpAddress: the ip address of object
2745 * IpPort: the ip port of the object
2748 * ULONG: the total size of the tdi address
2755 KsInitializeTdiAddress(
2756 IN OUT PTA_IP_ADDRESS pTransportAddress,
2761 pTransportAddress->TAAddressCount = 1;
2762 pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
2763 pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
2764 pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
2765 pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
2767 return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
2771 * KsQueryTdiAddressLength
2772 * Query the total size of the tdi address
2775 * pTransportAddress: tdi address to be queried
2778 * ULONG: the total size of the tdi address
2785 KsQueryTdiAddressLength(
2786 PTRANSPORT_ADDRESS pTransportAddress
2789 ULONG TotalLength = 0;
2792 PTA_ADDRESS pTaAddress = NULL;
2794 ASSERT (NULL != pTransportAddress);
2796 TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
2797 FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
2799 pTaAddress = (PTA_ADDRESS)pTransportAddress->Address;
2801 for (i = 0; i < pTransportAddress->TAAddressCount; i++)
2803 TotalLength += pTaAddress->AddressLength;
2804 pTaAddress = (PTA_ADDRESS)((PCHAR)pTaAddress +
2805 FIELD_OFFSET(TA_ADDRESS,Address) +
2806 pTaAddress->AddressLength );
2809 return (TotalLength);
2815 * Query the ip address of the tdi object
2818 * FileObject: tdi object to be queried
2819 * TdiAddress: TdiAddress buffer, to store the queried
2821 * AddressLength: buffer length of the TdiAddress
2824 * ULONG: the total size of the tdi ip address
2832 PFILE_OBJECT FileObject,
2834 ULONG* AddressLength
2839 PTDI_ADDRESS_INFO TdiAddressInfo;
2844 // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
2847 Length = MAX_ADDRESS_LENGTH;
2849 TdiAddressInfo = (PTDI_ADDRESS_INFO)
2850 ExAllocatePoolWithTag(
2855 if (NULL == TdiAddressInfo) {
2857 Status = STATUS_INSUFFICIENT_RESOURCES;
2862 Status = KsQueryAddressInfo(
2870 if (NT_SUCCESS(Status)) {
2872 if (*AddressLength < Length) {
2873 Status = STATUS_BUFFER_TOO_SMALL;
2875 *AddressLength = Length;
2878 &(TdiAddressInfo->Address),
2881 Status = STATUS_SUCCESS;
2885 if (NULL != TdiAddressInfo) {
2886 ExFreePool(TdiAddressInfo);
2894 * KsErrorEventHandler
2895 * the common error event handler callback
2898 * TdiEventContext: should be the socket
2899 * Status: the error code
2902 * Status: STATS_SUCCESS
2905 * We need not do anything in such a severe
2906 * error case. System will process it for us.
2910 KsErrorEventHandler(
2911 IN PVOID TdiEventContext,
2915 KsPrint((1, "KsErrorEventHandler called at Irql = %xh ...\n",
2916 KeGetCurrentIrql()));
2918 cfs_enter_debugger();
2920 return (STATUS_SUCCESS);
2924 * KsAcceptCompletionRoutine
2925 * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
2927 * Here system gives us a chance to check the conneciton is built
2931 * DeviceObject: the device object of the transport driver
2932 * Irp: the Irp is being completed.
2933 * Context: the context we specified when issuing the Irp
2943 KsAcceptCompletionRoutine(
2944 IN PDEVICE_OBJECT DeviceObject,
2949 ks_tconn_t * child = (ks_tconn_t *) Context;
2950 ks_tconn_t * parent = child->child.kstc_parent;
2952 KsPrint((2, "KsAcceptCompletionRoutine at Irql: %xh child: %p status: %p\n",
2953 KeGetCurrentIrql(), child, Irp->IoStatus.Status));
2955 LASSERT(child->kstc_type == kstt_child);
2957 spin_lock(&(child->kstc_lock));
2959 LASSERT(parent->kstc_state == ksts_listening);
2960 LASSERT(child->kstc_state == ksts_connecting);
2962 if (NT_SUCCESS(Irp->IoStatus.Status)) {
2964 child->child.kstc_accepted = TRUE;
2966 child->kstc_state = ksts_connected;
2968 /* wake up the daemon thread which waits on this event */
2970 &(parent->listener.kstc_accept_event),
2975 spin_unlock(&(child->kstc_lock));
2977 KsPrint((2, "KsAcceptCompletionRoutine: singal parent: %p (child: %p)\n",
2982 /* re-use this child connecton */
2983 child->child.kstc_accepted = FALSE;
2984 child->child.kstc_busy = FALSE;
2985 child->kstc_state = ksts_associated;
2987 spin_unlock(&(child->kstc_lock));
2990 /* now free the Irp */
2993 /* drop the refer count of the child */
2994 ks_put_tconn(child);
2996 return (STATUS_MORE_PROCESSING_REQUIRED);
3000 KsSearchIpAddress(PUNICODE_STRING DeviceName)
3002 ks_addr_slot_t * slot = NULL;
3003 PLIST_ENTRY list = NULL;
3005 spin_lock(&ks_data.ksnd_addrs_lock);
3007 list = ks_data.ksnd_addrs_list.Flink;
3008 while (list != &ks_data.ksnd_addrs_list) {
3009 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3010 if (RtlCompareUnicodeString(
3020 spin_unlock(&ks_data.ksnd_addrs_lock);
3026 KsCleanupIpAddresses()
3028 spin_lock(&ks_data.ksnd_addrs_lock);
3030 while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
3032 ks_addr_slot_t * slot = NULL;
3033 PLIST_ENTRY list = NULL;
3035 list = RemoveHeadList(&ks_data.ksnd_addrs_list);
3036 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3038 ks_data.ksnd_naddrs--;
3041 cfs_assert(ks_data.ksnd_naddrs == 0);
3042 spin_unlock(&ks_data.ksnd_addrs_lock);
3046 KsAddAddressHandler(
3047 IN PTA_ADDRESS Address,
3048 IN PUNICODE_STRING DeviceName,
3049 IN PTDI_PNP_CONTEXT Context
3052 PTDI_ADDRESS_IP IpAddress = NULL;
3054 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3055 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3057 ks_addr_slot_t * slot = NULL;
3059 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3060 KsPrint((2, "KsAddAddressHandle: Device=%wZ Context=%xh "
3061 "IpAddress=%xh(%d.%d.%d.%d)\n",
3062 DeviceName, Context, IpAddress->in_addr,
3063 (IpAddress->in_addr & 0x000000FF) >> 0,
3064 (IpAddress->in_addr & 0x0000FF00) >> 8,
3065 (IpAddress->in_addr & 0x00FF0000) >> 16,
3066 (IpAddress->in_addr & 0xFF000000) >> 24
3069 slot = KsSearchIpAddress(DeviceName);
3073 slot->ip_addr = ntohl(IpAddress->in_addr);
3076 /* Matt: only add 192.168.10/5/92.xxx for temporary test */
3077 if ((IpAddress->in_addr & 0x00FFFFFF) != 0x000aa8c0 &&
3078 (IpAddress->in_addr & 0x00FFFFFF) != 0x0092a8c0 &&
3079 (IpAddress->in_addr & 0x00FFFFFF) != 0x0005a8c0 ) {
3083 slot = kmalloc(sizeof(ks_addr_slot_t) + DeviceName->Length, __GFP_ZERO);
3085 spin_lock(&ks_data.ksnd_addrs_lock);
3086 InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
3087 sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
3088 slot->ip_addr = ntohl(IpAddress->in_addr);
3089 slot->netmask = 0x00FFFFFF; /* Matt: hardcode*/
3091 RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
3092 slot->devname.Length = DeviceName->Length;
3093 slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
3094 slot->devname.Buffer = slot->buffer;
3095 spin_unlock(&ks_data.ksnd_addrs_lock);
3097 KsPrint((0, "KsAddAddressHandle: %s added: ip=%xh(%d.%d.%d.%d)\n",
3098 slot->iface, IpAddress->in_addr,
3099 (IpAddress->in_addr & 0x000000FF) >> 0,
3100 (IpAddress->in_addr & 0x0000FF00) >> 8,
3101 (IpAddress->in_addr & 0x00FF0000) >> 16,
3102 (IpAddress->in_addr & 0xFF000000) >> 24
3110 KsDelAddressHandler(
3111 IN PTA_ADDRESS Address,
3112 IN PUNICODE_STRING DeviceName,
3113 IN PTDI_PNP_CONTEXT Context
3116 PTDI_ADDRESS_IP IpAddress = NULL;
3118 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3119 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3121 ks_addr_slot_t * slot = NULL;
3123 slot = KsSearchIpAddress(DeviceName);
3129 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3130 KsPrint((2, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
3131 DeviceName, Context, IpAddress->in_addr,
3132 (IpAddress->in_addr & 0xFF000000) >> 24,
3133 (IpAddress->in_addr & 0x00FF0000) >> 16,
3134 (IpAddress->in_addr & 0x0000FF00) >> 8,
3135 (IpAddress->in_addr & 0x000000FF) >> 0 ));
3140 KsRegisterPnpHandlers()
3142 TDI20_CLIENT_INTERFACE_INFO ClientInfo;
3144 /* initialize the global ks_data members */
3145 RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
3146 spin_lock_init(&ks_data.ksnd_addrs_lock);
3147 InitializeListHead(&ks_data.ksnd_addrs_list);
3149 /* register the pnp handlers */
3150 RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
3151 ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
3153 ClientInfo.ClientName = &ks_data.ksnd_client_name;
3154 ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
3155 ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
3157 return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
3158 &ks_data.ksnd_pnp_handle);
3162 KsDeregisterPnpHandlers()
3164 if (ks_data.ksnd_pnp_handle) {
3166 /* De-register the pnp handlers */
3168 TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
3169 ks_data.ksnd_pnp_handle = NULL;
3171 /* cleanup all the ip address slots */
3172 KsCleanupIpAddresses();
3178 * KsGetVacancyBacklog
3179 * Get a vacancy listeing child from the backlog list
3182 * parent: the listener daemon connection
3185 * the child listening connection or NULL in failure
3188 * Parent's lock should be acquired before calling.
3192 KsGetVacancyBacklog(
3198 LASSERT(parent->kstc_type == kstt_listener);
3199 LASSERT(parent->kstc_state == ksts_listening);
3201 if (list_empty(&(parent->listener.kstc_listening.list))) {
3207 struct list_head * tmp;
3209 /* check the listening queue and try to get a free connecton */
3211 list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
3212 child = list_entry (tmp, ks_tconn_t, child.kstc_link);
3213 spin_lock(&(child->kstc_lock));
3215 if (!child->child.kstc_busy) {
3216 LASSERT(child->kstc_state == ksts_associated);
3217 child->child.kstc_busy = TRUE;
3218 spin_unlock(&(child->kstc_lock));
3221 spin_unlock(&(child->kstc_lock));
3231 * KsConnectEventHandler
3232 * Connect event handler event handler, called by the underlying TDI
3233 * transport in response to an incoming request to the listening daemon.
3235 * it will grab a vacancy backlog from the children tconn list, and
3236 * build an acception Irp with it, then transfer the Irp to TDI driver.
3239 * TdiEventContext: the tdi connnection object of the listening daemon
3243 * Nt kernel status code
3250 KsConnectEventHandler(
3251 IN PVOID TdiEventContext,
3252 IN LONG RemoteAddressLength,
3253 IN PVOID RemoteAddress,
3254 IN LONG UserDataLength,
3256 IN LONG OptionsLength,
3258 OUT CONNECTION_CONTEXT * ConnectionContext,
3259 OUT PIRP * AcceptIrp
3262 ks_tconn_t * parent;
3265 PFILE_OBJECT FileObject;
3266 PDEVICE_OBJECT DeviceObject;
3270 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
3272 KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
3273 parent = (ks_tconn_t *) TdiEventContext;
3275 LASSERT(parent->kstc_type == kstt_listener);
3277 spin_lock(&(parent->kstc_lock));
3279 if (parent->kstc_state == ksts_listening) {
3281 /* allocate a new ConnectionInfo to backup the peer's info */
3283 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
3284 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
3285 RemoteAddressLength, 'iCsK' );
3287 if (NULL == ConnectionInfo) {
3289 Status = STATUS_INSUFFICIENT_RESOURCES;
3290 cfs_enter_debugger();
3294 /* initializing ConnectionInfo structure ... */
3296 ConnectionInfo->UserDataLength = UserDataLength;
3297 ConnectionInfo->UserData = UserData;
3298 ConnectionInfo->OptionsLength = OptionsLength;
3299 ConnectionInfo->Options = Options;
3300 ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
3301 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
3304 ConnectionInfo->RemoteAddress,
3309 /* get the vacancy listening child tdi connections */
3311 child = KsGetVacancyBacklog(parent);
3315 spin_lock(&(child->kstc_lock));
3316 child->child.kstc_info.ConnectionInfo = ConnectionInfo;
3317 child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
3318 child->kstc_state = ksts_connecting;
3319 spin_unlock(&(child->kstc_lock));
3323 KsPrint((1, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
3324 Status = STATUS_INSUFFICIENT_RESOURCES;
3328 FileObject = child->child.kstc_info.FileObject;
3329 DeviceObject = IoGetRelatedDeviceObject (FileObject);
3331 Irp = KsBuildTdiIrp(DeviceObject);
3337 KsAcceptCompletionRoutine,
3343 IoSetNextIrpStackLocation(Irp);
3345 /* grap the refer of the child tdi connection */
3346 ks_get_tconn(child);
3348 Status = STATUS_MORE_PROCESSING_REQUIRED;
3350 *ConnectionContext = child;
3354 Status = STATUS_CONNECTION_REFUSED;
3358 spin_unlock(&(parent->kstc_lock));
3364 spin_unlock(&(parent->kstc_lock));
3367 *ConnectionContext = NULL;
3369 if (ConnectionInfo) {
3370 ExFreePool(ConnectionInfo);
3381 * KsDisconnectCompletionRoutine
3382 * the Irp completion routine for TdiBuildDisconect
3384 * We just signal the event and return MORE_PRO... to
3385 * let the caller take the responsibility of the Irp.
3388 * DeviceObject: the device object of the transport
3389 * Irp: the Irp is being completed.
3390 * Context: the event specified by the caller
3400 KsDisconectCompletionRoutine (
3401 IN PDEVICE_OBJECT DeviceObject,
3407 KeSetEvent((PKEVENT) Context, 0, FALSE);
3409 return STATUS_MORE_PROCESSING_REQUIRED;
3411 UNREFERENCED_PARAMETER(DeviceObject);
3416 * KsDisconnectHelper
3417 * the routine to be executed in the WorkItem procedure
3418 * this routine is to disconnect a tdi connection
3421 * Workitem: the context transferred to the workitem
3427 * tconn is already referred in abort_connecton ...
3431 KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
3433 ks_tconn_t * tconn = WorkItem->tconn;
3435 KsPrint((1, "KsDisconnectHelper: disconnecting tconn=%p\n", tconn));
3436 ks_disconnect_tconn(tconn, WorkItem->Flags);
3438 KeSetEvent(&(WorkItem->Event), 0, FALSE);
3440 spin_lock(&(tconn->kstc_lock));
3441 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3442 spin_unlock(&(tconn->kstc_lock));
3443 ks_put_tconn(tconn);
3448 * KsDisconnectEventHandler
3449 * Disconnect event handler event handler, called by the underlying TDI transport
3450 * in response to an incoming disconnection notification from a remote node.
3453 * ConnectionContext: tdi connnection object
3454 * DisconnectFlags: specifies the nature of the disconnection
3458 * Nt kernel status code
3466 KsDisconnectEventHandler(
3467 IN PVOID TdiEventContext,
3468 IN CONNECTION_CONTEXT ConnectionContext,
3469 IN LONG DisconnectDataLength,
3470 IN PVOID DisconnectData,
3471 IN LONG DisconnectInformationLength,
3472 IN PVOID DisconnectInformation,
3473 IN ULONG DisconnectFlags
3478 PKS_DISCONNECT_WORKITEM WorkItem;
3480 tconn = (ks_tconn_t *)ConnectionContext;
3482 KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
3483 KeGetCurrentIrql() ));
3485 KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
3486 tconn, DisconnectFlags));
3488 ks_get_tconn(tconn);
3489 spin_lock(&(tconn->kstc_lock));
3491 WorkItem = &(tconn->kstc_disconnect);
3493 if (tconn->kstc_state != ksts_connected) {
3495 Status = STATUS_SUCCESS;
3499 if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
3501 Status = STATUS_REMOTE_DISCONNECT;
3503 } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
3505 Status = STATUS_GRACEFUL_DISCONNECT;
3508 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
3510 ks_get_tconn(tconn);
3512 WorkItem->Flags = DisconnectFlags;
3513 WorkItem->tconn = tconn;
3515 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3517 /* queue the workitem to call */
3518 ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
3522 spin_unlock(&(tconn->kstc_lock));
3523 ks_put_tconn(tconn);
3529 KsTcpReceiveCompletionRoutine(
3531 IN PKS_TCP_COMPLETION_CONTEXT Context
3534 ks_tconn_t *tconn = Context->tconn;
3535 NTSTATUS status = Irp->IoStatus.Status;
3536 ULONG length = (ULONG)Irp->IoStatus.Information;
3538 LASSERT(Context != NULL);
3540 if (NT_SUCCESS(status)) {
3542 PKS_TSDUMGR TsduMgr = Context->TsduMgr;
3543 PCHAR Buffer = Context->Buffer;
3545 KsPrint((4, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
3546 TsduMgr->TotalBytes ));
3548 ks_lock_tsdumgr(TsduMgr);
3549 KsWriteTsduBuf(TsduMgr, Context->Buffer, length, 0);
3550 /* signal TsduMgr event */
3551 KeSetEvent(&(Context->TsduMgr->Event), 0, FALSE);
3552 ks_unlock_tsdumgr(TsduMgr);
3554 /* re-active the ks connection and wake up the scheduler */
3555 if (KS_CAN_SCHED(TsduMgr)) {
3556 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3557 tconn->kstc_sched_cb(tconn, FALSE);
3561 ks_put_tconn(tconn);
3565 /* un-expected errors occur, we must abort the connection */
3566 ks_put_tconn(tconn);
3567 ks_abort_tconn(tconn);
3573 /* free the Context structure... */
3574 ASSERT(Context->Magic == KS_TCP_CONTEXT_MAGIC);
3575 Context->Magic = 'CDAB';
3582 /* release mdl chain */
3583 if (Irp->MdlAddress) {
3584 KsReleaseMdl(Irp->MdlAddress, FALSE);
3587 /* free irp packet */
3596 * KsTcpCompletionRoutine
3597 * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
3598 * We need call the use's own CompletionRoutine if specified. Or
3599 * it's a synchronous case, we need signal the event.
3602 * DeviceObject: the device object of the transport
3603 * Irp: the Irp is being completed.
3604 * Context: the context we specified when issuing the Irp
3614 KsTcpCompletionRoutine(
3615 IN PDEVICE_OBJECT DeviceObject,
3622 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3623 ks_tconn_t * tconn = NULL;
3625 context = (PKS_TCP_COMPLETION_CONTEXT) Context;
3626 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3627 tconn = context->tconn;
3629 if (context->CompletionRoutine) {
3632 // Giving control to user specified CompletionRoutine ...
3635 context->CompletionRoutine(Irp, context);
3640 // Signaling the Event ...
3642 LASSERT(NULL != context->Event);
3643 KeSetEvent(context->Event, 0, FALSE);
3645 /* drop the reference count of the tconn object */
3646 ks_put_tconn(tconn);
3651 /* cfs_enter_debugger(); */
3654 return STATUS_MORE_PROCESSING_REQUIRED;
3658 * KsTcpSendCompletionRoutine
3659 * the user specified Irp completion routine for asynchronous
3660 * data transmission requests.
3662 * It will do th cleanup job of the ks_tx_t and wake up the
3663 * ks scheduler thread
3666 * Irp: the Irp is being completed.
3667 * Context: the context we specified when issuing the Irp
3677 KsTcpSendCompletionRoutine(
3679 IN PKS_TCP_COMPLETION_CONTEXT context
3682 NTSTATUS status = Irp->IoStatus.Status;
3683 ULONG rc = (ULONG)(ULONG_PTR)Irp->IoStatus.Information;
3684 ks_tconn_t * tconn = context->tconn;
3686 PKS_TSDUMGR TsduMgr = context->TsduMgr;
3687 PKEVENT Event = context->Event;
3689 LASSERT(tconn != NULL && tconn->kstc_magic == KS_TCONN_MAGIC);
3690 LASSERT(context && context->Magic == KS_TCP_CONTEXT_MAGIC);
3692 KsPrint((4, "KsTcpSendCompltionRoutine: tconn = %p TsduMgr = %p "
3693 "status = %xh bytes = %xh/%x\n", tconn, TsduMgr, status,
3694 Irp->IoStatus.Information, TsduMgr->TotalBytes));
3696 ks_lock_tsdumgr(TsduMgr);
3698 if (NT_SUCCESS(status)) {
3700 /* cleanup processed TsduMgr queue */
3701 KsReleaseTsdus(tconn, TsduMgr, rc);
3703 /* queue to delivery engine if there's still remained data */
3704 TsduMgr->Busy = FALSE;
3705 if (TsduMgr->TotalBytes > 0) {
3706 KsQueueTdiEngine(tconn, TsduMgr);
3708 /* signal TsduMgr event */
3709 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3710 ks_unlock_tsdumgr(TsduMgr);
3713 * now it's time to re-queue the conns into the
3714 * scheduler queue and wake the scheduler thread.
3717 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3718 tconn->kstc_sched_cb(tconn, TRUE);
3723 ks_unlock_tsdumgr(TsduMgr);
3725 KsPrint((1, "KsTcpSendCompltionRoutine: failed tconn: %p "
3726 "TsduMgr: %p status: %xh\n", tconn, TsduMgr, status));
3728 /* cfs_enter_debugger(); */
3731 * for the case that the transmission is unsuccessful,
3732 * we need abort the tdi connection, but not destroy it.
3733 * the socknal conn will drop the refer count, then the
3734 * tdi connection will be freed.
3737 ks_abort_tconn(tconn);
3740 /* drop tconn reference */
3741 ks_put_tconn(tconn);
3743 /* freeing the context structure */
3745 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3746 context->Magic = 'CDAB';
3750 /* free the Irp structure */
3752 /* mdl chain was released by KsReleaseTsdus*/
3753 Irp->MdlAddress = NULL;
3762 * Normal receive event handler
3764 * It will move data from system Tsdu to our TsduList
3768 KsTcpReceiveEventHandler(
3769 IN PVOID TdiEventContext,
3770 IN CONNECTION_CONTEXT ConnectionContext,
3771 IN ULONG ReceiveFlags,
3772 IN ULONG BytesIndicated,
3773 IN ULONG BytesAvailable,
3774 OUT ULONG * BytesTaken,
3776 OUT PIRP * IoRequestPacket
3783 BOOLEAN bIsExpedited;
3784 BOOLEAN bIsCompleteTsdu;
3786 PCHAR Buffer = NULL;
3789 PFILE_OBJECT FileObject;
3790 PDEVICE_OBJECT DeviceObject;
3791 PKS_TSDUMGR TsduMgr;
3793 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3795 tconn = (ks_tconn_t *) ConnectionContext;
3796 ks_get_tconn(tconn);
3798 /* check expedited flag */
3799 bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
3801 /* check whether the whole body of payload is received or not */
3802 if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
3803 (BytesIndicated == BytesAvailable) ) {
3804 bIsCompleteTsdu = TRUE;
3806 bIsCompleteTsdu = FALSE;
3809 KsPrint((4, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n",
3810 BytesIndicated, BytesAvailable));
3811 KsPrint((4, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
3813 /* check whether we are conntected or not listener */
3814 if ( !((tconn->kstc_state == ksts_connected) &&
3815 (tconn->kstc_type == kstt_sender ||
3816 tconn->kstc_type == kstt_child))) {
3818 *BytesTaken = BytesIndicated;
3819 ks_put_tconn(tconn);
3820 return (STATUS_SUCCESS);
3823 /* query tsdu mgr */
3824 TsduMgr = KsQueryTsduMgr(tconn, bIsExpedited, FALSE);
3826 ks_lock_tsdumgr(TsduMgr);
3827 if (bIsCompleteTsdu) {
3829 *BytesTaken = KsWriteTsduDat(TsduMgr, Tsdu, BytesAvailable, 0);
3830 status = STATUS_SUCCESS;
3832 /* signal TsduMgr event */
3833 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3834 ks_unlock_tsdumgr(TsduMgr);
3836 /* re-active the ks connection and wake up the scheduler */
3837 if (KS_CAN_SCHED(TsduMgr)) {
3838 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3839 tconn->kstc_sched_cb(tconn, FALSE);
3845 ks_unlock_tsdumgr(TsduMgr);
3847 /* allocate buffer for further data in tsdu queue */
3848 Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
3849 if (NULL == Buffer) {
3850 status = STATUS_INSUFFICIENT_RESOURCES;
3854 /* there's still data in tdi internal queue, we need issue a new
3855 Irp to receive all of them. first allocate the tcp context */
3856 context = kmalloc(sizeof(KS_TCP_COMPLETION_CONTEXT), 0);
3858 status = STATUS_INSUFFICIENT_RESOURCES;
3862 /* setup the context */
3863 RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
3864 context->Magic = KS_TCP_CONTEXT_MAGIC;
3865 context->tconn = tconn;
3866 context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
3867 context->CompletionContext = Buffer;
3868 context->TsduMgr = TsduMgr;
3869 context->Buffer = Buffer;
3870 context->Event = &(TsduMgr->Event);
3872 if (tconn->kstc_type == kstt_sender) {
3873 FileObject = tconn->sender.kstc_info.FileObject;
3875 FileObject = tconn->child.kstc_info.FileObject;
3877 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3879 /* build new tdi Irp and setup it. */
3880 Irp = KsBuildTdiIrp(DeviceObject);
3885 status = KsLockUserBuffer(
3893 if (!NT_SUCCESS(status)) {
3901 KsTcpCompletionRoutine,
3904 ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
3908 IoSetNextIrpStackLocation(Irp);
3910 /* return the newly built Irp to transport driver,
3911 it will process it to receive all the data */
3913 *IoRequestPacket = Irp;
3916 ks_get_tconn(tconn);
3917 status = STATUS_MORE_PROCESSING_REQUIRED;
3920 ks_put_tconn(tconn);
3927 KsReleaseMdl(Mdl, FALSE);
3939 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3940 context->Magic = 'CDAB';
3944 ks_abort_tconn(tconn);
3945 ks_put_tconn(tconn);
3947 *BytesTaken = BytesAvailable;
3949 return STATUS_SUCCESS;
3953 * Expedited receive event handler
3957 KsTcpReceiveExpeditedEventHandler(
3958 IN PVOID TdiEventContext,
3959 IN CONNECTION_CONTEXT ConnectionContext,
3960 IN ULONG ReceiveFlags,
3961 IN ULONG BytesIndicated,
3962 IN ULONG BytesAvailable,
3963 OUT ULONG * BytesTaken,
3965 OUT PIRP * IoRequestPacket
3968 return KsTcpReceiveEventHandler(
3971 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
3981 * Bulk receive event handler
3983 * It will queue all the system Tsdus to our TsduList.
3984 * Then later ks_recv_mdl will release them.
3988 KsTcpChainedReceiveEventHandler (
3989 IN PVOID TdiEventContext, // the event context
3990 IN CONNECTION_CONTEXT ConnectionContext,
3991 IN ULONG ReceiveFlags,
3992 IN ULONG ReceiveLength,
3993 IN ULONG StartingOffset, // offset of start of client data in TSDU
3994 IN PMDL Tsdu, // TSDU data chain
3995 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4002 PKS_TSDUMGR TsduMgr;
4006 tconn = (ks_tconn_t *) ConnectionContext;
4007 expedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
4009 KsPrint((4, "KsTcpChainedReceive: sock: %p conn: %p ReceiveLength: %xh "
4010 "bIsExpedited: %d Tsdu=%p TsduDesc=%p data=%xh\n",
4011 tconn, tconn->kstc_conn, ReceiveLength, expedited,
4012 Tsdu, TsduDescriptor, *((PULONG)KsMapMdlBuffer(Tsdu))));
4014 ks_get_tconn(tconn);
4016 /* check whether we are conntected or not listener */
4017 if ( !((tconn->kstc_state == ksts_connected) &&
4018 (tconn->kstc_type == kstt_sender ||
4019 tconn->kstc_type == kstt_child))) {
4021 ks_put_tconn(tconn);
4022 return (STATUS_SUCCESS);
4027 TsduMgr = KsQueryTsduMgr(tconn, expedited, FALSE);
4028 ks_lock_tsdumgr(TsduMgr);
4030 KsWriteTsduMdl(TsduMgr, Tsdu, TsduDescriptor,
4031 StartingOffset, ReceiveLength, 0);
4032 status = STATUS_PENDING;
4034 KsWriteTsduDat(TsduMgr, (PCHAR)KsMapMdlBuffer(Tsdu) +
4035 StartingOffset, ReceiveLength, 0);
4036 status = STATUS_SUCCESS;
4038 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
4039 ks_unlock_tsdumgr(TsduMgr);
4041 /* re-active the ks connection and wake up the scheduler */
4042 if (KS_CAN_SCHED(TsduMgr)) {
4043 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
4044 tconn->kstc_sched_cb(tconn, FALSE);
4050 ks_abort_tconn(tconn);
4051 status = STATUS_CONNECTION_ABORTED;
4054 ks_put_tconn(tconn);
4056 /* Return STATUS_PENDING to system because we are still
4057 owning the MDL resources. ks_recv_mdl is expected
4058 to free the MDL resources. */
4065 * Expedited & Bulk receive event handler
4069 KsTcpChainedReceiveExpeditedEventHandler (
4070 IN PVOID TdiEventContext, // the event context
4071 IN CONNECTION_CONTEXT ConnectionContext,
4072 IN ULONG ReceiveFlags,
4073 IN ULONG ReceiveLength,
4074 IN ULONG StartingOffset, // offset of start of client data in TSDU
4075 IN PMDL Tsdu, // TSDU data chain
4076 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4079 return KsTcpChainedReceiveEventHandler(
4082 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
4092 * setup all the event handler callbacks
4095 * tconn: the tdi connecton object
4098 * int: ks error code
4109 NTSTATUS status = STATUS_SUCCESS;
4110 KS_EVENT_HANDLERS handlers;
4112 /* to make sure the address object is opened already */
4113 if (tconn->kstc_addr.FileObject == NULL) {
4117 /* initialize the handlers indictor array. for sender and listenr,
4118 there are different set of callbacks. for child, we just return. */
4120 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4122 SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
4123 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
4124 SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
4125 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
4126 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
4128 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
4130 if (tconn->kstc_type == kstt_listener) {
4131 SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
4132 } else if (tconn->kstc_type == kstt_child) {
4136 /* set all the event callbacks */
4137 status = KsSetEventHandlers(
4138 tconn->kstc_addr.FileObject, /* Address File Object */
4139 tconn, /* Event Context */
4140 &handlers /* Event callback handlers */
4145 return cfs_error_code(status);
4151 * disable all the event handler callbacks (set to NULL)
4154 * tconn: the tdi connecton object
4157 * int: ks error code
4168 NTSTATUS status = STATUS_SUCCESS;
4169 KS_EVENT_HANDLERS handlers;
4171 /* to make sure the address object is opened already */
4172 if (tconn->kstc_addr.FileObject == NULL) {
4176 /* initialize the handlers indictor array. for sender and listenr,
4177 there are different set of callbacks. for child, we just return. */
4179 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4181 SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
4182 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
4183 SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
4184 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
4185 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
4186 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
4188 if (tconn->kstc_type == kstt_listener) {
4189 SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
4190 } else if (tconn->kstc_type == kstt_child) {
4194 /* set all the event callbacks */
4195 status = KsSetEventHandlers(
4196 tconn->kstc_addr.FileObject, /* Address File Object */
4197 tconn, /* Event Context */
4198 &handlers /* Event callback handlers */
4203 return cfs_error_code(status);
4207 KsPrintProviderInfo(
4209 PTDI_PROVIDER_INFO ProviderInfo
4212 KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
4214 KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
4215 KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
4216 KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
4217 KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
4218 KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
4220 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
4221 KsPrint((2, " CONNECTION_MODE\n"));
4224 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
4225 KsPrint((2, " ORDERLY_RELEASE\n"));
4228 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
4229 KsPrint((2, " CONNECTIONLESS_MODE\n"));
4232 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
4233 KsPrint((2, " ERROR_FREE_DELIVERY\n"));
4236 if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
4237 KsPrint((2, " SECURITY_LEVEL\n"));
4240 if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
4241 KsPrint((2, " BROADCAST_SUPPORTED\n"));
4244 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
4245 KsPrint((2, " MULTICAST_SUPPORTED\n"));
4248 if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
4249 KsPrint((2, " DELAYED_ACCEPTANCE\n"));
4252 if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
4253 KsPrint((2, " EXPEDITED_DATA\n"));
4256 if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
4257 KsPrint((2, " INTERNAL_BUFFERING\n"));
4260 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
4261 KsPrint((2, " ROUTE_DIRECTED\n"));
4264 if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
4265 KsPrint((2, " NO_ZERO_LENGTH\n"));
4268 if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
4269 KsPrint((2, " POINT_TO_POINT\n"));
4272 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
4273 KsPrint((2, " MESSAGE_MODE\n"));
4276 if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
4277 KsPrint((2, " HALF_DUPLEX\n"));
4280 KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
4281 KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
4282 KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
4288 * allocate a new tconn structure from the SLAB cache or
4289 * NonPaged sysetm pool
4295 * ks_tconn_t *: the address of tconn or NULL if it fails
4304 ks_tconn_t * tconn = NULL;
4306 /* allocate ksoc_tconn_t from the slab cache memory */
4307 tconn = (ks_tconn_t *)kmem_cache_alloc(
4308 ks_data.ksnd_tconn_slab, __GFP_ZERO);
4312 /* zero tconn elements */
4313 memset(tconn, 0, sizeof(ks_tconn_t));
4315 /* initialize the tconn ... */
4316 tconn->kstc_magic = KS_TCONN_MAGIC;
4318 ExInitializeWorkItem(
4319 &(tconn->kstc_disconnect.WorkItem),
4321 &(tconn->kstc_disconnect)
4325 &(tconn->kstc_disconnect.Event),
4326 SynchronizationEvent,
4329 ExInitializeWorkItem(
4330 &(tconn->kstc_destroy),
4335 spin_lock_init(&(tconn->kstc_lock));
4337 ks_get_tconn(tconn);
4338 spin_lock(&(ks_data.ksnd_tconn_lock));
4340 /* attach it into global list in ks_data */
4342 list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
4343 ks_data.ksnd_ntconns++;
4344 spin_unlock(&(ks_data.ksnd_tconn_lock));
4346 tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
4348 KsPrint((3, "ks_create_tconn: new connection: %p\n", tconn));
4354 * free the tconn structure to the SLAB cache or NonPaged
4358 * tconn: the tcon is to be freed
4368 ks_free_tconn(ks_tconn_t * tconn)
4370 LASSERT(atomic_read(&(tconn->kstc_refcount)) == 0);
4372 spin_lock(&(ks_data.ksnd_tconn_lock));
4374 /* remove it from the global list */
4375 list_del(&tconn->kstc_list);
4376 ks_data.ksnd_ntconns--;
4378 /* if this is the last tconn, it would be safe for
4379 ks_tdi_fini_data to quit ... */
4380 if (ks_data.ksnd_ntconns == 0) {
4381 cfs_wake_event(&ks_data.ksnd_tconn_exit);
4383 spin_unlock(&(ks_data.ksnd_tconn_lock));
4385 /* free the structure memory */
4386 kmem_cache_free(ks_data.ksnd_tconn_slab, tconn);
4388 KsPrint((3, "ks_free_tconn: tconn %p is freed.\n", tconn));
4394 * Initialize the tconn as a listener (daemon)
4397 * tconn: the listener tconn
4411 /* preparation: intialize the tconn members */
4413 tconn->kstc_type = kstt_listener;
4415 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4417 INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
4418 INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
4420 cfs_init_event( &(tconn->listener.kstc_accept_event),
4424 cfs_init_event( &(tconn->listener.kstc_destroy_event),
4428 tconn->kstc_state = ksts_inited;
4434 * Initialize the tconn as a sender
4437 * tconn: the sender tconn
4451 tconn->kstc_type = kstt_sender;
4452 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4454 KsInitializeKsChain(&(tconn->sender.kstc_recv));
4455 KsInitializeKsChain(&(tconn->sender.kstc_send));
4457 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4458 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4460 tconn->kstc_state = ksts_inited;
4465 * Initialize the tconn as a child
4468 * tconn: the child tconn
4482 tconn->kstc_type = kstt_child;
4483 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4485 KsInitializeKsChain(&(tconn->child.kstc_recv));
4486 KsInitializeKsChain(&(tconn->child.kstc_send));
4488 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4489 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4491 tconn->kstc_state = ksts_inited;
4496 * increase the reference count of the tconn with 1
4499 * tconn: the tdi connection to be referred
4513 atomic_inc(&(tconn->kstc_refcount));
4518 * decrease the reference count of the tconn and destroy
4519 * it if the refercount becomes 0.
4522 * tconn: the tdi connection to be dereferred
4536 if (atomic_dec_and_test(&(tconn->kstc_refcount))) {
4538 spin_lock(&(tconn->kstc_lock));
4540 if ( ( tconn->kstc_type == kstt_child ||
4541 tconn->kstc_type == kstt_sender ) &&
4542 ( tconn->kstc_state == ksts_connected ) ) {
4544 spin_unlock(&(tconn->kstc_lock));
4546 ks_abort_tconn(tconn);
4550 if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
4551 cfs_enter_debugger();
4554 &(tconn->kstc_destroy),
4558 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
4561 spin_unlock(&(tconn->kstc_lock));
4568 * cleanup the tdi connection and free it
4571 * tconn: the tdi connection to be cleaned.
4585 LASSERT(tconn->kstc_refcount.counter == 0);
4587 if (tconn->kstc_type == kstt_listener) {
4589 KsResetHandlers(tconn);
4591 /* for listener, we just need to close the address object */
4593 tconn->kstc_addr.Handle,
4594 tconn->kstc_addr.FileObject
4597 tconn->kstc_state = ksts_inited;
4599 } else if (tconn->kstc_type == kstt_child) {
4601 /* for child tdi conections */
4603 /* disassociate the relation between it's connection object
4604 and the address object */
4606 if (tconn->kstc_state == ksts_associated) {
4607 KsDisassociateAddress(
4608 tconn->child.kstc_info.FileObject
4612 /* release the connection object */
4615 tconn->child.kstc_info.Handle,
4616 tconn->child.kstc_info.FileObject
4619 /* release it's refer of it's parent's address object */
4622 tconn->kstc_addr.FileObject
4625 spin_lock(&tconn->child.kstc_parent->kstc_lock);
4626 spin_lock(&tconn->kstc_lock);
4628 tconn->kstc_state = ksts_inited;
4630 /* remove it frome it's parent's queues */
4632 if (tconn->child.kstc_queued) {
4634 list_del(&(tconn->child.kstc_link));
4636 if (tconn->child.kstc_queueno) {
4638 LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
4639 tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
4643 LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
4644 tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
4647 tconn->child.kstc_queued = FALSE;
4650 spin_unlock(&tconn->kstc_lock);
4651 spin_unlock(&tconn->child.kstc_parent->kstc_lock);
4653 /* drop the reference of the parent tconn */
4654 ks_put_tconn(tconn->child.kstc_parent);
4656 } else if (tconn->kstc_type == kstt_sender) {
4658 KsResetHandlers(tconn);
4660 /* release the connection object */
4663 tconn->sender.kstc_info.Handle,
4664 tconn->sender.kstc_info.FileObject
4667 /* release it's refer of it's parent's address object */
4669 tconn->kstc_addr.Handle,
4670 tconn->kstc_addr.FileObject
4673 tconn->kstc_state = ksts_inited;
4676 cfs_enter_debugger();
4679 /* free the tconn structure ... */
4681 ks_free_tconn(tconn);
4686 * Query the the options of the tcp stream connnection
4689 * tconn: the tdi connection
4691 * OptionValue: buffer to store the option value
4692 * Length: the length of the value, to be returned
4695 * int: ks return code
4709 NTSTATUS Status = STATUS_SUCCESS;
4711 IO_STATUS_BLOCK IoStatus;
4713 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
4715 PFILE_OBJECT ConnectionObject;
4716 PDEVICE_OBJECT DeviceObject = NULL;
4719 PIO_STACK_LOCATION IrpSp = NULL;
4723 /* make sure the tdi connection is connected ? */
4725 ks_get_tconn(tconn);
4727 if (tconn->kstc_state != ksts_connected) {
4728 Status = STATUS_INVALID_PARAMETER;
4732 LASSERT(tconn->kstc_type == kstt_sender ||
4733 tconn->kstc_type == kstt_child);
4735 if (tconn->kstc_type == kstt_sender) {
4736 ConnectionObject = tconn->sender.kstc_info.FileObject;
4738 ConnectionObject = tconn->child.kstc_info.FileObject;
4741 QueryInfoEx.ID.toi_id = ID;
4742 QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
4743 QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
4744 QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
4745 QueryInfoEx.ID.toi_entity.tei_instance = 0;
4747 RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
4749 KeInitializeEvent(&Event, NotificationEvent, FALSE);
4750 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4752 Irp = IoBuildDeviceIoControlRequest(
4753 IOCTL_TCP_QUERY_INFORMATION_EX,
4756 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
4765 Status = STATUS_INSUFFICIENT_RESOURCES;
4769 IrpSp = IoGetNextIrpStackLocation(Irp);
4771 if (IrpSp == NULL) {
4775 Status = STATUS_INSUFFICIENT_RESOURCES;
4779 IrpSp->FileObject = ConnectionObject;
4780 IrpSp->DeviceObject = DeviceObject;
4782 Status = IoCallDriver(DeviceObject, Irp);
4784 if (Status == STATUS_PENDING) {
4786 KeWaitForSingleObject(
4794 Status = IoStatus.Status;
4798 if (NT_SUCCESS(Status)) {
4799 *Length = (ULONG)(ULONG_PTR)IoStatus.Information;
4801 cfs_enter_debugger();
4802 memset(OptionValue, 0, *Length);
4803 Status = STATUS_SUCCESS;
4808 ks_put_tconn(tconn);
4810 return cfs_error_code(Status);
4815 * Set the the options for the tcp stream connnection
4818 * tconn: the tdi connection
4820 * OptionValue: buffer containing the new option value
4821 * Length: the length of the value
4824 * int: ks return code
4838 NTSTATUS Status = STATUS_SUCCESS;
4840 IO_STATUS_BLOCK IoStatus;
4842 ULONG SetInfoExLength;
4843 PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
4845 PFILE_OBJECT ConnectionObject;
4846 PDEVICE_OBJECT DeviceObject = NULL;
4849 PIO_STACK_LOCATION IrpSp = NULL;
4853 /* make sure the tdi connection is connected ? */
4855 ks_get_tconn(tconn);
4857 if (tconn->kstc_state != ksts_connected) {
4858 Status = STATUS_INVALID_PARAMETER;
4862 LASSERT(tconn->kstc_type == kstt_sender ||
4863 tconn->kstc_type == kstt_child);
4865 if (tconn->kstc_type == kstt_sender) {
4866 ConnectionObject = tconn->sender.kstc_info.FileObject;
4868 ConnectionObject = tconn->child.kstc_info.FileObject;
4871 SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
4873 SetInfoEx = ExAllocatePoolWithTag(
4879 if (SetInfoEx == NULL) {
4880 Status = STATUS_INSUFFICIENT_RESOURCES;
4884 SetInfoEx->ID.toi_id = ID;
4886 SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
4887 SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
4888 SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
4889 SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
4891 SetInfoEx->BufferSize = Length;
4892 RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
4894 Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
4895 KeInitializeEvent(Event, NotificationEvent, FALSE);
4897 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4899 Irp = IoBuildDeviceIoControlRequest(
4900 IOCTL_TCP_SET_INFORMATION_EX,
4912 Status = STATUS_INSUFFICIENT_RESOURCES;
4916 IrpSp = IoGetNextIrpStackLocation(Irp);
4918 if (IrpSp == NULL) {
4921 Status = STATUS_INSUFFICIENT_RESOURCES;
4925 IrpSp->FileObject = ConnectionObject;
4926 IrpSp->DeviceObject = DeviceObject;
4928 Status = IoCallDriver(DeviceObject, Irp);
4930 if (Status == STATUS_PENDING) {
4932 KeWaitForSingleObject(
4940 Status = IoStatus.Status;
4946 ExFreePool(SetInfoEx);
4949 if (!NT_SUCCESS(Status)) {
4950 KsPrint((0, "ks_set_tcp_option: error setup tcp option: "
4951 "ID (%d) Status = %xh\n", ID, Status));
4952 Status = STATUS_SUCCESS;
4955 ks_put_tconn(tconn);
4957 return cfs_error_code(Status);
4962 * bind the tdi connection object with an address
4965 * tconn: tconn to be bound
4966 * parent: the parent tconn object
4967 * ipaddr: the ip address
4968 * port: the port number
4971 * int: 0 for success or ks error codes.
4980 ks_tconn_t * parent,
4988 ks_tdi_addr_t taddr;
4990 memset(&taddr, 0, sizeof(ks_tdi_addr_t));
4992 if (tconn->kstc_state != ksts_inited) {
4994 status = STATUS_INVALID_PARAMETER;
4995 rc = cfs_error_code(status);
4998 } else if (tconn->kstc_type == kstt_child) {
5000 if (NULL == parent) {
5001 status = STATUS_INVALID_PARAMETER;
5002 rc = cfs_error_code(status);
5007 /* refer it's parent's address object */
5009 taddr = parent->kstc_addr;
5010 ObReferenceObject(taddr.FileObject);
5012 ks_get_tconn(parent);
5016 PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
5019 /* intialize the tdi address*/
5021 TdiAddress->TAAddressCount = 1;
5022 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5023 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5025 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5026 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5028 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5031 /* open the transport address object */
5033 AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
5034 TDI_ADDRESS_LENGTH_IP;
5036 status = KsOpenAddress(
5044 if (!NT_SUCCESS(status)) {
5046 KsPrint((1, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
5047 addr, port, status ));
5048 rc = cfs_error_code(status);
5053 if (tconn->kstc_type == kstt_child) {
5054 tconn->child.kstc_parent = parent;
5057 tconn->kstc_state = ksts_bind;
5058 tconn->kstc_addr = taddr;
5067 * build tcp/streaming connection to remote peer
5070 * tconn: tconn to be connected to the peer
5071 * addr: the peer's ip address
5072 * port: the peer's port number
5075 * int: 0 for success or ks error codes.
5089 NTSTATUS status = STATUS_SUCCESS;
5092 PFILE_OBJECT ConnectionObject = NULL;
5093 PDEVICE_OBJECT DeviceObject = NULL;
5095 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
5100 LASSERT(tconn->kstc_type == kstt_sender);
5101 LASSERT(tconn->kstc_state == ksts_bind);
5103 ks_get_tconn(tconn);
5106 /* set the event callbacks */
5107 rc = KsSetHandlers(tconn);
5110 cfs_enter_debugger();
5115 /* create the connection file handle / object */
5116 status = KsOpenConnection(
5118 (CONNECTION_CONTEXT)tconn,
5119 &(tconn->sender.kstc_info.Handle),
5120 &(tconn->sender.kstc_info.FileObject)
5123 if (!NT_SUCCESS(status)) {
5124 rc = cfs_error_code(status);
5125 cfs_enter_debugger();
5129 /* associdate the the connection with the adress object of the tconn */
5131 status = KsAssociateAddress(
5132 tconn->kstc_addr.Handle,
5133 tconn->sender.kstc_info.FileObject
5136 if (!NT_SUCCESS(status)) {
5137 rc = cfs_error_code(status);
5138 cfs_enter_debugger();
5142 tconn->kstc_state = ksts_associated;
5144 /* Allocating Connection Info Together with the Address */
5145 AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
5146 + TDI_ADDRESS_LENGTH_IP;
5148 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
5149 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
5151 if (NULL == ConnectionInfo) {
5153 status = STATUS_INSUFFICIENT_RESOURCES;
5154 rc = cfs_error_code(status);
5155 cfs_enter_debugger();
5159 /* Initializing ConnectionInfo ... */
5161 PTRANSPORT_ADDRESS TdiAddress;
5163 /* ConnectionInfo settings */
5165 ConnectionInfo->UserDataLength = 0;
5166 ConnectionInfo->UserData = NULL;
5167 ConnectionInfo->OptionsLength = 0;
5168 ConnectionInfo->Options = NULL;
5169 ConnectionInfo->RemoteAddressLength = AddrLength;
5170 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
5173 /* intialize the tdi address*/
5175 TdiAddress = ConnectionInfo->RemoteAddress;
5177 TdiAddress->TAAddressCount = 1;
5178 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5179 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5181 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5182 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5184 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5187 /* Now prepare to connect the remote peer ... */
5189 ConnectionObject = tconn->sender.kstc_info.FileObject;
5190 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5192 /* allocate a new Irp */
5194 Irp = KsBuildTdiIrp(DeviceObject);
5198 status = STATUS_INSUFFICIENT_RESOURCES;
5199 rc = cfs_error_code(status);
5200 cfs_enter_debugger();
5218 /* sumbit the Irp to the underlying transport driver */
5219 status = KsSubmitTdiIrp(
5226 spin_lock(&(tconn->kstc_lock));
5228 if (NT_SUCCESS(status)) {
5230 /* Connected! the conneciton is built successfully. */
5232 tconn->kstc_state = ksts_connected;
5234 tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
5235 tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
5237 spin_unlock(&(tconn->kstc_lock));
5241 /* Not connected! Abort it ... */
5244 cfs_enter_debugger();
5248 rc = cfs_error_code(status);
5250 tconn->kstc_state = ksts_associated;
5251 spin_unlock(&(tconn->kstc_lock));
5253 /* disassocidate the connection and the address object,
5254 after cleanup, it's safe to set the state to abort ... */
5256 if ( NT_SUCCESS(KsDisassociateAddress(
5257 tconn->sender.kstc_info.FileObject))) {
5258 tconn->kstc_state = ksts_aborted;
5261 /* reset the event callbacks */
5262 rc = KsResetHandlers(tconn);
5269 if (NT_SUCCESS(status)) {
5271 ks_query_local_ipaddr(tconn);
5275 if (ConnectionInfo) {
5276 ExFreePool(ConnectionInfo);
5283 ks_put_tconn(tconn);
5290 * ks_disconnect_tconn
5291 * disconnect the tconn from a connection
5294 * tconn: the tdi connecton object connected already
5295 * flags: flags & options for disconnecting
5298 * int: ks error code
5305 ks_disconnect_tconn(
5310 NTSTATUS status = STATUS_SUCCESS;
5312 ks_tconn_info_t * info;
5314 PFILE_OBJECT ConnectionObject;
5315 PDEVICE_OBJECT DeviceObject = NULL;
5321 ks_get_tconn(tconn);
5323 /* make sure tt's connected already and it
5324 must be a sender or a child ... */
5326 LASSERT(tconn->kstc_state == ksts_connected);
5327 LASSERT( tconn->kstc_type == kstt_sender ||
5328 tconn->kstc_type == kstt_child);
5330 /* reset all the event handlers to NULL */
5332 if (tconn->kstc_type != kstt_child) {
5333 KsResetHandlers (tconn);
5336 /* Disconnecting to the remote peer ... */
5338 if (tconn->kstc_type == kstt_sender) {
5339 info = &(tconn->sender.kstc_info);
5341 info = &(tconn->child.kstc_info);
5344 ConnectionObject = info->FileObject;
5345 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5347 /* allocate an Irp and setup it */
5349 Irp = KsBuildTdiIrp(DeviceObject);
5353 status = STATUS_INSUFFICIENT_RESOURCES;
5354 cfs_enter_debugger();
5360 SynchronizationEvent,
5368 KsDisconectCompletionRoutine,
5376 /* issue the Irp to the underlying transport
5377 driver to disconnect the connection */
5379 status = IoCallDriver(DeviceObject, Irp);
5381 if (STATUS_PENDING == status) {
5383 status = KeWaitForSingleObject(
5391 status = Irp->IoStatus.Status;
5394 KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
5395 status, KsNtStatusToString(status)));
5399 if (info->ConnectionInfo) {
5401 /* disassociate the association between connection/address objects */
5403 status = KsDisassociateAddress(ConnectionObject);
5405 if (!NT_SUCCESS(status)) {
5406 cfs_enter_debugger();
5409 spin_lock(&(tconn->kstc_lock));
5411 /* cleanup the tsdumgr Lists */
5412 KsCleanupTsdu (tconn);
5414 /* set the state of the tconn */
5415 if (NT_SUCCESS(status)) {
5416 tconn->kstc_state = ksts_disconnected;
5418 tconn->kstc_state = ksts_associated;
5421 /* free the connection info to system pool*/
5422 ExFreePool(info->ConnectionInfo);
5423 info->ConnectionInfo = NULL;
5424 info->Remote = NULL;
5426 spin_unlock(&(tconn->kstc_lock));
5429 status = STATUS_SUCCESS;
5433 ks_put_tconn(tconn);
5435 return cfs_error_code(status);
5441 * The connection is broken un-expectedly. We need do
5445 * tconn: the tdi connection
5459 PKS_DISCONNECT_WORKITEM WorkItem = NULL;
5461 WorkItem = &(tconn->kstc_disconnect);
5463 ks_get_tconn(tconn);
5464 spin_lock(&(tconn->kstc_lock));
5466 if (tconn->kstc_state != ksts_connected) {
5467 ks_put_tconn(tconn);
5470 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
5472 WorkItem->Flags = TDI_DISCONNECT_ABORT;
5473 WorkItem->tconn = tconn;
5475 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
5478 &(WorkItem->WorkItem),
5484 spin_unlock(&(tconn->kstc_lock));
5489 * ks_query_local_ipaddr
5490 * query the local connection ip address
5493 * tconn: the tconn which is connected
5496 * int: ks error code
5503 ks_query_local_ipaddr(
5507 PFILE_OBJECT FileObject = NULL;
5510 PTRANSPORT_ADDRESS TdiAddress;
5511 ULONG AddressLength;
5513 if (tconn->kstc_type == kstt_sender) {
5514 FileObject = tconn->sender.kstc_info.FileObject;
5515 } else if (tconn->kstc_type == kstt_child) {
5516 FileObject = tconn->child.kstc_info.FileObject;
5518 status = STATUS_INVALID_PARAMETER;
5522 TdiAddress = &(tconn->kstc_addr.Tdi);
5523 AddressLength = MAX_ADDRESS_LENGTH;
5525 status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
5527 if (NT_SUCCESS(status)) {
5528 KsPrint((2, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
5529 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
5530 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
5532 KsPrint((2, "ks_query_local_ipaddr: Failed to query the connection local ip address.\n"));
5537 return cfs_error_code(status);
5541 KsCalcWhichEngine(ks_tconn_t * tconn)
5543 PTRANSPORT_ADDRESS TdiAddress = &(tconn->kstc_addr.Tdi);
5544 ULONG addr = ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr;
5545 ULONG sum = (addr & 0xFF) + ((addr & 0xFF00) >> 8) + ((addr & 0xFF0000) >> 16);
5547 return (int)(sum % ks_data.ksnd_engine_nums);
5551 KsQueueTdiEngine(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5553 ks_engine_mgr_t * engm;
5554 ks_engine_slot_t * engs;
5556 engm = &ks_data.ksnd_engine_mgr[KsCalcWhichEngine(tconn)];
5557 engs = &TsduMgr->Slot;
5559 if (!engs->queued) {
5560 spin_lock(&engm->lock);
5561 if (!engs->queued) {
5562 list_add_tail(&engs->link, &engm->list);
5563 engs->queued = TRUE;
5564 engs->tconn = tconn;
5566 engs->tsdumgr = TsduMgr;
5567 KeSetEvent(&(engm->start),0, FALSE);
5569 spin_unlock(&engm->lock);
5570 KsPrint((4, "KsQueueTdiEngine: TsduMgr=%p is queued to engine %p\n",
5573 KeSetEvent(&(engm->start),0, FALSE);
5577 KsRemoveTdiEngine(PKS_TSDUMGR TsduMgr)
5579 ks_engine_mgr_t * engm;
5580 ks_engine_slot_t * engs;
5582 engs = &TsduMgr->Slot;
5585 LASSERT(engm != NULL);
5586 spin_lock(&engm->lock);
5588 list_del(&engs->link);
5589 engs->queued = FALSE;
5592 engs->tsdumgr = NULL;
5594 spin_unlock(&engm->lock);
5595 KsPrint((4, "KsQueueTdiEngine: TsduMgr %p is removed from engine %p\n",
5601 KsDeliveryIrp(ks_tconn_t * tconn, PIRP irp)
5603 PFILE_OBJECT connobj;
5604 PDEVICE_OBJECT devobj;
5609 if (tconn->kstc_type == kstt_sender) {
5610 connobj = tconn->sender.kstc_info.FileObject;
5612 LASSERT(tconn->kstc_type == kstt_child);
5613 connobj = tconn->child.kstc_info.FileObject;
5615 devobj = IoGetRelatedDeviceObject(connobj);
5617 /* send irp to transport layer */
5618 status = IoCallDriver(devobj, irp);
5620 /* convert status to linux error code */
5621 if (!NT_SUCCESS(status)) {
5622 rc = cfs_error_code(status);
5625 KsPrint((4, "KsDeliveryIrp: tconn=%p irp=%p status=%xh rc=%d.\n",
5626 tconn, irp, status, rc));
5631 KsBuildSend(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr,
5632 ks_mdl_t * mdl, ulong flags )
5634 ks_tdi_tx_t * context;
5636 PFILE_OBJECT connobj;
5637 PDEVICE_OBJECT devobj;
5643 /* query mdl chain total length */
5644 length = KsQueryMdlsSize(mdl);
5646 /* we need allocate the ks_tx_t structure from memory pool. */
5647 context = kmalloc(sizeof(ks_tdi_tx_t), 0);
5649 status = STATUS_INSUFFICIENT_RESOURCES;
5653 /* intialize the TcpContext */
5654 memset(context,0, sizeof(ks_tdi_tx_t));
5655 context->Magic = KS_TCP_CONTEXT_MAGIC;
5656 context->tconn = tconn;
5657 context->CompletionRoutine = KsTcpSendCompletionRoutine;
5658 context->TsduMgr = TsduMgr;
5659 context->Length = length;
5662 if (tconn->kstc_type == kstt_sender) {
5663 connobj = tconn->sender.kstc_info.FileObject;
5665 LASSERT(tconn->kstc_type == kstt_child);
5666 connobj = tconn->child.kstc_info.FileObject;
5668 devobj = IoGetRelatedDeviceObject(connobj);
5669 irp = KsBuildTdiIrp(devobj);
5671 status = STATUS_INSUFFICIENT_RESOURCES;
5675 /* grab tconn reference */
5676 ks_get_tconn(tconn);
5678 /* delivery the sending request */
5683 KsTcpCompletionRoutine,
5694 /* free the context if is not used at all */
5696 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
5697 context->Magic = 'CDAB';
5701 /* here need free the Irp. */
5711 KsDeliveryTsdus(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5716 ks_mdl_t * mdl = NULL;
5720 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5722 ks_get_tconn(tconn);
5723 ks_lock_tsdumgr(TsduMgr);
5725 if ( tconn->kstc_type != kstt_sender &&
5726 tconn->kstc_type != kstt_child) {
5728 ks_unlock_tsdumgr(TsduMgr);
5732 if (tconn->kstc_state != ksts_connected) {
5734 ks_unlock_tsdumgr(TsduMgr);
5739 tflags = TDI_SEND_NON_BLOCKING | TDI_SEND_EXPEDITED;
5741 tflags = TDI_SEND_NON_BLOCKING;
5744 if (list_empty(&TsduMgr->TsduList)) {
5745 LASSERT(TsduMgr->TotalBytes == 0);
5746 ks_unlock_tsdumgr(TsduMgr);
5750 /* check whether there's outstanding sending requests */
5751 if (TsduMgr->Busy) {
5753 ks_unlock_tsdumgr(TsduMgr);
5757 /* probe all Tsdus and merge buffers together */
5758 mdl = KsLockTsdus(tconn, TsduMgr, &tflags, &length);
5761 LASSERT(TsduMgr->TotalBytes == 0);
5766 ks_unlock_tsdumgr(TsduMgr);
5770 KsPrint((4, "KsDeliveryTsdus: tconn=%p TsudMgr=%p, length=%xh/%xh\n",
5771 tconn, TsduMgr, length, TsduMgr->TotalBytes));
5773 /* build send irp request */
5774 irp = KsBuildSend(tconn, TsduMgr, mdl, tflags);
5777 ks_unlock_tsdumgr(TsduMgr);
5780 TsduMgr->Busy = TRUE;
5781 ks_unlock_tsdumgr(TsduMgr);
5783 /* delivery mdl chain */
5784 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5785 rc = KsDeliveryIrp(tconn, irp);
5792 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5793 ks_put_tconn(tconn);
5798 KsDeliveryEngineThread(void * context)
5800 ks_engine_mgr_t * engm = context;
5801 ks_engine_slot_t * engs;
5802 struct list_head * list;
5805 cfs_set_thread_priority(31);
5807 while (!engm->stop) {
5809 cfs_wait_event_internal(&engm->start, 0);
5811 spin_lock(&engm->lock);
5812 if (list_empty(&engm->list)) {
5813 spin_unlock(&engm->lock);
5817 list = engm->list.next;
5819 engs = list_entry(list, ks_engine_slot_t, link);
5820 LASSERT(engs->emgr == engm);
5821 LASSERT(engs->queued);
5823 engs->queued = FALSE;
5824 spin_unlock(&engm->lock);
5826 tconn = engs->tconn;
5827 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5829 KsPrint((4, "KsDeliveryEngineThread: %p active: tconn=%p "
5830 "TsduMgr=%p\n", engm, tconn, engs->tsdumgr));
5831 KsDeliveryTsdus(tconn, engs->tsdumgr);
5833 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5836 KeSetEvent(&engm->exit, 0, FALSE);
5843 * initialize the global data in ksockal_data
5849 * int: ks error code
5860 /* initialize tconn related globals */
5861 RtlZeroMemory(&ks_data, sizeof(ks_tdi_data_t));
5863 spin_lock_init(&ks_data.ksnd_tconn_lock);
5864 INIT_LIST_HEAD(&ks_data.ksnd_tconns);
5865 cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
5867 ks_data.ksnd_tconn_slab = kmem_cache_create("tcon", sizeof(ks_tconn_t),
5870 if (!ks_data.ksnd_tconn_slab) {
5875 /* initialize tsdu related globals */
5876 spin_lock_init(&ks_data.ksnd_tsdu_lock);
5877 INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
5878 ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
5879 ks_data.ksnd_tsdu_slab = kmem_cache_create("tsdu", ks_data.ksnd_tsdu_size,
5882 if (!ks_data.ksnd_tsdu_slab) {
5887 /* initialize engine threads list */
5888 ks_data.ksnd_engine_nums = num_online_cpus();
5889 if (ks_data.ksnd_engine_nums < 4) {
5890 ks_data.ksnd_engine_nums = 4;
5892 ks_data.ksnd_engine_mgr = kmalloc(sizeof(ks_engine_mgr_t) *
5893 ks_data.ksnd_engine_nums, __GFP_ZERO);
5894 if (ks_data.ksnd_engine_mgr == NULL) {
5898 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5899 spin_lock_init(&ks_data.ksnd_engine_mgr[i].lock);
5900 cfs_init_event(&ks_data.ksnd_engine_mgr[i].start, TRUE, FALSE);
5901 cfs_init_event(&ks_data.ksnd_engine_mgr[i].exit, TRUE, FALSE);
5902 INIT_LIST_HEAD(&ks_data.ksnd_engine_mgr[i].list);
5903 kthread_run(KsDeliveryEngineThread, &ks_data.ksnd_engine_mgr[i], "");
5906 /* register pnp handlers to watch network condition */
5907 KsRegisterPnpHandlers();
5911 /* do cleanup in case we get failures */
5913 if (ks_data.ksnd_tconn_slab) {
5914 kmem_cache_destroy(ks_data.ksnd_tconn_slab);
5915 ks_data.ksnd_tconn_slab = NULL;
5925 * finalize the global data in ksockal_data
5931 * int: ks error code
5940 PKS_TSDU KsTsdu = NULL;
5941 struct list_head * list = NULL;
5944 /* clean up the pnp handler and address slots */
5945 KsDeregisterPnpHandlers();
5947 /* stop all tcp sending engines */
5948 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5949 ks_data.ksnd_engine_mgr[i].stop = TRUE;
5950 KeSetEvent(&ks_data.ksnd_engine_mgr[i].start, 0, FALSE);
5953 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5954 cfs_wait_event_internal(&ks_data.ksnd_engine_mgr[i].exit, 0);
5957 /* we need wait until all the tconn are freed */
5958 spin_lock(&(ks_data.ksnd_tconn_lock));
5960 if (list_empty(&(ks_data.ksnd_tconns))) {
5961 cfs_wake_event(&ks_data.ksnd_tconn_exit);
5963 spin_unlock(&(ks_data.ksnd_tconn_lock));
5965 /* now wait on the tconn exit event */
5966 cfs_wait_event_internal(&ks_data.ksnd_tconn_exit, 0);
5968 /* it's safe to delete the tconn slab ... */
5969 kmem_cache_destroy(ks_data.ksnd_tconn_slab);
5970 ks_data.ksnd_tconn_slab = NULL;
5972 /* clean up all the tsud buffers in the free list */
5973 spin_lock(&(ks_data.ksnd_tsdu_lock));
5974 list_for_each (list, &ks_data.ksnd_freetsdus) {
5975 KsTsdu = list_entry (list, KS_TSDU, Link);
5978 ks_data.ksnd_tsdu_slab,
5981 spin_unlock(&(ks_data.ksnd_tsdu_lock));
5983 /* it's safe to delete the tsdu slab ... */
5984 kmem_cache_destroy(ks_data.ksnd_tsdu_slab);
5985 ks_data.ksnd_tsdu_slab = NULL;
5987 /* good! it's smooth to do the cleaning up...*/
5991 * ks_create_child_tconn
5992 * Create the backlog child connection for a listener
5995 * parent: the listener daemon connection
5998 * the child connection or NULL in failure
6005 ks_create_child_tconn(
6010 ks_tconn_t * backlog;
6012 /* allocate the tdi connecton object */
6013 backlog = ks_create_tconn();
6019 /* initialize the tconn as a child */
6020 ks_init_child(backlog);
6024 if (ks_bind_tconn(backlog, parent, 0, 0) < 0) {
6025 ks_free_tconn(backlog);
6030 /* open the connection object */
6031 status = KsOpenConnection(
6032 &(backlog->kstc_dev),
6034 &(backlog->child.kstc_info.Handle),
6035 &(backlog->child.kstc_info.FileObject)
6038 if (!NT_SUCCESS(status)) {
6040 ks_put_tconn(backlog);
6042 cfs_enter_debugger();
6046 /* associate it now ... */
6047 status = KsAssociateAddress(
6048 backlog->kstc_addr.Handle,
6049 backlog->child.kstc_info.FileObject
6052 if (!NT_SUCCESS(status)) {
6054 ks_put_tconn(backlog);
6056 cfs_enter_debugger();
6060 backlog->kstc_state = ksts_associated;
6068 * ks_replenish_backlogs(
6069 * to replenish the backlogs listening...
6072 * tconn: the parent listen tdi connect
6073 * nbacklog: number fo child connections in queue
6083 ks_replenish_backlogs(
6084 ks_tconn_t * parent,
6088 ks_tconn_t * backlog;
6091 /* calculate how many backlogs needed */
6092 if ( ( parent->listener.kstc_listening.num +
6093 parent->listener.kstc_accepted.num ) < nbacklog ) {
6094 n = nbacklog - ( parent->listener.kstc_listening.num +
6095 parent->listener.kstc_accepted.num );
6102 /* create the backlog child tconn */
6103 backlog = ks_create_child_tconn(parent);
6105 spin_lock(&(parent->kstc_lock));
6108 spin_lock(&backlog->kstc_lock);
6109 /* attch it into the listing list of daemon */
6110 list_add( &backlog->child.kstc_link,
6111 &parent->listener.kstc_listening.list );
6112 parent->listener.kstc_listening.num++;
6114 backlog->child.kstc_queued = TRUE;
6115 spin_unlock(&backlog->kstc_lock);
6117 cfs_enter_debugger();
6120 spin_unlock(&(parent->kstc_lock));
6126 * setup the listener tdi connection and make it listen
6127 * on the user specified ip address and port.
6130 * tconn: the parent listen tdi connect
6131 * nbacklog: number fo child connections in queue
6134 * ks error code >=: success; otherwise error.
6141 ks_start_listen(ks_tconn_t *tconn, int nbacklog)
6145 /* now replenish the backlogs */
6146 ks_replenish_backlogs(tconn, nbacklog);
6148 /* set the event callback handlers */
6149 rc = KsSetHandlers(tconn);
6155 spin_lock(&(tconn->kstc_lock));
6156 tconn->listener.nbacklog = nbacklog;
6157 tconn->kstc_state = ksts_listening;
6158 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6159 spin_unlock(&(tconn->kstc_lock));
6165 ks_stop_listen(ks_tconn_t *tconn)
6167 struct list_head * list;
6168 ks_tconn_t * backlog;
6170 /* reset all tdi event callbacks to NULL */
6171 KsResetHandlers (tconn);
6173 spin_lock(&tconn->kstc_lock);
6175 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6177 /* cleanup all the listening backlog child connections */
6178 list_for_each (list, &(tconn->listener.kstc_listening.list)) {
6179 backlog = list_entry(list, ks_tconn_t, child.kstc_link);
6181 /* destory and free it */
6182 ks_put_tconn(backlog);
6185 spin_unlock(&tconn->kstc_lock);
6187 /* wake up it from the waiting on new incoming connections */
6188 KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
6190 /* free the listening daemon tconn */
6191 ks_put_tconn(tconn);
6196 * ks_wait_child_tconn
6197 * accept a child connection from peer
6200 * parent: the daemon tdi connection listening
6201 * child: to contain the accepted connection
6211 ks_wait_child_tconn(
6212 ks_tconn_t * parent,
6216 struct list_head * tmp;
6217 ks_tconn_t * backlog = NULL;
6219 ks_replenish_backlogs(parent, parent->listener.nbacklog);
6221 spin_lock(&(parent->kstc_lock));
6223 if (parent->listener.kstc_listening.num <= 0) {
6224 spin_unlock(&(parent->kstc_lock));
6230 /* check the listening queue and try to search the accepted connecton */
6232 list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
6233 backlog = list_entry (tmp, ks_tconn_t, child.kstc_link);
6235 spin_lock(&(backlog->kstc_lock));
6237 if (backlog->child.kstc_accepted) {
6239 LASSERT(backlog->kstc_state == ksts_connected);
6240 LASSERT(backlog->child.kstc_busy);
6242 list_del(&(backlog->child.kstc_link));
6243 list_add(&(backlog->child.kstc_link),
6244 &(parent->listener.kstc_accepted.list));
6245 parent->listener.kstc_accepted.num++;
6246 parent->listener.kstc_listening.num--;
6247 backlog->child.kstc_queueno = 1;
6249 spin_unlock(&(backlog->kstc_lock));
6253 spin_unlock(&(backlog->kstc_lock));
6258 spin_unlock(&(parent->kstc_lock));
6260 /* we need wait until new incoming connections are requested
6261 or the case of shuting down the listenig daemon thread */
6262 if (backlog == NULL) {
6266 Status = KeWaitForSingleObject(
6267 &(parent->listener.kstc_accept_event),
6274 spin_lock(&(parent->kstc_lock));
6276 /* check whether it's exptected to exit ? */
6277 if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
6278 spin_unlock(&(parent->kstc_lock));
6284 KsPrint((2, "ks_wait_child_tconn: connection %p accepted.\n", backlog));
6287 /* query the local ip address of the connection */
6288 ks_query_local_ipaddr(backlog);
6298 ks_query_iovs_length(struct iovec *iov, int niov)
6303 LASSERT(iov != NULL);
6306 for (i=0; i < niov; i++) {
6307 total += iov[i].iov_len;
6314 ks_query_kiovs_length(lnet_kiov_t *kiov, int nkiov)
6319 LASSERT(kiov != NULL);
6322 for (i=0; i < nkiov; i++) {
6323 total += kiov[i].kiov_len;
6330 ks_sock_buf_cb(void *tsdu, int ns, int off, char **buf)
6335 *buf = (char *)tsdu + off;
6342 ks_sock_iov_cb(void *tsdu, int ns, int off, char **buf)
6345 struct iovec *iov = tsdu;
6347 for (i=0; i < ns; i++) {
6348 if ((size_t)off >= iov[i].iov_len) {
6349 off -= iov[i].iov_len;
6351 *buf = (char *)iov[i].iov_base + off;
6352 rc = iov[i].iov_len - off;
6360 ks_sock_kiov_cb(void *tsdu, int ns, int off, char **buf)
6363 lnet_kiov_t *kiov = tsdu;
6365 for (i=0; i < ns; i++) {
6366 if ((size_t)off >= kiov[i].kiov_len) {
6367 off -= kiov[i].kiov_len;
6369 *buf = (char *)kiov[i].kiov_page->addr +
6370 kiov[i].kiov_offset + off;
6371 rc = kiov[i].kiov_len - off;
6378 typedef int (*ks_tsdu_cb_t)(void *tsdu, int ns, int off, char **buf);
6381 ks_sock_io(ks_tconn_t *tconn, void *tsdu, int ns, int reqlen,
6382 int flags, int timeout, int out, ks_tsdu_cb_t callback)
6386 PKS_TSDUMGR TsduMgr;
6395 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6396 remained = (int64_t)cfs_time_seconds(timeout);
6398 /* query tsdu manager */
6399 expedited = cfs_is_flag_set(flags, MSG_OOB);
6400 TsduMgr = KsQueryTsduMgr(tconn, expedited, (BOOLEAN)out);
6402 /* check whether equest is nonblocking */
6403 if (async = cfs_is_flag_set(flags, MSG_DONTWAIT)) {
6407 ks_get_tconn(tconn);
6408 ks_lock_tsdumgr(TsduMgr);
6409 if ( tconn->kstc_type != kstt_sender &&
6410 tconn->kstc_type != kstt_child) {
6415 while (length = callback(tsdu, ns, total, &buffer)) {
6417 /* check whether socket is stil valid */
6418 if (tconn->kstc_state != ksts_connected) {
6424 tflags = KsTdiSendFlags(flags);
6425 rc = KsWriteTsdus(TsduMgr, buffer, length, tflags);
6427 tflags = KsTdiRecvFlags(flags);
6428 rc = KsReadTsdus(TsduMgr, buffer, length, tflags);
6433 } else if (!async && rc == -EAGAIN) {
6436 ks_unlock_tsdumgr(TsduMgr);
6437 remained = cfs_wait_event_internal(
6444 ks_unlock_tsdumgr(TsduMgr);
6445 cfs_wait_event_internal(&TsduMgr->Event, 0);
6447 ks_lock_tsdumgr(TsduMgr);
6456 TsduMgr->Payload = reqlen - total;
6458 ks_unlock_tsdumgr(TsduMgr);
6460 KsPrint((4, "ks_sock_io: tconn=%p tsdumgr=%p %c total=%xh/%xh rc=%d\n",
6461 tconn, TsduMgr, out?'W':'R', total, TsduMgr->TotalBytes, rc));
6465 /* signal Tdi sending engine */
6466 KsQueueTdiEngine(tconn, TsduMgr);
6471 ks_put_tconn(tconn);
6473 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6477 int ks_send_buf(ks_tconn_t * tconn, char *buf,
6478 int len, int flags, int timeout)
6480 return ks_sock_io(tconn, buf, len, len, flags,
6481 timeout, 1, ks_sock_buf_cb);
6484 int ks_recv_buf(ks_tconn_t * tconn, char *buf,
6485 int len, int flags, int timeout)
6487 return ks_sock_io(tconn, buf, len, len, flags,
6488 timeout, 0, ks_sock_buf_cb);
6491 int ks_send_iovs(ks_tconn_t * tconn, struct iovec *iov,
6492 int niov, int flags, int timeout)
6494 int reqlen = ks_query_iovs_length(iov, niov);
6495 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6496 timeout, TRUE, ks_sock_iov_cb);
6499 int ks_recv_iovs(ks_tconn_t * tconn, struct iovec *iov,
6500 int niov, int flags, int timeout)
6502 int reqlen = ks_query_iovs_length(iov, niov);
6503 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6504 timeout, FALSE, ks_sock_iov_cb);
6507 int ks_send_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6508 int nkiov, int flags, int timeout)
6510 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6511 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6512 timeout, TRUE, ks_sock_kiov_cb);
6515 int ks_recv_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6516 int nkiov, int flags, int timeout)
6518 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6519 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6520 timeout, FALSE, ks_sock_kiov_cb);
6523 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
6525 ks_addr_slot_t * slot = NULL;
6526 PLIST_ENTRY list = NULL;
6528 spin_lock(&ks_data.ksnd_addrs_lock);
6530 list = ks_data.ksnd_addrs_list.Flink;
6531 while (list != &ks_data.ksnd_addrs_list) {
6532 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6533 if (_stricmp(name, &slot->iface[0]) == 0) {
6535 *ip = slot->ip_addr;
6536 *mask = slot->netmask;
6543 spin_unlock(&ks_data.ksnd_addrs_lock);
6545 return (int)(slot == NULL);
6548 int libcfs_ipif_enumerate(char ***names)
6550 ks_addr_slot_t * slot = NULL;
6551 PLIST_ENTRY list = NULL;
6554 spin_lock(&ks_data.ksnd_addrs_lock);
6556 *names = kmalloc(sizeof(char *) * ks_data.ksnd_naddrs, __GFP_ZERO);
6557 if (*names == NULL) {
6561 list = ks_data.ksnd_addrs_list.Flink;
6562 while (list != &ks_data.ksnd_addrs_list) {
6563 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6565 (*names)[nips++] = slot->iface;
6566 cfs_assert(nips <= ks_data.ksnd_naddrs);
6569 cfs_assert(nips == ks_data.ksnd_naddrs);
6573 spin_unlock(&ks_data.ksnd_addrs_lock);
6577 void libcfs_ipif_free_enumeration(char **names, int n)
6584 int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
6587 ks_tconn_t * parent;
6589 parent = ks_create_tconn();
6595 /* initialize the tconn as a listener */
6596 ks_init_listener(parent);
6598 /* bind the daemon->tconn */
6599 rc = ks_bind_tconn(parent, NULL, ip, (unsigned short)port);
6602 ks_free_tconn(parent);
6606 /* create listening children and make it to listen state*/
6607 rc = ks_start_listen(parent, backlog);
6609 ks_stop_listen(parent);
6620 int libcfs_sock_accept(struct socket **newsockp, struct socket *sock)
6622 /* wait for incoming connecitons */
6623 return ks_wait_child_tconn(sock, newsockp);
6626 void libcfs_sock_abort_accept(struct socket *sock)
6628 LASSERT(sock->kstc_type == kstt_listener);
6630 spin_lock(&(sock->kstc_lock));
6632 /* clear the daemon flag */
6633 cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
6635 /* wake up it from the waiting on new incoming connections */
6636 KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
6638 spin_unlock(&(sock->kstc_lock));
6642 * libcfs_sock_connect
6643 * build a conntion between local ip/port and the peer ip/port.
6646 * laddr: local ip address
6647 * lport: local port number
6648 * paddr: peer's ip address
6649 * pport: peer's port number
6652 * int: return code ...
6659 int libcfs_sock_connect(struct socket **sockp, int *fatal,
6660 __u32 local_ip, int local_port,
6661 __u32 peer_ip, int peer_port)
6663 ks_tconn_t * tconn = NULL;
6667 if (fatal) *fatal = 0;
6669 KsPrint((2, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
6670 peer_ip, peer_port, local_ip, local_port ));
6672 /* create the tdi connecion structure */
6673 tconn = ks_create_tconn();
6679 /* initialize the tdi sender connection */
6680 ks_init_sender(tconn);
6682 /* bind the local ip address with the tconn */
6683 rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
6685 KsPrint((1, "libcfs_sock_connect: failed to bind address %x:%d...\n",
6686 local_ip, local_port ));
6687 ks_free_tconn(tconn);
6691 /* connect to the remote peer */
6692 rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
6694 KsPrint((1, "libcfs_sock_connect: failed to connect %x:%d ...\n",
6695 peer_ip, peer_port ));
6697 ks_put_tconn(tconn);
6708 int libcfs_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize)
6713 int libcfs_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize)
6718 int libcfs_sock_getaddr(struct socket *socket, int remote, __u32 *ip, int *port)
6720 PTRANSPORT_ADDRESS taddr = NULL;
6722 spin_lock(&socket->kstc_lock);
6724 if (socket->kstc_type == kstt_sender) {
6725 taddr = socket->sender.kstc_info.Remote;
6726 } else if (socket->kstc_type == kstt_child) {
6727 taddr = socket->child.kstc_info.Remote;
6730 taddr = &(socket->kstc_addr.Tdi);
6734 PTDI_ADDRESS_IP addr = (PTDI_ADDRESS_IP)(&(taddr->Address[0].Address));
6736 *ip = ntohl (addr->in_addr);
6738 *port = ntohs (addr->sin_port);
6740 spin_unlock(&socket->kstc_lock);
6744 spin_unlock(&socket->kstc_lock);
6748 int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
6753 while (nob > offset) {
6755 rc = ks_send_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6767 KsPrint((4, "libcfs_sock_write: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6771 int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
6776 while (nob > offset) {
6778 rc = ks_recv_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6790 KsPrint((4, "libcfs_sock_read: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6794 void libcfs_sock_release(struct socket *sock)
6796 if (sock->kstc_type == kstt_listener &&
6797 sock->kstc_state == ksts_listening) {
6798 ks_stop_listen(sock);