1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=4:tabstop=4:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_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 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
353 if (!cfs_list_empty (&(ks_data.ksnd_freetsdus))) {
355 LASSERT(ks_data.ksnd_nfreetsdus > 0);
357 KsTsdu = cfs_list_entry(ks_data.ksnd_freetsdus.next, KS_TSDU, Link);
358 cfs_list_del(&(KsTsdu->Link));
359 ks_data.ksnd_nfreetsdus--;
363 KsTsdu = (PKS_TSDU) cfs_mem_cache_alloc(
364 ks_data.ksnd_tsdu_slab, 0);
367 cfs_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 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
421 if (ks_data.ksnd_nfreetsdus > 128) {
422 KsFreeKsTsdu(KsTsdu);
424 cfs_list_add_tail( &(KsTsdu->Link), &(ks_data.ksnd_freetsdus));
425 ks_data.ksnd_nfreetsdus++;
427 cfs_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 cfs_list_for_each_entry_typed(KsTsdu,
451 &TsduMgr->TsduList,KS_TSDU, Link) {
455 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
456 start = KsTsdu->StartOffset;
458 while (start < KsTsdu->LastOffset) {
460 ks_mdl_t * iov = NULL;
462 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
463 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
464 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
465 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
466 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
467 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
469 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
471 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->TotalLength);
472 if (KsTsduDat->Mdl) {
473 iov = KsTsduDat->Mdl;
476 &KsTsduDat->Data[KsTsduDat->StartOffset],
478 KsTsduDat->DataLength,
481 KsTsduDat->Mdl = iov;
484 printk("KsLockTsdus: %u\n", KsTsduDat->DataLength);
486 &KsTsduDat->Data[KsTsduDat->StartOffset],
487 KsTsduDat->DataLength);
489 *Length += KsTsduDat->DataLength;
490 start += KsTsduDat->TotalLength;
492 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
494 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
495 if (KsTsduBuf->Mdl) {
496 iov = KsTsduBuf->Mdl;
499 (PUCHAR)KsTsduBuf->UserBuffer +
500 KsTsduBuf->StartOffset,
502 KsTsduBuf->DataLength,
505 KsTsduBuf->Mdl = iov;
508 *Length += KsTsduBuf->DataLength;
509 start += sizeof(KS_TSDU_BUF);
513 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
514 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
515 iov = KsTsduMdl->Mdl;
516 *Length += KsTsduMdl->DataLength;
517 start += sizeof(KS_TSDU_MDL);
521 cfs_enter_debugger();
533 printk("KsLockTsdus: mdl %d\n", tail->ByteCount);
534 KsDumpMdlChain(tail, tail->ByteCount);
553 IN ks_mdl_t * master,
558 ks_mdl_t * mdl = NULL;
561 /* calculate the start virtual address */
562 ptr = (char *)KsMapMdlBuffer(master) + offset;
564 /* allocate new mdl for new memory range */
565 mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
571 /* initialize the mdl */
572 IoBuildPartialMdl(master, mdl, (PVOID)ptr, length);
577 /* with tconn lock acquired */
586 PKS_TSDU_DAT KsTsduDat;
587 PKS_TSDU_BUF KsTsduBuf;
588 PKS_TSDU_MDL KsTsduMdl;
590 ULONG total = TsduMgr->TotalBytes;
594 LASSERT(TsduMgr->TotalBytes >= length);
596 while (!cfs_list_empty(&TsduMgr->TsduList)) {
600 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
601 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
602 start = KsTsdu->StartOffset;
604 while (length > 0 && start < KsTsdu->LastOffset) {
607 ks_mdl_t * mdl = NULL;
609 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + start);
610 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + start);
611 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + start);
612 LASSERT(KsTsduDat->TsduType == TSDU_TYPE_DAT ||
613 KsTsduBuf->TsduType == TSDU_TYPE_BUF ||
614 KsTsduMdl->TsduType == TSDU_TYPE_MDL);
616 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
618 ASSERT(KsTsdu->LastOffset >= start + KsTsduDat->DataLength);
619 if (length >= KsTsduDat->DataLength) {
620 /* whole tsdu is sent out */
621 size = KsTsduDat->DataLength;
622 start += KsTsduDat->TotalLength;
625 KsTsduDat->StartOffset += size;
628 if (KsTsduDat->Mdl) {
629 mdl = KsTsduDat->Mdl;
630 KsTsduDat->Mdl = NULL;
633 KsTsduDat->DataLength -= size;
635 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
637 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_BUF));
638 if (length >= KsTsduBuf->DataLength) {
639 /* whole tsdu is sent out */
640 size = KsTsduBuf->DataLength;
641 start += sizeof(KS_TSDU_BUF);
642 LASSERT(KsTsduBuf->UserBuffer);
643 ExFreePool(KsTsduBuf->UserBuffer);
644 KsTsduBuf->UserBuffer = NULL;
646 KsTsduBuf->StartOffset += length;
650 if (KsTsduBuf->Mdl) {
651 mdl = KsTsduBuf->Mdl;
652 KsTsduBuf->Mdl = NULL;
655 KsTsduBuf->DataLength -= size;
659 LASSERT(TSDU_TYPE_MDL == KsTsduMdl->TsduType);
660 ASSERT(KsTsdu->LastOffset >= start + sizeof(KS_TSDU_MDL));
661 mdl = KsTsduMdl->Mdl;
662 if (length >= KsTsduMdl->DataLength) {
663 /* whole mdl is sent out */
664 size = KsTsduMdl->DataLength;
665 start += sizeof(KS_TSDU_MDL);
666 KsTsduMdl->Mdl = NULL;
668 /* now split the remained data out */
669 ks_mdl_t * mdl1 = KsSplitMdl(mdl, length,
670 KsTsduMdl->DataLength - length);
672 mdl->ByteOffset += length;
675 KsTsduMdl->Mdl = mdl1;
678 KsTsduMdl->StartOffset += size;
681 KsTsduMdl->DataLength -= size;
685 TsduMgr->TotalBytes -= size;
689 KsReleaseMdl(mdl, FALSE);
692 KsTsdu->StartOffset = start;
695 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
697 /* remove KsTsdu from list */
698 cfs_list_del(&KsTsdu->Link);
699 TsduMgr->NumOfTsdu--;
708 LASSERT(length == 0);
710 LASSERT(total - size == TsduMgr->TotalBytes);
711 KsPrint((4, "KsReleaseTsdus: TsduMgr=%p Remained=%xh (%xh)\n",
712 TsduMgr, TsduMgr->TotalBytes, size ));
727 /* get the latest Tsdu buffer form TsduMgr list.
728 just set NULL if the list is empty. */
731 if (tconn->kstc_type == kstt_sender) {
732 KsChain = &(tconn->sender.kstc_send);
734 LASSERT(tconn->kstc_type == kstt_child);
735 KsChain = &(tconn->child.kstc_send);
738 if (tconn->kstc_type == kstt_sender) {
739 KsChain = &(tconn->sender.kstc_recv);
741 LASSERT(tconn->kstc_type == kstt_child);
742 KsChain = &(tconn->child.kstc_recv);
747 TsduMgr = &(KsChain->Expedited);
749 TsduMgr = &(KsChain->Normal);
756 KsGetTsdu(PKS_TSDUMGR TsduMgr, ULONG Length)
758 PKS_TSDU KsTsdu = NULL;
760 /* retrieve the latest Tsdu buffer form TsduMgr
761 list if the list is not empty. */
763 if (cfs_list_empty(&(TsduMgr->TsduList))) {
765 LASSERT(TsduMgr->NumOfTsdu == 0);
770 LASSERT(TsduMgr->NumOfTsdu > 0);
771 KsTsdu = cfs_list_entry(TsduMgr->TsduList.prev, KS_TSDU, Link);
773 /* if this Tsdu does not contain enough space, we need
774 allocate a new Tsdu queue. */
776 if (KsTsdu->LastOffset + Length > KsTsdu->TotalLength) {
781 /* allocate a new Tsdu in case we are not statisfied. */
782 if (NULL == KsTsdu) {
783 KsTsdu = KsAllocateKsTsdu();
784 if (NULL != KsTsdu) {
785 cfs_list_add_tail(&(KsTsdu->Link), &(TsduMgr->TsduList));
786 TsduMgr->NumOfTsdu++;
802 PKS_TSDU_DAT KsTsduDat;
803 PKS_TSDU_BUF KsTsduBuf;
805 BOOLEAN bNewBuff = FALSE;
809 printk("KsWriteTsduDat: %u\n", length);
810 KsDumpPrint(buffer, length);
812 /* if the Tsdu is even larger than the biggest Tsdu, we have
813 to allocate new buffer and use TSDU_TYPE_BUF to store it */
815 if ( KS_TSDU_STRU_SIZE(length) > ks_data.ksnd_tsdu_size -
816 KS_QWORD_ALIGN(sizeof(KS_TSDU))) {
820 /* allocating the buffer for TSDU_TYPE_BUF */
822 Buffer = ExAllocatePool(NonPagedPool, length);
823 if (NULL == Buffer) {
824 /* there's no enough memory for us. We just try to
825 receive maximum bytes with a new Tsdu */
827 length = ks_data.ksnd_tsdu_size - KS_TSDU_STRU_SIZE(0) -
828 KS_QWORD_ALIGN(sizeof(KS_TSDU));
832 /* get empty Tsdu from TsduMgr */
833 KsTsdu = KsGetTsdu(TsduMgr, bNewBuff ? sizeof(KS_TSDU_BUF) :
834 KS_TSDU_STRU_SIZE(length) );
836 /* allocate a new Tsdu in case we are not statisfied. */
837 if (NULL == KsTsdu) {
841 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
842 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
846 /* setup up the KS_TSDU_BUF record */
847 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
848 KsTsduBuf->TsduFlags = 0;
849 KsTsduBuf->StartOffset = 0;
850 KsTsduBuf->UserBuffer = Buffer;
851 KsTsduBuf->DataLength = length;
852 KsTsduBuf->Mdl = NULL;
853 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
854 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
857 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
861 /* setup the KS_TSDU_DATA to contain all the messages */
863 KsTsduDat->TsduType = TSDU_TYPE_DAT;
864 KsTsduDat->TsduFlags = 0;
866 if ( KsTsdu->TotalLength - KsTsdu->LastOffset <
867 KS_TSDU_STRU_SIZE(length) ) {
868 length = KsTsdu->TotalLength - KsTsdu->LastOffset -
869 FIELD_OFFSET(KS_TSDU_DAT, Data);
871 KsTsduDat->DataLength = length;
872 KsTsduDat->TotalLength = KS_TSDU_STRU_SIZE(length);
873 KsTsduDat->StartOffset = 0;
874 KsTsduDat->Mdl = NULL;
875 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
876 KsTsduDat->TsduFlags |= KS_TSDU_COMM_PARTIAL;
879 Buffer = &KsTsduDat->Data[0];
880 KsTsdu->LastOffset += KsTsduDat->TotalLength;
883 RtlMoveMemory(Buffer, buffer, length);
884 TsduMgr->TotalBytes += length;
886 KsPrint((4, "KsWriteTsduDat: TsduMgr=%p bytes in queue:%xh (%xh)\n",
887 TsduMgr, TsduMgr->TotalBytes, length));
904 PKS_TSDU_BUF KsTsduBuf;
906 /* get empty Tsdu from TsduMgr */
907 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_BUF));
909 /* allocate a new Tsdu in case we are not statisfied. */
910 if (NULL == KsTsdu) {
914 /* setup up the KS_TSDU_BUF record */
915 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
916 KsTsduBuf->TsduType = TSDU_TYPE_BUF;
917 KsTsduBuf->TsduFlags = 0;
918 KsTsduBuf->StartOffset = 0;
919 KsTsduBuf->UserBuffer = buffer;
920 KsTsduBuf->DataLength = length;
921 KsTsduBuf->Mdl = NULL;
922 KsTsdu->LastOffset += sizeof(KS_TSDU_BUF);
923 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
924 KsTsduBuf->TsduFlags |= KS_TSDU_COMM_PARTIAL;
927 TsduMgr->TotalBytes += length;
928 KsPrint((4, "KsWriteTsduBuf: TsduMgr=%p bytes in queue:%xh (%xh)\n",
929 TsduMgr, TsduMgr->TotalBytes, length));
948 PKS_TSDU_MDL KsTsduMdl;
950 /* get empty Tsdu from TsduMgr */
951 KsTsdu = KsGetTsdu(TsduMgr, sizeof(KS_TSDU_MDL));
953 /* allocate a new Tsdu in case we are not statisfied. */
954 if (NULL == KsTsdu) {
958 /* setup up the KS_TSDU_MDL record */
959 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->LastOffset);
960 KsTsduMdl->TsduType = TSDU_TYPE_MDL;
961 KsTsduMdl->TsduFlags = 0;
962 KsTsduMdl->StartOffset = 0;
963 KsTsduMdl->BaseOffset = offset;
964 KsTsduMdl->DataLength = length;
965 KsTsduMdl->Mdl = mdl;
966 KsTsduMdl->Descriptor = desc;
967 KsTsdu->LastOffset += sizeof(KS_TSDU_MDL);
968 if (cfs_is_flag_set(flags, TDI_SEND_PARTIAL)) {
969 KsTsduMdl->TsduFlags |= KS_TSDU_COMM_PARTIAL;
972 TsduMgr->TotalBytes += length;
973 KsPrint((4, "KsWriteTsduMdl: TsduMgr=%p bytes in queue:%xh (%xh)\n",
974 TsduMgr, TsduMgr->TotalBytes, length));
991 PKS_TSDU_DAT KsTsduDat;
992 PKS_TSDU_BUF KsTsduBuf;
993 PKS_TSDU_MDL KsTsduMdl;
996 ULONG BytesRecved = 0;
998 ULONG TotalBytes = TsduMgr->TotalBytes;
1001 KsPrint((4, "KsReadTsdu: TsduMgr=%p request=%xh total=%xh\n",
1002 TsduMgr, length, TsduMgr->TotalBytes ));
1005 if (TsduMgr->TotalBytes == 0) {
1007 /* It's a notification event. We need reset it to
1008 un-signaled state in case there no any tsdus. */
1010 KeResetEvent(&(TsduMgr->Event));
1014 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1015 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1017 /* remove the KsTsdu from TsduMgr list to release the lock */
1018 cfs_list_del(&(KsTsdu->Link));
1019 TsduMgr->NumOfTsdu--;
1021 while (length > BytesRecved) {
1023 ULONG BytesToCopy = 0;
1024 ULONG StartOffset = 0;
1025 ULONG BytesCopied = 0;
1027 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1028 /* KsTsdu is empty now, we need free it ... */
1029 KsPutKsTsdu(KsTsdu);
1034 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1035 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1036 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1038 if ( TSDU_TYPE_DAT == KsTsduDat->TsduType ||
1039 TSDU_TYPE_BUF == KsTsduBuf->TsduType ) {
1041 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1043 /* Data Tsdu Unit ... */
1044 Buffer = &KsTsduDat->Data[0];
1045 StartOffset = KsTsduDat->StartOffset;
1046 if (KsTsduDat->DataLength - KsTsduDat->StartOffset > length - BytesRecved) {
1047 /* Recvmsg requst could be statisfied ... */
1048 BytesToCopy = length - BytesRecved;
1050 BytesToCopy = KsTsduDat->DataLength - KsTsduDat->StartOffset;
1055 /* Buffer Tsdu Unit */
1056 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1057 Buffer = KsTsduBuf->UserBuffer;
1058 StartOffset = KsTsduBuf->StartOffset;
1060 if (KsTsduBuf->DataLength - KsTsduBuf->StartOffset > length - BytesRecved) {
1061 /* Recvmsg requst could be statisfied ... */
1062 BytesToCopy = length - BytesRecved;
1064 BytesToCopy = KsTsduBuf->DataLength - KsTsduBuf->StartOffset;
1068 if (BytesToCopy > 0) {
1069 RtlMoveMemory(buffer + BytesRecved, Buffer + StartOffset, BytesToCopy);
1071 BytesCopied = BytesToCopy;
1072 BytesRecved += BytesCopied;
1073 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1074 TsduMgr->TotalBytes -= BytesCopied;
1075 KsPrint((4, "KsReadTsdu: TsduMgr=%p copied=%xh recved=%xh\n",
1076 TsduMgr, BytesCopied, BytesRecved ));
1078 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1080 KsTsduDat->StartOffset += BytesCopied;
1081 if (KsTsduDat->StartOffset == KsTsduDat->DataLength) {
1082 if (KsTsduDat->Mdl) {
1083 KsTsduDat->Mdl->Next = NULL;
1084 KsReleaseMdl(KsTsduDat->Mdl, FALSE);
1086 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1091 ASSERT(TSDU_TYPE_BUF == KsTsduBuf->TsduType);
1092 KsTsduBuf->StartOffset += BytesCopied;
1093 if (KsTsduBuf->StartOffset == KsTsduBuf->DataLength) {
1094 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1095 /* now we need release the buf to system pool */
1096 if (KsTsduBuf->Mdl) {
1097 KsTsduBuf->Mdl->Next = NULL;
1098 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1100 ExFreePool(KsTsduBuf->UserBuffer);
1104 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1106 /* MDL Tsdu Unit ... */
1107 if (KsTsduMdl->DataLength > length - BytesRecved) {
1108 /* Recvmsg requst could be statisfied ... */
1109 BytesToCopy = length - BytesRecved;
1111 BytesToCopy = KsTsduMdl->DataLength;
1117 KsTsduMdl->StartOffset +
1118 KsTsduMdl->BaseOffset,
1123 KsPrint((4, "KsReadTsdu: TsduMgr=%p mdl=%p dec=%p copied=%xh "
1125 TsduMgr, KsTsduMdl->Mdl, KsTsduMdl->Descriptor,
1126 BytesCopied, BytesRecved + BytesCopied));
1127 if (BytesCopied == 0) {
1128 cfs_enter_debugger();
1132 KsTsduMdl->StartOffset += BytesCopied;
1133 KsTsduMdl->DataLength -= BytesCopied;
1134 BytesRecved += BytesCopied;
1135 LASSERT(TsduMgr->TotalBytes >= BytesCopied);
1136 TsduMgr->TotalBytes -= BytesCopied;
1138 if (0 == KsTsduMdl->DataLength) {
1140 /* Call TdiReturnChainedReceives to release the Tsdu memory */
1141 LASSERT(KsTsduMdl->Descriptor != NULL);
1142 if (KsTsduMdl->Descriptor) {
1143 TdiReturnChainedReceives(
1144 &(KsTsduMdl->Descriptor),
1148 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1152 KsPrint((1, "KsReadTsdu: unknown tsdu slot: slot = %x type = %x Start= %x Length=%x\n",
1153 KsTsduDat, KsTsduDat->TsduType, KsTsduDat->StartOffset, KsTsduDat->DataLength));
1154 KsPrint((1, " Tsdu = %x Magic=%x: Start = %x Last = %x Length = %x\n",
1155 KsTsdu, KsTsdu->Magic, KsTsdu->StartOffset, KsTsdu->LastOffset, KsTsdu->TotalLength));
1156 cfs_enter_debugger();
1160 /* we need attach the KsTsdu to the list header */
1162 if (KsTsdu->StartOffset >= KsTsdu->LastOffset) {
1163 KsPutKsTsdu(KsTsdu);
1166 TsduMgr->NumOfTsdu++;
1167 cfs_list_add(&(KsTsdu->Link), &(TsduMgr->TsduList));
1171 if (length > BytesRecved) {
1177 LASSERT(TotalBytes == TsduMgr->TotalBytes + BytesRecved);
1179 KsPrint((4, "KsReadTsdu: TsduMgr=%p recved=%xh (%xh) remained=%xh\n",
1180 TsduMgr, BytesRecved, length, TsduMgr->TotalBytes ));
1187 KsTdiSendFlags(int SockFlags)
1191 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1192 cfs_set_flag(TdiFlags, TDI_SEND_EXPEDITED);
1195 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1196 cfs_set_flag(TdiFlags, TDI_SEND_PARTIAL);
1199 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1200 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1207 KsTdiRecvFlags(int SockFlags)
1211 if (cfs_is_flag_set(SockFlags, MSG_OOB)) {
1212 cfs_set_flag(TdiFlags, TDI_RECEIVE_EXPEDITED);
1215 if (cfs_is_flag_set(SockFlags, MSG_MORE)) {
1216 cfs_set_flag(TdiFlags, TDI_RECEIVE_PARTIAL);
1219 if (cfs_is_flag_set(SockFlags, MSG_DONTWAIT)) {
1220 cfs_set_flag(TdiFlags, TDI_SEND_NON_BLOCKING);
1227 KsWriteTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1231 if (TsduMgr->TotalBytes <= TDINAL_MAX_TSDU_QUEUE_SIZE) {
1232 rc = KsWriteTsduDat(TsduMgr, buffer, length, flags);
1243 KsReadTsdus(PKS_TSDUMGR TsduMgr, char * buffer, int length, int flags)
1245 int rc = KsReadTsdu(TsduMgr, buffer, length, flags);
1255 * KsInitializeKsTsduMgr
1256 * Initialize the management structure of
1260 * TsduMgr: the TsduMgr to be initialized
1270 KsInitializeKsTsduMgr(
1281 &(TsduMgr->TsduList)
1284 TsduMgr->NumOfTsdu = 0;
1285 TsduMgr->TotalBytes = 0;
1287 cfs_spin_lock_init(&TsduMgr->Lock);
1292 * KsInitializeKsChain
1293 * Initialize the China structure for receiving
1297 * KsChain: the KsChain to be initialized
1307 KsInitializeKsChain(
1311 KsInitializeKsTsduMgr(&(KsChain->Normal));
1312 KsInitializeKsTsduMgr(&(KsChain->Expedited));
1313 KsChain->Expedited.OOB = TRUE;
1319 * Clean up all the Tsdus in the TsduMgr list
1322 * TsduMgr: the Tsdu list manager
1325 * NTSTATUS: nt status code
1337 PKS_TSDU_DAT KsTsduDat;
1338 PKS_TSDU_BUF KsTsduBuf;
1339 PKS_TSDU_MDL KsTsduMdl;
1341 LASSERT(NULL != TsduMgr);
1343 KsRemoveTdiEngine(TsduMgr);
1344 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
1346 while (!cfs_list_empty(&TsduMgr->TsduList)) {
1348 KsTsdu = cfs_list_entry(TsduMgr->TsduList.next, KS_TSDU, Link);
1349 LASSERT(KsTsdu->Magic == KS_TSDU_MAGIC);
1351 if (KsTsdu->StartOffset == KsTsdu->LastOffset) {
1354 // KsTsdu is empty now, we need free it ...
1357 cfs_list_del(&(KsTsdu->Link));
1358 TsduMgr->NumOfTsdu--;
1360 KsFreeKsTsdu(KsTsdu);
1364 KsTsduDat = (PKS_TSDU_DAT)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1365 KsTsduBuf = (PKS_TSDU_BUF)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1366 KsTsduMdl = (PKS_TSDU_MDL)((PUCHAR)KsTsdu + KsTsdu->StartOffset);
1368 if (TSDU_TYPE_DAT == KsTsduDat->TsduType) {
1370 KsTsdu->StartOffset += KsTsduDat->TotalLength;
1372 } else if (TSDU_TYPE_BUF == KsTsduBuf->TsduType) {
1374 ASSERT(KsTsduBuf->UserBuffer != NULL);
1376 if (KsTsduBuf->DataLength > KsTsduBuf->StartOffset) {
1377 if (KsTsduBuf->Mdl) {
1378 KsTsduBuf->Mdl->Next = NULL;
1379 KsReleaseMdl(KsTsduBuf->Mdl, FALSE);
1381 ExFreePool(KsTsduBuf->UserBuffer);
1383 cfs_enter_debugger();
1386 KsTsdu->StartOffset += sizeof(KS_TSDU_BUF);
1388 } else if (TSDU_TYPE_MDL == KsTsduMdl->TsduType) {
1391 // MDL Tsdu Unit ...
1393 if (KsTsduMdl->Descriptor) {
1394 TdiReturnChainedReceives(
1395 &(KsTsduMdl->Descriptor),
1397 } else if (KsTsduMdl->Mdl) {
1398 KsTsduMdl->Mdl->Next = NULL;
1399 KsReleaseMdl(KsTsduMdl->Mdl, FALSE);
1402 KsTsdu->StartOffset += sizeof(KS_TSDU_MDL);
1407 return STATUS_SUCCESS;
1413 * Clean up the TsduMgrs of the KsChain
1416 * KsChain: the chain managing TsduMgr
1419 * NTSTATUS: nt status code
1432 LASSERT(NULL != KsChain);
1434 Status = KsCleanupTsduMgr(
1438 if (!NT_SUCCESS(Status)) {
1439 cfs_enter_debugger();
1443 Status = KsCleanupTsduMgr(
1444 &(KsChain->Expedited)
1447 if (!NT_SUCCESS(Status)) {
1448 cfs_enter_debugger();
1460 * Clean up all the Tsdus of a tdi connected object
1463 * tconn: the tdi connection which is connected already.
1477 NTSTATUS Status = STATUS_SUCCESS;
1480 if (tconn->kstc_type != kstt_sender &&
1481 tconn->kstc_type != kstt_child ) {
1486 if (tconn->kstc_type == kstt_sender) {
1488 Status = KsCleanupKsChain(
1489 &(tconn->sender.kstc_recv)
1492 if (!NT_SUCCESS(Status)) {
1493 cfs_enter_debugger();
1497 Status = KsCleanupKsChain(
1498 &(tconn->sender.kstc_send)
1501 if (!NT_SUCCESS(Status)) {
1502 cfs_enter_debugger();
1508 Status = KsCleanupKsChain(
1509 &(tconn->child.kstc_recv)
1512 if (!NT_SUCCESS(Status)) {
1513 cfs_enter_debugger();
1517 Status = KsCleanupKsChain(
1518 &(tconn->child.kstc_send)
1521 if (!NT_SUCCESS(Status)) {
1522 cfs_enter_debugger();
1534 KsIrpCompletionRoutine(
1535 IN PDEVICE_OBJECT DeviceObject,
1540 if (NULL != Context) {
1541 KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
1544 return STATUS_MORE_PROCESSING_REQUIRED;
1546 UNREFERENCED_PARAMETER(DeviceObject);
1547 UNREFERENCED_PARAMETER(Irp);
1553 * Allocate a new IRP and initialize it to be issued to tdi
1556 * DeviceObject: device object created by the underlying
1557 * TDI transport driver
1560 * PRIP: the allocated Irp in success or NULL in failure.
1568 IN PDEVICE_OBJECT DeviceObject
1572 PIO_STACK_LOCATION IrpSp;
1575 // Allocating the IRP ...
1578 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1583 // Getting the Next Stack Location ...
1586 IrpSp = IoGetNextIrpStackLocation(Irp);
1589 // Initializing Irp ...
1592 IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1593 IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
1601 * Issue the Irp to the underlying tdi driver
1604 * DeviceObject: the device object created by TDI driver
1605 * Irp: the I/O request packet to be processed
1606 * bSynchronous: synchronous or not. If true, we need wait
1607 * until the process is finished.
1608 * Information: returned info
1611 * NTSTATUS: kernel status code
1619 IN PDEVICE_OBJECT DeviceObject,
1621 IN BOOLEAN bSynchronous,
1622 OUT PULONG Information
1632 SynchronizationEvent,
1637 IoSetCompletionRoutine(
1639 KsIrpCompletionRoutine,
1647 Status = IoCallDriver(DeviceObject, Irp);
1651 if (STATUS_PENDING == Status) {
1653 Status = KeWaitForSingleObject(
1662 Status = Irp->IoStatus.Status;
1665 *Information = (ULONG)(Irp->IoStatus.Information);
1671 if (!NT_SUCCESS(Status)) {
1673 KsPrint((1, "KsSubmitTdiIrp: Error when submitting the Irp: "
1674 "Status = %xh (%s)\n", Status, KsNtStatusToString(Status)));
1684 * Open the Control Channel Object ...
1687 * DeviceName: the device name to be opened
1688 * Handle: opened handle in success case
1689 * FileObject: the fileobject of the device
1692 * NTSTATUS: kernel status code (STATUS_SUCCESS
1693 * or other error code)
1701 IN PUNICODE_STRING DeviceName,
1702 OUT HANDLE * Handle,
1703 OUT PFILE_OBJECT * FileObject
1706 NTSTATUS Status = STATUS_SUCCESS;
1708 OBJECT_ATTRIBUTES ObjectAttributes;
1709 IO_STATUS_BLOCK IoStatus;
1712 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1718 InitializeObjectAttributes(
1721 OBJ_CASE_INSENSITIVE |
1727 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL );
1730 // Creating the Transport Address Object ...
1733 Status = ZwCreateFile(
1735 FILE_READ_DATA | FILE_WRITE_DATA,
1739 FILE_ATTRIBUTE_NORMAL,
1740 FILE_SHARE_READ | FILE_SHARE_WRITE,
1748 if (NT_SUCCESS(Status)) {
1751 // Now Obtaining the FileObject of the Transport Address ...
1754 Status = ObReferenceObjectByHandle(
1763 if (!NT_SUCCESS(Status)) {
1765 cfs_enter_debugger();
1771 cfs_enter_debugger();
1780 * Release the Control Channel Handle and FileObject
1783 * Handle: the channel handle to be released
1784 * FileObject: the fileobject to be released
1787 * NTSTATUS: kernel status code (STATUS_SUCCESS
1788 * or other error code)
1797 IN PFILE_OBJECT FileObject
1800 NTSTATUS Status = STATUS_SUCCESS;
1802 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1806 ObDereferenceObject(FileObject);
1811 Status = ZwClose(Handle);
1814 ASSERT(NT_SUCCESS(Status));
1822 * Open the tdi address object
1825 * DeviceName: device name of the address object
1826 * pAddress: tdi address of the address object
1827 * AddressLength: length in bytes of the tdi address
1828 * Handle: the newly opened handle
1829 * FileObject: the newly opened fileobject
1832 * NTSTATUS: kernel status code (STATUS_SUCCESS
1833 * or other error code)
1841 IN PUNICODE_STRING DeviceName,
1842 IN PTRANSPORT_ADDRESS pAddress,
1843 IN ULONG AddressLength,
1844 OUT HANDLE * Handle,
1845 OUT PFILE_OBJECT * FileObject
1848 NTSTATUS Status = STATUS_SUCCESS;
1850 PFILE_FULL_EA_INFORMATION Ea = NULL;
1852 UCHAR EaBuffer[EA_MAX_LENGTH];
1854 OBJECT_ATTRIBUTES ObjectAttributes;
1855 IO_STATUS_BLOCK IoStatus;
1858 // Building EA for the Address Object to be Opened ...
1861 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1862 Ea->NextEntryOffset = 0;
1864 Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
1865 Ea->EaValueLength = (USHORT)AddressLength;
1868 TdiTransportAddress,
1869 Ea->EaNameLength + 1
1872 &(Ea->EaName[Ea->EaNameLength + 1]),
1876 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
1877 Ea->EaNameLength + AddressLength;
1879 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1886 InitializeObjectAttributes(
1889 OBJ_CASE_INSENSITIVE |
1895 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
1898 // Creating the Transport Address Object ...
1901 Status = ZwCreateFile(
1903 FILE_READ_DATA | FILE_WRITE_DATA,
1907 FILE_ATTRIBUTE_NORMAL,
1908 FILE_SHARE_READ | FILE_SHARE_WRITE, /* 0: DON'T REUSE */
1916 if (NT_SUCCESS(Status)) {
1919 // Now Obtaining the FileObject of the Transport Address ...
1922 Status = ObReferenceObjectByHandle(
1931 if (!NT_SUCCESS(Status)) {
1933 cfs_enter_debugger();
1939 cfs_enter_debugger();
1947 * Release the Hanlde and FileObject of an opened tdi
1951 * Handle: the handle to be released
1952 * FileObject: the fileobject to be released
1955 * NTSTATUS: kernel status code (STATUS_SUCCESS
1956 * or other error code)
1965 IN PFILE_OBJECT FileObject
1968 NTSTATUS Status = STATUS_SUCCESS;
1972 ObDereferenceObject(FileObject);
1977 Status = ZwClose(Handle);
1980 ASSERT(NT_SUCCESS(Status));
1988 * Open a tdi connection object
1991 * DeviceName: device name of the connection object
1992 * ConnectionContext: the connection context
1993 * Handle: the newly opened handle
1994 * FileObject: the newly opened fileobject
1997 * NTSTATUS: kernel status code (STATUS_SUCCESS
1998 * or other error code)
2006 IN PUNICODE_STRING DeviceName,
2007 IN CONNECTION_CONTEXT ConnectionContext,
2008 OUT HANDLE * Handle,
2009 OUT PFILE_OBJECT * FileObject
2012 NTSTATUS Status = STATUS_SUCCESS;
2014 PFILE_FULL_EA_INFORMATION Ea = NULL;
2016 UCHAR EaBuffer[EA_MAX_LENGTH];
2018 OBJECT_ATTRIBUTES ObjectAttributes;
2019 IO_STATUS_BLOCK IoStatus;
2022 // Building EA for the Address Object to be Opened ...
2025 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
2026 Ea->NextEntryOffset = 0;
2028 Ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
2029 Ea->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
2032 TdiConnectionContext,
2033 Ea->EaNameLength + 1
2036 &(Ea->EaName[Ea->EaNameLength + 1]),
2038 sizeof(CONNECTION_CONTEXT)
2040 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
2041 Ea->EaNameLength + 1 + sizeof(CONNECTION_CONTEXT);
2043 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2050 InitializeObjectAttributes(
2053 OBJ_CASE_INSENSITIVE |
2059 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2062 // Creating the Connection Object ...
2065 Status = ZwCreateFile(
2067 FILE_READ_DATA | FILE_WRITE_DATA,
2071 FILE_ATTRIBUTE_NORMAL,
2072 FILE_SHARE_READ | FILE_SHARE_WRITE,
2080 if (NT_SUCCESS(Status)) {
2083 // Now Obtaining the FileObject of the Transport Address ...
2086 Status = ObReferenceObjectByHandle(
2095 if (!NT_SUCCESS(Status)) {
2097 cfs_enter_debugger();
2103 cfs_enter_debugger();
2111 * Release the Hanlde and FileObject of an opened tdi
2115 * Handle: the handle to be released
2116 * FileObject: the fileobject to be released
2119 * NTSTATUS: kernel status code (STATUS_SUCCESS
2120 * or other error code)
2129 IN PFILE_OBJECT FileObject
2132 NTSTATUS Status = STATUS_SUCCESS;
2136 ObDereferenceObject(FileObject);
2141 Status = ZwClose(Handle);
2144 ASSERT(NT_SUCCESS(Status));
2151 * KsAssociateAddress
2152 * Associate an address object with a connection object
2155 * AddressHandle: the handle of the address object
2156 * ConnectionObject: the FileObject of the connection
2159 * NTSTATUS: kernel status code (STATUS_SUCCESS
2160 * or other error code)
2168 IN HANDLE AddressHandle,
2169 IN PFILE_OBJECT ConnectionObject
2173 PDEVICE_OBJECT DeviceObject;
2177 // Getting the DeviceObject from Connection FileObject
2180 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2183 // Building Tdi Internal Irp ...
2186 Irp = KsBuildTdiIrp(DeviceObject);
2190 Status = STATUS_INSUFFICIENT_RESOURCES;
2195 // Assocating the Address Object with the Connection Object
2198 TdiBuildAssociateAddress(
2208 // Calling the Transprot Driver with the Prepared Irp
2211 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2219 * KsDisassociateAddress
2220 * Disassociate the connection object (the relationship will
2221 * the corresponding address object will be dismissed. )
2224 * ConnectionObject: the FileObject of the connection
2227 * NTSTATUS: kernel status code (STATUS_SUCCESS
2228 * or other error code)
2235 KsDisassociateAddress(
2236 IN PFILE_OBJECT ConnectionObject
2240 PDEVICE_OBJECT DeviceObject;
2244 // Getting the DeviceObject from Connection FileObject
2247 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2250 // Building Tdi Internal Irp ...
2253 Irp = KsBuildTdiIrp(DeviceObject);
2257 Status = STATUS_INSUFFICIENT_RESOURCES;
2262 // Disassocating the Address Object with the Connection Object
2265 TdiBuildDisassociateAddress(
2274 // Calling the Transprot Driver with the Prepared Irp
2277 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2287 // Connection Control Event Callbacks
2291 TDI_EVENT_DISCONNECT
2295 // Tcp Event Callbacks
2299 TDI_EVENT_RECEIVE_EXPEDITED
2300 TDI_EVENT_CHAINED_RECEIVE
2301 TDI_EVENT_CHAINED_RECEIVE_EXPEDITED
2304 // Udp Event Callbacks
2307 TDI_EVENT_RECEIVE_DATAGRAM
2308 TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
2314 * KsSetEventHandlers
2315 * Set the tdi event callbacks with an address object
2318 * AddressObject: the FileObject of the address object
2319 * EventContext: the parameter for the callbacks
2320 * Handlers: the handlers indictor array
2323 * NTSTATUS: kernel status code (STATUS_SUCCESS
2324 * or other error code)
2332 IN PFILE_OBJECT AddressObject, // Address File Object
2333 IN PVOID EventContext, // Context for Handlers
2334 IN PKS_EVENT_HANDLERS Handlers // Handlers Indictor
2337 NTSTATUS Status = STATUS_SUCCESS;
2338 PDEVICE_OBJECT DeviceObject;
2341 DeviceObject = IoGetRelatedDeviceObject(AddressObject);
2343 for (i=0; i < TDI_EVENT_MAXIMUM_HANDLER; i++) {
2346 // Setup the tdi event callback handler if requested.
2349 if (Handlers->IsActive[i]) {
2354 // Building Tdi Internal Irp ...
2357 Irp = KsBuildTdiIrp(DeviceObject);
2361 Status = STATUS_INSUFFICIENT_RESOURCES;
2366 // Building the Irp to set the Event Handler ...
2369 TdiBuildSetEventHandler(
2375 i, /* tdi event type */
2376 Handlers->Handler[i], /* tdi event handler */
2377 EventContext /* context for the handler */
2381 // Calling the Transprot Driver with the Prepared Irp
2384 Status = KsSubmitTdiIrp(DeviceObject, Irp, TRUE, NULL);
2387 // tcp/ip tdi does not support these two event callbacks
2390 if ((!NT_SUCCESS(Status)) && ( i == TDI_EVENT_SEND_POSSIBLE ||
2391 i == TDI_EVENT_CHAINED_RECEIVE_EXPEDITED )) {
2392 cfs_enter_debugger();
2393 Status = STATUS_SUCCESS;
2397 if (!NT_SUCCESS(Status)) {
2398 cfs_enter_debugger();
2407 if (!NT_SUCCESS(Status)) {
2409 KsPrint((1, "KsSetEventHandlers: Error Status = %xh (%s)\n",
2410 Status, KsNtStatusToString(Status) ));
2419 * KsQueryAddressInfo
2420 * Query the address of the FileObject specified
2423 * FileObject: the FileObject to be queried
2424 * AddressInfo: buffer to contain the address info
2425 * AddressSize: length of the AddressInfo buffer
2428 * NTSTATUS: kernel status code (STATUS_SUCCESS
2429 * or other error code)
2437 PFILE_OBJECT FileObject,
2438 PTDI_ADDRESS_INFO AddressInfo,
2442 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2445 PDEVICE_OBJECT DeviceObject;
2447 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2449 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2451 RtlZeroMemory(AddressInfo, *(AddressSize));
2454 // Allocating the Tdi Setting Irp ...
2457 Irp = KsBuildTdiIrp(DeviceObject);
2461 Status = STATUS_INSUFFICIENT_RESOURCES;
2466 // Locking the User Buffer / Allocating a MDL for it
2469 Status = KsLockUserBuffer(
2477 if (!NT_SUCCESS(Status)) {
2486 LASSERT(NT_SUCCESS(Status));
2488 TdiBuildQueryInformation(
2494 TDI_QUERY_ADDRESS_INFO,
2498 Status = KsSubmitTdiIrp(
2505 KsReleaseMdl(Mdl, FALSE);
2508 if (!NT_SUCCESS(Status)) {
2510 cfs_enter_debugger();
2511 //TDI_BUFFER_OVERFLOW
2518 * KsQueryProviderInfo
2519 * Query the underlying transport device's information
2522 * TdiDeviceName: the transport device's name string
2523 * ProviderInfo: TDI_PROVIDER_INFO struncture
2526 * NTSTATUS: Nt system status code
2533 KsQueryProviderInfo(
2534 PWSTR TdiDeviceName,
2535 PTDI_PROVIDER_INFO ProviderInfo
2538 NTSTATUS Status = STATUS_SUCCESS;
2543 UNICODE_STRING ControlName;
2546 PFILE_OBJECT FileObject;
2547 PDEVICE_OBJECT DeviceObject;
2549 ULONG ProviderSize = 0;
2551 RtlInitUnicodeString(&ControlName, TdiDeviceName);
2554 // Open the Tdi Control Channel
2557 Status = KsOpenControl(
2563 if (!NT_SUCCESS(Status)) {
2565 KsPrint((1, "KsQueryProviderInfo: Fail to open the tdi control channel.\n"));
2570 // Obtain The Related Device Object
2573 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2575 ProviderSize = sizeof(TDI_PROVIDER_INFO);
2576 RtlZeroMemory(ProviderInfo, ProviderSize);
2579 // Allocating the Tdi Setting Irp ...
2582 Irp = KsBuildTdiIrp(DeviceObject);
2586 Status = STATUS_INSUFFICIENT_RESOURCES;
2591 // Locking the User Buffer / Allocating a MDL for it
2594 Status = KsLockUserBuffer(
2602 if (!NT_SUCCESS(Status)) {
2611 LASSERT(NT_SUCCESS(Status));
2613 TdiBuildQueryInformation(
2619 TDI_QUERY_PROVIDER_INFO,
2623 Status = KsSubmitTdiIrp(
2630 KsReleaseMdl(Mdl, FALSE);
2633 if (!NT_SUCCESS(Status)) {
2635 cfs_enter_debugger();
2636 //TDI_BUFFER_OVERFLOW
2639 KsCloseControl(Handle, FileObject);
2645 * KsQueryConnectionInfo
2646 * Query the connection info of the FileObject specified
2647 * (some statics data of the traffic)
2650 * FileObject: the FileObject to be queried
2651 * ConnectionInfo: buffer to contain the connection info
2652 * ConnectionSize: length of the ConnectionInfo buffer
2655 * NTSTATUS: kernel status code (STATUS_SUCCESS
2656 * or other error code)
2663 KsQueryConnectionInfo(
2664 PFILE_OBJECT ConnectionObject,
2665 PTDI_CONNECTION_INFO ConnectionInfo,
2666 PULONG ConnectionSize
2669 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2672 PDEVICE_OBJECT DeviceObject;
2674 LASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
2676 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
2678 RtlZeroMemory(ConnectionInfo, *(ConnectionSize));
2681 // Allocating the Tdi Query Irp ...
2684 Irp = KsBuildTdiIrp(DeviceObject);
2688 Status = STATUS_INSUFFICIENT_RESOURCES;
2693 // Locking the User Buffer / Allocating a MDL for it
2696 Status = KsLockUserBuffer(
2704 if (NT_SUCCESS(Status)) {
2713 LASSERT(NT_SUCCESS(Status));
2715 TdiBuildQueryInformation(
2721 TDI_QUERY_CONNECTION_INFO,
2725 Status = KsSubmitTdiIrp(
2732 KsReleaseMdl(Mdl, FALSE);
2740 * KsInitializeTdiAddress
2741 * Initialize the tdi addresss
2744 * pTransportAddress: tdi address to be initialized
2745 * IpAddress: the ip address of object
2746 * IpPort: the ip port of the object
2749 * ULONG: the total size of the tdi address
2756 KsInitializeTdiAddress(
2757 IN OUT PTA_IP_ADDRESS pTransportAddress,
2762 pTransportAddress->TAAddressCount = 1;
2763 pTransportAddress->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
2764 pTransportAddress->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
2765 pTransportAddress->Address[ 0 ].Address[ 0 ].sin_port = IpPort;
2766 pTransportAddress->Address[ 0 ].Address[ 0 ].in_addr = IpAddress;
2768 return (FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) + TDI_ADDRESS_LENGTH_IP);
2772 * KsQueryTdiAddressLength
2773 * Query the total size of the tdi address
2776 * pTransportAddress: tdi address to be queried
2779 * ULONG: the total size of the tdi address
2786 KsQueryTdiAddressLength(
2787 PTRANSPORT_ADDRESS pTransportAddress
2790 ULONG TotalLength = 0;
2793 PTA_ADDRESS pTaAddress = NULL;
2795 ASSERT (NULL != pTransportAddress);
2797 TotalLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
2798 FIELD_OFFSET(TA_ADDRESS, Address) * pTransportAddress->TAAddressCount;
2800 pTaAddress = (PTA_ADDRESS)pTransportAddress->Address;
2802 for (i = 0; i < pTransportAddress->TAAddressCount; i++)
2804 TotalLength += pTaAddress->AddressLength;
2805 pTaAddress = (PTA_ADDRESS)((PCHAR)pTaAddress +
2806 FIELD_OFFSET(TA_ADDRESS,Address) +
2807 pTaAddress->AddressLength );
2810 return (TotalLength);
2816 * Query the ip address of the tdi object
2819 * FileObject: tdi object to be queried
2820 * TdiAddress: TdiAddress buffer, to store the queried
2822 * AddressLength: buffer length of the TdiAddress
2825 * ULONG: the total size of the tdi ip address
2833 PFILE_OBJECT FileObject,
2835 ULONG* AddressLength
2840 PTDI_ADDRESS_INFO TdiAddressInfo;
2845 // Maximum length of TDI_ADDRESSS_INFO with one TRANSPORT_ADDRESS
2848 Length = MAX_ADDRESS_LENGTH;
2850 TdiAddressInfo = (PTDI_ADDRESS_INFO)
2851 ExAllocatePoolWithTag(
2856 if (NULL == TdiAddressInfo) {
2858 Status = STATUS_INSUFFICIENT_RESOURCES;
2863 Status = KsQueryAddressInfo(
2871 if (NT_SUCCESS(Status)) {
2873 if (*AddressLength < Length) {
2874 Status = STATUS_BUFFER_TOO_SMALL;
2876 *AddressLength = Length;
2879 &(TdiAddressInfo->Address),
2882 Status = STATUS_SUCCESS;
2886 if (NULL != TdiAddressInfo) {
2887 ExFreePool(TdiAddressInfo);
2895 * KsErrorEventHandler
2896 * the common error event handler callback
2899 * TdiEventContext: should be the socket
2900 * Status: the error code
2903 * Status: STATS_SUCCESS
2906 * We need not do anything in such a severe
2907 * error case. System will process it for us.
2911 KsErrorEventHandler(
2912 IN PVOID TdiEventContext,
2916 KsPrint((1, "KsErrorEventHandler called at Irql = %xh ...\n",
2917 KeGetCurrentIrql()));
2919 cfs_enter_debugger();
2921 return (STATUS_SUCCESS);
2925 * KsAcceptCompletionRoutine
2926 * Irp completion routine for TdiBuildAccept (KsConnectEventHandler)
2928 * Here system gives us a chance to check the conneciton is built
2932 * DeviceObject: the device object of the transport driver
2933 * Irp: the Irp is being completed.
2934 * Context: the context we specified when issuing the Irp
2944 KsAcceptCompletionRoutine(
2945 IN PDEVICE_OBJECT DeviceObject,
2950 ks_tconn_t * child = (ks_tconn_t *) Context;
2951 ks_tconn_t * parent = child->child.kstc_parent;
2953 KsPrint((2, "KsAcceptCompletionRoutine at Irql: %xh child: %p status: %p\n",
2954 KeGetCurrentIrql(), child, Irp->IoStatus.Status));
2956 LASSERT(child->kstc_type == kstt_child);
2958 cfs_spin_lock(&(child->kstc_lock));
2960 LASSERT(parent->kstc_state == ksts_listening);
2961 LASSERT(child->kstc_state == ksts_connecting);
2963 if (NT_SUCCESS(Irp->IoStatus.Status)) {
2965 child->child.kstc_accepted = TRUE;
2967 child->kstc_state = ksts_connected;
2969 /* wake up the daemon thread which waits on this event */
2971 &(parent->listener.kstc_accept_event),
2976 cfs_spin_unlock(&(child->kstc_lock));
2978 KsPrint((2, "KsAcceptCompletionRoutine: singal parent: %p (child: %p)\n",
2983 /* re-use this child connecton */
2984 child->child.kstc_accepted = FALSE;
2985 child->child.kstc_busy = FALSE;
2986 child->kstc_state = ksts_associated;
2988 cfs_spin_unlock(&(child->kstc_lock));
2991 /* now free the Irp */
2994 /* drop the refer count of the child */
2995 ks_put_tconn(child);
2997 return (STATUS_MORE_PROCESSING_REQUIRED);
3001 KsSearchIpAddress(PUNICODE_STRING DeviceName)
3003 ks_addr_slot_t * slot = NULL;
3004 PLIST_ENTRY list = NULL;
3006 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3008 list = ks_data.ksnd_addrs_list.Flink;
3009 while (list != &ks_data.ksnd_addrs_list) {
3010 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3011 if (RtlCompareUnicodeString(
3021 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3027 KsCleanupIpAddresses()
3029 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3031 while (!IsListEmpty(&ks_data.ksnd_addrs_list)) {
3033 ks_addr_slot_t * slot = NULL;
3034 PLIST_ENTRY list = NULL;
3036 list = RemoveHeadList(&ks_data.ksnd_addrs_list);
3037 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
3039 ks_data.ksnd_naddrs--;
3042 cfs_assert(ks_data.ksnd_naddrs == 0);
3043 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3047 KsAddAddressHandler(
3048 IN PTA_ADDRESS Address,
3049 IN PUNICODE_STRING DeviceName,
3050 IN PTDI_PNP_CONTEXT Context
3053 PTDI_ADDRESS_IP IpAddress = NULL;
3055 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3056 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3058 ks_addr_slot_t * slot = NULL;
3060 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3061 KsPrint((2, "KsAddAddressHandle: Device=%wZ Context=%xh "
3062 "IpAddress=%xh(%d.%d.%d.%d)\n",
3063 DeviceName, Context, IpAddress->in_addr,
3064 (IpAddress->in_addr & 0x000000FF) >> 0,
3065 (IpAddress->in_addr & 0x0000FF00) >> 8,
3066 (IpAddress->in_addr & 0x00FF0000) >> 16,
3067 (IpAddress->in_addr & 0xFF000000) >> 24
3070 slot = KsSearchIpAddress(DeviceName);
3074 slot->ip_addr = ntohl(IpAddress->in_addr);
3077 /* Matt: only add 192.168.10/5/92.xxx for temporary test */
3078 if ((IpAddress->in_addr & 0x00FFFFFF) != 0x000aa8c0 &&
3079 (IpAddress->in_addr & 0x00FFFFFF) != 0x0092a8c0 &&
3080 (IpAddress->in_addr & 0x00FFFFFF) != 0x0005a8c0 ) {
3084 slot = cfs_alloc(sizeof(ks_addr_slot_t) + DeviceName->Length, CFS_ALLOC_ZERO);
3086 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
3087 InsertTailList(&ks_data.ksnd_addrs_list, &slot->link);
3088 sprintf(slot->iface, "eth%d", ks_data.ksnd_naddrs++);
3089 slot->ip_addr = ntohl(IpAddress->in_addr);
3090 slot->netmask = 0x00FFFFFF; /* Matt: hardcode*/
3092 RtlMoveMemory(&slot->buffer[0], DeviceName->Buffer, DeviceName->Length);
3093 slot->devname.Length = DeviceName->Length;
3094 slot->devname.MaximumLength = DeviceName->Length + sizeof(WCHAR);
3095 slot->devname.Buffer = slot->buffer;
3096 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
3098 KsPrint((0, "KsAddAddressHandle: %s added: ip=%xh(%d.%d.%d.%d)\n",
3099 slot->iface, IpAddress->in_addr,
3100 (IpAddress->in_addr & 0x000000FF) >> 0,
3101 (IpAddress->in_addr & 0x0000FF00) >> 8,
3102 (IpAddress->in_addr & 0x00FF0000) >> 16,
3103 (IpAddress->in_addr & 0xFF000000) >> 24
3111 KsDelAddressHandler(
3112 IN PTA_ADDRESS Address,
3113 IN PUNICODE_STRING DeviceName,
3114 IN PTDI_PNP_CONTEXT Context
3117 PTDI_ADDRESS_IP IpAddress = NULL;
3119 if ( Address->AddressType == TDI_ADDRESS_TYPE_IP &&
3120 Address->AddressLength == TDI_ADDRESS_LENGTH_IP ) {
3122 ks_addr_slot_t * slot = NULL;
3124 slot = KsSearchIpAddress(DeviceName);
3130 IpAddress = (PTDI_ADDRESS_IP) &Address->Address[0];
3131 KsPrint((2, "KsDelAddressHandle: Device=%wZ Context=%xh IpAddress=%xh(%d.%d.%d.%d)\n",
3132 DeviceName, Context, IpAddress->in_addr,
3133 (IpAddress->in_addr & 0xFF000000) >> 24,
3134 (IpAddress->in_addr & 0x00FF0000) >> 16,
3135 (IpAddress->in_addr & 0x0000FF00) >> 8,
3136 (IpAddress->in_addr & 0x000000FF) >> 0 ));
3141 KsRegisterPnpHandlers()
3143 TDI20_CLIENT_INTERFACE_INFO ClientInfo;
3145 /* initialize the global ks_data members */
3146 RtlInitUnicodeString(&ks_data.ksnd_client_name, TDILND_MODULE_NAME);
3147 cfs_spin_lock_init(&ks_data.ksnd_addrs_lock);
3148 InitializeListHead(&ks_data.ksnd_addrs_list);
3150 /* register the pnp handlers */
3151 RtlZeroMemory(&ClientInfo, sizeof(ClientInfo));
3152 ClientInfo.TdiVersion = TDI_CURRENT_VERSION;
3154 ClientInfo.ClientName = &ks_data.ksnd_client_name;
3155 ClientInfo.AddAddressHandlerV2 = KsAddAddressHandler;
3156 ClientInfo.DelAddressHandlerV2 = KsDelAddressHandler;
3158 return TdiRegisterPnPHandlers(&ClientInfo, sizeof(ClientInfo),
3159 &ks_data.ksnd_pnp_handle);
3163 KsDeregisterPnpHandlers()
3165 if (ks_data.ksnd_pnp_handle) {
3167 /* De-register the pnp handlers */
3169 TdiDeregisterPnPHandlers(ks_data.ksnd_pnp_handle);
3170 ks_data.ksnd_pnp_handle = NULL;
3172 /* cleanup all the ip address slots */
3173 KsCleanupIpAddresses();
3179 * KsGetVacancyBacklog
3180 * Get a vacancy listeing child from the backlog list
3183 * parent: the listener daemon connection
3186 * the child listening connection or NULL in failure
3189 * Parent's lock should be acquired before calling.
3193 KsGetVacancyBacklog(
3199 LASSERT(parent->kstc_type == kstt_listener);
3200 LASSERT(parent->kstc_state == ksts_listening);
3202 if (cfs_list_empty(&(parent->listener.kstc_listening.list))) {
3210 /* check the listening queue and try to get a free connecton */
3212 cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
3213 child = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
3214 cfs_spin_lock(&(child->kstc_lock));
3216 if (!child->child.kstc_busy) {
3217 LASSERT(child->kstc_state == ksts_associated);
3218 child->child.kstc_busy = TRUE;
3219 cfs_spin_unlock(&(child->kstc_lock));
3222 cfs_spin_unlock(&(child->kstc_lock));
3232 * KsConnectEventHandler
3233 * Connect event handler event handler, called by the underlying TDI
3234 * transport in response to an incoming request to the listening daemon.
3236 * it will grab a vacancy backlog from the children tconn list, and
3237 * build an acception Irp with it, then transfer the Irp to TDI driver.
3240 * TdiEventContext: the tdi connnection object of the listening daemon
3244 * Nt kernel status code
3251 KsConnectEventHandler(
3252 IN PVOID TdiEventContext,
3253 IN LONG RemoteAddressLength,
3254 IN PVOID RemoteAddress,
3255 IN LONG UserDataLength,
3257 IN LONG OptionsLength,
3259 OUT CONNECTION_CONTEXT * ConnectionContext,
3260 OUT PIRP * AcceptIrp
3263 ks_tconn_t * parent;
3266 PFILE_OBJECT FileObject;
3267 PDEVICE_OBJECT DeviceObject;
3271 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
3273 KsPrint((2,"KsConnectEventHandler: call at Irql: %u\n", KeGetCurrentIrql()));
3274 parent = (ks_tconn_t *) TdiEventContext;
3276 LASSERT(parent->kstc_type == kstt_listener);
3278 cfs_spin_lock(&(parent->kstc_lock));
3280 if (parent->kstc_state == ksts_listening) {
3282 /* allocate a new ConnectionInfo to backup the peer's info */
3284 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
3285 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) +
3286 RemoteAddressLength, 'iCsK' );
3288 if (NULL == ConnectionInfo) {
3290 Status = STATUS_INSUFFICIENT_RESOURCES;
3291 cfs_enter_debugger();
3295 /* initializing ConnectionInfo structure ... */
3297 ConnectionInfo->UserDataLength = UserDataLength;
3298 ConnectionInfo->UserData = UserData;
3299 ConnectionInfo->OptionsLength = OptionsLength;
3300 ConnectionInfo->Options = Options;
3301 ConnectionInfo->RemoteAddressLength = RemoteAddressLength;
3302 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
3305 ConnectionInfo->RemoteAddress,
3310 /* get the vacancy listening child tdi connections */
3312 child = KsGetVacancyBacklog(parent);
3316 cfs_spin_lock(&(child->kstc_lock));
3317 child->child.kstc_info.ConnectionInfo = ConnectionInfo;
3318 child->child.kstc_info.Remote = ConnectionInfo->RemoteAddress;
3319 child->kstc_state = ksts_connecting;
3320 cfs_spin_unlock(&(child->kstc_lock));
3324 KsPrint((1, "KsConnectEventHandler: No enough backlogs: Refsued the connectio: %xh\n", parent));
3325 Status = STATUS_INSUFFICIENT_RESOURCES;
3329 FileObject = child->child.kstc_info.FileObject;
3330 DeviceObject = IoGetRelatedDeviceObject (FileObject);
3332 Irp = KsBuildTdiIrp(DeviceObject);
3338 KsAcceptCompletionRoutine,
3344 IoSetNextIrpStackLocation(Irp);
3346 /* grap the refer of the child tdi connection */
3347 ks_get_tconn(child);
3349 Status = STATUS_MORE_PROCESSING_REQUIRED;
3351 *ConnectionContext = child;
3355 Status = STATUS_CONNECTION_REFUSED;
3359 cfs_spin_unlock(&(parent->kstc_lock));
3365 cfs_spin_unlock(&(parent->kstc_lock));
3368 *ConnectionContext = NULL;
3370 if (ConnectionInfo) {
3371 ExFreePool(ConnectionInfo);
3382 * KsDisconnectCompletionRoutine
3383 * the Irp completion routine for TdiBuildDisconect
3385 * We just signal the event and return MORE_PRO... to
3386 * let the caller take the responsibility of the Irp.
3389 * DeviceObject: the device object of the transport
3390 * Irp: the Irp is being completed.
3391 * Context: the event specified by the caller
3401 KsDisconectCompletionRoutine (
3402 IN PDEVICE_OBJECT DeviceObject,
3408 KeSetEvent((PKEVENT) Context, 0, FALSE);
3410 return STATUS_MORE_PROCESSING_REQUIRED;
3412 UNREFERENCED_PARAMETER(DeviceObject);
3417 * KsDisconnectHelper
3418 * the routine to be executed in the WorkItem procedure
3419 * this routine is to disconnect a tdi connection
3422 * Workitem: the context transferred to the workitem
3428 * tconn is already referred in abort_connecton ...
3432 KsDisconnectHelper(PKS_DISCONNECT_WORKITEM WorkItem)
3434 ks_tconn_t * tconn = WorkItem->tconn;
3436 KsPrint((1, "KsDisconnectHelper: disconnecting tconn=%p\n", tconn));
3437 ks_disconnect_tconn(tconn, WorkItem->Flags);
3439 KeSetEvent(&(WorkItem->Event), 0, FALSE);
3441 cfs_spin_lock(&(tconn->kstc_lock));
3442 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3443 cfs_spin_unlock(&(tconn->kstc_lock));
3444 ks_put_tconn(tconn);
3449 * KsDisconnectEventHandler
3450 * Disconnect event handler event handler, called by the underlying TDI transport
3451 * in response to an incoming disconnection notification from a remote node.
3454 * ConnectionContext: tdi connnection object
3455 * DisconnectFlags: specifies the nature of the disconnection
3459 * Nt kernel status code
3467 KsDisconnectEventHandler(
3468 IN PVOID TdiEventContext,
3469 IN CONNECTION_CONTEXT ConnectionContext,
3470 IN LONG DisconnectDataLength,
3471 IN PVOID DisconnectData,
3472 IN LONG DisconnectInformationLength,
3473 IN PVOID DisconnectInformation,
3474 IN ULONG DisconnectFlags
3479 PKS_DISCONNECT_WORKITEM WorkItem;
3481 tconn = (ks_tconn_t *)ConnectionContext;
3483 KsPrint((2, "KsTcpDisconnectEventHandler: called at Irql: %xh\n",
3484 KeGetCurrentIrql() ));
3486 KsPrint((2, "tconn = %x DisconnectFlags= %xh\n",
3487 tconn, DisconnectFlags));
3489 ks_get_tconn(tconn);
3490 cfs_spin_lock(&(tconn->kstc_lock));
3492 WorkItem = &(tconn->kstc_disconnect);
3494 if (tconn->kstc_state != ksts_connected) {
3496 Status = STATUS_SUCCESS;
3500 if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_ABORT)) {
3502 Status = STATUS_REMOTE_DISCONNECT;
3504 } else if (cfs_is_flag_set(DisconnectFlags, TDI_DISCONNECT_RELEASE)) {
3506 Status = STATUS_GRACEFUL_DISCONNECT;
3509 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
3511 ks_get_tconn(tconn);
3513 WorkItem->Flags = DisconnectFlags;
3514 WorkItem->tconn = tconn;
3516 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
3518 /* queue the workitem to call */
3519 ExQueueWorkItem(&(WorkItem->WorkItem), DelayedWorkQueue);
3523 cfs_spin_unlock(&(tconn->kstc_lock));
3524 ks_put_tconn(tconn);
3530 KsTcpReceiveCompletionRoutine(
3532 IN PKS_TCP_COMPLETION_CONTEXT Context
3535 ks_tconn_t *tconn = Context->tconn;
3536 NTSTATUS status = Irp->IoStatus.Status;
3537 ULONG length = (ULONG)Irp->IoStatus.Information;
3539 LASSERT(Context != NULL);
3541 if (NT_SUCCESS(status)) {
3543 PKS_TSDUMGR TsduMgr = Context->TsduMgr;
3544 PCHAR Buffer = Context->Buffer;
3546 KsPrint((4, "KsTcpReceiveCompletionRoutine: Total %xh bytes.\n",
3547 TsduMgr->TotalBytes ));
3549 ks_lock_tsdumgr(TsduMgr);
3550 KsWriteTsduBuf(TsduMgr, Context->Buffer, length, 0);
3551 /* signal TsduMgr event */
3552 KeSetEvent(&(Context->TsduMgr->Event), 0, FALSE);
3553 ks_unlock_tsdumgr(TsduMgr);
3555 /* re-active the ks connection and wake up the scheduler */
3556 if (KS_CAN_SCHED(TsduMgr)) {
3557 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3558 tconn->kstc_sched_cb(tconn, FALSE);
3562 ks_put_tconn(tconn);
3566 /* un-expected errors occur, we must abort the connection */
3567 ks_put_tconn(tconn);
3568 ks_abort_tconn(tconn);
3574 /* free the Context structure... */
3575 ASSERT(Context->Magic == KS_TCP_CONTEXT_MAGIC);
3576 Context->Magic = 'CDAB';
3583 /* release mdl chain */
3584 if (Irp->MdlAddress) {
3585 KsReleaseMdl(Irp->MdlAddress, FALSE);
3588 /* free irp packet */
3597 * KsTcpCompletionRoutine
3598 * the Irp completion routine for TdiBuildSend and TdiBuildReceive ...
3599 * We need call the use's own CompletionRoutine if specified. Or
3600 * it's a synchronous case, we need signal the event.
3603 * DeviceObject: the device object of the transport
3604 * Irp: the Irp is being completed.
3605 * Context: the context we specified when issuing the Irp
3615 KsTcpCompletionRoutine(
3616 IN PDEVICE_OBJECT DeviceObject,
3623 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3624 ks_tconn_t * tconn = NULL;
3626 context = (PKS_TCP_COMPLETION_CONTEXT) Context;
3627 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3628 tconn = context->tconn;
3630 if (context->CompletionRoutine) {
3633 // Giving control to user specified CompletionRoutine ...
3636 context->CompletionRoutine(Irp, context);
3641 // Signaling the Event ...
3643 LASSERT(NULL != context->Event);
3644 KeSetEvent(context->Event, 0, FALSE);
3646 /* drop the reference count of the tconn object */
3647 ks_put_tconn(tconn);
3652 /* cfs_enter_debugger(); */
3655 return STATUS_MORE_PROCESSING_REQUIRED;
3659 * KsTcpSendCompletionRoutine
3660 * the user specified Irp completion routine for asynchronous
3661 * data transmission requests.
3663 * It will do th cleanup job of the ks_tx_t and wake up the
3664 * ks scheduler thread
3667 * Irp: the Irp is being completed.
3668 * Context: the context we specified when issuing the Irp
3678 KsTcpSendCompletionRoutine(
3680 IN PKS_TCP_COMPLETION_CONTEXT context
3683 NTSTATUS status = Irp->IoStatus.Status;
3684 ULONG rc = (ULONG)(ULONG_PTR)Irp->IoStatus.Information;
3685 ks_tconn_t * tconn = context->tconn;
3687 PKS_TSDUMGR TsduMgr = context->TsduMgr;
3688 PKEVENT Event = context->Event;
3690 LASSERT(tconn != NULL && tconn->kstc_magic == KS_TCONN_MAGIC);
3691 LASSERT(context && context->Magic == KS_TCP_CONTEXT_MAGIC);
3693 KsPrint((4, "KsTcpSendCompltionRoutine: tconn = %p TsduMgr = %p "
3694 "status = %xh bytes = %xh/%x\n", tconn, TsduMgr, status,
3695 Irp->IoStatus.Information, TsduMgr->TotalBytes));
3697 ks_lock_tsdumgr(TsduMgr);
3699 if (NT_SUCCESS(status)) {
3701 /* cleanup processed TsduMgr queue */
3702 KsReleaseTsdus(tconn, TsduMgr, rc);
3704 /* queue to delivery engine if there's still remained data */
3705 TsduMgr->Busy = FALSE;
3706 if (TsduMgr->TotalBytes > 0) {
3707 KsQueueTdiEngine(tconn, TsduMgr);
3709 /* signal TsduMgr event */
3710 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3711 ks_unlock_tsdumgr(TsduMgr);
3714 * now it's time to re-queue the conns into the
3715 * scheduler queue and wake the scheduler thread.
3718 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3719 tconn->kstc_sched_cb(tconn, TRUE);
3724 ks_unlock_tsdumgr(TsduMgr);
3726 KsPrint((1, "KsTcpSendCompltionRoutine: failed tconn: %p "
3727 "TsduMgr: %p status: %xh\n", tconn, TsduMgr, status));
3729 /* cfs_enter_debugger(); */
3732 * for the case that the transmission is unsuccessful,
3733 * we need abort the tdi connection, but not destroy it.
3734 * the socknal conn will drop the refer count, then the
3735 * tdi connection will be freed.
3738 ks_abort_tconn(tconn);
3741 /* drop tconn reference */
3742 ks_put_tconn(tconn);
3744 /* freeing the context structure */
3746 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3747 context->Magic = 'CDAB';
3751 /* free the Irp structure */
3753 /* mdl chain was released by KsReleaseTsdus*/
3754 Irp->MdlAddress = NULL;
3763 * Normal receive event handler
3765 * It will move data from system Tsdu to our TsduList
3769 KsTcpReceiveEventHandler(
3770 IN PVOID TdiEventContext,
3771 IN CONNECTION_CONTEXT ConnectionContext,
3772 IN ULONG ReceiveFlags,
3773 IN ULONG BytesIndicated,
3774 IN ULONG BytesAvailable,
3775 OUT ULONG * BytesTaken,
3777 OUT PIRP * IoRequestPacket
3784 BOOLEAN bIsExpedited;
3785 BOOLEAN bIsCompleteTsdu;
3787 PCHAR Buffer = NULL;
3790 PFILE_OBJECT FileObject;
3791 PDEVICE_OBJECT DeviceObject;
3792 PKS_TSDUMGR TsduMgr;
3794 PKS_TCP_COMPLETION_CONTEXT context = NULL;
3796 tconn = (ks_tconn_t *) ConnectionContext;
3797 ks_get_tconn(tconn);
3799 /* check expedited flag */
3800 bIsExpedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
3802 /* check whether the whole body of payload is received or not */
3803 if ( (cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_ENTIRE_MESSAGE)) &&
3804 (BytesIndicated == BytesAvailable) ) {
3805 bIsCompleteTsdu = TRUE;
3807 bIsCompleteTsdu = FALSE;
3810 KsPrint((4, "KsTcpReceiveEventHandler BytesIndicated = %d BytesAvailable = %d ...\n",
3811 BytesIndicated, BytesAvailable));
3812 KsPrint((4, "bIsCompleteTsdu = %d bIsExpedited = %d\n", bIsCompleteTsdu, bIsExpedited ));
3814 /* check whether we are conntected or not listener */
3815 if ( !((tconn->kstc_state == ksts_connected) &&
3816 (tconn->kstc_type == kstt_sender ||
3817 tconn->kstc_type == kstt_child))) {
3819 *BytesTaken = BytesIndicated;
3820 ks_put_tconn(tconn);
3821 return (STATUS_SUCCESS);
3824 /* query tsdu mgr */
3825 TsduMgr = KsQueryTsduMgr(tconn, bIsExpedited, FALSE);
3827 ks_lock_tsdumgr(TsduMgr);
3828 if (bIsCompleteTsdu) {
3830 *BytesTaken = KsWriteTsduDat(TsduMgr, Tsdu, BytesAvailable, 0);
3831 status = STATUS_SUCCESS;
3833 /* signal TsduMgr event */
3834 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
3835 ks_unlock_tsdumgr(TsduMgr);
3837 /* re-active the ks connection and wake up the scheduler */
3838 if (KS_CAN_SCHED(TsduMgr)) {
3839 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
3840 tconn->kstc_sched_cb(tconn, FALSE);
3846 ks_unlock_tsdumgr(TsduMgr);
3848 /* allocate buffer for further data in tsdu queue */
3849 Buffer = ExAllocatePool(NonPagedPool, BytesAvailable);
3850 if (NULL == Buffer) {
3851 status = STATUS_INSUFFICIENT_RESOURCES;
3855 /* there's still data in tdi internal queue, we need issue a new
3856 Irp to receive all of them. first allocate the tcp context */
3857 context = cfs_alloc(sizeof(KS_TCP_COMPLETION_CONTEXT), 0);
3859 status = STATUS_INSUFFICIENT_RESOURCES;
3863 /* setup the context */
3864 RtlZeroMemory(context, sizeof(KS_TCP_COMPLETION_CONTEXT));
3865 context->Magic = KS_TCP_CONTEXT_MAGIC;
3866 context->tconn = tconn;
3867 context->CompletionRoutine = KsTcpReceiveCompletionRoutine;
3868 context->CompletionContext = Buffer;
3869 context->TsduMgr = TsduMgr;
3870 context->Buffer = Buffer;
3871 context->Event = &(TsduMgr->Event);
3873 if (tconn->kstc_type == kstt_sender) {
3874 FileObject = tconn->sender.kstc_info.FileObject;
3876 FileObject = tconn->child.kstc_info.FileObject;
3878 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3880 /* build new tdi Irp and setup it. */
3881 Irp = KsBuildTdiIrp(DeviceObject);
3886 status = KsLockUserBuffer(
3894 if (!NT_SUCCESS(status)) {
3902 KsTcpCompletionRoutine,
3905 ReceiveFlags & (TDI_RECEIVE_NORMAL | TDI_RECEIVE_EXPEDITED),
3909 IoSetNextIrpStackLocation(Irp);
3911 /* return the newly built Irp to transport driver,
3912 it will process it to receive all the data */
3914 *IoRequestPacket = Irp;
3917 ks_get_tconn(tconn);
3918 status = STATUS_MORE_PROCESSING_REQUIRED;
3921 ks_put_tconn(tconn);
3928 KsReleaseMdl(Mdl, FALSE);
3940 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
3941 context->Magic = 'CDAB';
3945 ks_abort_tconn(tconn);
3946 ks_put_tconn(tconn);
3948 *BytesTaken = BytesAvailable;
3950 return STATUS_SUCCESS;
3954 * Expedited receive event handler
3958 KsTcpReceiveExpeditedEventHandler(
3959 IN PVOID TdiEventContext,
3960 IN CONNECTION_CONTEXT ConnectionContext,
3961 IN ULONG ReceiveFlags,
3962 IN ULONG BytesIndicated,
3963 IN ULONG BytesAvailable,
3964 OUT ULONG * BytesTaken,
3966 OUT PIRP * IoRequestPacket
3969 return KsTcpReceiveEventHandler(
3972 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
3982 * Bulk receive event handler
3984 * It will queue all the system Tsdus to our TsduList.
3985 * Then later ks_recv_mdl will release them.
3989 KsTcpChainedReceiveEventHandler (
3990 IN PVOID TdiEventContext, // the event context
3991 IN CONNECTION_CONTEXT ConnectionContext,
3992 IN ULONG ReceiveFlags,
3993 IN ULONG ReceiveLength,
3994 IN ULONG StartingOffset, // offset of start of client data in TSDU
3995 IN PMDL Tsdu, // TSDU data chain
3996 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4003 PKS_TSDUMGR TsduMgr;
4007 tconn = (ks_tconn_t *) ConnectionContext;
4008 expedited = cfs_is_flag_set(ReceiveFlags, TDI_RECEIVE_EXPEDITED);
4010 KsPrint((4, "KsTcpChainedReceive: sock: %p conn: %p ReceiveLength: %xh "
4011 "bIsExpedited: %d Tsdu=%p TsduDesc=%p data=%xh\n",
4012 tconn, tconn->kstc_conn, ReceiveLength, expedited,
4013 Tsdu, TsduDescriptor, *((PULONG)KsMapMdlBuffer(Tsdu))));
4015 ks_get_tconn(tconn);
4017 /* check whether we are conntected or not listener */
4018 if ( !((tconn->kstc_state == ksts_connected) &&
4019 (tconn->kstc_type == kstt_sender ||
4020 tconn->kstc_type == kstt_child))) {
4022 ks_put_tconn(tconn);
4023 return (STATUS_SUCCESS);
4028 TsduMgr = KsQueryTsduMgr(tconn, expedited, FALSE);
4029 ks_lock_tsdumgr(TsduMgr);
4031 KsWriteTsduMdl(TsduMgr, Tsdu, TsduDescriptor,
4032 StartingOffset, ReceiveLength, 0);
4033 status = STATUS_PENDING;
4035 KsWriteTsduDat(TsduMgr, (PCHAR)KsMapMdlBuffer(Tsdu) +
4036 StartingOffset, ReceiveLength, 0);
4037 status = STATUS_SUCCESS;
4039 KeSetEvent(&(TsduMgr->Event), 0, FALSE);
4040 ks_unlock_tsdumgr(TsduMgr);
4042 /* re-active the ks connection and wake up the scheduler */
4043 if (KS_CAN_SCHED(TsduMgr)) {
4044 if (tconn->kstc_conn && tconn->kstc_sched_cb) {
4045 tconn->kstc_sched_cb(tconn, FALSE);
4051 ks_abort_tconn(tconn);
4052 status = STATUS_CONNECTION_ABORTED;
4055 ks_put_tconn(tconn);
4057 /* Return STATUS_PENDING to system because we are still
4058 owning the MDL resources. ks_recv_mdl is expected
4059 to free the MDL resources. */
4066 * Expedited & Bulk receive event handler
4070 KsTcpChainedReceiveExpeditedEventHandler (
4071 IN PVOID TdiEventContext, // the event context
4072 IN CONNECTION_CONTEXT ConnectionContext,
4073 IN ULONG ReceiveFlags,
4074 IN ULONG ReceiveLength,
4075 IN ULONG StartingOffset, // offset of start of client data in TSDU
4076 IN PMDL Tsdu, // TSDU data chain
4077 IN PVOID TsduDescriptor // for call to TdiReturnChainedReceives
4080 return KsTcpChainedReceiveEventHandler(
4083 ReceiveFlags | TDI_RECEIVE_EXPEDITED,
4093 * setup all the event handler callbacks
4096 * tconn: the tdi connecton object
4099 * int: ks error code
4110 NTSTATUS status = STATUS_SUCCESS;
4111 KS_EVENT_HANDLERS handlers;
4113 /* to make sure the address object is opened already */
4114 if (tconn->kstc_addr.FileObject == NULL) {
4118 /* initialize the handlers indictor array. for sender and listenr,
4119 there are different set of callbacks. for child, we just return. */
4121 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4123 SetEventHandler(handlers, TDI_EVENT_ERROR, KsErrorEventHandler);
4124 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, KsDisconnectEventHandler);
4125 SetEventHandler(handlers, TDI_EVENT_RECEIVE, KsTcpReceiveEventHandler);
4126 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, KsTcpReceiveExpeditedEventHandler);
4127 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, KsTcpChainedReceiveEventHandler);
4129 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, KsTcpChainedReceiveExpeditedEventHandler);
4131 if (tconn->kstc_type == kstt_listener) {
4132 SetEventHandler(handlers, TDI_EVENT_CONNECT, KsConnectEventHandler);
4133 } else if (tconn->kstc_type == kstt_child) {
4137 /* set all the event callbacks */
4138 status = KsSetEventHandlers(
4139 tconn->kstc_addr.FileObject, /* Address File Object */
4140 tconn, /* Event Context */
4141 &handlers /* Event callback handlers */
4146 return cfs_error_code(status);
4152 * disable all the event handler callbacks (set to NULL)
4155 * tconn: the tdi connecton object
4158 * int: ks error code
4169 NTSTATUS status = STATUS_SUCCESS;
4170 KS_EVENT_HANDLERS handlers;
4172 /* to make sure the address object is opened already */
4173 if (tconn->kstc_addr.FileObject == NULL) {
4177 /* initialize the handlers indictor array. for sender and listenr,
4178 there are different set of callbacks. for child, we just return. */
4180 memset(&handlers, 0, sizeof(KS_EVENT_HANDLERS));
4182 SetEventHandler(handlers, TDI_EVENT_ERROR, NULL);
4183 SetEventHandler(handlers, TDI_EVENT_DISCONNECT, NULL);
4184 SetEventHandler(handlers, TDI_EVENT_RECEIVE, NULL);
4185 SetEventHandler(handlers, TDI_EVENT_RECEIVE_EXPEDITED, NULL);
4186 SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE, NULL);
4187 // SetEventHandler(handlers, TDI_EVENT_CHAINED_RECEIVE_EXPEDITED, NULL);
4189 if (tconn->kstc_type == kstt_listener) {
4190 SetEventHandler(handlers, TDI_EVENT_CONNECT, NULL);
4191 } else if (tconn->kstc_type == kstt_child) {
4195 /* set all the event callbacks */
4196 status = KsSetEventHandlers(
4197 tconn->kstc_addr.FileObject, /* Address File Object */
4198 tconn, /* Event Context */
4199 &handlers /* Event callback handlers */
4204 return cfs_error_code(status);
4208 KsPrintProviderInfo(
4210 PTDI_PROVIDER_INFO ProviderInfo
4213 KsPrint((2, "%ws ProviderInfo:\n", DeviceName));
4215 KsPrint((2, " Version : 0x%4.4X\n", ProviderInfo->Version ));
4216 KsPrint((2, " MaxSendSize : %d\n", ProviderInfo->MaxSendSize ));
4217 KsPrint((2, " MaxConnectionUserData: %d\n", ProviderInfo->MaxConnectionUserData ));
4218 KsPrint((2, " MaxDatagramSize : %d\n", ProviderInfo->MaxDatagramSize ));
4219 KsPrint((2, " ServiceFlags : 0x%8.8X\n", ProviderInfo->ServiceFlags ));
4221 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) {
4222 KsPrint((2, " CONNECTION_MODE\n"));
4225 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ORDERLY_RELEASE) {
4226 KsPrint((2, " ORDERLY_RELEASE\n"));
4229 if (ProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE) {
4230 KsPrint((2, " CONNECTIONLESS_MODE\n"));
4233 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY) {
4234 KsPrint((2, " ERROR_FREE_DELIVERY\n"));
4237 if( ProviderInfo->ServiceFlags & TDI_SERVICE_SECURITY_LEVEL ) {
4238 KsPrint((2, " SECURITY_LEVEL\n"));
4241 if (ProviderInfo->ServiceFlags & TDI_SERVICE_BROADCAST_SUPPORTED) {
4242 KsPrint((2, " BROADCAST_SUPPORTED\n"));
4245 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MULTICAST_SUPPORTED) {
4246 KsPrint((2, " MULTICAST_SUPPORTED\n"));
4249 if (ProviderInfo->ServiceFlags & TDI_SERVICE_DELAYED_ACCEPTANCE) {
4250 KsPrint((2, " DELAYED_ACCEPTANCE\n"));
4253 if (ProviderInfo->ServiceFlags & TDI_SERVICE_EXPEDITED_DATA) {
4254 KsPrint((2, " EXPEDITED_DATA\n"));
4257 if( ProviderInfo->ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) {
4258 KsPrint((2, " INTERNAL_BUFFERING\n"));
4261 if (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) {
4262 KsPrint((2, " ROUTE_DIRECTED\n"));
4265 if (ProviderInfo->ServiceFlags & TDI_SERVICE_NO_ZERO_LENGTH) {
4266 KsPrint((2, " NO_ZERO_LENGTH\n"));
4269 if (ProviderInfo->ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
4270 KsPrint((2, " POINT_TO_POINT\n"));
4273 if (ProviderInfo->ServiceFlags & TDI_SERVICE_MESSAGE_MODE) {
4274 KsPrint((2, " MESSAGE_MODE\n"));
4277 if (ProviderInfo->ServiceFlags & TDI_SERVICE_HALF_DUPLEX) {
4278 KsPrint((2, " HALF_DUPLEX\n"));
4281 KsPrint((2, " MinimumLookaheadData : %d\n", ProviderInfo->MinimumLookaheadData ));
4282 KsPrint((2, " MaximumLookaheadData : %d\n", ProviderInfo->MaximumLookaheadData ));
4283 KsPrint((2, " NumberOfResources : %d\n", ProviderInfo->NumberOfResources ));
4289 * allocate a new tconn structure from the SLAB cache or
4290 * NonPaged sysetm pool
4296 * ks_tconn_t *: the address of tconn or NULL if it fails
4305 ks_tconn_t * tconn = NULL;
4307 /* allocate ksoc_tconn_t from the slab cache memory */
4308 tconn = (ks_tconn_t *)cfs_mem_cache_alloc(
4309 ks_data.ksnd_tconn_slab, CFS_ALLOC_ZERO);
4313 /* zero tconn elements */
4314 memset(tconn, 0, sizeof(ks_tconn_t));
4316 /* initialize the tconn ... */
4317 tconn->kstc_magic = KS_TCONN_MAGIC;
4319 ExInitializeWorkItem(
4320 &(tconn->kstc_disconnect.WorkItem),
4322 &(tconn->kstc_disconnect)
4326 &(tconn->kstc_disconnect.Event),
4327 SynchronizationEvent,
4330 ExInitializeWorkItem(
4331 &(tconn->kstc_destroy),
4336 cfs_spin_lock_init(&(tconn->kstc_lock));
4338 ks_get_tconn(tconn);
4339 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
4341 /* attach it into global list in ks_data */
4343 cfs_list_add(&(tconn->kstc_list), &(ks_data.ksnd_tconns));
4344 ks_data.ksnd_ntconns++;
4345 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
4347 tconn->kstc_rcv_wnd = tconn->kstc_snd_wnd = 0x10000;
4349 KsPrint((3, "ks_create_tconn: new connection: %p\n", tconn));
4355 * free the tconn structure to the SLAB cache or NonPaged
4359 * tconn: the tcon is to be freed
4369 ks_free_tconn(ks_tconn_t * tconn)
4371 LASSERT(cfs_atomic_read(&(tconn->kstc_refcount)) == 0);
4373 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
4375 /* remove it from the global list */
4376 cfs_list_del(&tconn->kstc_list);
4377 ks_data.ksnd_ntconns--;
4379 /* if this is the last tconn, it would be safe for
4380 ks_tdi_fini_data to quit ... */
4381 if (ks_data.ksnd_ntconns == 0) {
4382 cfs_wake_event(&ks_data.ksnd_tconn_exit);
4384 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
4386 /* free the structure memory */
4387 cfs_mem_cache_free(ks_data.ksnd_tconn_slab, tconn);
4389 KsPrint((3, "ks_free_tconn: tconn %p is freed.\n", tconn));
4395 * Initialize the tconn as a listener (daemon)
4398 * tconn: the listener tconn
4412 /* preparation: intialize the tconn members */
4414 tconn->kstc_type = kstt_listener;
4416 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4418 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_listening.list));
4419 CFS_INIT_LIST_HEAD(&(tconn->listener.kstc_accepted.list));
4421 cfs_init_event( &(tconn->listener.kstc_accept_event),
4425 cfs_init_event( &(tconn->listener.kstc_destroy_event),
4429 tconn->kstc_state = ksts_inited;
4435 * Initialize the tconn as a sender
4438 * tconn: the sender tconn
4452 tconn->kstc_type = kstt_sender;
4453 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4455 KsInitializeKsChain(&(tconn->sender.kstc_recv));
4456 KsInitializeKsChain(&(tconn->sender.kstc_send));
4458 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4459 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4461 tconn->kstc_state = ksts_inited;
4466 * Initialize the tconn as a child
4469 * tconn: the child tconn
4483 tconn->kstc_type = kstt_child;
4484 RtlInitUnicodeString(&(tconn->kstc_dev), TCP_DEVICE_NAME);
4486 KsInitializeKsChain(&(tconn->child.kstc_recv));
4487 KsInitializeKsChain(&(tconn->child.kstc_send));
4489 tconn->kstc_snd_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4490 tconn->kstc_rcv_wnd = TDINAL_WINDOW_DEFAULT_SIZE;
4492 tconn->kstc_state = ksts_inited;
4497 * increase the reference count of the tconn with 1
4500 * tconn: the tdi connection to be referred
4514 cfs_atomic_inc(&(tconn->kstc_refcount));
4519 * decrease the reference count of the tconn and destroy
4520 * it if the refercount becomes 0.
4523 * tconn: the tdi connection to be dereferred
4537 if (cfs_atomic_dec_and_test(&(tconn->kstc_refcount))) {
4539 cfs_spin_lock(&(tconn->kstc_lock));
4541 if ( ( tconn->kstc_type == kstt_child ||
4542 tconn->kstc_type == kstt_sender ) &&
4543 ( tconn->kstc_state == ksts_connected ) ) {
4545 cfs_spin_unlock(&(tconn->kstc_lock));
4547 ks_abort_tconn(tconn);
4551 if (cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY)) {
4552 cfs_enter_debugger();
4555 &(tconn->kstc_destroy),
4559 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DESTROY_BUSY);
4562 cfs_spin_unlock(&(tconn->kstc_lock));
4569 * cleanup the tdi connection and free it
4572 * tconn: the tdi connection to be cleaned.
4586 LASSERT(tconn->kstc_refcount.counter == 0);
4588 if (tconn->kstc_type == kstt_listener) {
4590 KsResetHandlers(tconn);
4592 /* for listener, we just need to close the address object */
4594 tconn->kstc_addr.Handle,
4595 tconn->kstc_addr.FileObject
4598 tconn->kstc_state = ksts_inited;
4600 } else if (tconn->kstc_type == kstt_child) {
4602 /* for child tdi conections */
4604 /* disassociate the relation between it's connection object
4605 and the address object */
4607 if (tconn->kstc_state == ksts_associated) {
4608 KsDisassociateAddress(
4609 tconn->child.kstc_info.FileObject
4613 /* release the connection object */
4616 tconn->child.kstc_info.Handle,
4617 tconn->child.kstc_info.FileObject
4620 /* release it's refer of it's parent's address object */
4623 tconn->kstc_addr.FileObject
4626 cfs_spin_lock(&tconn->child.kstc_parent->kstc_lock);
4627 cfs_spin_lock(&tconn->kstc_lock);
4629 tconn->kstc_state = ksts_inited;
4631 /* remove it frome it's parent's queues */
4633 if (tconn->child.kstc_queued) {
4635 cfs_list_del(&(tconn->child.kstc_link));
4637 if (tconn->child.kstc_queueno) {
4639 LASSERT(tconn->child.kstc_parent->listener.kstc_accepted.num > 0);
4640 tconn->child.kstc_parent->listener.kstc_accepted.num -= 1;
4644 LASSERT(tconn->child.kstc_parent->listener.kstc_listening.num > 0);
4645 tconn->child.kstc_parent->listener.kstc_listening.num -= 1;
4648 tconn->child.kstc_queued = FALSE;
4651 cfs_spin_unlock(&tconn->kstc_lock);
4652 cfs_spin_unlock(&tconn->child.kstc_parent->kstc_lock);
4654 /* drop the reference of the parent tconn */
4655 ks_put_tconn(tconn->child.kstc_parent);
4657 } else if (tconn->kstc_type == kstt_sender) {
4659 KsResetHandlers(tconn);
4661 /* release the connection object */
4664 tconn->sender.kstc_info.Handle,
4665 tconn->sender.kstc_info.FileObject
4668 /* release it's refer of it's parent's address object */
4670 tconn->kstc_addr.Handle,
4671 tconn->kstc_addr.FileObject
4674 tconn->kstc_state = ksts_inited;
4677 cfs_enter_debugger();
4680 /* free the tconn structure ... */
4682 ks_free_tconn(tconn);
4687 * Query the the options of the tcp stream connnection
4690 * tconn: the tdi connection
4692 * OptionValue: buffer to store the option value
4693 * Length: the length of the value, to be returned
4696 * int: ks return code
4710 NTSTATUS Status = STATUS_SUCCESS;
4712 IO_STATUS_BLOCK IoStatus;
4714 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfoEx;
4716 PFILE_OBJECT ConnectionObject;
4717 PDEVICE_OBJECT DeviceObject = NULL;
4720 PIO_STACK_LOCATION IrpSp = NULL;
4724 /* make sure the tdi connection is connected ? */
4726 ks_get_tconn(tconn);
4728 if (tconn->kstc_state != ksts_connected) {
4729 Status = STATUS_INVALID_PARAMETER;
4733 LASSERT(tconn->kstc_type == kstt_sender ||
4734 tconn->kstc_type == kstt_child);
4736 if (tconn->kstc_type == kstt_sender) {
4737 ConnectionObject = tconn->sender.kstc_info.FileObject;
4739 ConnectionObject = tconn->child.kstc_info.FileObject;
4742 QueryInfoEx.ID.toi_id = ID;
4743 QueryInfoEx.ID.toi_type = INFO_TYPE_CONNECTION;
4744 QueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
4745 QueryInfoEx.ID.toi_entity.tei_entity = CO_TL_ENTITY;
4746 QueryInfoEx.ID.toi_entity.tei_instance = 0;
4748 RtlZeroMemory(&(QueryInfoEx.Context), CONTEXT_SIZE);
4750 KeInitializeEvent(&Event, NotificationEvent, FALSE);
4751 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4753 Irp = IoBuildDeviceIoControlRequest(
4754 IOCTL_TCP_QUERY_INFORMATION_EX,
4757 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
4766 Status = STATUS_INSUFFICIENT_RESOURCES;
4770 IrpSp = IoGetNextIrpStackLocation(Irp);
4772 if (IrpSp == NULL) {
4776 Status = STATUS_INSUFFICIENT_RESOURCES;
4780 IrpSp->FileObject = ConnectionObject;
4781 IrpSp->DeviceObject = DeviceObject;
4783 Status = IoCallDriver(DeviceObject, Irp);
4785 if (Status == STATUS_PENDING) {
4787 KeWaitForSingleObject(
4795 Status = IoStatus.Status;
4799 if (NT_SUCCESS(Status)) {
4800 *Length = (ULONG)(ULONG_PTR)IoStatus.Information;
4802 cfs_enter_debugger();
4803 memset(OptionValue, 0, *Length);
4804 Status = STATUS_SUCCESS;
4809 ks_put_tconn(tconn);
4811 return cfs_error_code(Status);
4816 * Set the the options for the tcp stream connnection
4819 * tconn: the tdi connection
4821 * OptionValue: buffer containing the new option value
4822 * Length: the length of the value
4825 * int: ks return code
4839 NTSTATUS Status = STATUS_SUCCESS;
4841 IO_STATUS_BLOCK IoStatus;
4843 ULONG SetInfoExLength;
4844 PTCP_REQUEST_SET_INFORMATION_EX SetInfoEx = NULL;
4846 PFILE_OBJECT ConnectionObject;
4847 PDEVICE_OBJECT DeviceObject = NULL;
4850 PIO_STACK_LOCATION IrpSp = NULL;
4854 /* make sure the tdi connection is connected ? */
4856 ks_get_tconn(tconn);
4858 if (tconn->kstc_state != ksts_connected) {
4859 Status = STATUS_INVALID_PARAMETER;
4863 LASSERT(tconn->kstc_type == kstt_sender ||
4864 tconn->kstc_type == kstt_child);
4866 if (tconn->kstc_type == kstt_sender) {
4867 ConnectionObject = tconn->sender.kstc_info.FileObject;
4869 ConnectionObject = tconn->child.kstc_info.FileObject;
4872 SetInfoExLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) - 1 + Length + sizeof(KEVENT);
4874 SetInfoEx = ExAllocatePoolWithTag(
4880 if (SetInfoEx == NULL) {
4881 Status = STATUS_INSUFFICIENT_RESOURCES;
4885 SetInfoEx->ID.toi_id = ID;
4887 SetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
4888 SetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
4889 SetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
4890 SetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
4892 SetInfoEx->BufferSize = Length;
4893 RtlCopyMemory(&(SetInfoEx->Buffer[0]), OptionValue, Length);
4895 Event = (PKEVENT)(&(SetInfoEx->Buffer[Length]));
4896 KeInitializeEvent(Event, NotificationEvent, FALSE);
4898 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
4900 Irp = IoBuildDeviceIoControlRequest(
4901 IOCTL_TCP_SET_INFORMATION_EX,
4913 Status = STATUS_INSUFFICIENT_RESOURCES;
4917 IrpSp = IoGetNextIrpStackLocation(Irp);
4919 if (IrpSp == NULL) {
4922 Status = STATUS_INSUFFICIENT_RESOURCES;
4926 IrpSp->FileObject = ConnectionObject;
4927 IrpSp->DeviceObject = DeviceObject;
4929 Status = IoCallDriver(DeviceObject, Irp);
4931 if (Status == STATUS_PENDING) {
4933 KeWaitForSingleObject(
4941 Status = IoStatus.Status;
4947 ExFreePool(SetInfoEx);
4950 if (!NT_SUCCESS(Status)) {
4951 KsPrint((0, "ks_set_tcp_option: error setup tcp option: "
4952 "ID (%d) Status = %xh\n", ID, Status));
4953 Status = STATUS_SUCCESS;
4956 ks_put_tconn(tconn);
4958 return cfs_error_code(Status);
4963 * bind the tdi connection object with an address
4966 * tconn: tconn to be bound
4967 * parent: the parent tconn object
4968 * ipaddr: the ip address
4969 * port: the port number
4972 * int: 0 for success or ks error codes.
4981 ks_tconn_t * parent,
4989 ks_tdi_addr_t taddr;
4991 memset(&taddr, 0, sizeof(ks_tdi_addr_t));
4993 if (tconn->kstc_state != ksts_inited) {
4995 status = STATUS_INVALID_PARAMETER;
4996 rc = cfs_error_code(status);
4999 } else if (tconn->kstc_type == kstt_child) {
5001 if (NULL == parent) {
5002 status = STATUS_INVALID_PARAMETER;
5003 rc = cfs_error_code(status);
5008 /* refer it's parent's address object */
5010 taddr = parent->kstc_addr;
5011 ObReferenceObject(taddr.FileObject);
5013 ks_get_tconn(parent);
5017 PTRANSPORT_ADDRESS TdiAddress = &(taddr.Tdi);
5020 /* intialize the tdi address*/
5022 TdiAddress->TAAddressCount = 1;
5023 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5024 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5026 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5027 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5029 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5032 /* open the transport address object */
5034 AddrLen = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address) +
5035 TDI_ADDRESS_LENGTH_IP;
5037 status = KsOpenAddress(
5045 if (!NT_SUCCESS(status)) {
5047 KsPrint((1, "ks_bind_tconn: failed to open ip addr object (%x:%d), status = %xh\n",
5048 addr, port, status ));
5049 rc = cfs_error_code(status);
5054 if (tconn->kstc_type == kstt_child) {
5055 tconn->child.kstc_parent = parent;
5058 tconn->kstc_state = ksts_bind;
5059 tconn->kstc_addr = taddr;
5068 * build tcp/streaming connection to remote peer
5071 * tconn: tconn to be connected to the peer
5072 * addr: the peer's ip address
5073 * port: the peer's port number
5076 * int: 0 for success or ks error codes.
5090 NTSTATUS status = STATUS_SUCCESS;
5093 PFILE_OBJECT ConnectionObject = NULL;
5094 PDEVICE_OBJECT DeviceObject = NULL;
5096 PTDI_CONNECTION_INFORMATION ConnectionInfo = NULL;
5101 LASSERT(tconn->kstc_type == kstt_sender);
5102 LASSERT(tconn->kstc_state == ksts_bind);
5104 ks_get_tconn(tconn);
5107 /* set the event callbacks */
5108 rc = KsSetHandlers(tconn);
5111 cfs_enter_debugger();
5116 /* create the connection file handle / object */
5117 status = KsOpenConnection(
5119 (CONNECTION_CONTEXT)tconn,
5120 &(tconn->sender.kstc_info.Handle),
5121 &(tconn->sender.kstc_info.FileObject)
5124 if (!NT_SUCCESS(status)) {
5125 rc = cfs_error_code(status);
5126 cfs_enter_debugger();
5130 /* associdate the the connection with the adress object of the tconn */
5132 status = KsAssociateAddress(
5133 tconn->kstc_addr.Handle,
5134 tconn->sender.kstc_info.FileObject
5137 if (!NT_SUCCESS(status)) {
5138 rc = cfs_error_code(status);
5139 cfs_enter_debugger();
5143 tconn->kstc_state = ksts_associated;
5145 /* Allocating Connection Info Together with the Address */
5146 AddrLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address->Address)
5147 + TDI_ADDRESS_LENGTH_IP;
5149 ConnectionInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePoolWithTag(
5150 NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + AddrLength, 'iCsK');
5152 if (NULL == ConnectionInfo) {
5154 status = STATUS_INSUFFICIENT_RESOURCES;
5155 rc = cfs_error_code(status);
5156 cfs_enter_debugger();
5160 /* Initializing ConnectionInfo ... */
5162 PTRANSPORT_ADDRESS TdiAddress;
5164 /* ConnectionInfo settings */
5166 ConnectionInfo->UserDataLength = 0;
5167 ConnectionInfo->UserData = NULL;
5168 ConnectionInfo->OptionsLength = 0;
5169 ConnectionInfo->Options = NULL;
5170 ConnectionInfo->RemoteAddressLength = AddrLength;
5171 ConnectionInfo->RemoteAddress = ConnectionInfo + 1;
5174 /* intialize the tdi address*/
5176 TdiAddress = ConnectionInfo->RemoteAddress;
5178 TdiAddress->TAAddressCount = 1;
5179 TdiAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
5180 TdiAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
5182 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_port = htons(port);
5183 ((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->in_addr = (ULONG)htonl(addr);
5185 memset(&(((PTDI_ADDRESS_IP)&(TdiAddress->Address[0].Address))->sin_zero[0]),0,8);
5188 /* Now prepare to connect the remote peer ... */
5190 ConnectionObject = tconn->sender.kstc_info.FileObject;
5191 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5193 /* allocate a new Irp */
5195 Irp = KsBuildTdiIrp(DeviceObject);
5199 status = STATUS_INSUFFICIENT_RESOURCES;
5200 rc = cfs_error_code(status);
5201 cfs_enter_debugger();
5219 /* sumbit the Irp to the underlying transport driver */
5220 status = KsSubmitTdiIrp(
5227 cfs_spin_lock(&(tconn->kstc_lock));
5229 if (NT_SUCCESS(status)) {
5231 /* Connected! the conneciton is built successfully. */
5233 tconn->kstc_state = ksts_connected;
5235 tconn->sender.kstc_info.ConnectionInfo = ConnectionInfo;
5236 tconn->sender.kstc_info.Remote = ConnectionInfo->RemoteAddress;
5238 cfs_spin_unlock(&(tconn->kstc_lock));
5242 /* Not connected! Abort it ... */
5245 cfs_enter_debugger();
5249 rc = cfs_error_code(status);
5251 tconn->kstc_state = ksts_associated;
5252 cfs_spin_unlock(&(tconn->kstc_lock));
5254 /* disassocidate the connection and the address object,
5255 after cleanup, it's safe to set the state to abort ... */
5257 if ( NT_SUCCESS(KsDisassociateAddress(
5258 tconn->sender.kstc_info.FileObject))) {
5259 tconn->kstc_state = ksts_aborted;
5262 /* reset the event callbacks */
5263 rc = KsResetHandlers(tconn);
5270 if (NT_SUCCESS(status)) {
5272 ks_query_local_ipaddr(tconn);
5276 if (ConnectionInfo) {
5277 ExFreePool(ConnectionInfo);
5284 ks_put_tconn(tconn);
5291 * ks_disconnect_tconn
5292 * disconnect the tconn from a connection
5295 * tconn: the tdi connecton object connected already
5296 * flags: flags & options for disconnecting
5299 * int: ks error code
5306 ks_disconnect_tconn(
5311 NTSTATUS status = STATUS_SUCCESS;
5313 ks_tconn_info_t * info;
5315 PFILE_OBJECT ConnectionObject;
5316 PDEVICE_OBJECT DeviceObject = NULL;
5322 ks_get_tconn(tconn);
5324 /* make sure tt's connected already and it
5325 must be a sender or a child ... */
5327 LASSERT(tconn->kstc_state == ksts_connected);
5328 LASSERT( tconn->kstc_type == kstt_sender ||
5329 tconn->kstc_type == kstt_child);
5331 /* reset all the event handlers to NULL */
5333 if (tconn->kstc_type != kstt_child) {
5334 KsResetHandlers (tconn);
5337 /* Disconnecting to the remote peer ... */
5339 if (tconn->kstc_type == kstt_sender) {
5340 info = &(tconn->sender.kstc_info);
5342 info = &(tconn->child.kstc_info);
5345 ConnectionObject = info->FileObject;
5346 DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
5348 /* allocate an Irp and setup it */
5350 Irp = KsBuildTdiIrp(DeviceObject);
5354 status = STATUS_INSUFFICIENT_RESOURCES;
5355 cfs_enter_debugger();
5361 SynchronizationEvent,
5369 KsDisconectCompletionRoutine,
5377 /* issue the Irp to the underlying transport
5378 driver to disconnect the connection */
5380 status = IoCallDriver(DeviceObject, Irp);
5382 if (STATUS_PENDING == status) {
5384 status = KeWaitForSingleObject(
5392 status = Irp->IoStatus.Status;
5395 KsPrint((2, "KsDisconnect: Disconnection is done with Status = %xh (%s) ...\n",
5396 status, KsNtStatusToString(status)));
5400 if (info->ConnectionInfo) {
5402 /* disassociate the association between connection/address objects */
5404 status = KsDisassociateAddress(ConnectionObject);
5406 if (!NT_SUCCESS(status)) {
5407 cfs_enter_debugger();
5410 cfs_spin_lock(&(tconn->kstc_lock));
5412 /* cleanup the tsdumgr Lists */
5413 KsCleanupTsdu (tconn);
5415 /* set the state of the tconn */
5416 if (NT_SUCCESS(status)) {
5417 tconn->kstc_state = ksts_disconnected;
5419 tconn->kstc_state = ksts_associated;
5422 /* free the connection info to system pool*/
5423 ExFreePool(info->ConnectionInfo);
5424 info->ConnectionInfo = NULL;
5425 info->Remote = NULL;
5427 cfs_spin_unlock(&(tconn->kstc_lock));
5430 status = STATUS_SUCCESS;
5434 ks_put_tconn(tconn);
5436 return cfs_error_code(status);
5442 * The connection is broken un-expectedly. We need do
5446 * tconn: the tdi connection
5460 PKS_DISCONNECT_WORKITEM WorkItem = NULL;
5462 WorkItem = &(tconn->kstc_disconnect);
5464 ks_get_tconn(tconn);
5465 cfs_spin_lock(&(tconn->kstc_lock));
5467 if (tconn->kstc_state != ksts_connected) {
5468 ks_put_tconn(tconn);
5471 if (!cfs_is_flag_set(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY)) {
5473 WorkItem->Flags = TDI_DISCONNECT_ABORT;
5474 WorkItem->tconn = tconn;
5476 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DISCONNECT_BUSY);
5479 &(WorkItem->WorkItem),
5485 cfs_spin_unlock(&(tconn->kstc_lock));
5490 * ks_query_local_ipaddr
5491 * query the local connection ip address
5494 * tconn: the tconn which is connected
5497 * int: ks error code
5504 ks_query_local_ipaddr(
5508 PFILE_OBJECT FileObject = NULL;
5511 PTRANSPORT_ADDRESS TdiAddress;
5512 ULONG AddressLength;
5514 if (tconn->kstc_type == kstt_sender) {
5515 FileObject = tconn->sender.kstc_info.FileObject;
5516 } else if (tconn->kstc_type == kstt_child) {
5517 FileObject = tconn->child.kstc_info.FileObject;
5519 status = STATUS_INVALID_PARAMETER;
5523 TdiAddress = &(tconn->kstc_addr.Tdi);
5524 AddressLength = MAX_ADDRESS_LENGTH;
5526 status = KsQueryIpAddress(FileObject, TdiAddress, &AddressLength);
5528 if (NT_SUCCESS(status)) {
5529 KsPrint((2, "ks_query_local_ipaddr: Local ip address = %xh port = %xh\n",
5530 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr,
5531 ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->sin_port ));
5533 KsPrint((2, "ks_query_local_ipaddr: Failed to query the connection local ip address.\n"));
5538 return cfs_error_code(status);
5542 KsCalcWhichEngine(ks_tconn_t * tconn)
5544 PTRANSPORT_ADDRESS TdiAddress = &(tconn->kstc_addr.Tdi);
5545 ULONG addr = ((PTDI_ADDRESS_IP)(&(TdiAddress->Address[0].Address)))->in_addr;
5546 ULONG sum = (addr & 0xFF) + ((addr & 0xFF00) >> 8) + ((addr & 0xFF0000) >> 16);
5548 return (int)(sum % ks_data.ksnd_engine_nums);
5552 KsQueueTdiEngine(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5554 ks_engine_mgr_t * engm;
5555 ks_engine_slot_t * engs;
5557 engm = &ks_data.ksnd_engine_mgr[KsCalcWhichEngine(tconn)];
5558 engs = &TsduMgr->Slot;
5560 if (!engs->queued) {
5561 cfs_spin_lock(&engm->lock);
5562 if (!engs->queued) {
5563 cfs_list_add_tail(&engs->link, &engm->list);
5564 engs->queued = TRUE;
5565 engs->tconn = tconn;
5567 engs->tsdumgr = TsduMgr;
5568 KeSetEvent(&(engm->start),0, FALSE);
5570 cfs_spin_unlock(&engm->lock);
5571 KsPrint((4, "KsQueueTdiEngine: TsduMgr=%p is queued to engine %p\n",
5574 KeSetEvent(&(engm->start),0, FALSE);
5578 KsRemoveTdiEngine(PKS_TSDUMGR TsduMgr)
5580 ks_engine_mgr_t * engm;
5581 ks_engine_slot_t * engs;
5583 engs = &TsduMgr->Slot;
5586 LASSERT(engm != NULL);
5587 cfs_spin_lock(&engm->lock);
5589 cfs_list_del(&engs->link);
5590 engs->queued = FALSE;
5593 engs->tsdumgr = NULL;
5595 cfs_spin_unlock(&engm->lock);
5596 KsPrint((4, "KsQueueTdiEngine: TsduMgr %p is removed from engine %p\n",
5602 KsDeliveryIrp(ks_tconn_t * tconn, PIRP irp)
5604 PFILE_OBJECT connobj;
5605 PDEVICE_OBJECT devobj;
5610 if (tconn->kstc_type == kstt_sender) {
5611 connobj = tconn->sender.kstc_info.FileObject;
5613 LASSERT(tconn->kstc_type == kstt_child);
5614 connobj = tconn->child.kstc_info.FileObject;
5616 devobj = IoGetRelatedDeviceObject(connobj);
5618 /* send irp to transport layer */
5619 status = IoCallDriver(devobj, irp);
5621 /* convert status to linux error code */
5622 if (!NT_SUCCESS(status)) {
5623 rc = cfs_error_code(status);
5626 KsPrint((4, "KsDeliveryIrp: tconn=%p irp=%p status=%xh rc=%d.\n",
5627 tconn, irp, status, rc));
5632 KsBuildSend(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr,
5633 ks_mdl_t * mdl, ulong flags )
5635 ks_tdi_tx_t * context;
5637 PFILE_OBJECT connobj;
5638 PDEVICE_OBJECT devobj;
5644 /* query mdl chain total length */
5645 length = KsQueryMdlsSize(mdl);
5647 /* we need allocate the ks_tx_t structure from memory pool. */
5648 context = cfs_alloc(sizeof(ks_tdi_tx_t), 0);
5650 status = STATUS_INSUFFICIENT_RESOURCES;
5654 /* intialize the TcpContext */
5655 memset(context,0, sizeof(ks_tdi_tx_t));
5656 context->Magic = KS_TCP_CONTEXT_MAGIC;
5657 context->tconn = tconn;
5658 context->CompletionRoutine = KsTcpSendCompletionRoutine;
5659 context->TsduMgr = TsduMgr;
5660 context->Length = length;
5663 if (tconn->kstc_type == kstt_sender) {
5664 connobj = tconn->sender.kstc_info.FileObject;
5666 LASSERT(tconn->kstc_type == kstt_child);
5667 connobj = tconn->child.kstc_info.FileObject;
5669 devobj = IoGetRelatedDeviceObject(connobj);
5670 irp = KsBuildTdiIrp(devobj);
5672 status = STATUS_INSUFFICIENT_RESOURCES;
5676 /* grab tconn reference */
5677 ks_get_tconn(tconn);
5679 /* delivery the sending request */
5684 KsTcpCompletionRoutine,
5695 /* free the context if is not used at all */
5697 ASSERT(context->Magic == KS_TCP_CONTEXT_MAGIC);
5698 context->Magic = 'CDAB';
5702 /* here need free the Irp. */
5712 KsDeliveryTsdus(ks_tconn_t * tconn, PKS_TSDUMGR TsduMgr)
5717 ks_mdl_t * mdl = NULL;
5721 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5723 ks_get_tconn(tconn);
5724 ks_lock_tsdumgr(TsduMgr);
5726 if ( tconn->kstc_type != kstt_sender &&
5727 tconn->kstc_type != kstt_child) {
5729 ks_unlock_tsdumgr(TsduMgr);
5733 if (tconn->kstc_state != ksts_connected) {
5735 ks_unlock_tsdumgr(TsduMgr);
5740 tflags = TDI_SEND_NON_BLOCKING | TDI_SEND_EXPEDITED;
5742 tflags = TDI_SEND_NON_BLOCKING;
5745 if (cfs_list_empty(&TsduMgr->TsduList)) {
5746 LASSERT(TsduMgr->TotalBytes == 0);
5747 ks_unlock_tsdumgr(TsduMgr);
5751 /* check whether there's outstanding sending requests */
5752 if (TsduMgr->Busy) {
5754 ks_unlock_tsdumgr(TsduMgr);
5758 /* probe all Tsdus and merge buffers together */
5759 mdl = KsLockTsdus(tconn, TsduMgr, &tflags, &length);
5762 LASSERT(TsduMgr->TotalBytes == 0);
5767 ks_unlock_tsdumgr(TsduMgr);
5771 KsPrint((4, "KsDeliveryTsdus: tconn=%p TsudMgr=%p, length=%xh/%xh\n",
5772 tconn, TsduMgr, length, TsduMgr->TotalBytes));
5774 /* build send irp request */
5775 irp = KsBuildSend(tconn, TsduMgr, mdl, tflags);
5778 ks_unlock_tsdumgr(TsduMgr);
5781 TsduMgr->Busy = TRUE;
5782 ks_unlock_tsdumgr(TsduMgr);
5784 /* delivery mdl chain */
5785 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5786 rc = KsDeliveryIrp(tconn, irp);
5793 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5794 ks_put_tconn(tconn);
5799 KsDeliveryEngineThread(void * context)
5801 ks_engine_mgr_t * engm = context;
5802 ks_engine_slot_t * engs;
5806 cfs_set_thread_priority(31);
5808 while (!engm->stop) {
5810 cfs_wait_event_internal(&engm->start, 0);
5812 cfs_spin_lock(&engm->lock);
5813 if (cfs_list_empty(&engm->list)) {
5814 cfs_spin_unlock(&engm->lock);
5818 list = engm->list.next;
5820 engs = cfs_list_entry(list, ks_engine_slot_t, link);
5821 LASSERT(engs->emgr == engm);
5822 LASSERT(engs->queued);
5824 engs->queued = FALSE;
5825 cfs_spin_unlock(&engm->lock);
5827 tconn = engs->tconn;
5828 LASSERT(tconn->kstc_magic == KS_TCONN_MAGIC);
5830 KsPrint((4, "KsDeliveryEngineThread: %p active: tconn=%p "
5831 "TsduMgr=%p\n", engm, tconn, engs->tsdumgr));
5832 KsDeliveryTsdus(tconn, engs->tsdumgr);
5834 LASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
5837 KeSetEvent(&engm->exit, 0, FALSE);
5844 * initialize the global data in ksockal_data
5850 * int: ks error code
5861 /* initialize tconn related globals */
5862 RtlZeroMemory(&ks_data, sizeof(ks_tdi_data_t));
5864 cfs_spin_lock_init(&ks_data.ksnd_tconn_lock);
5865 CFS_INIT_LIST_HEAD(&ks_data.ksnd_tconns);
5866 cfs_init_event(&ks_data.ksnd_tconn_exit, TRUE, FALSE);
5868 ks_data.ksnd_tconn_slab = cfs_mem_cache_create(
5869 "tcon", sizeof(ks_tconn_t) , 0, 0);
5871 if (!ks_data.ksnd_tconn_slab) {
5876 /* initialize tsdu related globals */
5877 cfs_spin_lock_init(&ks_data.ksnd_tsdu_lock);
5878 CFS_INIT_LIST_HEAD(&ks_data.ksnd_freetsdus);
5879 ks_data.ksnd_tsdu_size = TDINAL_TSDU_DEFAULT_SIZE; /* 64k */
5880 ks_data.ksnd_tsdu_slab = cfs_mem_cache_create(
5881 "tsdu", ks_data.ksnd_tsdu_size, 0, 0);
5883 if (!ks_data.ksnd_tsdu_slab) {
5888 /* initialize engine threads list */
5889 ks_data.ksnd_engine_nums = cfs_num_online_cpus();
5890 if (ks_data.ksnd_engine_nums < 4) {
5891 ks_data.ksnd_engine_nums = 4;
5893 ks_data.ksnd_engine_mgr = cfs_alloc(sizeof(ks_engine_mgr_t) *
5894 ks_data.ksnd_engine_nums,CFS_ALLOC_ZERO);
5895 if (ks_data.ksnd_engine_mgr == NULL) {
5899 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5900 cfs_spin_lock_init(&ks_data.ksnd_engine_mgr[i].lock);
5901 cfs_init_event(&ks_data.ksnd_engine_mgr[i].start, TRUE, FALSE);
5902 cfs_init_event(&ks_data.ksnd_engine_mgr[i].exit, TRUE, FALSE);
5903 CFS_INIT_LIST_HEAD(&ks_data.ksnd_engine_mgr[i].list);
5904 cfs_create_thread(KsDeliveryEngineThread, &ks_data.ksnd_engine_mgr[i], 0);
5907 /* register pnp handlers to watch network condition */
5908 KsRegisterPnpHandlers();
5912 /* do cleanup in case we get failures */
5914 if (ks_data.ksnd_tconn_slab) {
5915 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5916 ks_data.ksnd_tconn_slab = NULL;
5926 * finalize the global data in ksockal_data
5932 * int: ks error code
5941 PKS_TSDU KsTsdu = NULL;
5942 cfs_list_t * list = NULL;
5945 /* clean up the pnp handler and address slots */
5946 KsDeregisterPnpHandlers();
5948 /* stop all tcp sending engines */
5949 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5950 ks_data.ksnd_engine_mgr[i].stop = TRUE;
5951 KeSetEvent(&ks_data.ksnd_engine_mgr[i].start, 0, FALSE);
5954 for (i = 0; i < ks_data.ksnd_engine_nums; i++) {
5955 cfs_wait_event_internal(&ks_data.ksnd_engine_mgr[i].exit, 0);
5958 /* we need wait until all the tconn are freed */
5959 cfs_spin_lock(&(ks_data.ksnd_tconn_lock));
5961 if (cfs_list_empty(&(ks_data.ksnd_tconns))) {
5962 cfs_wake_event(&ks_data.ksnd_tconn_exit);
5964 cfs_spin_unlock(&(ks_data.ksnd_tconn_lock));
5966 /* now wait on the tconn exit event */
5967 cfs_wait_event_internal(&ks_data.ksnd_tconn_exit, 0);
5969 /* it's safe to delete the tconn slab ... */
5970 cfs_mem_cache_destroy(ks_data.ksnd_tconn_slab);
5971 ks_data.ksnd_tconn_slab = NULL;
5973 /* clean up all the tsud buffers in the free list */
5974 cfs_spin_lock(&(ks_data.ksnd_tsdu_lock));
5975 cfs_list_for_each (list, &ks_data.ksnd_freetsdus) {
5976 KsTsdu = cfs_list_entry (list, KS_TSDU, Link);
5979 ks_data.ksnd_tsdu_slab,
5982 cfs_spin_unlock(&(ks_data.ksnd_tsdu_lock));
5984 /* it's safe to delete the tsdu slab ... */
5985 cfs_mem_cache_destroy(ks_data.ksnd_tsdu_slab);
5986 ks_data.ksnd_tsdu_slab = NULL;
5988 /* good! it's smooth to do the cleaning up...*/
5992 * ks_create_child_tconn
5993 * Create the backlog child connection for a listener
5996 * parent: the listener daemon connection
5999 * the child connection or NULL in failure
6006 ks_create_child_tconn(
6011 ks_tconn_t * backlog;
6013 /* allocate the tdi connecton object */
6014 backlog = ks_create_tconn();
6020 /* initialize the tconn as a child */
6021 ks_init_child(backlog);
6025 if (ks_bind_tconn(backlog, parent, 0, 0) < 0) {
6026 ks_free_tconn(backlog);
6031 /* open the connection object */
6032 status = KsOpenConnection(
6033 &(backlog->kstc_dev),
6035 &(backlog->child.kstc_info.Handle),
6036 &(backlog->child.kstc_info.FileObject)
6039 if (!NT_SUCCESS(status)) {
6041 ks_put_tconn(backlog);
6043 cfs_enter_debugger();
6047 /* associate it now ... */
6048 status = KsAssociateAddress(
6049 backlog->kstc_addr.Handle,
6050 backlog->child.kstc_info.FileObject
6053 if (!NT_SUCCESS(status)) {
6055 ks_put_tconn(backlog);
6057 cfs_enter_debugger();
6061 backlog->kstc_state = ksts_associated;
6069 * ks_replenish_backlogs(
6070 * to replenish the backlogs listening...
6073 * tconn: the parent listen tdi connect
6074 * nbacklog: number fo child connections in queue
6084 ks_replenish_backlogs(
6085 ks_tconn_t * parent,
6089 ks_tconn_t * backlog;
6092 /* calculate how many backlogs needed */
6093 if ( ( parent->listener.kstc_listening.num +
6094 parent->listener.kstc_accepted.num ) < nbacklog ) {
6095 n = nbacklog - ( parent->listener.kstc_listening.num +
6096 parent->listener.kstc_accepted.num );
6103 /* create the backlog child tconn */
6104 backlog = ks_create_child_tconn(parent);
6106 cfs_spin_lock(&(parent->kstc_lock));
6109 cfs_spin_lock(&backlog->kstc_lock);
6110 /* attch it into the listing list of daemon */
6111 cfs_list_add( &backlog->child.kstc_link,
6112 &parent->listener.kstc_listening.list );
6113 parent->listener.kstc_listening.num++;
6115 backlog->child.kstc_queued = TRUE;
6116 cfs_spin_unlock(&backlog->kstc_lock);
6118 cfs_enter_debugger();
6121 cfs_spin_unlock(&(parent->kstc_lock));
6127 * setup the listener tdi connection and make it listen
6128 * on the user specified ip address and port.
6131 * tconn: the parent listen tdi connect
6132 * nbacklog: number fo child connections in queue
6135 * ks error code >=: success; otherwise error.
6142 ks_start_listen(ks_tconn_t *tconn, int nbacklog)
6146 /* now replenish the backlogs */
6147 ks_replenish_backlogs(tconn, nbacklog);
6149 /* set the event callback handlers */
6150 rc = KsSetHandlers(tconn);
6156 cfs_spin_lock(&(tconn->kstc_lock));
6157 tconn->listener.nbacklog = nbacklog;
6158 tconn->kstc_state = ksts_listening;
6159 cfs_set_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6160 cfs_spin_unlock(&(tconn->kstc_lock));
6166 ks_stop_listen(ks_tconn_t *tconn)
6169 ks_tconn_t * backlog;
6171 /* reset all tdi event callbacks to NULL */
6172 KsResetHandlers (tconn);
6174 cfs_spin_lock(&tconn->kstc_lock);
6176 cfs_clear_flag(tconn->kstc_flags, KS_TCONN_DAEMON_STARTED);
6178 /* cleanup all the listening backlog child connections */
6179 cfs_list_for_each (list, &(tconn->listener.kstc_listening.list)) {
6180 backlog = cfs_list_entry(list, ks_tconn_t, child.kstc_link);
6182 /* destory and free it */
6183 ks_put_tconn(backlog);
6186 cfs_spin_unlock(&tconn->kstc_lock);
6188 /* wake up it from the waiting on new incoming connections */
6189 KeSetEvent(&tconn->listener.kstc_accept_event, 0, FALSE);
6191 /* free the listening daemon tconn */
6192 ks_put_tconn(tconn);
6197 * ks_wait_child_tconn
6198 * accept a child connection from peer
6201 * parent: the daemon tdi connection listening
6202 * child: to contain the accepted connection
6212 ks_wait_child_tconn(
6213 ks_tconn_t * parent,
6218 ks_tconn_t * backlog = NULL;
6220 ks_replenish_backlogs(parent, parent->listener.nbacklog);
6222 cfs_spin_lock(&(parent->kstc_lock));
6224 if (parent->listener.kstc_listening.num <= 0) {
6225 cfs_spin_unlock(&(parent->kstc_lock));
6231 /* check the listening queue and try to search the accepted connecton */
6233 cfs_list_for_each(tmp, &(parent->listener.kstc_listening.list)) {
6234 backlog = cfs_list_entry (tmp, ks_tconn_t, child.kstc_link);
6236 cfs_spin_lock(&(backlog->kstc_lock));
6238 if (backlog->child.kstc_accepted) {
6240 LASSERT(backlog->kstc_state == ksts_connected);
6241 LASSERT(backlog->child.kstc_busy);
6243 cfs_list_del(&(backlog->child.kstc_link));
6244 cfs_list_add(&(backlog->child.kstc_link),
6245 &(parent->listener.kstc_accepted.list));
6246 parent->listener.kstc_accepted.num++;
6247 parent->listener.kstc_listening.num--;
6248 backlog->child.kstc_queueno = 1;
6250 cfs_spin_unlock(&(backlog->kstc_lock));
6254 cfs_spin_unlock(&(backlog->kstc_lock));
6259 cfs_spin_unlock(&(parent->kstc_lock));
6261 /* we need wait until new incoming connections are requested
6262 or the case of shuting down the listenig daemon thread */
6263 if (backlog == NULL) {
6267 Status = KeWaitForSingleObject(
6268 &(parent->listener.kstc_accept_event),
6275 cfs_spin_lock(&(parent->kstc_lock));
6277 /* check whether it's exptected to exit ? */
6278 if (!cfs_is_flag_set(parent->kstc_flags, KS_TCONN_DAEMON_STARTED)) {
6279 cfs_spin_unlock(&(parent->kstc_lock));
6285 KsPrint((2, "ks_wait_child_tconn: connection %p accepted.\n", backlog));
6288 /* query the local ip address of the connection */
6289 ks_query_local_ipaddr(backlog);
6299 ks_query_iovs_length(struct iovec *iov, int niov)
6304 LASSERT(iov != NULL);
6307 for (i=0; i < niov; i++) {
6308 total += iov[i].iov_len;
6315 ks_query_kiovs_length(lnet_kiov_t *kiov, int nkiov)
6320 LASSERT(kiov != NULL);
6323 for (i=0; i < nkiov; i++) {
6324 total += kiov[i].kiov_len;
6331 ks_sock_buf_cb(void *tsdu, int ns, int off, char **buf)
6336 *buf = (char *)tsdu + off;
6343 ks_sock_iov_cb(void *tsdu, int ns, int off, char **buf)
6346 struct iovec *iov = tsdu;
6348 for (i=0; i < ns; i++) {
6349 if ((size_t)off >= iov[i].iov_len) {
6350 off -= iov[i].iov_len;
6352 *buf = (char *)iov[i].iov_base + off;
6353 rc = iov[i].iov_len - off;
6361 ks_sock_kiov_cb(void *tsdu, int ns, int off, char **buf)
6364 lnet_kiov_t *kiov = tsdu;
6366 for (i=0; i < ns; i++) {
6367 if ((size_t)off >= kiov[i].kiov_len) {
6368 off -= kiov[i].kiov_len;
6370 *buf = (char *)kiov[i].kiov_page->addr +
6371 kiov[i].kiov_offset + off;
6372 rc = kiov[i].kiov_len - off;
6379 typedef int (*ks_tsdu_cb_t)(void *tsdu, int ns, int off, char **buf);
6382 ks_sock_io(ks_tconn_t *tconn, void *tsdu, int ns, int reqlen,
6383 int flags, int timeout, int out, ks_tsdu_cb_t callback)
6387 PKS_TSDUMGR TsduMgr;
6396 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6397 remained = (int64_t)cfs_time_seconds(timeout);
6399 /* query tsdu manager */
6400 expedited = cfs_is_flag_set(flags, MSG_OOB);
6401 TsduMgr = KsQueryTsduMgr(tconn, expedited, (BOOLEAN)out);
6403 /* check whether equest is nonblocking */
6404 if (async = cfs_is_flag_set(flags, MSG_DONTWAIT)) {
6408 ks_get_tconn(tconn);
6409 ks_lock_tsdumgr(TsduMgr);
6410 if ( tconn->kstc_type != kstt_sender &&
6411 tconn->kstc_type != kstt_child) {
6416 while (length = callback(tsdu, ns, total, &buffer)) {
6418 /* check whether socket is stil valid */
6419 if (tconn->kstc_state != ksts_connected) {
6425 tflags = KsTdiSendFlags(flags);
6426 rc = KsWriteTsdus(TsduMgr, buffer, length, tflags);
6428 tflags = KsTdiRecvFlags(flags);
6429 rc = KsReadTsdus(TsduMgr, buffer, length, tflags);
6434 } else if (!async && rc == -EAGAIN) {
6437 ks_unlock_tsdumgr(TsduMgr);
6438 remained = cfs_wait_event_internal(
6445 ks_unlock_tsdumgr(TsduMgr);
6446 cfs_wait_event_internal(&TsduMgr->Event, 0);
6448 ks_lock_tsdumgr(TsduMgr);
6457 TsduMgr->Payload = reqlen - total;
6459 ks_unlock_tsdumgr(TsduMgr);
6461 KsPrint((4, "ks_sock_io: tconn=%p tsdumgr=%p %c total=%xh/%xh rc=%d\n",
6462 tconn, TsduMgr, out?'W':'R', total, TsduMgr->TotalBytes, rc));
6466 /* signal Tdi sending engine */
6467 KsQueueTdiEngine(tconn, TsduMgr);
6472 ks_put_tconn(tconn);
6474 LASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
6478 int ks_send_buf(ks_tconn_t * tconn, char *buf,
6479 int len, int flags, int timeout)
6481 return ks_sock_io(tconn, buf, len, len, flags,
6482 timeout, 1, ks_sock_buf_cb);
6485 int ks_recv_buf(ks_tconn_t * tconn, char *buf,
6486 int len, int flags, int timeout)
6488 return ks_sock_io(tconn, buf, len, len, flags,
6489 timeout, 0, ks_sock_buf_cb);
6492 int ks_send_iovs(ks_tconn_t * tconn, struct iovec *iov,
6493 int niov, int flags, int timeout)
6495 int reqlen = ks_query_iovs_length(iov, niov);
6496 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6497 timeout, TRUE, ks_sock_iov_cb);
6500 int ks_recv_iovs(ks_tconn_t * tconn, struct iovec *iov,
6501 int niov, int flags, int timeout)
6503 int reqlen = ks_query_iovs_length(iov, niov);
6504 return ks_sock_io(tconn, iov, niov, reqlen, flags,
6505 timeout, FALSE, ks_sock_iov_cb);
6508 int ks_send_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6509 int nkiov, int flags, int timeout)
6511 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6512 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6513 timeout, TRUE, ks_sock_kiov_cb);
6516 int ks_recv_kiovs(ks_tconn_t * tconn, lnet_kiov_t *kiov,
6517 int nkiov, int flags, int timeout)
6519 int reqlen = ks_query_kiovs_length(kiov, nkiov);
6520 return ks_sock_io(tconn, kiov, nkiov, reqlen, flags,
6521 timeout, FALSE, ks_sock_kiov_cb);
6524 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask)
6526 ks_addr_slot_t * slot = NULL;
6527 PLIST_ENTRY list = NULL;
6529 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
6531 list = ks_data.ksnd_addrs_list.Flink;
6532 while (list != &ks_data.ksnd_addrs_list) {
6533 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6534 if (_stricmp(name, &slot->iface[0]) == 0) {
6536 *ip = slot->ip_addr;
6537 *mask = slot->netmask;
6544 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
6546 return (int)(slot == NULL);
6549 int libcfs_ipif_enumerate(char ***names)
6551 ks_addr_slot_t * slot = NULL;
6552 PLIST_ENTRY list = NULL;
6555 cfs_spin_lock(&ks_data.ksnd_addrs_lock);
6557 *names = cfs_alloc(sizeof(char *) * ks_data.ksnd_naddrs, CFS_ALLOC_ZERO);
6558 if (*names == NULL) {
6562 list = ks_data.ksnd_addrs_list.Flink;
6563 while (list != &ks_data.ksnd_addrs_list) {
6564 slot = CONTAINING_RECORD(list, ks_addr_slot_t, link);
6566 (*names)[nips++] = slot->iface;
6567 cfs_assert(nips <= ks_data.ksnd_naddrs);
6570 cfs_assert(nips == ks_data.ksnd_naddrs);
6574 cfs_spin_unlock(&ks_data.ksnd_addrs_lock);
6578 void libcfs_ipif_free_enumeration(char **names, int n)
6585 int libcfs_sock_listen(struct socket **sockp, __u32 ip, int port, int backlog)
6588 ks_tconn_t * parent;
6590 parent = ks_create_tconn();
6596 /* initialize the tconn as a listener */
6597 ks_init_listener(parent);
6599 /* bind the daemon->tconn */
6600 rc = ks_bind_tconn(parent, NULL, ip, (unsigned short)port);
6603 ks_free_tconn(parent);
6607 /* create listening children and make it to listen state*/
6608 rc = ks_start_listen(parent, backlog);
6610 ks_stop_listen(parent);
6621 int libcfs_sock_accept(struct socket **newsockp, struct socket *sock)
6623 /* wait for incoming connecitons */
6624 return ks_wait_child_tconn(sock, newsockp);
6627 void libcfs_sock_abort_accept(struct socket *sock)
6629 LASSERT(sock->kstc_type == kstt_listener);
6631 cfs_spin_lock(&(sock->kstc_lock));
6633 /* clear the daemon flag */
6634 cfs_clear_flag(sock->kstc_flags, KS_TCONN_DAEMON_STARTED);
6636 /* wake up it from the waiting on new incoming connections */
6637 KeSetEvent(&sock->listener.kstc_accept_event, 0, FALSE);
6639 cfs_spin_unlock(&(sock->kstc_lock));
6643 * libcfs_sock_connect
6644 * build a conntion between local ip/port and the peer ip/port.
6647 * laddr: local ip address
6648 * lport: local port number
6649 * paddr: peer's ip address
6650 * pport: peer's port number
6653 * int: return code ...
6660 int libcfs_sock_connect(struct socket **sockp, int *fatal,
6661 __u32 local_ip, int local_port,
6662 __u32 peer_ip, int peer_port)
6664 ks_tconn_t * tconn = NULL;
6668 if (fatal) *fatal = 0;
6670 KsPrint((2, "libcfs_sock_connect: connecting to %x:%d with %x:%d...\n",
6671 peer_ip, peer_port, local_ip, local_port ));
6673 /* create the tdi connecion structure */
6674 tconn = ks_create_tconn();
6680 /* initialize the tdi sender connection */
6681 ks_init_sender(tconn);
6683 /* bind the local ip address with the tconn */
6684 rc = ks_bind_tconn(tconn, NULL, local_ip, (unsigned short)local_port);
6686 KsPrint((1, "libcfs_sock_connect: failed to bind address %x:%d...\n",
6687 local_ip, local_port ));
6688 ks_free_tconn(tconn);
6692 /* connect to the remote peer */
6693 rc = ks_build_tconn(tconn, peer_ip, (unsigned short)peer_port);
6695 KsPrint((1, "libcfs_sock_connect: failed to connect %x:%d ...\n",
6696 peer_ip, peer_port ));
6698 ks_put_tconn(tconn);
6709 int libcfs_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize)
6714 int libcfs_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize)
6719 int libcfs_sock_getaddr(struct socket *socket, int remote, __u32 *ip, int *port)
6721 PTRANSPORT_ADDRESS taddr = NULL;
6723 cfs_spin_lock(&socket->kstc_lock);
6725 if (socket->kstc_type == kstt_sender) {
6726 taddr = socket->sender.kstc_info.Remote;
6727 } else if (socket->kstc_type == kstt_child) {
6728 taddr = socket->child.kstc_info.Remote;
6731 taddr = &(socket->kstc_addr.Tdi);
6735 PTDI_ADDRESS_IP addr = (PTDI_ADDRESS_IP)(&(taddr->Address[0].Address));
6737 *ip = ntohl (addr->in_addr);
6739 *port = ntohs (addr->sin_port);
6741 cfs_spin_unlock(&socket->kstc_lock);
6745 cfs_spin_unlock(&socket->kstc_lock);
6749 int libcfs_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
6754 while (nob > offset) {
6756 rc = ks_send_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6768 KsPrint((4, "libcfs_sock_write: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6772 int libcfs_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
6777 while (nob > offset) {
6779 rc = ks_recv_buf(sock, (char *)buffer + offset, nob - offset, 0, timeout);
6791 KsPrint((4, "libcfs_sock_read: sock: %p %d bytes rc: %d\n", sock, offset, rc));
6795 void libcfs_sock_release(struct socket *sock)
6797 if (sock->kstc_type == kstt_listener &&
6798 sock->kstc_state == ksts_listening) {
6799 ks_stop_listen(sock);