/* * FUNCTION: Closes an address file object * ARGUMENTS: * Request = Pointer to TDI request structure for this request * RETURNS: * Status of operation */ NTSTATUS FileCloseAddress( PTDI_REQUEST Request) { PADDRESS_FILE AddrFile = Request->Handle.AddressHandle; KIRQL OldIrql; if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER; LockObject(AddrFile, &OldIrql); if (InterlockedDecrement(&AddrFile->Sharers) != 0) { /* Still other guys have open handles to this, so keep it around */ UnlockObject(AddrFile, OldIrql); return STATUS_SUCCESS; } /* We have to close this listener because we started it */ if( AddrFile->Listener ) { TCPClose( AddrFile->Listener ); } UnlockObject(AddrFile, OldIrql); DereferenceObject(AddrFile); TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return STATUS_SUCCESS; }
static void InternalErrorEventHandler(void *arg, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; KIRQL OldIrql; /* Make sure the socket didn't get closed */ if (!arg) return; /* Check if data is left to be read */ LockObject(Connection, &OldIrql); if (IsListEmpty(&Connection->PacketQueue)) { UnlockObject(Connection, OldIrql); /* Deliver the error now */ TCPFinEventHandler(arg, err); } else { UnlockObject(Connection, OldIrql); /* Defer the error delivery until all data is gone */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = TCPTranslateError(err); TCPRecvEventHandler(arg); } }
NTSTATUS TCPSendData ( PCONNECTION_ENDPOINT Connection, PCHAR BufferData, ULONG SendLength, PULONG BytesSent, ULONG Flags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; LockObject(Connection, &OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n", SendLength, Connection->SocketContext)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n", Connection->SocketContext)); Status = TCPTranslateError(LibTCPSend(Connection, BufferData, SendLength, BytesSent, FALSE)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength)); /* Keep this request around ... there was no data yet */ if (Status == STATUS_PENDING) { /* Freed in TCPSocketState */ Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n")); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->SendRequest, &Bucket->Entry ); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n")); } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status)); return Status; }
NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection ) { KIRQL OldIrql; LockObject(Connection, &OldIrql); FlushAllQueues(Connection, STATUS_CANCELLED); LibTCPClose(Connection, FALSE, TRUE); UnlockObject(Connection, OldIrql); DereferenceObject(Connection); return STATUS_SUCCESS; }
BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) { PLIST_ENTRY Entry; PLIST_ENTRY ListHead[5]; KIRQL OldIrql; PTDI_BUCKET Bucket; UINT i = 0; BOOLEAN Found = FALSE; ListHead[0] = &Endpoint->SendRequest; ListHead[1] = &Endpoint->ReceiveRequest; ListHead[2] = &Endpoint->ConnectRequest; ListHead[3] = &Endpoint->ListenRequest; ListHead[4] = &Endpoint->ShutdownRequest; LockObject(Endpoint, &OldIrql); for( i = 0; i < 5; i++ ) { for( Entry = ListHead[i]->Flink; Entry != ListHead[i]; Entry = Entry->Flink ) { Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); if( Bucket->Request.RequestContext == Irp ) { RemoveEntryList( &Bucket->Entry ); ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket); Found = TRUE; break; } } } UnlockObject(Endpoint, OldIrql); return Found; }
NTSTATUS TCPGetSockAddress ( PCONNECTION_ENDPOINT Connection, PTRANSPORT_ADDRESS Address, BOOLEAN GetRemote ) { PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address; struct ip_addr ipaddr; NTSTATUS Status; KIRQL OldIrql; AddressIP->TAAddressCount = 1; AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; LockObject(Connection, &OldIrql); if (GetRemote) { Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext, &ipaddr, &AddressIP->Address[0].Address[0].sin_port)); } else { Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext, &ipaddr, &AddressIP->Address[0].Address[0].sin_port)); } UnlockObject(Connection, OldIrql); AddressIP->Address[0].Address[0].in_addr = ipaddr.addr; RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero, sizeof(AddressIP->Address[0].Address[0].sin_zero)); return Status; }
NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection, UINT Family, UINT Type, UINT Proto ) { NTSTATUS Status; KIRQL OldIrql; LockObject(Connection, &OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, " "Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n", Connection, Family, Type, Proto, sizeof(CONNECTION_ENDPOINT))); Connection->SocketContext = LibTCPSocket(Connection); if (Connection->SocketContext) Status = STATUS_SUCCESS; else Status = STATUS_INSUFFICIENT_RESOURCES; UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status)); return Status; }
NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHAR RecvBuffer, UINT RecvLen, UINT *Received) { PQUEUE_ENTRY qp; struct pbuf* p; NTSTATUS Status; UINT ReadLength, PayloadLength, Offset, Copied; KIRQL OldIrql; (*Received) = 0; LockObject(Connection, &OldIrql); if (!IsListEmpty(&Connection->PacketQueue)) { while ((qp = LibTCPDequeuePacket(Connection)) != NULL) { p = qp->p; /* Calculate the payload length first */ PayloadLength = p->tot_len; PayloadLength -= qp->Offset; Offset = qp->Offset; /* Check if we're reading the whole buffer */ ReadLength = MIN(PayloadLength, RecvLen); ASSERT(ReadLength != 0); if (ReadLength != PayloadLength) { /* Save this one for later */ qp->Offset += ReadLength; InsertHeadList(&Connection->PacketQueue, &qp->ListEntry); qp = NULL; } UnlockObject(Connection, OldIrql); Copied = pbuf_copy_partial(p, RecvBuffer, ReadLength, Offset); ASSERT(Copied == ReadLength); LockObject(Connection, &OldIrql); /* Update trackers */ RecvLen -= ReadLength; RecvBuffer += ReadLength; (*Received) += ReadLength; if (qp != NULL) { /* Use this special pbuf free callback function because we're outside tcpip thread */ pbuf_free_callback(qp->p); ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp); } else { /* If we get here, it means we've filled the buffer */ ASSERT(RecvLen == 0); } ASSERT((*Received) != 0); Status = STATUS_SUCCESS; if (!RecvLen) break; } } else { if (Connection->ReceiveShutdown) Status = Connection->ReceiveShutdownStatus; else Status = STATUS_PENDING; } UnlockObject(Connection, OldIrql); return Status; }
NTSTATUS DispTdiListen( PIRP Irp) /* * FUNCTION: TDI_LISTEN handler * ARGUMENTS: * Irp = Pointer to an I/O request packet * RETURNS: * Status of operation */ { PCONNECTION_ENDPOINT Connection; PTDI_REQUEST_KERNEL Parameters; PTRANSPORT_CONTEXT TranContext; PIO_STACK_LOCATION IrpSp; NTSTATUS Status = STATUS_SUCCESS; KIRQL OldIrql; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); /* Get associated connection endpoint file object. Quit if none exists */ TranContext = IrpSp->FileObject->FsContext; if (TranContext == NULL) { TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); Status = STATUS_INVALID_PARAMETER; goto done; } Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; if (Connection == NULL) { TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n")); Status = STATUS_INVALID_PARAMETER; goto done; } Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters; Status = DispPrepareIrpForCancel (TranContext->Handle.ConnectionContext, Irp, (PDRIVER_CANCEL)DispCancelListenRequest); LockObject(Connection, &OldIrql); if (Connection->AddressFile == NULL) { TI_DbgPrint(MID_TRACE, ("No associated address file\n")); UnlockObject(Connection, OldIrql); Status = STATUS_INVALID_PARAMETER; goto done; } LockObjectAtDpcLevel(Connection->AddressFile); /* Listening will require us to create a listening socket and store it in * the address file. It will be signalled, and attempt to complete an irp * when a new connection arrives. */ /* The important thing to note here is that the irp we'll complete belongs * to the socket to be accepted onto, not the listener */ if( NT_SUCCESS(Status) && !Connection->AddressFile->Listener ) { Connection->AddressFile->Listener = TCPAllocateConnectionEndpoint( NULL ); if( !Connection->AddressFile->Listener ) Status = STATUS_NO_MEMORY; if( NT_SUCCESS(Status) ) { ReferenceObject(Connection->AddressFile); Connection->AddressFile->Listener->AddressFile = Connection->AddressFile; Status = TCPSocket( Connection->AddressFile->Listener, Connection->AddressFile->Family, SOCK_STREAM, Connection->AddressFile->Protocol ); } if( NT_SUCCESS(Status) ) { ReferenceObject(Connection->AddressFile->Listener); Status = TCPListen( Connection->AddressFile->Listener, 1024 ); /* BACKLOG */ } } if( NT_SUCCESS(Status) ) { Status = TCPAccept ( (PTDI_REQUEST)Parameters, Connection->AddressFile->Listener, Connection, DispDataRequestComplete, Irp ); } UnlockObjectFromDpcLevel(Connection->AddressFile); UnlockObject(Connection, OldIrql); done: if (Status != STATUS_PENDING) { DispDataRequestComplete(Irp, Status, 0); } else IoMarkIrpPending(Irp); TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status)); return Status; }
NTSTATUS DispTdiAssociateAddress( PIRP Irp) /* * FUNCTION: TDI_ASSOCIATE_ADDRESS handler * ARGUMENTS: * Irp = Pointer to an I/O request packet * RETURNS: * Status of operation */ { PTDI_REQUEST_KERNEL_ASSOCIATE Parameters; PTRANSPORT_CONTEXT TranContext; PIO_STACK_LOCATION IrpSp; PCONNECTION_ENDPOINT Connection, LastConnection; PFILE_OBJECT FileObject; PADDRESS_FILE AddrFile = NULL; NTSTATUS Status; KIRQL OldIrql; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); /* Get associated connection endpoint file object. Quit if none exists */ TranContext = IrpSp->FileObject->FsContext; if (!TranContext) { TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); return STATUS_INVALID_PARAMETER; } Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; if (!Connection) { TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n")); return STATUS_INVALID_PARAMETER; } Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters; Status = ObReferenceObjectByHandle( Parameters->AddressHandle, 0, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); if (!NT_SUCCESS(Status)) { TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n", Parameters->AddressHandle, Status)); return STATUS_INVALID_PARAMETER; } LockObject(Connection, &OldIrql); if (Connection->AddressFile) { ObDereferenceObject(FileObject); UnlockObject(Connection, OldIrql); TI_DbgPrint(MID_TRACE, ("An address file is already asscociated.\n")); return STATUS_INVALID_PARAMETER; } if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { ObDereferenceObject(FileObject); UnlockObject(Connection, OldIrql); TI_DbgPrint(MID_TRACE, ("Bad address file object. Magic (0x%X).\n", FileObject->FsContext2)); return STATUS_INVALID_PARAMETER; } /* Get associated address file object. Quit if none exists */ TranContext = FileObject->FsContext; if (!TranContext) { ObDereferenceObject(FileObject); UnlockObject(Connection, OldIrql); TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); return STATUS_INVALID_PARAMETER; } AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle; if (!AddrFile) { UnlockObject(Connection, OldIrql); ObDereferenceObject(FileObject); TI_DbgPrint(MID_TRACE, ("No address file object.\n")); return STATUS_INVALID_PARAMETER; } LockObjectAtDpcLevel(AddrFile); ReferenceObject(AddrFile); Connection->AddressFile = AddrFile; /* Add connection endpoint to the address file */ ReferenceObject(Connection); if (AddrFile->Connection == NULL) AddrFile->Connection = Connection; else { LastConnection = AddrFile->Connection; while (LastConnection->Next != NULL) LastConnection = LastConnection->Next; LastConnection->Next = Connection; } ObDereferenceObject(FileObject); UnlockObjectFromDpcLevel(AddrFile); UnlockObject(Connection, OldIrql); return STATUS_SUCCESS; }
NTSTATUS DispTdiSetEventHandler(PIRP Irp) /* * FUNCTION: TDI_SET_EVENT_HANDER handler * ARGUMENTS: * Irp = Pointer to a I/O request packet * RETURNS: * Status of operation */ { PTDI_REQUEST_KERNEL_SET_EVENT Parameters; PTRANSPORT_CONTEXT TranContext; PIO_STACK_LOCATION IrpSp; PADDRESS_FILE AddrFile; NTSTATUS Status; KIRQL OldIrql; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); /* Get associated address file object. Quit if none exists */ TranContext = IrpSp->FileObject->FsContext; if (!TranContext) { TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n")); return STATUS_INVALID_PARAMETER; } AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle; if (!AddrFile) { TI_DbgPrint(MIN_TRACE, ("No address file object.\n")); return STATUS_INVALID_PARAMETER; } Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters; Status = STATUS_SUCCESS; LockObject(AddrFile, &OldIrql); /* Set the event handler. if an event handler is associated with a specific event, it's flag (RegisteredXxxHandler) is TRUE. If an event handler is not used it's flag is FALSE */ switch (Parameters->EventType) { case TDI_EVENT_CONNECT: if (!Parameters->EventHandler) { AddrFile->ConnectHandlerContext = NULL; AddrFile->RegisteredConnectHandler = FALSE; } else { AddrFile->ConnectHandler = (PTDI_IND_CONNECT)Parameters->EventHandler; AddrFile->ConnectHandlerContext = Parameters->EventContext; AddrFile->RegisteredConnectHandler = TRUE; } break; case TDI_EVENT_DISCONNECT: if (!Parameters->EventHandler) { AddrFile->DisconnectHandlerContext = NULL; AddrFile->RegisteredDisconnectHandler = FALSE; } else { AddrFile->DisconnectHandler = (PTDI_IND_DISCONNECT)Parameters->EventHandler; AddrFile->DisconnectHandlerContext = Parameters->EventContext; AddrFile->RegisteredDisconnectHandler = TRUE; } break; case TDI_EVENT_ERROR: if (Parameters->EventHandler == NULL) { AddrFile->ErrorHandlerContext = NULL; AddrFile->RegisteredErrorHandler = FALSE; } else { AddrFile->ErrorHandler = (PTDI_IND_ERROR)Parameters->EventHandler; AddrFile->ErrorHandlerContext = Parameters->EventContext; AddrFile->RegisteredErrorHandler = TRUE; } break; case TDI_EVENT_RECEIVE: if (Parameters->EventHandler == NULL) { AddrFile->ReceiveHandlerContext = NULL; AddrFile->RegisteredReceiveHandler = FALSE; } else { AddrFile->ReceiveHandler = (PTDI_IND_RECEIVE)Parameters->EventHandler; AddrFile->ReceiveHandlerContext = Parameters->EventContext; AddrFile->RegisteredReceiveHandler = TRUE; } break; case TDI_EVENT_RECEIVE_DATAGRAM: if (Parameters->EventHandler == NULL) { AddrFile->ReceiveDatagramHandlerContext = NULL; AddrFile->RegisteredReceiveDatagramHandler = FALSE; } else { AddrFile->ReceiveDatagramHandler = (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler; AddrFile->ReceiveDatagramHandlerContext = Parameters->EventContext; AddrFile->RegisteredReceiveDatagramHandler = TRUE; } break; case TDI_EVENT_RECEIVE_EXPEDITED: if (Parameters->EventHandler == NULL) { AddrFile->ExpeditedReceiveHandlerContext = NULL; AddrFile->RegisteredExpeditedReceiveHandler = FALSE; } else { AddrFile->ExpeditedReceiveHandler = (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler; AddrFile->ExpeditedReceiveHandlerContext = Parameters->EventContext; AddrFile->RegisteredExpeditedReceiveHandler = TRUE; } break; case TDI_EVENT_CHAINED_RECEIVE: if (Parameters->EventHandler == NULL) { AddrFile->ChainedReceiveHandlerContext = NULL; AddrFile->RegisteredChainedReceiveHandler = FALSE; } else { AddrFile->ChainedReceiveHandler = (PTDI_IND_CHAINED_RECEIVE)Parameters->EventHandler; AddrFile->ChainedReceiveHandlerContext = Parameters->EventContext; AddrFile->RegisteredChainedReceiveHandler = TRUE; } break; case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM: if (Parameters->EventHandler == NULL) { AddrFile->ChainedReceiveDatagramHandlerContext = NULL; AddrFile->RegisteredChainedReceiveDatagramHandler = FALSE; } else { AddrFile->ChainedReceiveDatagramHandler = (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler; AddrFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext; AddrFile->RegisteredChainedReceiveDatagramHandler = TRUE; } break; case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED: if (Parameters->EventHandler == NULL) { AddrFile->ChainedReceiveExpeditedHandlerContext = NULL; AddrFile->RegisteredChainedReceiveExpeditedHandler = FALSE; } else { AddrFile->ChainedReceiveExpeditedHandler = (PTDI_IND_CHAINED_RECEIVE_EXPEDITED)Parameters->EventHandler; AddrFile->ChainedReceiveExpeditedHandlerContext = Parameters->EventContext; AddrFile->RegisteredChainedReceiveExpeditedHandler = TRUE; } break; default: TI_DbgPrint(MIN_TRACE, ("Unknown event type (0x%X).\n", Parameters->EventType)); Status = STATUS_INVALID_PARAMETER; } UnlockObject(AddrFile, OldIrql); return Status; }
NTSTATUS TCPDisconnect ( PCONNECTION_ENDPOINT Connection, UINT Flags, PLARGE_INTEGER Timeout, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status = STATUS_INVALID_PARAMETER; PTDI_BUCKET Bucket; KIRQL OldIrql; LARGE_INTEGER ActualTimeout; TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n")); LockObject(Connection, &OldIrql); if (Connection->SocketContext) { if (Flags & TDI_DISCONNECT_RELEASE) { if (IsListEmpty(&Connection->SendRequest)) { Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); } else if (Timeout && Timeout->QuadPart == 0) { FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); Status = STATUS_TIMEOUT; } else { /* Use the timeout specified or 1 second if none was specified */ if (Timeout) { ActualTimeout = *Timeout; } else { ActualTimeout.QuadPart = -1000000; } /* We couldn't complete the request now because we need to wait for outstanding I/O */ Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = (PVOID)Complete; Bucket->Request.RequestContext = Context; InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry); ReferenceObject(Connection); if (KeCancelTimer(&Connection->DisconnectTimer)) { DereferenceObject(Connection); } KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc); Status = STATUS_PENDING; } } if ((Flags & TDI_DISCONNECT_ABORT) || !Flags) { FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE); FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE); Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1)); } } else { /* We already got closed by the other side so just return success */ Status = STATUS_SUCCESS; } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status)); return Status; }
NTSTATUS TCPConnect ( PCONNECTION_ENDPOINT Connection, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; struct ip_addr bindaddr, connaddr; IP_ADDRESS RemoteAddress; USHORT RemotePort; TA_IP_ADDRESS LocalAddress; PTDI_BUCKET Bucket; PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n")); Status = AddrBuildAddress ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress, &RemoteAddress, &RemotePort); if (!NT_SUCCESS(Status)) { TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n")); return Status; } /* Freed in TCPSocketState */ TI_DbgPrint(DEBUG_TCP, ("Connecting to address %x:%x\n", RemoteAddress.Address.IPv4Address, RemotePort)); LockObject(Connection, &OldIrql); if (!Connection->AddressFile) { UnlockObject(Connection, OldIrql); return STATUS_INVALID_PARAMETER; } if (AddrIsUnspecified(&Connection->AddressFile->Address)) { if (!(NCE = RouteGetRouteToDestination(&RemoteAddress))) { UnlockObject(Connection, OldIrql); return STATUS_NETWORK_UNREACHABLE; } bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address; } else { bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address; } Status = TCPTranslateError(LibTCPBind(Connection, &bindaddr, Connection->AddressFile->Port)); if (NT_SUCCESS(Status)) { /* Check if we had an unspecified port */ if (!Connection->AddressFile->Port) { /* We did, so we need to copy back the port */ Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE); if (NT_SUCCESS(Status)) { /* Allocate the port in the port bitmap */ Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port); /* This should never fail */ ASSERT(Connection->AddressFile->Port != 0xFFFF); } } if (NT_SUCCESS(Status)) { connaddr.addr = RemoteAddress.Address.IPv4Address; Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = (PVOID)Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->ConnectRequest, &Bucket->Entry ); Status = TCPTranslateError(LibTCPConnect(Connection, &connaddr, RemotePort)); } } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status)); return Status; }
NTSTATUS ICMPSendDatagram( PADDRESS_FILE AddrFile, PTDI_CONNECTION_INFORMATION ConnInfo, PCHAR BufferData, ULONG DataSize, PULONG DataUsed ) /* * FUNCTION: Sends an ICMP datagram to a remote address * ARGUMENTS: * Request = Pointer to TDI request * ConnInfo = Pointer to connection information * Buffer = Pointer to NDIS buffer with data * DataSize = Size in bytes of data to be sent * RETURNS: * Status of operation */ { IP_PACKET Packet; PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress; IP_ADDRESS RemoteAddress, LocalAddress; NTSTATUS Status; PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n", AddrFile, ConnInfo, BufferData, DataSize)); TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa)); switch( RemoteAddressTa->Address[0].AddressType ) { case TDI_ADDRESS_TYPE_IP: RemoteAddress.Type = IP_ADDRESS_V4; RemoteAddress.Address.IPv4Address = RemoteAddressTa->Address[0].Address[0].in_addr; break; default: return STATUS_UNSUCCESSFUL; } TI_DbgPrint(MID_TRACE,("About to get route to destination\n")); LockObject(AddrFile, &OldIrql); LocalAddress = AddrFile->Address; if (AddrIsUnspecified(&LocalAddress)) { /* If the local address is unspecified (0), * then use the unicast address of the * interface we're sending over */ if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) { UnlockObject(AddrFile, OldIrql); return STATUS_NETWORK_UNREACHABLE; } LocalAddress = NCE->Interface->Unicast; } else { if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) { UnlockObject(AddrFile, OldIrql); return STATUS_INVALID_PARAMETER; } } Status = PrepareICMPPacket( AddrFile, NCE->Interface, &Packet, &RemoteAddress, BufferData, DataSize ); UnlockObject(AddrFile, OldIrql); if( !NT_SUCCESS(Status) ) return Status; TI_DbgPrint(MID_TRACE,("About to send datagram\n")); Status = IPSendDatagram(&Packet, NCE); if (!NT_SUCCESS(Status)) return Status; *DataUsed = DataSize; TI_DbgPrint(MID_TRACE,("Leaving\n")); return STATUS_SUCCESS; }