mirror of
https://github.com/reactos/reactos.git
synced 2024-07-29 23:58:44 +00:00
[IP]
- Rewrite most of the lower TCP layer code to work with lwIP [LWIP] - Write all of the implementation-specific code and headers [TCPIP] - Add assertions in the object reference functions - Remove the completion queue hack This is still isn't totally finished yet. There are still two main issues that need to be overcome: listen/accept don't work at all and the performance is horrible. I hope that once I tune some of the options, I can get it to perform reasonably well. If any curious testers want to try this out, be my guest but realize that not a lot of apps will work yet. Suggestions are welcome! :) svn path=/branches/tcp-rewrite-branch/; revision=48840
This commit is contained in:
parent
fa58fc5f13
commit
459e413725
|
@ -29,7 +29,6 @@
|
|||
#include <fileobjs.h>
|
||||
#include <lock.h>
|
||||
#include <wait.h>
|
||||
#include <oskittcp.h>
|
||||
#include <interface.h>
|
||||
#include <ports.h>
|
||||
#include <ipifcons.h>
|
||||
|
|
|
@ -24,15 +24,6 @@ typedef struct TCPv4_HEADER {
|
|||
USHORT Urgent; /* Pointer to urgent data */
|
||||
} TCPv4_HEADER, *PTCPv4_HEADER;
|
||||
|
||||
/* TCPv4 header flags */
|
||||
#define TCP_URG 0x20
|
||||
#define TCP_ACK 0x10
|
||||
#define TCP_PSH 0x08
|
||||
#define TCP_RST 0x04
|
||||
#define TCP_SYN 0x02
|
||||
#define TCP_FIN 0x01
|
||||
|
||||
|
||||
#define TCPOPT_END_OF_LIST 0x0
|
||||
#define TCPOPT_NO_OPERATION 0x1
|
||||
#define TCPOPT_MAX_SEG_SIZE 0x2
|
||||
|
@ -79,6 +70,19 @@ typedef struct _CLIENT_DATA {
|
|||
/* Delay variance factor */
|
||||
#define TCP_BETA_RETRANSMISSION_TIMEOUT(x)(((x)*16)/10) /* 1.6 */
|
||||
|
||||
#define SEL_CONNECT 1
|
||||
#define SEL_FIN 2
|
||||
#define SEL_RST 4
|
||||
#define SEL_ABRT 8
|
||||
#define SEL_READ 16
|
||||
#define SEL_WRITE 32
|
||||
#define SEL_ACCEPT 64
|
||||
#define SEL_OOB 128
|
||||
#define SEL_ERROR 256
|
||||
#define SEL_FINOUT 512
|
||||
|
||||
#define FREAD 0x0001
|
||||
#define FWRITE 0x0002
|
||||
|
||||
/* Datagram/segment send request flags */
|
||||
|
||||
|
@ -93,9 +97,8 @@ extern LONG TCP_IPIdentification;
|
|||
extern CLIENT_DATA ClientInfo;
|
||||
|
||||
/* accept.c */
|
||||
NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
|
||||
PCONNECTION_ENDPOINT Connection,
|
||||
PTDI_REQUEST_KERNEL Request );
|
||||
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
|
||||
PTDI_REQUEST_KERNEL Request);
|
||||
NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog );
|
||||
BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
|
||||
PCONNECTION_ENDPOINT Connection );
|
||||
|
@ -163,7 +166,7 @@ NTSTATUS TCPSendData(
|
|||
|
||||
NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection );
|
||||
|
||||
NTSTATUS TCPTranslateError( int OskitError );
|
||||
NTSTATUS TCPTranslateError( INT8 err );
|
||||
|
||||
UINT TCPAllocatePort( UINT HintPort );
|
||||
|
||||
|
@ -181,3 +184,12 @@ NTSTATUS TCPShutdown(
|
|||
VOID);
|
||||
|
||||
BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Connection, PIRP Irp );
|
||||
|
||||
VOID
|
||||
TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF);
|
||||
|
||||
VOID
|
||||
TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF);
|
||||
|
||||
VOID
|
||||
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status);
|
||||
|
|
|
@ -135,19 +135,9 @@ struct in_addr
|
|||
#define s_impno S_un.S_un_b.s_b4
|
||||
#define s_lh S_un.S_un_b.s_b3
|
||||
};
|
||||
struct sockaddr_in
|
||||
{
|
||||
short sin_family;
|
||||
u_short sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
typedef struct sockaddr_in SOCKADDR_IN;
|
||||
struct sockaddr
|
||||
{
|
||||
u_short sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
#define __LWIP_INET_H__
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
/* Sufficient information to manage the entity list */
|
||||
typedef struct {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
#define ReferenceObject(Object) \
|
||||
{ \
|
||||
ASSERT(((Object)->RefCount) > 0); \
|
||||
InterlockedIncrement(&((Object)->RefCount)); \
|
||||
}
|
||||
|
||||
|
@ -22,6 +23,7 @@
|
|||
*/
|
||||
#define DereferenceObject(Object) \
|
||||
{ \
|
||||
ASSERT(((Object)->RefCount) > 0); \
|
||||
if (InterlockedDecrement(&((Object)->RefCount)) == 0) \
|
||||
(((Object)->Free)(Object)); \
|
||||
}
|
||||
|
@ -33,7 +35,7 @@
|
|||
{ \
|
||||
ReferenceObject(Object); \
|
||||
KeAcquireSpinLock(&((Object)->Lock), Irql); \
|
||||
memcpy(&(Object)->OldIrql, Irql, sizeof(KIRQL)); \
|
||||
(Object)->OldIrql = *Irql; \
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -266,10 +268,6 @@ typedef struct _CONNECTION_ENDPOINT {
|
|||
LIST_ENTRY ListenRequest; /* Queued listen requests */
|
||||
LIST_ENTRY ReceiveRequest; /* Queued receive requests */
|
||||
LIST_ENTRY SendRequest; /* Queued send requests */
|
||||
LIST_ENTRY CompletionQueue;/* Completed requests to finish */
|
||||
|
||||
/* Signals */
|
||||
UINT SignalState; /* Active signals from oskit */
|
||||
} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
|
||||
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
<module name="tcpip" type="kernelmodedriver" installbase="system32/drivers" installname="tcpip.sys">
|
||||
<importlibrary definition="tcpip.spec" />
|
||||
<include base="tcpip">include</include>
|
||||
<include base="oskittcp">include</include>
|
||||
<include base="lwip">src/include</include>
|
||||
<include base="lwip">src/include/ipv4</include>
|
||||
<define name="NDIS40" />
|
||||
<define name="_NTDRIVER_" />
|
||||
<library>ip</library>
|
||||
<library>oskittcp</library>
|
||||
<library>lwip</library>
|
||||
<library>ndis</library>
|
||||
<library>pseh</library>
|
||||
<library>chew</library>
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<directory name="oskittcp">
|
||||
<xi:include href="oskittcp/oskittcp.rbuild" />
|
||||
</directory>
|
||||
<directory name="lwip">
|
||||
<xi:include href="lwip/lwip.rbuild" />
|
||||
</directory>
|
||||
<directory name="chew">
|
||||
<xi:include href="chew/chew.rbuild" />
|
||||
</directory>
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
<module name="ip" type="staticlibrary">
|
||||
<define name="__NTDRIVER__"/>
|
||||
<include base="tcpip">include</include>
|
||||
<include base="oskittcp">include</include>
|
||||
<include base="lwip">src/include</include>
|
||||
<include base="lwip">src/include/ipv4</include>
|
||||
<directory name="network">
|
||||
<if property="ARCH" value="i386">
|
||||
<directory name="i386">
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
#define __LWIP_INET_H__
|
||||
#include "lwip/netifapi.h"
|
||||
|
||||
|
||||
LIST_ENTRY InterfaceListHead;
|
||||
KSPIN_LOCK InterfaceListLock;
|
||||
|
@ -21,6 +24,12 @@ BOOLEAN IpWorkItemQueued = FALSE;
|
|||
|
||||
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
|
||||
|
||||
VOID
|
||||
TCPRegisterInterface(PIP_INTERFACE IF);
|
||||
|
||||
VOID
|
||||
TCPUnregisterInterface(PIP_INTERFACE IF);
|
||||
|
||||
VOID DontFreePacket(
|
||||
PVOID Object)
|
||||
/*
|
||||
|
@ -162,14 +171,15 @@ PIP_INTERFACE IPCreateInterface(
|
|||
|
||||
TcpipInitializeSpinLock(&IF->Lock);
|
||||
|
||||
IF->TCPContext = ExAllocatePoolWithTag
|
||||
( NonPagedPool, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in ),
|
||||
OSKITTCP_CONTEXT_TAG );
|
||||
IF->TCPContext = ExAllocatePool
|
||||
( NonPagedPool, sizeof(struct netif));
|
||||
if (!IF->TCPContext) {
|
||||
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TCPRegisterInterface(IF);
|
||||
|
||||
#ifdef __NTDRIVER__
|
||||
InsertTDIInterfaceEntity( IF );
|
||||
#endif
|
||||
|
@ -192,7 +202,9 @@ VOID IPDestroyInterface(
|
|||
RemoveTDIInterfaceEntity( IF );
|
||||
#endif
|
||||
|
||||
ExFreePoolWithTag(IF->TCPContext, OSKITTCP_CONTEXT_TAG);
|
||||
TCPUnregisterInterface(IF);
|
||||
|
||||
ExFreePool(IF->TCPContext);
|
||||
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
|
||||
}
|
||||
|
||||
|
@ -219,6 +231,8 @@ VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
|
|||
* other computers */
|
||||
if (IF != Loopback)
|
||||
ARPTransmit(NULL, NULL, IF);
|
||||
|
||||
TCPUpdateInterfaceIPInformation(IF);
|
||||
}
|
||||
|
||||
BOOLEAN IPRegisterInterface(
|
||||
|
|
|
@ -54,46 +54,9 @@ static VOID DisplayIPHeader(
|
|||
((IPHeader->DstAddr >> 16) & 0xFF), ((IPHeader->DstAddr >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
static VOID DisplayTCPHeader(
|
||||
PCHAR Header,
|
||||
UINT Length)
|
||||
{
|
||||
/* FIXME: IPv4 only */
|
||||
PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header;
|
||||
PTCPv4_HEADER TCPHeader;
|
||||
|
||||
if (IPHeader->Protocol != IPPROTO_TCP) {
|
||||
DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
TCPHeader = (PTCPv4_HEADER)((PCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4);
|
||||
|
||||
DbgPrint("TCP header:\n");
|
||||
DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort));
|
||||
DbgPrint(" DestinationPort: %d\n", WN2H(TCPHeader->DestinationPort));
|
||||
DbgPrint(" SequenceNumber: 0x%x\n", DN2H(TCPHeader->SequenceNumber));
|
||||
DbgPrint(" AckNumber: 0x%x\n", DN2H(TCPHeader->AckNumber));
|
||||
DbgPrint(" DataOffset: 0x%x (0x%x) 32-bit words\n", TCPHeader->DataOffset, TCPHeader->DataOffset >> 4);
|
||||
DbgPrint(" Flags: 0x%x (0x%x)\n", TCPHeader->Flags, TCPHeader->Flags & 0x3F);
|
||||
if ((TCPHeader->Flags & TCP_URG) > 0) DbgPrint(" TCP_URG - Urgent Pointer field significant\n");
|
||||
if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgement field significant\n");
|
||||
if ((TCPHeader->Flags & TCP_PSH) > 0) DbgPrint(" TCP_PSH - Push Function\n");
|
||||
if ((TCPHeader->Flags & TCP_RST) > 0) DbgPrint(" TCP_RST - Reset the connection\n");
|
||||
if ((TCPHeader->Flags & TCP_SYN) > 0) DbgPrint(" TCP_SYN - Synchronize sequence numbers\n");
|
||||
if ((TCPHeader->Flags & TCP_FIN) > 0) DbgPrint(" TCP_FIN - No more data from sender\n");
|
||||
DbgPrint(" Window: 0x%x\n", WN2H(TCPHeader->Window));
|
||||
DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum));
|
||||
DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent));
|
||||
}
|
||||
|
||||
|
||||
VOID DisplayTCPPacket(
|
||||
PIP_PACKET IPPacket)
|
||||
{
|
||||
UINT Length;
|
||||
PCHAR Buffer;
|
||||
|
||||
if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != TRUE) ||
|
||||
(DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_TCP | DPFLTR_MASK) != TRUE)) {
|
||||
return;
|
||||
|
@ -112,20 +75,6 @@ VOID DisplayTCPPacket(
|
|||
TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
|
||||
TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
|
||||
TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
|
||||
|
||||
if (IPPacket->NdisPacket) {
|
||||
NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length);
|
||||
Buffer = ExAllocatePool(NonPagedPool, Length);
|
||||
if (Buffer) {
|
||||
Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, 0, Length);
|
||||
DisplayTCPHeader(Buffer, Length);
|
||||
ExFreePool(Buffer);
|
||||
}
|
||||
} else {
|
||||
Buffer = IPPacket->Header;
|
||||
Length = IPPacket->ContigSize;
|
||||
DisplayTCPHeader(Buffer, Length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -10,54 +10,31 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
/* Listener->Lock MUST be acquired */
|
||||
NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
|
||||
PCONNECTION_ENDPOINT Connection,
|
||||
PTDI_REQUEST_KERNEL Request ) {
|
||||
#include "rosip.h"
|
||||
|
||||
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
|
||||
PTDI_REQUEST_KERNEL Request) {
|
||||
struct tcp_pcb *newpcb = Context;
|
||||
NTSTATUS Status;
|
||||
SOCKADDR_IN OutAddr;
|
||||
OSK_UINT OutAddrLen;
|
||||
PTA_IP_ADDRESS RequestAddressReturn;
|
||||
PTDI_CONNECTION_INFORMATION WhoIsConnecting;
|
||||
PTA_IP_ADDRESS RemoteAddress;
|
||||
struct ip_addr ipaddr;
|
||||
|
||||
/* Unpack TDI info -- We need the return connection information
|
||||
* struct to return the address so it can be filtered if needed
|
||||
* by WSAAccept -- The returned address will be passed on to
|
||||
* userland after we complete this irp */
|
||||
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)
|
||||
Request->ReturnConnectionInformation;
|
||||
if (Request->RequestFlags & TDI_QUERY_ACCEPT)
|
||||
DbgPrint("TDI_QUERY_ACCEPT NOT SUPPORTED!!!\n");
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPAccept( Listener->SocketContext,
|
||||
&Connection->SocketContext,
|
||||
Connection,
|
||||
&OutAddr,
|
||||
sizeof(OutAddr),
|
||||
&OutAddrLen,
|
||||
Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) );
|
||||
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)Request->ReturnConnectionInformation;
|
||||
RemoteAddress = (PTA_IP_ADDRESS)WhoIsConnecting->RemoteAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
|
||||
RemoteAddress->TAAddressCount = 1;
|
||||
RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
||||
RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
||||
|
||||
if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) {
|
||||
RequestAddressReturn = WhoIsConnecting->RemoteAddress;
|
||||
Status = TCPTranslateError(LibTCPGetPeerName(newpcb,
|
||||
&ipaddr,
|
||||
&RemoteAddress->Address[0].Address[0].sin_port));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n",
|
||||
RequestAddressReturn, WhoIsConnecting));
|
||||
|
||||
RequestAddressReturn->TAAddressCount = 1;
|
||||
RequestAddressReturn->Address[0].AddressLength = OutAddrLen;
|
||||
|
||||
/* BSD uses the first byte of the sockaddr struct as a length.
|
||||
* Since windows doesn't do that we strip it */
|
||||
RequestAddressReturn->Address[0].AddressType =
|
||||
(OutAddr.sin_family >> 8) & 0xff;
|
||||
|
||||
RtlCopyMemory( &RequestAddressReturn->Address[0].Address,
|
||||
((PCHAR)&OutAddr) + sizeof(USHORT),
|
||||
sizeof(RequestAddressReturn->Address[0].Address[0]) );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
|
||||
}
|
||||
RemoteAddress->Address[0].Address[0].in_addr = ipaddr.addr;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
|
||||
|
||||
|
@ -68,7 +45,7 @@ NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
|
|||
* lifetime as the address file */
|
||||
NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
SOCKADDR_IN AddressToBind;
|
||||
struct ip_addr AddressToBind;
|
||||
KIRQL OldIrql;
|
||||
|
||||
ASSERT(Connection);
|
||||
|
@ -81,20 +58,18 @@ NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
|
|||
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
|
||||
Connection->SocketContext));
|
||||
|
||||
AddressToBind.sin_family = AF_INET;
|
||||
memcpy( &AddressToBind.sin_addr,
|
||||
&Connection->AddressFile->Address.Address.IPv4Address,
|
||||
sizeof(AddressToBind.sin_addr) );
|
||||
AddressToBind.sin_port = Connection->AddressFile->Port;
|
||||
AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
|
||||
|
||||
Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext,
|
||||
Status = TCPTranslateError(LibTCPBind(Connection->SocketContext,
|
||||
&AddressToBind,
|
||||
sizeof(AddressToBind) ) );
|
||||
Connection->AddressFile->Port));
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
|
||||
{
|
||||
Connection->SocketContext = LibTCPListen(Connection->SocketContext, Backlog);
|
||||
if (!Connection->SocketContext)
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
||||
|
@ -145,22 +120,17 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request,
|
|||
|
||||
LockObject(Listener, &OldIrql);
|
||||
|
||||
Status = TCPServiceListeningSocket( Listener, Connection,
|
||||
(PTDI_REQUEST_KERNEL)Request );
|
||||
|
||||
if( Status == STATUS_PENDING ) {
|
||||
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
|
||||
TDI_BUCKET_TAG );
|
||||
|
||||
if( Bucket ) {
|
||||
ReferenceObject(Connection);
|
||||
Bucket->AssociatedEndpoint = Connection;
|
||||
Bucket->Request.RequestNotifyObject = Complete;
|
||||
Bucket->Request.RequestContext = Context;
|
||||
InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
|
||||
Status = STATUS_PENDING;
|
||||
} else
|
||||
Status = STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
UnlockObject(Listener, OldIrql);
|
||||
|
||||
|
|
|
@ -2,248 +2,327 @@
|
|||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: transport/tcp/event.c
|
||||
* PURPOSE: Transmission Control Protocol -- Events from oskittcp
|
||||
* PROGRAMMERS: Art Yerkes
|
||||
* REVISIONS:
|
||||
* CSH 01/08-2000 Created
|
||||
* PURPOSE: Transmission Control Protocol
|
||||
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
int TCPSocketState(void *ClientData,
|
||||
void *WhichSocket,
|
||||
void *WhichConnection,
|
||||
OSK_UINT NewState ) {
|
||||
PCONNECTION_ENDPOINT Connection = WhichConnection;
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Connection: %x Flags: %c%c%c%c%c\n",
|
||||
Connection,
|
||||
NewState & SEL_CONNECT ? 'C' : 'c',
|
||||
NewState & SEL_READ ? 'R' : 'r',
|
||||
NewState & SEL_FIN ? 'F' : 'f',
|
||||
NewState & SEL_ACCEPT ? 'A' : 'a',
|
||||
NewState & SEL_WRITE ? 'W' : 'w'));
|
||||
#include "rosip.h"
|
||||
|
||||
/* If this socket is missing its socket context, that means that it
|
||||
* has been created as a new connection in sonewconn but not accepted
|
||||
* yet. We can safely ignore event notifications on these sockets.
|
||||
* Once they are accepted, they will get a socket context and we will
|
||||
* be able to process them.
|
||||
*/
|
||||
if (!Connection)
|
||||
return 0;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
|
||||
NewState, Connection,
|
||||
Connection->SignalState ^ NewState,
|
||||
NewState));
|
||||
|
||||
Connection->SignalState = NewState;
|
||||
|
||||
HandleSignalledConnection(Connection);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TCPPacketSendComplete( PVOID Context,
|
||||
PNDIS_PACKET NdisPacket,
|
||||
NDIS_STATUS NdisStatus ) {
|
||||
TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
|
||||
FreeNdisPacket(NdisPacket);
|
||||
TI_DbgPrint(DEBUG_TCP,("done\n"));
|
||||
}
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
|
||||
int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
|
||||
NDIS_STATUS NdisStatus;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
IP_PACKET Packet = { 0 };
|
||||
IP_ADDRESS RemoteAddress, LocalAddress;
|
||||
PIPv4_HEADER Header;
|
||||
|
||||
if( *data == 0x45 ) { /* IPv4 */
|
||||
Header = (PIPv4_HEADER)data;
|
||||
LocalAddress.Type = IP_ADDRESS_V4;
|
||||
LocalAddress.Address.IPv4Address = Header->SrcAddr;
|
||||
RemoteAddress.Type = IP_ADDRESS_V4;
|
||||
RemoteAddress.Address.IPv4Address = Header->DstAddr;
|
||||
} else {
|
||||
TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
|
||||
OskitDumpBuffer( data, len );
|
||||
return OSK_EINVAL;
|
||||
}
|
||||
|
||||
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
|
||||
TI_DbgPrint(MIN_TRACE,("Unable to get route to %s\n", A2S(&RemoteAddress)));
|
||||
return OSK_EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL, len );
|
||||
|
||||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||||
TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
|
||||
return OSK_ENOBUFS;
|
||||
}
|
||||
|
||||
GetDataPtr( Packet.NdisPacket, 0,
|
||||
(PCHAR *)&Packet.Header, &Packet.ContigSize );
|
||||
|
||||
RtlCopyMemory( Packet.Header, data, len );
|
||||
|
||||
Packet.HeaderSize = sizeof(IPv4_HEADER);
|
||||
Packet.TotalSize = len;
|
||||
Packet.SrcAddr = LocalAddress;
|
||||
Packet.DstAddr = RemoteAddress;
|
||||
|
||||
if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL )))
|
||||
{
|
||||
FreeNdisPacket(Packet.NdisPacket);
|
||||
return OSK_EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory management routines
|
||||
*
|
||||
* By far the most requests for memory are either for 128 or 2049 byte blocks,
|
||||
* so we want to satisfy those from lookaside lists. Unfortunately, the
|
||||
* TCPFree() function doesn't pass the size of the block to be freed, so we
|
||||
* need to keep track of it ourselves. We do it by prepending each block with
|
||||
* 4 bytes, indicating if this is a 'L'arge (2049), 'S'mall (128) or 'O'ther
|
||||
* block.
|
||||
*/
|
||||
|
||||
/* Set to some non-zero value to get a profile of memory allocation sizes */
|
||||
#define MEM_PROFILE 0
|
||||
|
||||
#define SMALL_SIZE 128
|
||||
#define LARGE_SIZE 2049
|
||||
|
||||
#define SIGNATURE_LARGE 'LLLL'
|
||||
#define SIGNATURE_SMALL 'SSSS'
|
||||
#define SIGNATURE_OTHER 'OOOO'
|
||||
static NPAGED_LOOKASIDE_LIST LargeLookasideList;
|
||||
static NPAGED_LOOKASIDE_LIST SmallLookasideList;
|
||||
|
||||
NTSTATUS
|
||||
TCPMemStartup( void )
|
||||
VOID
|
||||
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
|
||||
{
|
||||
ExInitializeNPagedLookasideList( &LargeLookasideList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
LARGE_SIZE + sizeof( ULONG ),
|
||||
OSK_LARGE_TAG,
|
||||
0 );
|
||||
ExInitializeNPagedLookasideList( &SmallLookasideList,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
SMALL_SIZE + sizeof( ULONG ),
|
||||
OSK_SMALL_TAG,
|
||||
0 );
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
ReferenceObject(Connection);
|
||||
|
||||
void *TCPMalloc( void *ClientData,
|
||||
OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
|
||||
void *v;
|
||||
ULONG Signature;
|
||||
DbgPrint("Flushing recv/all with status: 0x%x\n", Status);
|
||||
|
||||
#if 0 != MEM_PROFILE
|
||||
static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
|
||||
static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
|
||||
OSK_UINT i, NewSize, *NewArray;
|
||||
int Found;
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) {
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Found = 0;
|
||||
for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
|
||||
Found = ( Sizes[i] == Bytes );
|
||||
if ( Found ) {
|
||||
Counts[i]++;
|
||||
}
|
||||
}
|
||||
if ( ! Found ) {
|
||||
if ( ArrayAllocated <= ArrayUsed ) {
|
||||
NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
|
||||
NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) );
|
||||
if ( NULL != NewArray ) {
|
||||
if ( 0 != ArrayAllocated ) {
|
||||
memcpy( NewArray, Sizes,
|
||||
ArrayAllocated * sizeof( OSK_UINT ) );
|
||||
exFreePool( Sizes );
|
||||
memcpy( NewArray + NewSize, Counts,
|
||||
ArrayAllocated * sizeof( OSK_UINT ) );
|
||||
exFreePool( Counts );
|
||||
}
|
||||
Sizes = NewArray;
|
||||
Counts = NewArray + NewSize;
|
||||
ArrayAllocated = NewSize;
|
||||
} else if ( 0 != ArrayAllocated ) {
|
||||
exFreePool( Sizes );
|
||||
exFreePool( Counts );
|
||||
ArrayAllocated = 0;
|
||||
}
|
||||
}
|
||||
if ( ArrayUsed < ArrayAllocated ) {
|
||||
Sizes[ArrayUsed] = Bytes;
|
||||
Counts[ArrayUsed] = 1;
|
||||
ArrayUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
|
||||
TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
|
||||
for ( i = 0; i < ArrayUsed; i++ ) {
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Size %4u Count %5u\n", Sizes[i], Counts[i]));
|
||||
}
|
||||
TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
|
||||
}
|
||||
#endif /* MEM_PROFILE */
|
||||
("Completing Receive request: %x %x\n",
|
||||
Bucket->Request, Status));
|
||||
|
||||
if ( SMALL_SIZE == Bytes ) {
|
||||
v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
|
||||
Signature = SIGNATURE_SMALL;
|
||||
} else if ( LARGE_SIZE == Bytes ) {
|
||||
v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
|
||||
Signature = SIGNATURE_LARGE;
|
||||
} else {
|
||||
v = ExAllocatePoolWithTag( NonPagedPool, Bytes + sizeof(ULONG),
|
||||
OSK_OTHER_TAG );
|
||||
Signature = SIGNATURE_OTHER;
|
||||
}
|
||||
if( v ) {
|
||||
*((ULONG *) v) = Signature;
|
||||
v = (void *)((char *) v + sizeof(ULONG));
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = 0;
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
return v;
|
||||
if (Status == STATUS_SUCCESS) Status = STATUS_FILE_CLOSED;
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) {
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = 0;
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) {
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Completing Send request: %x %x\n",
|
||||
Bucket->Request, Status));
|
||||
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = 0;
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) {
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = 0;
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
DereferenceObject(Connection);
|
||||
}
|
||||
|
||||
void TCPFree( void *ClientData,
|
||||
void *data, OSK_PCHAR File, OSK_UINT Line ) {
|
||||
ULONG Signature;
|
||||
|
||||
data = (void *)((char *) data - sizeof(ULONG));
|
||||
Signature = *((ULONG *) data);
|
||||
if ( SIGNATURE_SMALL == Signature ) {
|
||||
ExFreeToNPagedLookasideList( &SmallLookasideList, data );
|
||||
} else if ( SIGNATURE_LARGE == Signature ) {
|
||||
ExFreeToNPagedLookasideList( &LargeLookasideList, data );
|
||||
} else if ( SIGNATURE_OTHER == Signature ) {
|
||||
ExFreePoolWithTag( data, OSK_OTHER_TAG );
|
||||
} else {
|
||||
ASSERT( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TCPMemShutdown( void )
|
||||
VOID
|
||||
TCPFinEventHandler(void *arg, err_t err)
|
||||
{
|
||||
ExDeleteNPagedLookasideList( &SmallLookasideList );
|
||||
ExDeleteNPagedLookasideList( &LargeLookasideList );
|
||||
PCONNECTION_ENDPOINT Connection = arg;
|
||||
|
||||
FlushAllQueues(Connection, TCPTranslateError(err));
|
||||
|
||||
/* We're already closed so we don't want to call lwip_close */
|
||||
Connection->SocketContext = NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb)
|
||||
{
|
||||
PCONNECTION_ENDPOINT Connection = arg;
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
PIRP Irp;
|
||||
NTSTATUS Status;
|
||||
KIRQL OldIrql;
|
||||
|
||||
DbgPrint("TCPAcceptEventHandler\n");
|
||||
|
||||
ReferenceObject(Connection);
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
|
||||
|
||||
Status = TCPCheckPeerForAccept(newpcb,
|
||||
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters);
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
|
||||
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = 0;
|
||||
|
||||
DbgPrint("Associated with: 0x%x\n", Bucket->AssociatedEndpoint->SocketContext);
|
||||
|
||||
DbgPrint("Completing accept event %x\n", Status);
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
if (Status == STATUS_SUCCESS)
|
||||
{
|
||||
LockObject(Bucket->AssociatedEndpoint, &OldIrql);
|
||||
Bucket->AssociatedEndpoint->SocketContext = newpcb;
|
||||
|
||||
LibTCPAccept(newpcb, Bucket->AssociatedEndpoint);
|
||||
UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
|
||||
}
|
||||
|
||||
DbgPrint("Done!\n");
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
DereferenceObject(Connection);
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPSendEventHandler(void *arg, u16_t space)
|
||||
{
|
||||
PCONNECTION_ENDPOINT Connection = arg;
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
PIRP Irp;
|
||||
NTSTATUS Status;
|
||||
PMDL Mdl;
|
||||
|
||||
DbgPrint("TCPSendEventHandler\n");
|
||||
|
||||
ReferenceObject(Connection);
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) {
|
||||
UINT SendLen = 0;
|
||||
PVOID SendBuffer = 0;
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
Mdl = Irp->MdlAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Getting the user buffer from %x\n", Mdl));
|
||||
|
||||
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Writing %d bytes to %x\n", SendLen, SendBuffer));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
|
||||
TI_DbgPrint
|
||||
(DEBUG_TCP,
|
||||
("Connection->SocketContext: %x\n",
|
||||
Connection->SocketContext));
|
||||
|
||||
Status = TCPTranslateError(LibTCPSend(Connection->SocketContext,
|
||||
SendBuffer,
|
||||
SendLen));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen));
|
||||
|
||||
if( Status == STATUS_PENDING ) {
|
||||
ExInterlockedInsertHeadList(&Connection->SendRequest,
|
||||
&Bucket->Entry,
|
||||
&Connection->Lock);
|
||||
break;
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Completing Send request: %x %x\n",
|
||||
Bucket->Request, Status));
|
||||
|
||||
Bucket->Status = Status;
|
||||
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? SendLen : 0;
|
||||
|
||||
DbgPrint("Completing send req %x\n", Status);
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
DereferenceObject(Connection);
|
||||
}
|
||||
|
||||
u32_t
|
||||
TCPRecvEventHandler(void *arg, struct pbuf *p)
|
||||
{
|
||||
PCONNECTION_ENDPOINT Connection = arg;
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
PIRP Irp;
|
||||
PMDL Mdl;
|
||||
UINT Received = 0;
|
||||
UINT RecvLen;
|
||||
PUCHAR RecvBuffer;
|
||||
|
||||
ASSERT(p);
|
||||
|
||||
ReferenceObject(Connection);
|
||||
|
||||
DbgPrint("TCPRecvEventHandler\n");
|
||||
|
||||
if ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) {
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
Mdl = Irp->MdlAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Getting the user buffer from %x\n", Mdl));
|
||||
|
||||
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
|
||||
TI_DbgPrint
|
||||
(DEBUG_TCP,
|
||||
("Connection->SocketContext: %x\n",
|
||||
Connection->SocketContext));
|
||||
TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
|
||||
|
||||
RecvLen = MIN(p->tot_len, RecvLen);
|
||||
|
||||
for (Received = 0; Received < RecvLen; Received += p->len, p = p->next)
|
||||
{
|
||||
DbgPrint("0x%x: Copying %d bytes to 0x%x from 0x%x\n", p, p->len, ((PUCHAR)RecvBuffer) + Received, p->payload);
|
||||
RtlCopyMemory(RecvBuffer + Received, p->payload, p->len);
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
|
||||
|
||||
Bucket->Status = STATUS_SUCCESS;
|
||||
Bucket->Information = Received;
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
DereferenceObject(Connection);
|
||||
|
||||
return Received;
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPConnectEventHandler(void *arg, err_t err)
|
||||
{
|
||||
PCONNECTION_ENDPOINT Connection = arg;
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
DbgPrint("TCPConnectEventHandler\n");
|
||||
|
||||
ReferenceObject(Connection);
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) {
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Bucket->Status = TCPTranslateError(err);
|
||||
Bucket->Information = 0;
|
||||
|
||||
DbgPrint("Completing connection request! (0x%x)\n", err);
|
||||
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
DereferenceObject(Connection);
|
||||
}
|
|
@ -1,117 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 1997-1998 University of Utah and the Flux Group.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the Flux OSKit. The OSKit is free software, also known
|
||||
* as "open source;" you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License (GPL), version 2, as published by the Free
|
||||
* Software Foundation (FSF). To explore alternate licensing terms, contact
|
||||
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
|
||||
*
|
||||
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
|
||||
* received a copy of the GPL along with the OSKit; see the file COPYING. If
|
||||
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
int if_index = 0;
|
||||
struct ifaddr **ifnet_addrs;
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
int ifqmaxlen = OSK_IFQ_MAXLEN;
|
||||
struct ifnet *ifnet;
|
||||
|
||||
/*
|
||||
* Network interface utility routines.
|
||||
*
|
||||
* Routines with ifa_ifwith* names take sockaddr *'s as
|
||||
* parameters.
|
||||
*/
|
||||
|
||||
POSK_IFADDR TCPGetInterfaceData( PIP_INTERFACE IF ) {
|
||||
NTSTATUS Status;
|
||||
POSK_IFADDR ifaddr = IF->TCPContext;
|
||||
struct sockaddr_in *addr_in;
|
||||
struct sockaddr_in *dstaddr_in;
|
||||
struct sockaddr_in *netmask_in;
|
||||
ASSERT(ifaddr);
|
||||
|
||||
RtlZeroMemory(ifaddr, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in ));
|
||||
|
||||
addr_in = (struct sockaddr_in *)&ifaddr[1];
|
||||
dstaddr_in = (struct sockaddr_in *)&addr_in[1];
|
||||
netmask_in = (struct sockaddr_in *)&dstaddr_in[1];
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("Called\n"));
|
||||
|
||||
ifaddr->ifa_addr = (struct sockaddr *)addr_in;
|
||||
Status = GetInterfaceIPv4Address( IF,
|
||||
ADE_UNICAST,
|
||||
(PULONG)&addr_in->sin_addr.s_addr );
|
||||
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
ifaddr->ifa_dstaddr = (struct sockaddr *)dstaddr_in;
|
||||
Status = GetInterfaceIPv4Address(IF,
|
||||
ADE_POINTOPOINT,
|
||||
(PULONG)&dstaddr_in->sin_addr.s_addr );
|
||||
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
ifaddr->ifa_netmask = (struct sockaddr *)netmask_in;
|
||||
Status = GetInterfaceIPv4Address(IF,
|
||||
ADE_ADDRMASK,
|
||||
(PULONG)&netmask_in->sin_addr.s_addr );
|
||||
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("interface %x : addr %x\n",
|
||||
IF, addr_in->sin_addr.s_addr));
|
||||
|
||||
ifaddr->ifa_flags = 0;
|
||||
ifaddr->ifa_refcnt = 0; /* Anachronistic */
|
||||
ifaddr->ifa_metric = 1; /* We can get it like in ninfo.c, if we want */
|
||||
ifaddr->ifa_mtu = IF->MTU;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("Leaving\n"));
|
||||
|
||||
return ifaddr;
|
||||
void TCPPacketSendComplete(PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus)
|
||||
{
|
||||
FreeNdisPacket(NdisPacket);
|
||||
}
|
||||
|
||||
POSK_IFADDR TCPFindInterface( void *ClientData,
|
||||
OSK_UINT AddrType,
|
||||
OSK_UINT FindType,
|
||||
OSK_SOCKADDR *ReqAddr,
|
||||
OSK_IFADDR *Interface ) {
|
||||
err_t
|
||||
TCPSendDataCallback(struct netif *netif, struct pbuf *p, struct ip_addr *dest)
|
||||
{
|
||||
NDIS_STATUS NdisStatus;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
IP_ADDRESS Destination;
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)ReqAddr;
|
||||
POSK_IFADDR InterfaceData;
|
||||
IP_PACKET Packet = { 0 };
|
||||
IP_ADDRESS RemoteAddress, LocalAddress;
|
||||
PIPv4_HEADER Header;
|
||||
UINT i;
|
||||
struct pbuf *p1;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("called for type %d\n", FindType));
|
||||
/* The caller frees the pbuf struct */
|
||||
|
||||
if( !ReqAddr ) {
|
||||
TI_DbgPrint(DEBUG_TCPIF,("no addr or no ifaddr (%x)\n", ReqAddr));
|
||||
return NULL;
|
||||
DbgPrint("Sending data out on %c%c\n", netif->name[0], netif->name[1]);
|
||||
|
||||
if (((*(u8_t*)p->payload) & 0xF0) == 0x40)
|
||||
{
|
||||
Header = p->payload;
|
||||
|
||||
LocalAddress.Type = IP_ADDRESS_V4;
|
||||
LocalAddress.Address.IPv4Address = Header->SrcAddr;
|
||||
|
||||
RemoteAddress.Type = IP_ADDRESS_V4;
|
||||
RemoteAddress.Address.IPv4Address = Header->DstAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
Destination.Type = IP_ADDRESS_V4;
|
||||
Destination.Address.IPv4Address = addr_in->sin_addr.s_addr;
|
||||
if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("Address is %x\n", addr_in->sin_addr.s_addr));
|
||||
NdisStatus = AllocatePacketWithBuffer(&Packet.NdisPacket, NULL, p->tot_len);
|
||||
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
||||
{
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
NCE = RouteGetRouteToDestination(&Destination);
|
||||
if (!NCE) return NULL;
|
||||
GetDataPtr(Packet.NdisPacket, 0, (PCHAR*)&Packet.Header, &Packet.ContigSize);
|
||||
|
||||
InterfaceData = TCPGetInterfaceData(NCE->Interface);
|
||||
for (i = 0, p1 = p; i < p->tot_len; i += p1->len, p1 = p1->next)
|
||||
{
|
||||
ASSERT(p1);
|
||||
RtlCopyMemory(((PUCHAR)Packet.Header) + i, p1->payload, p1->len);
|
||||
}
|
||||
|
||||
addr_in = (struct sockaddr_in *)
|
||||
InterfaceData->ifa_addr;
|
||||
Packet.HeaderSize = sizeof(IPv4_HEADER);
|
||||
Packet.TotalSize = p->tot_len;
|
||||
Packet.SrcAddr = LocalAddress;
|
||||
Packet.DstAddr = RemoteAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCPIF,("returning addr %x\n", addr_in->sin_addr.s_addr));
|
||||
if (!NT_SUCCESS(IPSendDatagram(&Packet, NCE, TCPPacketSendComplete, NULL)))
|
||||
{
|
||||
FreeNdisPacket(Packet.NdisPacket);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return InterfaceData;
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF)
|
||||
{
|
||||
#if 0
|
||||
ULONG OperationalStatus;
|
||||
|
||||
GetInterfaceConnectionStatus(IF, &OperationalStatus);
|
||||
|
||||
if (OperationalStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
|
||||
netif_set_link_up(IF->TCPContext);
|
||||
else
|
||||
netif_set_link_down(IF->TCPContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
err_t
|
||||
TCPInterfaceInit(struct netif *netif)
|
||||
{
|
||||
PIP_INTERFACE IF = netif->state;
|
||||
|
||||
netif->hwaddr_len = IF->AddressLength;
|
||||
RtlCopyMemory(netif->hwaddr, IF->Address, netif->hwaddr_len);
|
||||
|
||||
netif->output = TCPSendDataCallback;
|
||||
netif->mtu = IF->MTU;
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->flags |= NETIF_FLAG_BROADCAST;
|
||||
|
||||
TCPUpdateInterfaceLinkStatus(IF);
|
||||
|
||||
TCPUpdateInterfaceIPInformation(IF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPRegisterInterface(PIP_INTERFACE IF)
|
||||
{
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
|
||||
gw.addr = 0;
|
||||
ipaddr.addr = 0;
|
||||
netmask.addr = 0;
|
||||
|
||||
IF->TCPContext = netif_add(IF->TCPContext,
|
||||
&ipaddr,
|
||||
&netmask,
|
||||
&gw,
|
||||
IF,
|
||||
TCPInterfaceInit,
|
||||
tcpip_input);
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPUnregisterInterface(PIP_INTERFACE IF)
|
||||
{
|
||||
netif_remove(IF->TCPContext);
|
||||
}
|
||||
|
||||
VOID
|
||||
TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF)
|
||||
{
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
|
||||
gw.addr = 0;
|
||||
|
||||
GetInterfaceIPv4Address(IF,
|
||||
ADE_UNICAST,
|
||||
(PULONG)&ipaddr.addr);
|
||||
|
||||
GetInterfaceIPv4Address(IF,
|
||||
ADE_ADDRMASK,
|
||||
(PULONG)&netmask.addr);
|
||||
|
||||
netif_set_addr(IF->TCPContext, &ipaddr, &netmask, &gw);
|
||||
|
||||
if (ipaddr.addr != 0)
|
||||
{
|
||||
netif_set_up(IF->TCPContext);
|
||||
netif_set_default(IF->TCPContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
netif_set_down(IF->TCPContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,231 +14,14 @@
|
|||
|
||||
LONG TCP_IPIdentification = 0;
|
||||
static BOOLEAN TCPInitialized = FALSE;
|
||||
static NPAGED_LOOKASIDE_LIST TCPSegmentList;
|
||||
PORT_SET TCPPorts;
|
||||
CLIENT_DATA ClientInfo;
|
||||
|
||||
VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
|
||||
{
|
||||
PTDI_BUCKET Bucket;
|
||||
PLIST_ENTRY Entry;
|
||||
NTSTATUS Status;
|
||||
PIRP Irp;
|
||||
PMDL Mdl;
|
||||
KIRQL OldIrql;
|
||||
PTCP_COMPLETION_ROUTINE Complete;
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/arch.h"
|
||||
|
||||
if (ClientInfo.Unlocked)
|
||||
LockObjectAtDpcLevel(Connection);
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
|
||||
Connection, Connection->SocketContext));
|
||||
|
||||
/* Things that can happen when we try the initial connection */
|
||||
if( Connection->SignalState & (SEL_CONNECT | SEL_FIN) ) {
|
||||
while (!IsListEmpty(&Connection->ConnectRequest)) {
|
||||
Entry = RemoveHeadList( &Connection->ConnectRequest );
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Bucket->Status = (Connection->SignalState & SEL_CONNECT) ? STATUS_SUCCESS : STATUS_CANCELLED;
|
||||
Bucket->Information = 0;
|
||||
|
||||
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
|
||||
}
|
||||
}
|
||||
|
||||
if( Connection->SignalState & (SEL_ACCEPT | SEL_FIN) ) {
|
||||
/* Handle readable on a listening socket --
|
||||
* TODO: Implement filtering
|
||||
*/
|
||||
TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
|
||||
Connection,
|
||||
IsListEmpty(&Connection->ListenRequest) ?
|
||||
"empty" : "nonempty"));
|
||||
|
||||
while (!IsListEmpty(&Connection->ListenRequest)) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
Entry = RemoveHeadList( &Connection->ListenRequest );
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
|
||||
|
||||
Status = TCPServiceListeningSocket
|
||||
( Connection->AddressFile->Listener,
|
||||
Bucket->AssociatedEndpoint,
|
||||
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
|
||||
|
||||
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
|
||||
InsertHeadList( &Connection->ListenRequest, &Bucket->Entry );
|
||||
break;
|
||||
} else {
|
||||
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
|
||||
Bucket->Information = 0;
|
||||
DereferenceObject(Bucket->AssociatedEndpoint);
|
||||
|
||||
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Things that happen after we're connected */
|
||||
if( Connection->SignalState & (SEL_READ | SEL_FIN) ) {
|
||||
TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
|
||||
IsListEmpty(&Connection->ReceiveRequest) ?
|
||||
"empty" : "nonempty"));
|
||||
|
||||
while (!IsListEmpty(&Connection->ReceiveRequest)) {
|
||||
OSK_UINT RecvLen = 0, Received = 0;
|
||||
PVOID RecvBuffer = 0;
|
||||
|
||||
Entry = RemoveHeadList( &Connection->ReceiveRequest );
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
Mdl = Irp->MdlAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Getting the user buffer from %x\n", Mdl));
|
||||
|
||||
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
|
||||
TI_DbgPrint
|
||||
(DEBUG_TCP,
|
||||
("Connection->SocketContext: %x\n",
|
||||
Connection->SocketContext));
|
||||
TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPRecv( Connection->SocketContext,
|
||||
RecvBuffer,
|
||||
RecvLen,
|
||||
&Received,
|
||||
0 ) );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
|
||||
|
||||
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
|
||||
InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
|
||||
break;
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Completing Receive request: %x %x\n",
|
||||
Bucket->Request, Status));
|
||||
|
||||
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
|
||||
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Received : 0;
|
||||
|
||||
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( Connection->SignalState & (SEL_WRITE | SEL_FIN) ) {
|
||||
TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
|
||||
IsListEmpty(&Connection->SendRequest) ?
|
||||
"empty" : "nonempty"));
|
||||
|
||||
while (!IsListEmpty(&Connection->SendRequest)) {
|
||||
OSK_UINT SendLen = 0, Sent = 0;
|
||||
PVOID SendBuffer = 0;
|
||||
|
||||
Entry = RemoveHeadList( &Connection->SendRequest );
|
||||
|
||||
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
|
||||
|
||||
Irp = Bucket->Request.RequestContext;
|
||||
Mdl = Irp->MdlAddress;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Getting the user buffer from %x\n", Mdl));
|
||||
|
||||
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Writing %d bytes to %x\n", SendLen, SendBuffer));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
|
||||
TI_DbgPrint
|
||||
(DEBUG_TCP,
|
||||
("Connection->SocketContext: %x\n",
|
||||
Connection->SocketContext));
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPSend( Connection->SocketContext,
|
||||
SendBuffer,
|
||||
SendLen,
|
||||
&Sent,
|
||||
0 ) );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
|
||||
|
||||
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
|
||||
InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
|
||||
break;
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_TCP,
|
||||
("Completing Send request: %x %x\n",
|
||||
Bucket->Request, Status));
|
||||
|
||||
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
|
||||
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Sent : 0;
|
||||
|
||||
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceObject(Connection);
|
||||
if (ClientInfo.Unlocked)
|
||||
{
|
||||
UnlockObjectFromDpcLevel(Connection);
|
||||
KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnlockObject(Connection, Connection->OldIrql);
|
||||
}
|
||||
|
||||
while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue,
|
||||
&Connection->Lock)))
|
||||
{
|
||||
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
|
||||
Complete = Bucket->Request.RequestNotifyObject;
|
||||
|
||||
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
|
||||
|
||||
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
|
||||
}
|
||||
|
||||
if (!ClientInfo.Unlocked)
|
||||
{
|
||||
LockObject(Connection, &OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql);
|
||||
}
|
||||
DereferenceObject(Connection);
|
||||
|
||||
/* If the socket is dead, remove the reference we added for oskit */
|
||||
if (Connection->SignalState & SEL_FIN)
|
||||
{
|
||||
Connection->SocketContext = NULL;
|
||||
DereferenceObject(Connection);
|
||||
}
|
||||
}
|
||||
#include "rosip.h"
|
||||
|
||||
VOID ConnectionFree(PVOID Object) {
|
||||
PCONNECTION_ENDPOINT Connection = Object;
|
||||
|
@ -246,6 +29,8 @@ VOID ConnectionFree(PVOID Object) {
|
|||
|
||||
TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
|
||||
|
||||
DbgPrint("CONNECTION ENDPOINT: Freeing 0x%x\n", Object);
|
||||
|
||||
TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
|
||||
RemoveEntryList(&Connection->ListEntry);
|
||||
TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
|
||||
|
@ -270,13 +55,11 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
|
|||
InitializeListHead(&Connection->ListenRequest);
|
||||
InitializeListHead(&Connection->ReceiveRequest);
|
||||
InitializeListHead(&Connection->SendRequest);
|
||||
InitializeListHead(&Connection->CompletionQueue);
|
||||
|
||||
/* Save client context pointer */
|
||||
Connection->ClientContext = ClientContext;
|
||||
|
||||
/* Add an extra reference for oskit */
|
||||
Connection->RefCount = 2;
|
||||
Connection->RefCount = 1;
|
||||
Connection->Free = ConnectionFree;
|
||||
|
||||
/* Add connection endpoint to global list */
|
||||
|
@ -298,16 +81,11 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
|
|||
"Proto %d\n",
|
||||
Connection, Family, Type, Proto));
|
||||
|
||||
Status = TCPTranslateError( OskitTCPSocket( Connection,
|
||||
&Connection->SocketContext,
|
||||
Family,
|
||||
Type,
|
||||
Proto ) );
|
||||
|
||||
ASSERT_KM_POINTER(Connection->SocketContext);
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
|
||||
Connection->SocketContext));
|
||||
Connection->SocketContext = LibTCPSocket(Connection);
|
||||
if (Connection->SocketContext)
|
||||
Status = STATUS_SUCCESS;
|
||||
else
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
||||
|
@ -323,110 +101,13 @@ VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
|
|||
* This is the low level interface for receiving TCP data
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
DbgPrint("Got packet from network stack\n");
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
|
||||
TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n",
|
||||
IPPacket->TotalSize,
|
||||
IPPacket->HeaderSize));
|
||||
|
||||
KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
|
||||
ClientInfo.Unlocked = TRUE;
|
||||
ClientInfo.OldIrql = OldIrql;
|
||||
|
||||
OskitTCPReceiveDatagram( IPPacket->Header,
|
||||
IPPacket->TotalSize,
|
||||
IPPacket->HeaderSize );
|
||||
|
||||
ClientInfo.Unlocked = FALSE;
|
||||
KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
|
||||
}
|
||||
|
||||
/* event.c */
|
||||
int TCPSocketState( void *ClientData,
|
||||
void *WhichSocket,
|
||||
void *WhichConnection,
|
||||
OSK_UINT NewState );
|
||||
|
||||
int TCPPacketSend( void *ClientData,
|
||||
OSK_PCHAR Data,
|
||||
OSK_UINT Len );
|
||||
|
||||
POSK_IFADDR TCPFindInterface( void *ClientData,
|
||||
OSK_UINT AddrType,
|
||||
OSK_UINT FindType,
|
||||
OSK_SOCKADDR *ReqAddr );
|
||||
|
||||
NTSTATUS TCPMemStartup( void );
|
||||
void *TCPMalloc( void *ClientData,
|
||||
OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
|
||||
void TCPFree( void *ClientData,
|
||||
void *data, OSK_PCHAR file, OSK_UINT line );
|
||||
void TCPMemShutdown( void );
|
||||
|
||||
OSKITTCP_EVENT_HANDLERS EventHandlers = {
|
||||
NULL, /* Client Data */
|
||||
TCPSocketState, /* SocketState */
|
||||
TCPPacketSend, /* PacketSend */
|
||||
TCPFindInterface, /* FindInterface */
|
||||
TCPMalloc, /* Malloc */
|
||||
TCPFree, /* Free */
|
||||
NULL, /* Sleep */
|
||||
NULL, /* Wakeup */
|
||||
};
|
||||
|
||||
static KEVENT TimerLoopEvent;
|
||||
static HANDLE TimerThreadHandle;
|
||||
|
||||
/*
|
||||
* We are running 2 timers here, one with a 200ms interval (fast) and the other
|
||||
* with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
|
||||
* 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
|
||||
* "slow" events at 500 and 1000.
|
||||
*/
|
||||
static VOID NTAPI
|
||||
TimerThread(PVOID Context)
|
||||
{
|
||||
LARGE_INTEGER Timeout;
|
||||
NTSTATUS Status;
|
||||
unsigned Current, NextFast, NextSlow, Next;
|
||||
|
||||
Current = 0;
|
||||
Next = 0;
|
||||
NextFast = 0;
|
||||
NextSlow = 0;
|
||||
while ( 1 ) {
|
||||
if (Next == NextFast) {
|
||||
NextFast += 2;
|
||||
}
|
||||
if (Next == NextSlow) {
|
||||
NextSlow += 5;
|
||||
}
|
||||
Next = min(NextFast, NextSlow);
|
||||
Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
|
||||
Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
|
||||
FALSE, &Timeout);
|
||||
if (Status != STATUS_TIMEOUT) {
|
||||
PsTerminateSystemThread(Status);
|
||||
}
|
||||
|
||||
TimerOskitTCP( Next == NextFast, Next == NextSlow );
|
||||
|
||||
Current = Next;
|
||||
if (10 <= Current) {
|
||||
Current = 0;
|
||||
Next = 0;
|
||||
NextFast = 0;
|
||||
NextSlow = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID
|
||||
StartTimer(VOID)
|
||||
{
|
||||
KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
|
||||
PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
|
||||
TimerThread, NULL);
|
||||
LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize);
|
||||
}
|
||||
|
||||
NTSTATUS TCPStartup(VOID)
|
||||
|
@ -438,37 +119,17 @@ NTSTATUS TCPStartup(VOID)
|
|||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = TCPMemStartup();
|
||||
if ( ! NT_SUCCESS(Status) ) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = PortsStartup( &TCPPorts, 1, 0xfffe );
|
||||
if( !NT_SUCCESS(Status) ) {
|
||||
TCPMemShutdown();
|
||||
return Status;
|
||||
}
|
||||
|
||||
KeInitializeSpinLock(&ClientInfo.Lock);
|
||||
ClientInfo.Unlocked = FALSE;
|
||||
|
||||
RegisterOskitTCPEventHandlers( &EventHandlers );
|
||||
InitOskitTCP();
|
||||
/* Initialize our IP library */
|
||||
LibIPInitialize();
|
||||
|
||||
/* Register this protocol with IP layer */
|
||||
IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
|
||||
|
||||
ExInitializeNPagedLookasideList(
|
||||
&TCPSegmentList, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(TCP_SEGMENT), /* Size of each entry */
|
||||
'SPCT', /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
StartTimer();
|
||||
|
||||
TCPInitialized = TRUE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -482,59 +143,50 @@ NTSTATUS TCPShutdown(VOID)
|
|||
* Status of operation
|
||||
*/
|
||||
{
|
||||
LARGE_INTEGER WaitForThread;
|
||||
|
||||
if (!TCPInitialized)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
WaitForThread.QuadPart = -2500000; /* 250 ms */
|
||||
KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
|
||||
ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
|
||||
LibIPShutdown();
|
||||
|
||||
/* Deregister this protocol with IP layer */
|
||||
IPRegisterProtocol(IPPROTO_TCP, NULL);
|
||||
|
||||
ExDeleteNPagedLookasideList(&TCPSegmentList);
|
||||
|
||||
TCPInitialized = FALSE;
|
||||
|
||||
DeinitOskitTCP();
|
||||
|
||||
PortsShutdown( &TCPPorts );
|
||||
|
||||
TCPMemShutdown();
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS TCPTranslateError( int OskitError ) {
|
||||
NTSTATUS TCPTranslateError( err_t err ) {
|
||||
NTSTATUS Status;
|
||||
|
||||
switch( OskitError ) {
|
||||
case 0: Status = STATUS_SUCCESS; break;
|
||||
case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
|
||||
case OSK_EADDRINUSE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break;
|
||||
case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
|
||||
case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break;
|
||||
case OSK_ECONNRESET: Status = STATUS_REMOTE_DISCONNECT; break;
|
||||
case OSK_ECONNABORTED: Status = STATUS_LOCAL_DISCONNECT; break;
|
||||
case OSK_EWOULDBLOCK:
|
||||
case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
|
||||
case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
|
||||
case OSK_ENOMEM:
|
||||
case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
|
||||
case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
|
||||
case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
|
||||
case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
|
||||
case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
|
||||
case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
|
||||
switch (err)
|
||||
{
|
||||
case ERR_OK: Status = STATUS_SUCCESS; break; //0
|
||||
case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1
|
||||
case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2
|
||||
case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3
|
||||
case ERR_RTE: Status = STATUS_HOST_UNREACHABLE; break; //-4
|
||||
case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-5
|
||||
case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-6
|
||||
case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-7
|
||||
case ERR_CONN: Status = STATUS_UNSUCCESSFUL; break; //-8 (FIXME)
|
||||
case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-9
|
||||
case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-10
|
||||
case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-11
|
||||
case ERR_IF: Status = STATUS_NETWORK_UNREACHABLE; break; //-12
|
||||
case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-13 (FIXME)
|
||||
case ERR_INPROGRESS: Status = STATUS_PENDING; break; //-14
|
||||
default:
|
||||
DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
|
||||
Status = STATUS_INVALID_CONNECTION;
|
||||
DbgPrint("Invalid error value: %d\n", err);
|
||||
ASSERT(FALSE);
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
break;
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
|
||||
DbgPrint("TCPTranslateError: %d -> %x\n", (unsigned int)err, Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -545,7 +197,7 @@ NTSTATUS TCPConnect
|
|||
PTCP_COMPLETION_ROUTINE Complete,
|
||||
PVOID Context ) {
|
||||
NTSTATUS Status;
|
||||
SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
|
||||
struct ip_addr bindaddr, connaddr;
|
||||
IP_ADDRESS RemoteAddress;
|
||||
USHORT RemotePort;
|
||||
PTDI_BUCKET Bucket;
|
||||
|
@ -570,9 +222,6 @@ NTSTATUS TCPConnect
|
|||
RemoteAddress.Address.IPv4Address,
|
||||
RemotePort));
|
||||
|
||||
AddressToConnect.sin_family = AF_INET;
|
||||
AddressToBind = AddressToConnect;
|
||||
|
||||
LockObject(Connection, &OldIrql);
|
||||
|
||||
if (!Connection->AddressFile)
|
||||
|
@ -589,28 +238,27 @@ NTSTATUS TCPConnect
|
|||
return STATUS_NETWORK_UNREACHABLE;
|
||||
}
|
||||
|
||||
AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
|
||||
bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address;
|
||||
bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
|
||||
}
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPBind( Connection->SocketContext,
|
||||
&AddressToBind,
|
||||
sizeof(AddressToBind) ) );
|
||||
Status = TCPTranslateError(LibTCPBind(Connection->SocketContext,
|
||||
&bindaddr,
|
||||
Connection->AddressFile->Port));
|
||||
|
||||
DbgPrint("LibTCPBind: 0x%x\n", Status);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
memcpy( &AddressToConnect.sin_addr,
|
||||
&RemoteAddress.Address.IPv4Address,
|
||||
sizeof(AddressToConnect.sin_addr) );
|
||||
AddressToConnect.sin_port = RemotePort;
|
||||
connaddr.addr = RemoteAddress.Address.IPv4Address;
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPConnect( Connection->SocketContext,
|
||||
&AddressToConnect,
|
||||
sizeof(AddressToConnect) ) );
|
||||
Status = TCPTranslateError(LibTCPConnect(Connection->SocketContext,
|
||||
&connaddr,
|
||||
RemotePort));
|
||||
|
||||
DbgPrint("LibTCPConnect: 0x%x\n", Status);
|
||||
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
|
@ -648,10 +296,20 @@ NTSTATUS TCPDisconnect
|
|||
LockObject(Connection, &OldIrql);
|
||||
|
||||
if (Flags & TDI_DISCONNECT_RELEASE)
|
||||
Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
|
||||
{
|
||||
/* FIXME */
|
||||
LibTCPClose(Connection->SocketContext);
|
||||
}
|
||||
|
||||
if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
|
||||
Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
|
||||
{
|
||||
/* FIXME */
|
||||
LibTCPClose(Connection->SocketContext);
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
DbgPrint("LibTCPClose: %x\n", Status);
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
||||
|
@ -664,7 +322,6 @@ NTSTATUS TCPClose
|
|||
( PCONNECTION_ENDPOINT Connection )
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
NTSTATUS Status;
|
||||
PVOID Socket;
|
||||
PADDRESS_FILE AddressFile = NULL;
|
||||
PCONNECTION_ENDPOINT AddressConnection = NULL;
|
||||
|
@ -676,21 +333,9 @@ NTSTATUS TCPClose
|
|||
/* Don't try to close again if the other side closed us already */
|
||||
if (Socket)
|
||||
{
|
||||
/* We need to close here otherwise oskit will never indicate
|
||||
* SEL_FIN and we will never fully close the connection */
|
||||
Status = TCPTranslateError( OskitTCPClose( Socket ) );
|
||||
LibTCPClose(Socket);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Connection->SocketContext = Socket;
|
||||
UnlockObject(Connection, OldIrql);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are already closed by the other end so return success */
|
||||
Status = STATUS_SUCCESS;
|
||||
FlushAllQueues(Connection, STATUS_CANCELLED);
|
||||
}
|
||||
|
||||
if (Connection->AddressFile)
|
||||
|
@ -715,7 +360,7 @@ NTSTATUS TCPClose
|
|||
if (AddressFile)
|
||||
DereferenceObject(AddressFile);
|
||||
|
||||
return Status;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS TCPReceiveData
|
||||
|
@ -726,33 +371,14 @@ NTSTATUS TCPReceiveData
|
|||
ULONG ReceiveFlags,
|
||||
PTCP_COMPLETION_ROUTINE Complete,
|
||||
PVOID Context ) {
|
||||
PVOID DataBuffer;
|
||||
UINT DataLen, Received = 0;
|
||||
NTSTATUS Status;
|
||||
PTDI_BUCKET Bucket;
|
||||
KIRQL OldIrql;
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
|
||||
ReceiveLength, Connection->SocketContext));
|
||||
|
||||
NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
|
||||
|
||||
LockObject(Connection, &OldIrql);
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPRecv
|
||||
( Connection->SocketContext,
|
||||
DataBuffer,
|
||||
DataLen,
|
||||
&Received,
|
||||
ReceiveFlags ) );
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
|
||||
|
||||
/* Keep this request around ... there was no data yet */
|
||||
if( Status == STATUS_PENDING ) {
|
||||
/* Freed in TCPSocketState */
|
||||
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
|
||||
if( !Bucket ) {
|
||||
|
@ -767,16 +393,10 @@ NTSTATUS TCPReceiveData
|
|||
|
||||
InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
|
||||
TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
|
||||
*BytesReceived = Received;
|
||||
}
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
|
||||
|
||||
return Status;
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
NTSTATUS TCPSendData
|
||||
|
@ -787,7 +407,6 @@ NTSTATUS TCPSendData
|
|||
ULONG Flags,
|
||||
PTCP_COMPLETION_ROUTINE Complete,
|
||||
PVOID Context ) {
|
||||
UINT Sent = 0;
|
||||
NTSTATUS Status;
|
||||
PTDI_BUCKET Bucket;
|
||||
KIRQL OldIrql;
|
||||
|
@ -801,12 +420,13 @@ NTSTATUS TCPSendData
|
|||
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
|
||||
Connection->SocketContext));
|
||||
|
||||
Status = TCPTranslateError
|
||||
( OskitTCPSend( Connection->SocketContext,
|
||||
(OSK_PCHAR)BufferData, SendLength,
|
||||
&Sent, 0 ) );
|
||||
Status = TCPTranslateError(LibTCPSend(Connection->SocketContext,
|
||||
BufferData,
|
||||
SendLength));
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
|
||||
DbgPrint("LibTCPSend: 0x%x\n", Status);
|
||||
|
||||
TI_DbgPrint(DEBUG_TCP,("Send: %x, %d\n", Status, SendLength));
|
||||
|
||||
/* Keep this request around ... there was no data yet */
|
||||
if( Status == STATUS_PENDING ) {
|
||||
|
@ -825,8 +445,8 @@ NTSTATUS TCPSendData
|
|||
InsertTailList( &Connection->SendRequest, &Bucket->Entry );
|
||||
TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
|
||||
*BytesSent = Sent;
|
||||
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, SendLength));
|
||||
*BytesSent = SendLength;
|
||||
}
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
@ -855,28 +475,35 @@ NTSTATUS TCPGetSockAddress
|
|||
( PCONNECTION_ENDPOINT Connection,
|
||||
PTRANSPORT_ADDRESS Address,
|
||||
BOOLEAN GetRemote ) {
|
||||
OSK_UINT LocalAddress, RemoteAddress;
|
||||
OSK_UI16 LocalPort, RemotePort;
|
||||
PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
|
||||
struct ip_addr ipaddr;
|
||||
NTSTATUS Status;
|
||||
KIRQL OldIrql;
|
||||
|
||||
LockObject(Connection, &OldIrql);
|
||||
|
||||
Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
|
||||
&LocalAddress, &LocalPort,
|
||||
&RemoteAddress, &RemotePort));
|
||||
|
||||
UnlockObject(Connection, OldIrql);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
AddressIP->TAAddressCount = 1;
|
||||
AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
||||
AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
||||
AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
|
||||
AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
|
||||
|
||||
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;
|
||||
|
||||
DbgPrint("LibTCPGetXXXName: 0x%x\n", Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
|
37
lib/drivers/lwip/lwip.rbuild
Executable file
37
lib/drivers/lwip/lwip.rbuild
Executable file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
|
||||
<module name="lwip" type="staticlibrary">
|
||||
<include base="lwip">src/include</include>
|
||||
<include base="lwip">src/include/ipv4</include>
|
||||
<directory name="src">
|
||||
<file>rosip.c</file>
|
||||
<file>rostcp.c</file>
|
||||
<file>rosmem.c</file>
|
||||
<file>sys_arch.c</file>
|
||||
<directory name="api">
|
||||
<file>err.c</file>
|
||||
<file>netbuf.c</file>
|
||||
<file>netifapi.c</file>
|
||||
<file>tcpip.c</file>
|
||||
</directory>
|
||||
<directory name="core">
|
||||
<file>init.c</file>
|
||||
<file>mem.c</file>
|
||||
<file>memp.c</file>
|
||||
<file>netif.c</file>
|
||||
<file>pbuf.c</file>
|
||||
<file>stats.c</file>
|
||||
<file>sys.c</file>
|
||||
<file>tcp_in.c</file>
|
||||
<file>tcp_out.c</file>
|
||||
<file>tcp.c</file>
|
||||
<directory name="ipv4">
|
||||
<file>inet_chksum.c</file>
|
||||
<file>inet.c</file>
|
||||
<file>ip.c</file>
|
||||
<file>ip_addr.c</file>
|
||||
<file>ip_frag.c</file>
|
||||
</directory>
|
||||
</directory>
|
||||
</directory>
|
||||
</module>
|
1
lib/drivers/lwip/src/include/arch/bpstruct.h
Executable file
1
lib/drivers/lwip/src/include/arch/bpstruct.h
Executable file
|
@ -0,0 +1 @@
|
|||
#pragma pack(push,1)
|
63
lib/drivers/lwip/src/include/arch/cc.h
Executable file
63
lib/drivers/lwip/src/include/arch/cc.h
Executable file
|
@ -0,0 +1,63 @@
|
|||
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
|
||||
|
||||
#include <wdm.h>
|
||||
|
||||
#define LWIP_PROVIDE_ERRNO
|
||||
|
||||
/* ROS-specific mem defs */
|
||||
void *
|
||||
malloc(size_t size);
|
||||
|
||||
void *
|
||||
calloc(size_t count, size_t size);
|
||||
|
||||
void
|
||||
free(void *mem);
|
||||
|
||||
void *
|
||||
realloc(void *mem, size_t size);
|
||||
|
||||
#define mem_realloc(_m_, _s_) realloc(_m_, _s_)
|
||||
|
||||
/* Unsigned int types */
|
||||
typedef unsigned char u8_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef unsigned long u32_t;
|
||||
|
||||
/* Signed int types */
|
||||
typedef signed char s8_t;
|
||||
typedef signed short s16_t;
|
||||
typedef signed long s32_t;
|
||||
|
||||
/* Memory pointer */
|
||||
typedef u32_t mem_ptr_t;
|
||||
|
||||
/* Printf/DPRINT formatters */
|
||||
#define U16_F "hu"
|
||||
#define S16_F "hd"
|
||||
#define X16_F "hx"
|
||||
#define U32_F "lu"
|
||||
#define S32_F "ld"
|
||||
#define X32_F "lx"
|
||||
|
||||
/* Endianness */
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
/* Checksum calculation algorithm choice */
|
||||
#define LWIP_CHKSUM_ALGORITHM 3
|
||||
|
||||
/* Diagnostics */
|
||||
#define LWIP_PLATFORM_DIAG(x) DbgPrint(x)
|
||||
#define LWIP_PLATFORM_ASSERT(x) ASSERTMSG(x, FALSE)
|
||||
|
||||
/* Synchronization */
|
||||
#define SYS_ARCH_DECL_PROTECT(lev) \
|
||||
sys_prot_t lev; \
|
||||
sys_arch_decl_protect(&lev)
|
||||
#define SYS_ARCH_PROTECT(lev) sys_arch_protect(&lev)
|
||||
#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(&lev)
|
||||
|
||||
/* Compiler hints for packing structures */
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
1
lib/drivers/lwip/src/include/arch/epstruct.h
Executable file
1
lib/drivers/lwip/src/include/arch/epstruct.h
Executable file
|
@ -0,0 +1 @@
|
|||
#pragma pack(pop)
|
4
lib/drivers/lwip/src/include/arch/perf.h
Executable file
4
lib/drivers/lwip/src/include/arch/perf.h
Executable file
|
@ -0,0 +1,4 @@
|
|||
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
|
||||
|
||||
#define PERF_START
|
||||
#define PERF_STOP
|
45
lib/drivers/lwip/src/include/arch/sys_arch.h
Executable file
45
lib/drivers/lwip/src/include/arch/sys_arch.h
Executable file
|
@ -0,0 +1,45 @@
|
|||
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
|
||||
|
||||
/* Implmentation specific structs */
|
||||
typedef PRKEVENT sys_sem_t;
|
||||
|
||||
typedef struct _sys_mbox_t
|
||||
{
|
||||
KSPIN_LOCK Lock;
|
||||
LIST_ENTRY ListHead;
|
||||
KEVENT Event;
|
||||
} *sys_mbox_t;
|
||||
|
||||
typedef struct _sys_prot_t
|
||||
{
|
||||
KSPIN_LOCK Lock;
|
||||
KIRQL OldIrql;
|
||||
} sys_prot_t;
|
||||
|
||||
typedef u32_t sys_thread_t;
|
||||
|
||||
typedef struct _LWIP_MESSAGE_CONTAINER
|
||||
{
|
||||
PVOID Message;
|
||||
LIST_ENTRY ListEntry;
|
||||
} LWIP_MESSAGE_CONTAINER, *PLWIP_MESSAGE_CONTAINER;
|
||||
|
||||
#define sys_jiffies() sys_now()
|
||||
|
||||
/* NULL definitions */
|
||||
#define SYS_MBOX_NULL NULL
|
||||
#define SYS_SEM_NULL NULL
|
||||
#define SYS_ARCH_NULL NULL
|
||||
|
||||
void
|
||||
sys_arch_protect(sys_prot_t *lev);
|
||||
|
||||
void
|
||||
sys_arch_unprotect(sys_prot_t *lev);
|
||||
|
||||
void
|
||||
sys_arch_decl_protect(sys_prot_t *lev);
|
||||
|
||||
void
|
||||
sys_shutdown(void);
|
||||
|
194
lib/drivers/lwip/src/include/lwipopts.h
Executable file
194
lib/drivers/lwip/src/include/lwipopts.h
Executable file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
------------------------------------
|
||||
---------- Memory options ----------
|
||||
------------------------------------
|
||||
*/
|
||||
|
||||
/* This combo allows us to implement malloc, free, and realloc ourselves */
|
||||
#define MEM_LIBC_MALLOC 1
|
||||
#define MEMP_MEM_MALLOC 1
|
||||
|
||||
#define MEM_ALIGNMENT 4
|
||||
|
||||
#define LWIP_ARP 0
|
||||
|
||||
#define ARP_QUEUEING 0
|
||||
|
||||
#define IP_FORWARD 0
|
||||
|
||||
#define IP_REASS_MAX_PBUFS 0xFFFFFFFF
|
||||
|
||||
#define IP_DEFAULT_TTL 128
|
||||
|
||||
#define IP_SOF_BROADCAST 1
|
||||
|
||||
#define IP_SOF_BROADCAST_RECV 1
|
||||
|
||||
#define LWIP_ICMP 0
|
||||
|
||||
#define LWIP_RAW 0
|
||||
|
||||
#define LWIP_DHCP 0
|
||||
|
||||
#define LWIP_AUTOIP 0
|
||||
|
||||
#define LWIP_SNMP 0
|
||||
|
||||
#define LWIP_IGMP 0
|
||||
|
||||
#define LWIP_DNS 0
|
||||
|
||||
#define LWIP_UDP 0
|
||||
|
||||
#define LWIP_UDPLITE 0
|
||||
|
||||
#define LWIP_TCP 1
|
||||
|
||||
#define TCP_QUEUE_OOSEQ 1
|
||||
|
||||
#define TCP_MSS 1024
|
||||
|
||||
#define TCP_SND_BUF (TCP_MSS * 8)
|
||||
|
||||
#define TCP_SND_QUEUELEN (8 * (TCP_SND_BUF / TCP_MSS))
|
||||
|
||||
#define TCP_SNDLOWAT TCP_MSS
|
||||
|
||||
#define TCP_WND 0xFFFF
|
||||
|
||||
#define TCP_MAXRTX 12
|
||||
|
||||
#define TCP_SYNMAXRTX 4
|
||||
|
||||
#define TCP_LISTEN_BACKLOG 1
|
||||
|
||||
#define LWIP_TCP_TIMESTAMPS 1
|
||||
|
||||
#define LWIP_CALLBACK_API 1
|
||||
|
||||
#define LWIP_NETIF_API 1
|
||||
|
||||
#define LWIP_SOCKET 0
|
||||
|
||||
#define LWIP_NETCONN 0
|
||||
|
||||
#define LWIP_NETIF_HWADDRHINT 0
|
||||
|
||||
#define LWIP_STATS 0
|
||||
|
||||
#define ICMP_STATS 0
|
||||
|
||||
#define PPP_SUPPORT 0
|
||||
|
||||
#define PPPOE_SUPPORT 0
|
||||
|
||||
#define PPPOS_SUPPORT 0
|
||||
|
||||
/*
|
||||
---------------------------------------
|
||||
---------- Debugging options ----------
|
||||
---------------------------------------
|
||||
*/
|
||||
/**
|
||||
* LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is
|
||||
* compared against this value. If it is smaller, then debugging
|
||||
* messages are written.
|
||||
*/
|
||||
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
|
||||
|
||||
/**
|
||||
* LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable
|
||||
* debug messages of certain types.
|
||||
*/
|
||||
#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
|
||||
|
||||
/**
|
||||
* NETIF_DEBUG: Enable debugging in netif.c.
|
||||
*/
|
||||
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* PBUF_DEBUG: Enable debugging in pbuf.c.
|
||||
*/
|
||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* INET_DEBUG: Enable debugging in inet.c.
|
||||
*/
|
||||
#define INET_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* IP_DEBUG: Enable debugging for IP.
|
||||
*/
|
||||
#define IP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.
|
||||
*/
|
||||
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* MEM_DEBUG: Enable debugging in mem.c.
|
||||
*/
|
||||
#define MEM_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* MEMP_DEBUG: Enable debugging in memp.c.
|
||||
*/
|
||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* SYS_DEBUG: Enable debugging in sys.c.
|
||||
*/
|
||||
#define SYS_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_DEBUG: Enable debugging for TCP.
|
||||
*/
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.
|
||||
*/
|
||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.
|
||||
*/
|
||||
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_RTO_DEBUG: Enable debugging in TCP for retransmit
|
||||
* timeout.
|
||||
*/
|
||||
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_CWND_DEBUG: Enable debugging for TCP congestion window.
|
||||
*/
|
||||
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.
|
||||
*/
|
||||
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.
|
||||
*/
|
||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_RST_DEBUG: Enable debugging for TCP with the RST message.
|
||||
*/
|
||||
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.
|
||||
*/
|
||||
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* TCPIP_DEBUG: Enable debugging in tcpip.c.
|
||||
*/
|
||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
31
lib/drivers/lwip/src/include/rosip.h
Executable file
31
lib/drivers/lwip/src/include/rosip.h
Executable file
|
@ -0,0 +1,31 @@
|
|||
#ifndef _ROS_IP_H_
|
||||
#define _ROS_IP_H_
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
/* External TCP event handlers */
|
||||
extern void TCPConnectEventHandler(void *arg, err_t err);
|
||||
extern void TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb);
|
||||
extern void TCPSendEventHandler(void *arg, u16_t space);
|
||||
extern void TCPFinEventHandler(void *arg, err_t err);
|
||||
extern u32_t TCPRecvEventHandler(void *arg, struct pbuf *p);
|
||||
|
||||
/* TCP functions */
|
||||
struct tcp_pcb *LibTCPSocket(void *arg);
|
||||
err_t LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port);
|
||||
struct tcp_pcb *LibTCPListen(struct tcp_pcb *pcb, u8_t backlog);
|
||||
err_t LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len);
|
||||
err_t LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port);
|
||||
err_t LibTCPClose(struct tcp_pcb *pcb);
|
||||
err_t LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port);
|
||||
err_t LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port);
|
||||
void LibTCPAccept(struct tcp_pcb *pcb, void *arg);
|
||||
|
||||
/* IP functions */
|
||||
void LibIPInsertPacket(void *ifarg, void *data, u32_t size);
|
||||
void LibIPInitialize(void);
|
||||
void LibIPShutdown(void);
|
||||
|
||||
#endif
|
45
lib/drivers/lwip/src/rosip.c
Executable file
45
lib/drivers/lwip/src/rosip.c
Executable file
|
@ -0,0 +1,45 @@
|
|||
#include "lwip/sys.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#include "rosip.h"
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
void
|
||||
LibIPInsertPacket(void *ifarg,
|
||||
void *data,
|
||||
u32_t size)
|
||||
{
|
||||
struct pbuf *p, *p1;
|
||||
u32_t i;
|
||||
|
||||
ASSERT(ifarg);
|
||||
ASSERT(data);
|
||||
ASSERT(size > 0);
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_POOL);
|
||||
if (p)
|
||||
{
|
||||
for (i = 0, p1 = p; i < size; i += p1->len, p1 = p1->next)
|
||||
{
|
||||
ASSERT(p1);
|
||||
RtlCopyMemory(p1->payload, ((PUCHAR)data) + i, p1->len);
|
||||
}
|
||||
|
||||
((struct netif *)ifarg)->input(p, ifarg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibIPInitialize(void)
|
||||
{
|
||||
/* This completes asynchronously */
|
||||
tcpip_init(NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
LibIPShutdown(void)
|
||||
{
|
||||
/* This is synchronous */
|
||||
sys_shutdown();
|
||||
}
|
38
lib/drivers/lwip/src/rosmem.c
Executable file
38
lib/drivers/lwip/src/rosmem.c
Executable file
|
@ -0,0 +1,38 @@
|
|||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#define LWIP_TAG 'PIwl'
|
||||
|
||||
void *
|
||||
malloc(mem_size_t size)
|
||||
{
|
||||
return ExAllocatePoolWithTag(NonPagedPool, size, LWIP_TAG);
|
||||
}
|
||||
|
||||
void *
|
||||
calloc(mem_size_t count, mem_size_t size)
|
||||
{
|
||||
void *mem = malloc(count * size);
|
||||
|
||||
if (!mem) return NULL;
|
||||
|
||||
RtlZeroMemory(mem, count * size);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void
|
||||
free(void *mem)
|
||||
{
|
||||
ExFreePoolWithTag(mem, LWIP_TAG);
|
||||
}
|
||||
|
||||
void *
|
||||
realloc(void *mem, size_t size)
|
||||
{
|
||||
free(mem);
|
||||
return malloc(size);
|
||||
}
|
581
lib/drivers/lwip/src/rostcp.c
Executable file
581
lib/drivers/lwip/src/rostcp.c
Executable file
|
@ -0,0 +1,581 @@
|
|||
#include "lwip/sys.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#include "rosip.h"
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
/* The way that lwIP does multi-threading is really not ideal for our purposes but
|
||||
* we best go along with it unless we want another unstable TCP library. lwIP uses
|
||||
* a thread called the "tcpip thread" which is the only one allowed to call raw API
|
||||
* functions. Since this is the case, for each of our LibTCP* functions, we queue a request
|
||||
* for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is
|
||||
* a lot of unnecessary thread swapping and it could definitely be faster, but I don't want
|
||||
* to going messing around in lwIP because I have no desire to create another mess like oskittcp */
|
||||
|
||||
extern KEVENT TerminationEvent;
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
WaitForEventSafely(PRKEVENT Event)
|
||||
{
|
||||
PVOID WaitObjects[] = {Event, &TerminationEvent};
|
||||
|
||||
if (KeWaitForMultipleObjects(2,
|
||||
WaitObjects,
|
||||
WaitAny,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL,
|
||||
NULL) == STATUS_WAIT_0)
|
||||
{
|
||||
/* Signalled by the caller's event */
|
||||
return TRUE;
|
||||
}
|
||||
else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */
|
||||
{
|
||||
/* Signalled by our termination event */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
err_t
|
||||
InternalSendEventHandler(void *arg, struct tcp_pcb *pcb, u16_t space)
|
||||
{
|
||||
DbgPrint("SendEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)space);
|
||||
|
||||
/* Make sure the socket didn't get closed */
|
||||
if (!arg) return ERR_OK;
|
||||
|
||||
TCPSendEventHandler(arg, space);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
err_t
|
||||
InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
u32_t len;
|
||||
|
||||
DbgPrint("RecvEvent(0x%x, 0x%x, 0x%x, %d)\n", arg, pcb, p, (unsigned int)err);
|
||||
|
||||
/* Make sure the socket didn't get closed */
|
||||
if (!arg)
|
||||
{
|
||||
if (p) pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
if (!p)
|
||||
{
|
||||
TCPFinEventHandler(arg, ERR_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
DbgPrint("RECV - p:0x%x p->payload:0x%x p->len:%d p->tot_len:%d\n", p, p->payload, p->len, p->tot_len);
|
||||
|
||||
if (err == ERR_OK)
|
||||
{
|
||||
len = TCPRecvEventHandler(arg, p);
|
||||
if (len != 0)
|
||||
{
|
||||
tcp_recved(pcb, len);
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We want lwIP to store the pbuf on its queue for later */
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
err_t
|
||||
InternalAcceptEventHandler(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
{
|
||||
DbgPrint("AcceptEvent(0x%x, 0x%x, %d)\n", arg, newpcb, (unsigned int)err);
|
||||
|
||||
/* Make sure the socket didn't get closed */
|
||||
if (!arg) return ERR_ABRT;
|
||||
|
||||
TCPAcceptEventHandler(arg, newpcb);
|
||||
|
||||
/* Set in LibTCPAccept (called from TCPAcceptEventHandler) */
|
||||
if (newpcb->callback_arg)
|
||||
return ERR_OK;
|
||||
else
|
||||
return ERR_ABRT;
|
||||
}
|
||||
|
||||
static
|
||||
err_t
|
||||
InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||
{
|
||||
DbgPrint("ConnectEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)err);
|
||||
|
||||
/* Make sure the socket didn't get closed */
|
||||
if (!arg) return ERR_OK;
|
||||
|
||||
TCPConnectEventHandler(arg, err);
|
||||
|
||||
tcp_recv(pcb, InternalRecvEventHandler);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
InternalErrorEventHandler(void *arg, err_t err)
|
||||
{
|
||||
DbgPrint("ErrorEvent(0x%x, %d)\n", arg, (unsigned int)err);
|
||||
|
||||
/* Make sure the socket didn't get closed */
|
||||
if (!arg) return;
|
||||
|
||||
TCPFinEventHandler(arg, err);
|
||||
}
|
||||
|
||||
struct socket_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
PVOID Arg;
|
||||
|
||||
/* Output */
|
||||
PVOID NewPcb;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPSocketCallback(void *arg)
|
||||
{
|
||||
struct socket_callback_msg *msg = arg;
|
||||
|
||||
ASSERT(msg);
|
||||
|
||||
msg->NewPcb = tcp_new();
|
||||
|
||||
if (msg->NewPcb)
|
||||
{
|
||||
tcp_arg(msg->NewPcb, msg->Arg);
|
||||
tcp_err(msg->NewPcb, InternalErrorEventHandler);
|
||||
}
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
struct tcp_pcb *
|
||||
LibTCPSocket(void *arg)
|
||||
{
|
||||
struct socket_callback_msg *msg = ExAllocatePool(NonPagedPool, sizeof(struct socket_callback_msg));
|
||||
void *ret;
|
||||
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Arg = arg;
|
||||
|
||||
tcpip_callback_with_block(LibTCPSocketCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->NewPcb;
|
||||
else
|
||||
ret = NULL;
|
||||
|
||||
DbgPrint("LibTCPSocket(0x%x) = 0x%x\n", arg, ret);
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bind_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
struct tcp_pcb *Pcb;
|
||||
struct ip_addr *IpAddress;
|
||||
u16_t Port;
|
||||
|
||||
/* Output */
|
||||
err_t Error;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPBindCallback(void *arg)
|
||||
{
|
||||
struct bind_callback_msg *msg = arg;
|
||||
|
||||
ASSERT(msg);
|
||||
|
||||
msg->Error = tcp_bind(msg->Pcb, msg->IpAddress, ntohs(msg->Port));
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct bind_callback_msg *msg;
|
||||
err_t ret;
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
msg = ExAllocatePool(NonPagedPool, sizeof(struct bind_callback_msg));
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Pcb = pcb;
|
||||
msg->IpAddress = ipaddr;
|
||||
msg->Port = port;
|
||||
|
||||
tcpip_callback_with_block(LibTCPBindCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->Error;
|
||||
else
|
||||
ret = ERR_CLSD;
|
||||
|
||||
DbgPrint("LibTCPBind(0x%x)\n", pcb);
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
struct listen_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
struct tcp_pcb *Pcb;
|
||||
u8_t Backlog;
|
||||
|
||||
/* Output */
|
||||
struct tcp_pcb *NewPcb;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPListenCallback(void *arg)
|
||||
{
|
||||
struct listen_callback_msg *msg = arg;
|
||||
void *p;
|
||||
|
||||
ASSERT(msg);
|
||||
|
||||
p = msg->Pcb->callback_arg;
|
||||
msg->NewPcb = tcp_listen_with_backlog(msg->Pcb, msg->Backlog);
|
||||
|
||||
if (msg->NewPcb)
|
||||
{
|
||||
tcp_arg(msg->NewPcb, p);
|
||||
tcp_accept(msg->NewPcb, InternalAcceptEventHandler);
|
||||
tcp_err(msg->NewPcb, InternalErrorEventHandler);
|
||||
}
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
struct tcp_pcb *
|
||||
LibTCPListen(struct tcp_pcb *pcb, u8_t backlog)
|
||||
{
|
||||
struct listen_callback_msg *msg;
|
||||
void *ret;
|
||||
|
||||
if (!pcb)
|
||||
return NULL;
|
||||
|
||||
msg = ExAllocatePool(NonPagedPool, sizeof(struct listen_callback_msg));
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Pcb = pcb;
|
||||
msg->Backlog = backlog;
|
||||
|
||||
tcpip_callback_with_block(LibTCPListenCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->NewPcb;
|
||||
else
|
||||
ret = NULL;
|
||||
|
||||
DbgPrint("LibTCPListen(0x%x,0x%x)\n", pcb, ret);
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct send_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
struct tcp_pcb *Pcb;
|
||||
void *Data;
|
||||
u16_t DataLength;
|
||||
|
||||
/* Output */
|
||||
err_t Error;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPSendCallback(void *arg)
|
||||
{
|
||||
struct send_callback_msg *msg = arg;
|
||||
|
||||
ASSERT(msg);
|
||||
|
||||
if (tcp_sndbuf(msg->Pcb) < msg->DataLength)
|
||||
{
|
||||
msg->Error = ERR_INPROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp_sent(msg->Pcb, InternalSendEventHandler);
|
||||
|
||||
msg->Error = tcp_write(msg->Pcb, msg->Data, msg->DataLength, TCP_WRITE_FLAG_COPY);
|
||||
|
||||
tcp_output(msg->Pcb);
|
||||
}
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len)
|
||||
{
|
||||
struct send_callback_msg *msg;
|
||||
err_t ret;
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
msg = ExAllocatePool(NonPagedPool, sizeof(struct send_callback_msg));
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Pcb = pcb;
|
||||
msg->Data = dataptr;
|
||||
msg->DataLength = len;
|
||||
|
||||
tcpip_callback_with_block(LibTCPSendCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->Error;
|
||||
else
|
||||
ret = ERR_CLSD;
|
||||
|
||||
DbgPrint("LibTCPSend(0x%x)\n", pcb);
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
struct connect_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
struct tcp_pcb *Pcb;
|
||||
struct ip_addr *IpAddress;
|
||||
u16_t Port;
|
||||
|
||||
/* Output */
|
||||
err_t Error;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPConnectCallback(void *arg)
|
||||
{
|
||||
struct connect_callback_msg *msg = arg;
|
||||
|
||||
ASSERT(arg);
|
||||
|
||||
msg->Error = tcp_connect(msg->Pcb, msg->IpAddress, ntohs(msg->Port), InternalConnectEventHandler);
|
||||
if (msg->Error == ERR_OK)
|
||||
msg->Error = ERR_INPROGRESS;
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct connect_callback_msg *msg;
|
||||
err_t ret;
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
msg = ExAllocatePool(NonPagedPool, sizeof(struct connect_callback_msg));
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Pcb = pcb;
|
||||
msg->IpAddress = ipaddr;
|
||||
msg->Port = port;
|
||||
|
||||
tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->Error;
|
||||
else
|
||||
ret = ERR_CLSD;
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
DbgPrint("LibTCPConnect(0x%x)\n", pcb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
struct close_callback_msg
|
||||
{
|
||||
/* Synchronization */
|
||||
KEVENT Event;
|
||||
|
||||
/* Input */
|
||||
struct tcp_pcb *Pcb;
|
||||
|
||||
/* Output */
|
||||
err_t Error;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
LibTCPCloseCallback(void *arg)
|
||||
{
|
||||
struct close_callback_msg *msg = arg;
|
||||
|
||||
msg->Error = tcp_close(msg->Pcb);
|
||||
|
||||
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPClose(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct close_callback_msg *msg;
|
||||
err_t ret;
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
tcp_arg(pcb, NULL);
|
||||
tcp_recv(pcb, NULL);
|
||||
tcp_sent(pcb, NULL);
|
||||
tcp_err(pcb, NULL);
|
||||
tcp_accept(pcb, NULL);
|
||||
|
||||
msg = ExAllocatePool(NonPagedPool, sizeof(struct close_callback_msg));
|
||||
if (msg)
|
||||
{
|
||||
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
|
||||
msg->Pcb = pcb;
|
||||
|
||||
tcpip_callback_with_block(LibTCPCloseCallback, msg, 1);
|
||||
|
||||
if (WaitForEventSafely(&msg->Event))
|
||||
ret = msg->Error;
|
||||
else
|
||||
ret = ERR_CLSD;
|
||||
|
||||
ExFreePool(msg);
|
||||
|
||||
DbgPrint("LibTCPClose(0x%x)\n", pcb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
void
|
||||
LibTCPAccept(struct tcp_pcb *pcb, void *arg)
|
||||
{
|
||||
DbgPrint("LibTCPAccept(0x%x, 0x%x)\n", pcb, arg);
|
||||
|
||||
ASSERT(arg);
|
||||
|
||||
tcp_arg(pcb, NULL);
|
||||
tcp_recv(pcb, InternalRecvEventHandler);
|
||||
tcp_sent(pcb, InternalSendEventHandler);
|
||||
tcp_arg(pcb, arg);
|
||||
|
||||
tcp_accepted(pcb);
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
|
||||
{
|
||||
DbgPrint("LibTCPGetHostName(0x%x)\n", pcb);
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
*ipaddr = pcb->local_ip;
|
||||
*port = pcb->local_port;
|
||||
|
||||
DbgPrint("Got host port: %d\n", *port);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
|
||||
{
|
||||
DbgPrint("LibTCPGetPeerName(0x%x)\n", pcb);
|
||||
|
||||
if (!pcb)
|
||||
return ERR_CLSD;
|
||||
|
||||
*ipaddr = pcb->remote_ip;
|
||||
*port = pcb->remote_port;
|
||||
|
||||
DbgPrint("Got remote port: %d\n", *port);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
380
lib/drivers/lwip/src/sys_arch.c
Executable file
380
lib/drivers/lwip/src/sys_arch.c
Executable file
|
@ -0,0 +1,380 @@
|
|||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/err.h"
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
static LIST_ENTRY ThreadListHead;
|
||||
static KSPIN_LOCK ThreadListLock;
|
||||
|
||||
KEVENT TerminationEvent;
|
||||
|
||||
static LARGE_INTEGER StartTime;
|
||||
|
||||
typedef struct _thread_t
|
||||
{
|
||||
PVOID ThreadId;
|
||||
HANDLE Handle;
|
||||
struct sys_timeouts Timeouts;
|
||||
void (* ThreadFunction)(void *arg);
|
||||
void *ThreadContext;
|
||||
LIST_ENTRY ListEntry;
|
||||
char Name[1];
|
||||
} *thread_t;
|
||||
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
LARGE_INTEGER CurrentTime;
|
||||
|
||||
KeQuerySystemTime(&CurrentTime);
|
||||
|
||||
return (CurrentTime.QuadPart - StartTime.QuadPart) / 10000;
|
||||
}
|
||||
|
||||
void
|
||||
sys_arch_protect(sys_prot_t *lev)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
|
||||
KeAcquireSpinLock(&lev->Lock, &OldIrql);
|
||||
|
||||
lev->OldIrql = OldIrql;
|
||||
}
|
||||
|
||||
void
|
||||
sys_arch_unprotect(sys_prot_t *lev)
|
||||
{
|
||||
KeReleaseSpinLock(&lev->Lock, lev->OldIrql);
|
||||
}
|
||||
|
||||
void
|
||||
sys_arch_decl_protect(sys_prot_t *lev)
|
||||
{
|
||||
KeInitializeSpinLock(&lev->Lock);
|
||||
}
|
||||
|
||||
sys_sem_t
|
||||
sys_sem_new(u8_t count)
|
||||
{
|
||||
sys_sem_t sem = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
||||
if (!sem)
|
||||
return SYS_SEM_NULL;
|
||||
|
||||
ASSERT(count == 0 || count == 1);
|
||||
|
||||
/* It seems lwIP uses the semaphore implementation as either a completion event or a lock
|
||||
* so I optimize for this case by using a synchronization event and setting its initial state
|
||||
* to signalled for a lock and non-signalled for a completion event */
|
||||
|
||||
KeInitializeEvent(sem, SynchronizationEvent, count);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
void
|
||||
sys_sem_free(sys_sem_t sem)
|
||||
{
|
||||
ExFreePool(sem);
|
||||
}
|
||||
|
||||
void
|
||||
sys_sem_signal(sys_sem_t sem)
|
||||
{
|
||||
KeSetEvent(sem, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
u32_t
|
||||
sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
||||
{
|
||||
LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
|
||||
UINT64 TimeDiff;
|
||||
NTSTATUS Status;
|
||||
PVOID WaitObjects[] = {sem, &TerminationEvent};
|
||||
|
||||
LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
|
||||
|
||||
KeQuerySystemTime(&PreWaitTime);
|
||||
|
||||
Status = KeWaitForMultipleObjects(2,
|
||||
WaitObjects,
|
||||
WaitAny,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
timeout != 0 ? &LargeTimeout : NULL,
|
||||
NULL);
|
||||
if (Status == STATUS_WAIT_0)
|
||||
{
|
||||
KeQuerySystemTime(&PostWaitTime);
|
||||
TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
|
||||
TimeDiff /= 10000;
|
||||
return TimeDiff;
|
||||
}
|
||||
else if (Status == STATUS_WAIT_1)
|
||||
{
|
||||
/* DON'T remove ourselves from the thread list! */
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
|
||||
/* We should never get here! */
|
||||
ASSERT(FALSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
sys_mbox_t
|
||||
sys_mbox_new(int size)
|
||||
{
|
||||
sys_mbox_t mbox = ExAllocatePool(NonPagedPool, sizeof(struct _sys_mbox_t));
|
||||
|
||||
if (!mbox)
|
||||
return SYS_MBOX_NULL;
|
||||
|
||||
KeInitializeSpinLock(&mbox->Lock);
|
||||
|
||||
InitializeListHead(&mbox->ListHead);
|
||||
|
||||
KeInitializeEvent(&mbox->Event, NotificationEvent, FALSE);
|
||||
|
||||
return mbox;
|
||||
}
|
||||
|
||||
void
|
||||
sys_mbox_free(sys_mbox_t mbox)
|
||||
{
|
||||
ASSERT(IsListEmpty(&mbox->ListHead));
|
||||
|
||||
ExFreePool(mbox);
|
||||
}
|
||||
|
||||
void
|
||||
sys_mbox_post(sys_mbox_t mbox, void *msg)
|
||||
{
|
||||
PLWIP_MESSAGE_CONTAINER Container;
|
||||
KIRQL OldIrql;
|
||||
|
||||
Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
|
||||
ASSERT(Container);
|
||||
|
||||
Container->Message = msg;
|
||||
|
||||
KeAcquireSpinLock(&mbox->Lock, &OldIrql);
|
||||
InsertTailList(&mbox->ListHead,
|
||||
&Container->ListEntry);
|
||||
|
||||
KeSetEvent(&mbox->Event, IO_NO_INCREMENT, FALSE);
|
||||
KeReleaseSpinLock(&mbox->Lock, OldIrql);
|
||||
}
|
||||
|
||||
u32_t
|
||||
sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
||||
{
|
||||
LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
|
||||
UINT64 TimeDiff;
|
||||
NTSTATUS Status;
|
||||
PVOID Message;
|
||||
PLWIP_MESSAGE_CONTAINER Container;
|
||||
PLIST_ENTRY Entry;
|
||||
KIRQL OldIrql;
|
||||
PVOID WaitObjects[] = {&mbox->Event, &TerminationEvent};
|
||||
|
||||
LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
|
||||
|
||||
KeQuerySystemTime(&PreWaitTime);
|
||||
|
||||
Status = KeWaitForMultipleObjects(2,
|
||||
WaitObjects,
|
||||
WaitAny,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
timeout != 0 ? &LargeTimeout : NULL,
|
||||
NULL);
|
||||
if (Status == STATUS_WAIT_0)
|
||||
{
|
||||
KeAcquireSpinLock(&mbox->Lock, &OldIrql);
|
||||
Entry = RemoveHeadList(&mbox->ListHead);
|
||||
ASSERT(Entry);
|
||||
if (IsListEmpty(&mbox->ListHead))
|
||||
KeClearEvent(&mbox->Event);
|
||||
Container = CONTAINING_RECORD(Entry, LWIP_MESSAGE_CONTAINER, ListEntry);
|
||||
KeReleaseSpinLock(&mbox->Lock, OldIrql);
|
||||
|
||||
KeQuerySystemTime(&PostWaitTime);
|
||||
TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
|
||||
TimeDiff /= 10000;
|
||||
|
||||
Message = Container->Message;
|
||||
ExFreePool(Container);
|
||||
|
||||
if (msg)
|
||||
*msg = Message;
|
||||
|
||||
return TimeDiff;
|
||||
}
|
||||
else if (Status == STATUS_WAIT_1)
|
||||
{
|
||||
/* DON'T remove ourselves from the thread list! */
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
|
||||
/* We should never get here! */
|
||||
ASSERT(FALSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
u32_t
|
||||
sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
||||
{
|
||||
if (sys_arch_mbox_fetch(mbox, msg, 1) != SYS_ARCH_TIMEOUT)
|
||||
return 0;
|
||||
else
|
||||
return SYS_MBOX_EMPTY;
|
||||
}
|
||||
|
||||
err_t
|
||||
sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
||||
{
|
||||
sys_mbox_post(mbox, msg);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
struct sys_timeouts *sys_arch_timeouts(void)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
thread_t Container;
|
||||
|
||||
KeAcquireSpinLock(&ThreadListLock, &OldIrql);
|
||||
CurrentEntry = ThreadListHead.Flink;
|
||||
while (CurrentEntry != &ThreadListHead)
|
||||
{
|
||||
Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
|
||||
|
||||
if (Container->ThreadId == KeGetCurrentThread())
|
||||
{
|
||||
KeReleaseSpinLock(&ThreadListLock, OldIrql);
|
||||
return &Container->Timeouts;
|
||||
}
|
||||
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
KeReleaseSpinLock(&ThreadListLock, OldIrql);
|
||||
|
||||
Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
|
||||
if (!Container)
|
||||
return SYS_ARCH_NULL;
|
||||
|
||||
Container->Name[0] = ANSI_NULL;
|
||||
Container->ThreadFunction = NULL;
|
||||
Container->ThreadContext = NULL;
|
||||
Container->Timeouts.next = NULL;
|
||||
Container->ThreadId = KeGetCurrentThread();
|
||||
|
||||
ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
|
||||
|
||||
return &Container->Timeouts;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LwipThreadMain(PVOID Context)
|
||||
{
|
||||
thread_t Container = Context;
|
||||
KIRQL OldIrql;
|
||||
|
||||
Container->ThreadId = KeGetCurrentThread();
|
||||
|
||||
ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
|
||||
|
||||
Container->ThreadFunction(Container->ThreadContext);
|
||||
|
||||
KeAcquireSpinLock(&ThreadListLock, &OldIrql);
|
||||
RemoveEntryList(&Container->ListEntry);
|
||||
KeReleaseSpinLock(&ThreadListLock, OldIrql);
|
||||
|
||||
ExFreePool(Container);
|
||||
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
sys_thread_t
|
||||
sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
||||
{
|
||||
thread_t Container;
|
||||
NTSTATUS Status;
|
||||
|
||||
Container = ExAllocatePool(NonPagedPool, strlen(name) + sizeof(*Container));
|
||||
if (!Container)
|
||||
return 0;
|
||||
|
||||
strcpy(Container->Name, name);
|
||||
Container->ThreadFunction = thread;
|
||||
Container->ThreadContext = arg;
|
||||
Container->Timeouts.next = NULL;
|
||||
|
||||
Status = PsCreateSystemThread(&Container->Handle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
LwipThreadMain,
|
||||
Container);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(Container);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sys_init(void)
|
||||
{
|
||||
KeInitializeSpinLock(&ThreadListLock);
|
||||
|
||||
InitializeListHead(&ThreadListHead);
|
||||
|
||||
KeQuerySystemTime(&StartTime);
|
||||
|
||||
KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
sys_shutdown(void)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
thread_t Container;
|
||||
|
||||
/* Set the termination event */
|
||||
KeSetEvent(&TerminationEvent, IO_NO_INCREMENT, FALSE);
|
||||
|
||||
/* Loop through the thread list and wait for each to die */
|
||||
while ((CurrentEntry = ExInterlockedRemoveHeadList(&ThreadListHead, &ThreadListLock)))
|
||||
{
|
||||
Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
|
||||
|
||||
if (Container->ThreadFunction)
|
||||
{
|
||||
KeWaitForSingleObject(Container->Handle,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
ZwClose(Container->Handle);
|
||||
}
|
||||
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue