#define IOCTL_WSP_ACCEPT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED ,FILE_ANY_ACCESS)\r
#define IOCTL_WSP_GET_XXX_NAME CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED ,FILE_ANY_ACCESS)\r
#define IOCTL_WSP_CLOSE_SOCKET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED ,FILE_ANY_ACCESS)\r
+#define IOCTL_WSP_USER_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_BUFFERED ,FILE_ANY_ACCESS)\r
\r
\r
// Data structures that are used for connect\r
class SdpArp;\r
\r
#include "ib_al.h"\r
-#include "..\..\ipoib\ip_addresses_shared.h"\r
-\r
+#include "..\..\..\inc\iba\ib_at_ioctl.h"\r
#include "sdpMsgs.h"\r
#include "SdpGenUtils.h"\r
#include "SdpTrace.h"\r
\r
OBJECT_ATTRIBUTES objectAttributes;\r
\r
- RtlInitUnicodeString( &DevName1, IPOIB_DEV_NAME );\r
+ RtlInitUnicodeString( &DevName1, IBAT_DEV_NAME );\r
\r
InitializeObjectAttributes( &objectAttributes,\r
&DevName1,\r
IO_STATUS_BLOCK ioStatus;\r
char temp [1000]; // BUGBUG: Handle the case of more IPs\r
\r
- IOCTL_IPOIB_PORTS_IN ipoib_ports_in;\r
- IOCTL_IPOIB_PORTS_OUT *pipoib_ports_out;\r
- IPOIB_AT_PORT_RECORD *ports_records;\r
+ IOCTL_IBAT_PORTS_IN ipoib_ports_in;\r
+ IOCTL_IBAT_PORTS_OUT *pipoib_ports_out;\r
+ IBAT_PORT_RECORD *ports_records;\r
\r
- ipoib_ports_in.Version = IPOIB_IOCTL_VERSION;\r
- ipoib_ports_in.Size = sizeof temp;\r
+ ipoib_ports_in.Version = IBAT_IOCTL_VERSION;\r
\r
- pipoib_ports_out = (IOCTL_IPOIB_PORTS_OUT *)temp;\r
+ pipoib_ports_out = (IOCTL_IBAT_PORTS_OUT *)temp;\r
\r
ASSERT(m_DeviceObject != NULL);\r
\r
KeInitializeEvent(&event, NotificationEvent, FALSE);\r
irp = IoBuildDeviceIoControlRequest(\r
- IOCTL_IPOIB_PORTS ,\r
+ IOCTL_IBAT_PORTS ,\r
m_DeviceObject,\r
&ipoib_ports_in,\r
sizeof ipoib_ports_in,\r
SDP_PRINT(SDP_ERR, SDP_ARP, ("IoCallDriver failed rc = 0x%x\n", rc )); \r
goto Cleanup;\r
}\r
- if (pipoib_ports_out->Size != 0) {\r
+ if (pipoib_ports_out->Size > sizeof temp) {\r
// The number of bytes that we have allocated wasn't enough\r
SDP_PRINT(SDP_ERR, SDP_ARP, ("pipoib_ports_out.Size = %d\n", pipoib_ports_out->Size ));\r
rc = STATUS_INSUFFICIENT_RESOURCES;\r
NTSTATUS\r
SdpArp::SourcePortGidFromPorts(\r
IN ULONG SourceAddr, \r
- IN IOCTL_IPOIB_PORTS_OUT *pPorts, \r
+ IN IOCTL_IBAT_PORTS_OUT *pPorts, \r
OUT ib_net64_t *SrcPortGuid,\r
OUT ib_net64_t *SrcCaGuid\r
)\r
PIRP irp;\r
IO_STATUS_BLOCK ioStatus;\r
\r
- unsigned int i = 0, j = 0;\r
+ int i = 0, j = 0;\r
\r
- struct IOCTL_IPOIB_IP_ADDRESSES_IN addresses_in;\r
- struct IOCTL_IPOIB_IP_ADDRESSES_OUT *addresses_out;\r
+ IOCTL_IBAT_IP_ADDRESSES_IN addresses_in;\r
+ IOCTL_IBAT_IP_ADDRESSES_OUT *addresses_out;\r
char temp[1000];\r
- addresses_out = (struct IOCTL_IPOIB_IP_ADDRESSES_OUT *)temp;\r
+ addresses_out = (IOCTL_IBAT_IP_ADDRESSES_OUT *)temp;\r
\r
- addresses_in.Version = IPOIB_IOCTL_VERSION;\r
+ addresses_in.Version = IBAT_IOCTL_VERSION;\r
\r
for (i = 0 ; i < pPorts->NumPorts; i++) {\r
SDP_PRINT(SDP_TRACE, SDP_SOCKET, (\r
\r
KeInitializeEvent(&event, NotificationEvent, FALSE);\r
irp = IoBuildDeviceIoControlRequest(\r
- IOCTL_IPOIB_IP_ADDRESSES ,\r
+ IOCTL_IBAT_IP_ADDRESSES ,\r
m_DeviceObject,\r
&addresses_in,\r
sizeof addresses_in,\r
SDP_PRINT(SDP_ERR, SDP_ARP, ("IoCallDriver failed rc = 0x%x\n", rc )); \r
goto Cleanup;\r
}\r
- if (addresses_out->Size != 0) {\r
+ if (addresses_out->Size > sizeof temp) {\r
// The number of bytes that we have allocated wasn't enough\r
SDP_PRINT(SDP_ERR, SDP_ARP, ("addresses_out.Size = %d\n", addresses_out->Size ));\r
rc = STATUS_INSUFFICIENT_RESOURCES;\r
\r
\r
// We now have the addreses, we can check if this is what we need\r
- for (j = 0 ; j < addresses_out->NumIps; j++) {\r
+ for (j = 0 ; j < addresses_out->AddressCount; j++) {\r
ULONG *pIp;\r
- ASSERT(addresses_out->Addreses[j].IpVersion == 4);\r
- pIp = (ULONG *) (&addresses_out->Addreses[j].Data[12]);\r
+ ASSERT(addresses_out->Address[j].IpVersion == 4);\r
+ pIp = (ULONG *) (&addresses_out->Address[j].Address[12]);\r
if (*pIp == CL_NTOH32(SourceAddr)) {\r
SDP_PRINT(SDP_TRACE, SDP_ARP, \r
("Found the IP: ca guid = 0x%I64x port guid=0x%I64x\n", \r
\r
}\r
// If we have reached here the data was not found\r
+ SDP_PRINT(SDP_WARN, SDP_ARP, \r
+ ("HCA not found for ip=%d.%d.%d.%d\n", \r
+ (SourceAddr & 0xff000000) >> 24,\r
+ (SourceAddr & 0xff0000) >> 16,\r
+ (SourceAddr & 0xff00) >> 8 , \r
+ SourceAddr & 0xff\r
+ ));\r
rc = STATUS_NOT_FOUND;\r
\r
Cleanup:\r
\r
NTSTATUS \r
SdpArp::DestPortGidFromMac(\r
+ IN ib_net64_t SrcPortGuid,\r
IN MAC_ADDR DestMac, \r
OUT ib_gid_t *pDestPortGid)\r
{\r
- SDP_PRINT(SDP_TRACE, SDP_SOCKET,("MAC = ????"));\r
+ SDP_PRINT(SDP_TRACE, SDP_SOCKET,("MAC = ????\n"));\r
NTSTATUS rc = STATUS_SUCCESS;\r
\r
KEVENT event;\r
PIRP irp;\r
IO_STATUS_BLOCK ioStatus;\r
\r
- IOCTL_IPOIB_MAC_2_GID_IN ipoib_mac2gid_in;\r
- IOCTL_IPOIB_MAC_2_GID_OUT ipoib_mac2gid_out;\r
+ IOCTL_IBAT_MAC_TO_GID_IN ipoib_mac2gid_in;\r
+ IOCTL_IBAT_MAC_TO_GID_OUT ipoib_mac2gid_out;\r
\r
C_ASSERT(MAC_ADDR_SIZE == sizeof (ipoib_mac2gid_in.DestMac));\r
+ ipoib_mac2gid_in.Version = IBAT_IOCTL_VERSION;\r
+ ipoib_mac2gid_in.PortGuid = SrcPortGuid;\r
memcpy(ipoib_mac2gid_in.DestMac, DestMac, MAC_ADDR_SIZE);\r
+ \r
+\r
\r
ASSERT(m_DeviceObject != NULL);\r
\r
KeInitializeEvent(&event, NotificationEvent, FALSE);\r
irp = IoBuildDeviceIoControlRequest(\r
- IOCTL_IPOIB_MAC_2_GID ,\r
+ IOCTL_IBAT_MAC_TO_GID ,\r
m_DeviceObject,\r
&ipoib_mac2gid_in,\r
sizeof ipoib_mac2gid_in,\r
OUT ib_net64_t *SrcCaGuid\r
);\r
NTSTATUS DestPortGidFromMac(\r
- IN MAC_ADDR DestMac, \r
+ IN ib_net64_t SrcPortGuid,\r
+ IN MAC_ADDR DestMac, \r
OUT ib_gid_t *pDestPortGid);\r
\r
/* \r
NTSTATUS\r
SourcePortGidFromPorts(\r
IN ULONG SourceAddr, \r
- IN IOCTL_IPOIB_PORTS_OUT *pPorts, \r
+ IN IOCTL_IBAT_PORTS_OUT *pPorts, \r
OUT ib_net64_t *SrcPortGuid,\r
OUT ib_net64_t *SrcCaGuid\r
);\r
ExFreePoolWithTag(pBufferDescriptor, Tag);\r
\r
}\r
+\r
/*\r
Currently the implmentation of shutdown should allow it to work, even without\r
init being called\r
{\r
m_SendSeq = 0;\r
m_AdvtSeq = 0;\r
- m_ClientBeingServed = false;\r
m_CurrentlySentBuffers = 0;\r
m_CurrentlyAllocated = 0;\r
- m_ClientWaiting = false;\r
m_PostCreditsWhenCan = false;\r
m_CreditsCurrentlyPosted = false;\r
m_CreditdBufferDescriptor = NULL;\r
m_MaxBuffers = MaxBuffers;\r
m_MaxConcurrentSends = MaxConcurrentSends;\r
m_MaxMessageSize = MaxMessageSize; \r
- KeInitializeEvent(&m_WaitingClients, NotificationEvent, FALSE);\r
ASSERT(pd != NULL);\r
m_pd = pd;\r
ASSERT(qp != NULL); \r
ASSERT(lkey != NULL);\r
m_lkey = lkey;\r
m_pSdpSocket = pSdpSocket;\r
+ m_CallBackPending = false;\r
+\r
+ \r
+\r
return STATUS_SUCCESS;\r
}\r
\r
*/\r
NTSTATUS \r
BufferPool::GetBuffer(\r
- BufferDescriptor **ppBufferDescriptor, \r
- KEVENT **ppEvent,\r
- bool FirstBuffer\r
+ BufferDescriptor **ppBufferDescriptor\r
)\r
{\r
- SDP_PRINT(SDP_DEBUG, SDP_BUFFER_POOL, ("this = 0x%p FirstBuffer = %s\n",this,\r
- FirstBuffer ? "TRUE" : "FALSE"));\r
+ SDP_PRINT(SDP_DEBUG, SDP_BUFFER_POOL, ("this = 0x%p \n",this));\r
AssertLocked();\r
\r
NTSTATUS rc = STATUS_SUCCESS;\r
*ppBufferDescriptor = NULL;\r
\r
- if (m_ClientBeingServed == true && (FirstBuffer != false)) {\r
- // The request can not be staisfied right now. We need to hold it\r
- // until our request is being freed\r
- // BUGBUG: iMPLMENT: create event and put it in the queue\r
- // This might only happen when there are two threads calling us\r
- ASSERT(FALSE);\r
- return STATUS_UNEXPECTED_IO_ERROR;\r
- }\r
-\r
- if (FirstBuffer == true) {\r
- m_ClientBeingServed = true; \r
- }\r
-\r
- // Can we supply a buffer right now ?\r
- if (m_CurrentlySentBuffers < m_MaxConcurrentSends) {\r
- // yes, supply a buffer\r
- if (m_FreePackets.Size() > 0) {\r
- LIST_ENTRY *item = m_FreePackets.RemoveHeadList();\r
- *ppBufferDescriptor = CONTAINING_RECORD(item, BufferDescriptor , BuffersList);\r
- goto Cleanup;\r
- } else if (m_CurrentlyAllocated < m_MaxBuffers) {\r
- // we need to alocate a new buffer\r
- rc = BufferDescriptor::AllocateBuffer(ppBufferDescriptor, m_MaxMessageSize, SEND_BUFFERS_ALLOCATION_TAG);\r
- if (!NT_SUCCESS(rc)) {\r
- SDP_PRINT(SDP_ERR, SDP_BUFFER_POOL, ("AllocateBuffer failed rc = 0x%x\n", rc ));\r
- ASSERT(*ppBufferDescriptor == NULL);\r
- goto Cleanup;\r
- }\r
- m_CurrentlyAllocated++;\r
+ if (m_FreePackets.Size() > 0) {\r
+ LIST_ENTRY *item = m_FreePackets.RemoveHeadList();\r
+ *ppBufferDescriptor = CONTAINING_RECORD(item, BufferDescriptor , BuffersList);\r
+ goto Cleanup;\r
+ } else if (m_CurrentlyAllocated < m_MaxBuffers) {\r
+ // we need to alocate a new buffer\r
+ rc = BufferDescriptor::AllocateBuffer(ppBufferDescriptor, m_MaxMessageSize, SEND_BUFFERS_ALLOCATION_TAG);\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_BUFFER_POOL, ("AllocateBuffer failed rc = 0x%x\n", rc ));\r
+ ASSERT(*ppBufferDescriptor == NULL);\r
goto Cleanup;\r
- } \r
- } \r
- // No buffers available, we have to wait\r
- ASSERT(m_ClientWaiting == false);\r
- KeClearEvent(&m_WaitingClients);\r
- m_ClientWaiting = true;\r
- *ppEvent = &m_WaitingClients;\r
+ }\r
+ m_CurrentlyAllocated++;\r
+ goto Cleanup;\r
+ } \r
+ // No buffers available, we return NULL\r
+ ASSERT(*ppBufferDescriptor == NULL);\r
\r
Cleanup: \r
return rc;\r
ASSERT(pBufferDescriptor->GetFlags() == 0 || \r
pBufferDescriptor->GetFlags() == DISCONNECT_MESSAGE);\r
\r
+ // Assert that we are not sending an empty buffer\r
+ if (pBufferDescriptor->DataSize == 0) {\r
+ msg_hdr_bsdh *pHeader = (msg_hdr_bsdh *) pBufferDescriptor->pBuffer;\r
+ ASSERT(pHeader->mid == SDP_MID_DISCONNECT );\r
+ }\r
+\r
m_QueuedPackets.InsertTailList(&pBufferDescriptor->BuffersList);\r
rc = SendBuffersIfCan();\r
if (!NT_SUCCESS(rc)) {\r
\r
}\r
\r
-/* \r
- This function is being called by a client that has asked for some buffers\r
- when he has recieved all it's data\r
-*/\r
-VOID \r
-BufferPool::AllowOthersToGet()\r
-{\r
- ASSERT(m_ClientBeingServed == true);\r
- m_ClientBeingServed = false;\r
-\r
- // BUGBUG: this means that we should free the next waiter (Once we support more\r
- // than one thread).\r
-}\r
-\r
/*\r
called when a send packet has finished.\r
*/\r
\r
#if DBG \r
if (m_CurrentlySentBuffers == 1) {\r
- SDP_PRINT(SDP_WARN, SDP_PERFORMANCE, ("Currently no packets are bing sent m_ClientWaiting = %s\n", \r
- m_ClientWaiting ? "true" : "false")); \r
+ SDP_PRINT(SDP_WARN, SDP_PERFORMANCE, ("Currently no packets are bing sent\n")); \r
}\r
#endif\r
ASSERT( pBufferDescriptor->GetFlags() == CREDIT_UPDATE ||\r
}\r
} else {\r
m_FreePackets.InsertTailList(&pBufferDescriptor->BuffersList);\r
- // Is there a client waiting ?\r
- if ( m_ClientWaiting) {\r
- KeSetEvent( &m_WaitingClients, IO_NO_INCREMENT, FALSE );\r
- m_ClientWaiting = false; \r
+ // We have to ask for another thread to do the job, as\r
+ // we might be in a DPC context\r
+\r
+ // Ask for a new callback only in the following conditions:\r
+ // 1) There is no request on the way AND\r
+ // 2) There is a buffer that can be used AND\r
+ // 3) We have enough free space to complete a packet\r
+ // 4) We have gone under some threshold\r
+// TODO: 4 above, didn't seem to have a real influance, so it is not in\r
+// the code now. It should be testsed in the future.\r
+ if (!m_CallBackPending && (m_UserPackets.Size() > 0)) {\r
+ // Now testing 3,4\r
+\r
+ LIST_ENTRY *item = m_UserPackets.Head();\r
+ IRP * pIrp = CONTAINING_RECORD(item, IRP ,Tail.Overlay.ListEntry);\r
+ \r
+ if ((RemainingToCopy(pIrp) < m_MaxMessageSize * m_FreePackets.Size())) {\r
+ rc = m_pSdpSocket->RequestCallBack();\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_BUFFER_POOL, ("PostCredits failed rc = 0x%x\n", rc ));\r
+ goto Cleanup;\r
+ } \r
+ m_CallBackPending = true;\r
+ }\r
}\r
+\r
if (DissconnectMessage) {\r
SDP_PRINT(SDP_TRACE, SDP_BUFFER_POOL, ("We have recieved a DissconnectMessage complition\n" ));\r
m_pSdpSocket->DisconectSentEvent();\r
}\r
}\r
-Cleanup: \r
+Cleanup:\r
+ ASSERT(m_CurrentlySentBuffers != 0);\r
m_CurrentlySentBuffers--;\r
- ASSERT(m_CurrentlySentBuffers >= 0);\r
\r
return rc;\r
}\r
\r
+NTSTATUS \r
+BufferPool::AddToUserBuffers(\r
+ bool *pCopied, \r
+ bool ForceCopy,\r
+ char *pData, \r
+ uint32_t BufferSize, \r
+ uint32_t Coppied, \r
+ IRP* pIrp\r
+ )\r
+{\r
+ SDP_PRINT(SDP_DEBUG, SDP_BUFFER_POOL, ("this = 0x%p \n",this));\r
+ AssertLocked();\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
+\r
+ if ((m_UserPackets.Size() == 0) && (ForceCopy == false) ){\r
+ *pCopied = false;\r
+ goto Cleanup;\r
+ }\r
+\r
+ // We have to queue this IRP (following logic from sample)\r
+ ASSERT(pData != NULL);\r
+ SetBufferSize(pIrp, BufferSize);\r
+ SetUserBuffer(pIrp, pData);\r
+ SetCoppied(pIrp,Coppied);\r
+ SetSocket(pIrp,m_pSdpSocket);\r
+\r
+\r
+ ASSERT(m_UserPackets.Size()==0);\r
+ IoMarkIrpPending(pIrp);\r
+ m_UserPackets.InsertTailList(&pIrp->Tail.Overlay.ListEntry);\r
+ *pCopied = true;\r
+ // We mark the IRP as pending\r
+ pIrp->IoStatus.Status = STATUS_PENDING;\r
+ rc = STATUS_PENDING;\r
+\r
+Cleanup:\r
+\r
+ \r
+#if 0\r
+The above code should be activated if we want to allow returning offsetof\r
+the user mode thread as fast as possible.\r
+\r
+ if (m_CallBackPending == false) {\r
+ NTSTATUS rc1 = m_pSdpSocket->RequestCallBack();\r
+ if (!NT_SUCCESS(rc1)) {\r
+ SDP_PRINT(SDP_ERR, SDP_BUFFER_POOL, ("PostCredits failed rc = 0x%x\n", rc ));\r
+ ASSERT(FALSE);\r
+ } \r
+ m_CallBackPending = true;\r
+ }\r
+#endif\r
+ \r
+ ASSERT(rc == STATUS_PENDING || rc == STATUS_SUCCESS);\r
+ return rc;\r
+}\r
+\r
+\r
+NTSTATUS \r
+BufferPool::UsersThreadCallBack()\r
+{\r
+ SDP_PRINT(SDP_DEBUG, SDP_BUFFER_POOL, ("this = 0x%p \n",this));\r
+ AssertLocked();\r
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
+ IRP *pIrp = NULL;\r
+ LIST_ENTRY *item;\r
+ \r
+ NTSTATUS rc = STATUS_SUCCESS, rc1;\r
+ BufferDescriptor *pBufferDescriptor = NULL;\r
+ ASSERT(m_CallBackPending == true);\r
+ ASSERT(m_UserPackets.Size() > 0 );\r
+\r
+ m_CallBackPending = false;\r
+\r
+ while (m_UserPackets.Size() > 0) {\r
+ rc = GetBuffer(&pBufferDescriptor);\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("GetBuffer failed rc = 0x%x\n", rc ));\r
+ goto Cleanup;\r
+ }\r
+\r
+ if (pBufferDescriptor == NULL) {\r
+ // We don't have a new buffer any more, we just\r
+ // wait for a new packet to be freed\r
+ ASSERT(rc == STATUS_SUCCESS);\r
+ goto Cleanup;\r
+ }\r
+\r
+ item = m_UserPackets.Head();\r
+\r
+ pIrp = CONTAINING_RECORD(item, IRP ,Tail.Overlay.ListEntry);\r
+\r
+ // copy the data from the user mode to the buffers \r
+ ULONG CopySize = pBufferDescriptor->BufferSize - sizeof msg_hdr_bsdh;\r
+ CopySize = min(CopySize, RemainingToCopy(pIrp));\r
+ \r
+ rc = pBufferDescriptor->WriteData((CHAR *)GetUserBuffer(pIrp) + GetCoppied(pIrp), CopySize);\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("pBufferDescriptor->WriteData failed rc = 0x%x\n", rc ));\r
+ // free the buffer that you have\r
+ rc1 = ReturnBuffer(pBufferDescriptor);\r
+ ASSERT(NT_SUCCESS(rc1));\r
+ goto Cleanup;\r
+ }\r
+ // Update the user buffer\r
+ SetCoppied(pIrp, GetCoppied(pIrp) + CopySize);\r
+ \r
+ // send the data to the buffer\r
+ pBufferDescriptor->SetMid(SDP_MID_DATA);\r
+ rc = AddBufferToQueuedList(pBufferDescriptor);\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("AddBufferToQueuedList failed rc = 0x%x\n", rc ));\r
+ // free the buffer that you have\r
+ rc1 = ReturnBuffer(pBufferDescriptor);\r
+ ASSERT(NT_SUCCESS(rc1));\r
+ goto Cleanup;\r
+ }\r
+\r
+ if (RemainingToCopy(pIrp) == 0) {\r
+ // We have finished with this users packet, we should\r
+ // compleate the IRP\r
+\r
+ WspSendOut *pWspSendOut = (WspSendOut *) pIrp->AssociatedIrp.SystemBuffer;\r
+ m_UserPackets.RemoveHeadList();\r
+\r
+ pIrp->IoStatus.Status = STATUS_SUCCESS;\r
+ pIrp->IoStatus.Information = sizeof (WspSendOut);\r
+ pWspSendOut->Errno = 0;\r
+ pWspSendOut->NumberOfBytesSent = GetBufferSize(pIrp);\r
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);\r
+\r
+ }\r
+ }\r
+\r
+Cleanup:\r
+\r
+ return rc;\r
+}\r
+\r
+\r
/*\r
This function goes over the list of packets that we can send, and sends\r
them. It is called under the lock, and might be called also from a DPC\r
} \r
}\r
\r
-\r
-\r
while ((m_QueuedPackets.Size() > 0) && \r
(m_CurrentlySentBuffers < m_MaxConcurrentSends) &&\r
(m_rRecvBuf > 2)) {\r
VOID \r
BufferPool::CloseSocket()\r
{\r
- SDP_PRINT(SDP_TRACE, SDP_BUFFER_POOL, ("this = 0x%p m_WaitingClients = %s\n",\r
- m_ClientWaiting ? "true" : "false"));\r
+ SDP_PRINT(SDP_TRACE, SDP_BUFFER_POOL, ("this = 0x%p \n"));\r
AssertLocked();\r
\r
- if (m_ClientWaiting) {\r
- KeSetEvent( &m_WaitingClients, IO_NO_INCREMENT, FALSE );\r
- m_ClientWaiting = false;\r
- }\r
- // The next time our client will try to get data, he will get \r
- // the error \r
+ //??? Should we do something here \r
+\r
}\r
\r
\r
BufferPool::ShutDown()\r
{\r
SDP_PRINT(SDP_TRACE, SDP_BUFFER_POOL, ("this = 0x%p \n",this));\r
- //???? AssertLocked();\r
+\r
+ //AssertLocked();\r
BufferDescriptor *pBufferDescriptor = NULL;\r
LIST_ENTRY *item = NULL;\r
+ IRP *pIrp = NULL;\r
\r
while (m_FreePackets.Size() > 0 ) {\r
item = m_FreePackets.RemoveHeadList();\r
BufferDescriptor::DeAllocateBuffer(pBufferDescriptor, SEND_BUFFERS_ALLOCATION_TAG);\r
}\r
\r
+ while (m_UserPackets.Size() > 0 ) {\r
+ item = m_UserPackets.RemoveHeadList();\r
+ pIrp = CONTAINING_RECORD(item, IRP ,Tail.Overlay.ListEntry);\r
+ pIrp->IoStatus.Status = STATUS_CANCELLED;\r
+ pIrp->IoStatus.Information = 0;\r
+ IoCompleteRequest (pIrp, IO_NO_INCREMENT);\r
+ }\r
+\r
if(m_CreditdBufferDescriptor != NULL) {\r
BufferDescriptor::DeAllocateBuffer(m_CreditdBufferDescriptor, SEND_BUFFERS_ALLOCATION_TAG);\r
m_CreditdBufferDescriptor = NULL;\r
pHeader->seq_ack = m_pSdpSocket->m_RecvBufferPool.GetRecvSeq();\r
m_AdvtSeq = pHeader->seq_ack;// Currently only for debug\r
pHeader->flags = SDP_MSG_FLAG_NON_FLAG;\r
+\r
/*\r
* endian swap\r
*/\r
#ifndef H_SDP_BUFFER_POOL_H\r
#define H_SDP_BUFFER_POOL_H \r
\r
-\r
-\r
// This is simply a wrapper to the LIST_ENTRY class that allows \r
// easier work with this list\r
class LinkedList {\r
size--;\r
}\r
\r
-\r
private:\r
int size;\r
LIST_ENTRY m_Data;\r
\r
};\r
\r
+\r
+// We will define 4 pointers to store send data for the IRP:\r
+// This will have to change one day()\r
+// The users data\r
+\r
+inline VOID SetUserBuffer(IRP *pIrp, VOID * p) {\r
+ pIrp->Tail.Overlay.DriverContext[0] = (VOID *)p;\r
+}\r
+inline VOID* GetUserBuffer(IRP *pIrp) {\r
+ return (pIrp->Tail.Overlay.DriverContext[0]);\r
+}\r
+\r
+inline VOID SetBufferSize(IRP *pIrp, uint32_t i) {\r
+ pIrp->Tail.Overlay.DriverContext[1] = (VOID *)(UINT_PTR)i;\r
+}\r
+inline uint32_t GetBufferSize(IRP *pIrp) {\r
+ return (uint32_t)(UINT_PTR) (pIrp->Tail.Overlay.DriverContext[1]);\r
+}\r
+\r
+inline VOID SetCoppied(IRP *pIrp, uint32_t i) {\r
+ pIrp->Tail.Overlay.DriverContext[2] = (VOID *)(UINT_PTR)i;\r
+ ASSERT(i <= GetBufferSize(pIrp));\r
+}\r
+inline uint32_t GetCoppied(IRP *pIrp) {\r
+ return (uint32_t)(UINT_PTR) (pIrp->Tail.Overlay.DriverContext[2]);\r
+}\r
+\r
+/* \r
+ BUGBUG:\r
+ As I intend to change this in any case, \r
+ I will not use Referance count on the socket\r
+ here.\r
+*/ // ???????????????????\r
+inline void SetSocket(IRP *pIrp, SdpSocket *pSdpSocket) {\r
+ pIrp->Tail.Overlay.DriverContext[3] = pSdpSocket;\r
+}\r
+\r
+inline SdpSocket *GetSocket(IRP *pIrp) {\r
+ return (SdpSocket *)pIrp->Tail.Overlay.DriverContext[3];\r
+}\r
+\r
+inline uint32_t RemainingToCopy(IRP *pIrp) {\r
+ uint32_t Coppied = GetCoppied(pIrp);\r
+ uint32_t BufferSize = GetBufferSize(pIrp);\r
+ ASSERT(BufferSize >= Coppied);\r
+ return BufferSize - Coppied;\r
+}\r
+\r
class BufferPool {\r
\r
public:\r
);\r
\r
NTSTATUS GetBuffer(\r
- BufferDescriptor ** ppBufferDescriptor, \r
- KEVENT **ppEvent,\r
- bool FirstBuffer\r
+ BufferDescriptor ** ppBufferDescriptor\r
);\r
\r
NTSTATUS AddBufferToQueuedList(BufferDescriptor *pBufferDescriptor); \r
\r
- VOID AllowOthersToGet(); \r
-\r
NTSTATUS ReturnBuffer(BufferDescriptor *pBufferDescriptor);\r
\r
+ NTSTATUS AddToUserBuffers(bool *pCopied, bool ForceCopy,char *pData, uint32_t BufferSize, uint32_t Coppied, IRP* pIrp);\r
+\r
+ VOID RemoveFromUserBuffers(PIRP pIrp) {\r
+ m_UserPackets.RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);\r
+ }\r
+\r
+ NTSTATUS UsersThreadCallBack();\r
+\r
NTSTATUS SendBuffersIfCan();\r
\r
VOID CloseSocket();\r
NTSTATUS SendBuffer(BufferDescriptor *pBufferDescriptor);\r
\r
// Global data about this connection\r
- int m_MaxBuffers; // The maximum number of buffers that we allow for this QP (to be allocated)\r
- int m_MaxConcurrentSends; // The total numbers of sends that are allowd for the QP\r
- int m_MaxMessageSize; // The maximum buffer size that we allow\r
-\r
- int m_CurrentlySentBuffers; // Number of buffers that we have sent, and didn't get an ack yet\r
- int m_CurrentlyAllocated; // The number of buffers that we have allocated\r
+ uint32_t m_MaxBuffers; // The maximum number of buffers that we allow for this QP (to be allocated)\r
+ uint32_t m_MaxConcurrentSends; // The total numbers of sends that are allowd for the QP\r
+ uint32_t m_MaxMessageSize; // The maximum buffer size that we allow\r
\r
- bool m_ClientBeingServed; // true if we have already started giving buffers to a client\r
+ uint32_t m_CurrentlySentBuffers; // Number of buffers that we have sent, and didn't get an ack yet\r
+ uint32_t m_CurrentlyAllocated; // The number of buffers that we have allocated\r
\r
LinkedList m_FreePackets; // This packets are free and might be used\r
LinkedList m_QueuedPackets; // This packets were filled with data and should be sent\r
+\r
+\r
+//?????\r
+ public:\r
+ LinkedList m_UserPackets; // This is a list of user packets that we should send\r
+\r
\r
\r
- // TODO: A queue of events for threads that are waiting for buffers.\r
+private: //????????? \r
\r
// IBAL constants from the main socket structure \r
// TODO: Should they stay here and be used like this ?\r
net32_t m_lkey;\r
\r
// A list of events that the users has to wait on. ???? currently only one\r
- KEVENT m_WaitingClients; // switch to a linked list\r
- bool m_ClientWaiting;\r
\r
uint32_t m_SendSeq; //sequence number of last message sent (send_seq in linux)\r
uint32_t m_AdvtSeq; // sequence number of last message acknowledged (advt_seq in linux)\r
bool m_PostCreditsWhenCan;\r
bool m_CreditsCurrentlyPosted;\r
BufferDescriptor *m_CreditdBufferDescriptor;\r
+ bool m_CallBackPending; // Set to true if we have requesetd a callback from \r
+ // the users thread\r
\r
VOID AssertLocked();\r
\r
\r
// fill the device functions\r
pDriverObject->DriverUnload = DriverUnload;\r
- pDriverObject->FastIoDispatch = NULL;\r
+ pDriverObject->FastIoDispatch = NULL;\r
pDriverObject->DriverStartIo = NULL;\r
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {\r
pDriverObject->MajorFunction[i] = SdpDriver::Dispatch;\r
SDP_PRINT(SDP_ERR, SDP_DRIVER, ("new SdpSocket failed rc = 0x%x\n", rc )); \r
goto Cleanup;\r
}\r
- rc = pSdpSocket->Init(&wspSocketIn, pWspSocketOut);\r
+ rc = pSdpSocket->Init(&wspSocketIn, pWspSocketOut, pSdpUserFile);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_DRIVER, ("pSdpSocket->Init failed rc = 0x%x\n", rc ));\r
goto Cleanup;\r
pWspSendOut->Errno = WSAENOTSOCK;\r
goto Cleanup;\r
}\r
- rc = pSdpSocket->WSPSend(&wspSendIn, pWspSendOut);\r
+ rc = pSdpSocket->WSPSend(&wspSendIn, pWspSendOut, pIrp);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_DRIVER, ("pSdpSocket->WSPSend failed rc = 0x%x\n", rc )); \r
goto Cleanup;\r
}\r
}\r
break;\r
- \r
-\r
case IOCTL_WSP_CLOSE_SOCKET :\r
{\r
SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("IOCTL_WSP_CLOSE_SOCKET recieved\n" )); \r
goto Cleanup;\r
}\r
rc = pSdpSocket->WSPCloseSocket(&wspSocketCloseIn, pWspSocketCloseOut);\r
- // After closing a socket we "unlink" the kernel object, and it won't\r
- // be accessable for the user. (currently succesfull or not)\r
- // BUGBUG: Change this behavior while the linger don't linger staff is fixed\r
- pSdpUserFile->RemoveSocket(pSdpSocket); // Must succed\r
- // BUGBUG: are we taking the socket from the correct place\r
- // It is possible that not, but the chanses of an error seems small\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_DRIVER, ("pSdpSocket->WSPCloseSocket failed rc = 0x%x\n", rc )); \r
goto Cleanup; \r
}\r
}\r
break;\r
+\r
+ case IOCTL_WSP_USER_THREAD :\r
+ {\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("IOCTL_WSP_USER_THREAD recieved\n" )); \r
+ pSdpUserFile = (SdpUserFile *)pIrpSp->FileObject->FsContext;\r
+\r
+ /* Ignore Error = */ pSdpUserFile->UsersThread();\r
+ }\r
+ break;\r
\r
default:\r
// This is an unrecgnized IOCTL\r
\r
#include "Precompile.h"\r
\r
+//#define DONT_COPY_DATA\r
+\r
USHORT ntohs(USHORT in)\r
{\r
return ((in & 0xff) << 8) | ((in & 0xff00) >> 8);\r
__try\r
{\r
ProbeForRead( (void*)p_src, count, 1 );\r
+#ifdef DONT_COPY_DATA \r
+ if (count < 1000){\r
+ RtlCopyMemory( p_dest, p_src, count );\r
+ }\r
+#else\r
RtlCopyMemory( p_dest, p_src, count );\r
+#endif\r
return STATUS_SUCCESS;\r
}\r
__except(EXCEPTION_EXECUTE_HANDLER)\r
__try\r
{\r
ProbeForWrite( p_dest, count, 1 );\r
+#ifdef DONT_COPY_DATA \r
+ if (count < 1000){\r
+ RtlCopyMemory( p_dest, p_src, count );\r
+ }\r
+#else\r
RtlCopyMemory( p_dest, p_src, count );\r
+#endif\r
return CL_SUCCESS;\r
}\r
__except(EXCEPTION_EXECUTE_HANDLER)\r
#define WSAESTALE (WSABASEERR+70)\r
#define WSAEREMOTE (WSABASEERR+71)\r
\r
-\r
-\r
-\r
+// Used for IRP cancell\r
+#define ERROR_OPERATION_ABORTED 995L\r
+#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED)\r
\r
#endif // _SDP_GEN_UTILS_H\r
bool Lock(bool Force = false) {\r
KIRQL OldIrql;\r
int OldFlags = 0;\r
- NTSTATUS rc = STATUS_SUCCESS;\r
+ NTSTATUS rc = STATUS_SUCCESS, rc1 = STATUS_SUCCESS;\r
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
bool Locked = false;\r
bool WaitedOnLock = false;\r
ASSERT(m_NumberOfClientWaiting >= 0); \r
KeReleaseSpinLock(&m_SpinLock, OldIrql);\r
rc = HandleFlags(OldFlags);\r
+ if(!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_LOCK, ("HandleFlags failed rc = 0x%x\n", rc ));\r
+ }\r
if ((Force == false) && \r
(!NT_SUCCESS(rc) ||\r
(m_flags & ERROR_SIGNALLED) ||\r
- (!NT_SUCCESS(rc = m_CheckSocketState(m_pSdpSocket)))\r
+ (!NT_SUCCESS(rc1 = m_CheckSocketState(m_pSdpSocket)))\r
)) {\r
// We have to signal the error to the calling side\r
- SDP_PRINT(SDP_ERR, SDP_LOCK, ("HandleFlags failed rc = 0x%x\n", rc ));\r
+ if(!NT_SUCCESS(rc1)) {\r
+ SDP_PRINT(SDP_ERR, SDP_LOCK, ("m_CheckSocketState failed rc1 = 0x%x\n", rc1 ));\r
+ }\r
Locked = false;\r
KeAcquireSpinLock(&m_SpinLock, &OldIrql);\r
m_InUse = false;\r
(int)pHeader->seq_ack));\r
m_pSdpSocket->m_SendBufferPool.SetRemoteRecvBuf(rRecvBuf);\r
\r
- // m_DisConnRecieved is the last message that should be recieved\r
- ASSERT(m_DisConnRecieved == false); // BUGBUG: do a real check here\r
+ // m_DisConnRecieved is the last "real" message that should be recieved\r
+ // we might still get credits update\r
+ ASSERT(m_DisConnRecieved == false ||\r
+ (pHeader->mid == SDP_MID_DATA && pHeader->size == sizeof msg_hdr_bsdh)); // BUGBUG: do a real check here\r
\r
// ???? Handle more state changes here ????\r
if (pHeader->mid != SDP_MID_DATA) {\r
m_CloseSocketCalled = false;\r
m_ShutdownCalled = false;\r
m_DisconnectConnectionRecieved = false;\r
+ m_pSdpUserFile = NULL;\r
+ InitializeListHead(&m_CallBackRequestList);\r
\r
}\r
\r
\r
NTSTATUS SdpSocket::Init(\r
WspSocketIn *pSocketInParam, \r
- WspSocketOut *pSocketOutParam)\r
+ WspSocketOut *pSocketOutParam,\r
+ SdpUserFile *pSdpUserFile)\r
{\r
NTSTATUS rc = STATUS_SUCCESS;\r
SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p\n", this));\r
rc = STATUS_NO_MEMORY;\r
goto Cleanup;\r
}\r
+\r
+ m_pSdpUserFile = pSdpUserFile;\r
+ m_pSdpUserFile->AddRef();\r
+ \r
\r
Cleanup:\r
return rc;\r
{\r
// Check if our state allows us to handle send/recv/accept ...\r
if (m_ShutdownCalled) return STATUS_SHUTDOWN_IN_PROGRESS;\r
- if (m_CloseSocketCalled) return STATUS_SHUTDOWN_IN_PROGRESS;\r
+ if (m_CloseSocketCalled) return STATUS_HANDLES_CLOSED; // Not the exact code\r
+ // But it seems relatively closest\r
return STATUS_SUCCESS;\r
}\r
\r
NTSTATUS SdpSocket::WSPSend(\r
WspSendIn *pWspSendIn,\r
- WspSendOut *pWspSendOut\r
+ WspSendOut *pWspSendOut,\r
+ IRP *pIrp\r
)\r
{ \r
SDP_PRINT(SDP_DEBUG, SDP_SOCKET, ("this = 0x%p size = %d \n",this, pWspSendIn->BufferSize));\r
\r
NTSTATUS rc = STATUS_SUCCESS; \r
- NTSTATUS rc1; // used only to check that there are no more errors on the \r
- // return path\r
BufferDescriptor * pBufferDescriptor = NULL;\r
bool First = true;\r
ULONG Coppied = 0;\r
- bool Locked = false;\r
PRKEVENT pBuffersEvent = NULL;\r
+ bool BufferCopied;\r
+ NTSTATUS rc1;\r
\r
// For zero bytes send we currently don't do anything and return with status \r
// success\r
goto Cleanup;\r
}\r
\r
- while (Coppied < pWspSendIn->BufferSize) {\r
- if ((Locked == false) && !m_Lock.Lock()) {\r
- SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to lock this = 0x%p \n",this));\r
- rc = STATUS_SHUTDOWN_IN_PROGRESS;\r
- goto Cleanup;\r
- }\r
- Locked = true;\r
- ASSERT(pBuffersEvent == NULL);\r
+ if (!m_Lock.Lock()) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to lock this = 0x%p \n",this));\r
+ rc = STATUS_SHUTDOWN_IN_PROGRESS;\r
+ goto Cleanup;\r
+ }\r
\r
- if ((m_state != SS_CONNECTED)) {\r
- // We can not send now.\r
- SDP_PRINT(SDP_WARN, SDP_SOCKET, ("Can't send now, m_state = %s\n",\r
- SS2String(m_state)\r
- ));\r
- rc = STATUS_SHUTDOWN_IN_PROGRESS;\r
- pWspSendOut->Errno = WSAENOTCONN;\r
- \r
- m_Lock.Unlock(); // Error ignored as this is already an error pass\r
- Locked = false;\r
+ if ((m_state != SS_CONNECTED)) {\r
+ // We can not send now.\r
+ SDP_PRINT(SDP_WARN, SDP_SOCKET, ("Can't send now, m_state = %s\n",\r
+ SS2String(m_state)\r
+ ));\r
+ rc = STATUS_SHUTDOWN_IN_PROGRESS;\r
+ pWspSendOut->Errno = WSAENOTCONN;\r
+ \r
+ m_Lock.Unlock(); // Error ignored as this is already an error pass\r
+ goto Cleanup;\r
+ }\r
+\r
+ // Check if there is already data in the queue, if yes we just \r
+ // increase the queue and leave.\r
+\r
+ ASSERT(!m_CloseSocketCalled);\r
+ rc = m_SendBufferPool.AddToUserBuffers(&BufferCopied, false , pWspSendIn->pData, pWspSendIn->BufferSize,Coppied, pIrp);\r
+ ASSERT(rc == STATUS_PENDING || rc == STATUS_SUCCESS);\r
+ if (rc == STATUS_PENDING) {\r
+ ASSERT(BufferCopied);\r
+ // TODO: We already took the lock, and we are in the right context,\r
+ // We should probably do some work there\r
+ // Data was already copied to the buffer we are done.\r
+ rc = m_Lock.Unlock();\r
+ if (!NT_SUCCESS(rc)) {\r
+ // No need to complete the IRP, as it will be be deleted\r
+ // when all other IRPs will be\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_Lock.Unlock() failed rc = 0x%x\n", rc ));\r
goto Cleanup;\r
}\r
+ // This IRP will be pending (make sure to change this after the unlock)\r
+ rc = STATUS_PENDING;\r
+\r
+ goto Cleanup;\r
+ } \r
+\r
+ ASSERT(rc == STATUS_SUCCESS);\r
+ ASSERT(BufferCopied == false);\r
+ // We now try to copy the data to the internal buffers\r
+\r
+ while (Coppied < pWspSendIn->BufferSize) {\r
\r
- rc = m_SendBufferPool.GetBuffer(&pBufferDescriptor, &pBuffersEvent, First);\r
+ rc = m_SendBufferPool.GetBuffer(&pBufferDescriptor);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_SendBufferPool.GetBuffer failed rc = 0x%x\n", rc ));\r
m_Lock.Unlock(); // Error ignored as this is already an error pass\r
- Locked = false;\r
goto Cleanup;\r
}\r
- First = false;\r
- \r
- if (pBuffersEvent != NULL) {\r
- // We are told to wait on this event\r
+\r
+ if (pBufferDescriptor == NULL) {\r
+ // We don't have a new buffer any more, we store the remaining\r
+ // buffer and quit\r
+ rc = m_SendBufferPool.AddToUserBuffers(\r
+ &BufferCopied, \r
+ true , \r
+ pWspSendIn->pData, \r
+ pWspSendIn->BufferSize,\r
+ Coppied,\r
+ pIrp);\r
+ ASSERT(rc == STATUS_PENDING);\r
+ ASSERT(BufferCopied == true);\r
+\r
rc = m_Lock.Unlock();\r
- Locked = false;\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_Lock.Unlock() failed rc = 0x%x\n", rc ));\r
+ // No need to complete the IRP, as it will be be deleted\r
+ // when all other IRPs will be\r
goto Cleanup;\r
}\r
-\r
- rc = MyKeWaitForSingleObject(\r
- pBuffersEvent,\r
- UserRequest,\r
- UserMode,\r
- FALSE,\r
- NULL\r
- ); \r
- pBuffersEvent = NULL;\r
- if (( rc == STATUS_ALERTED ) ||( rc == STATUS_USER_APC )) {\r
- // BUGBUG: Think what to do here, we should be able to stop the\r
- // connect, and quit (probably shutdown should be enough)\r
- SDP_PRINT(SDP_WARN, SDP_SOCKET, ("MyKeWaitForSingleObject was alerted rc = 0x%x\n", rc ));\r
- rc = STATUS_UNEXPECTED_IO_ERROR;\r
- //pWspConnectOut->Errno = WSAENETUNREACH; // BUGBUG: verify this error\r
- Shutdown();\r
- goto Cleanup;\r
- }\r
- // try getting the buffer again\r
- continue;\r
+ rc = STATUS_PENDING;// This IRP will be pending (make sure to change this after the unlock)\r
+ goto Cleanup;\r
}\r
-\r
// copy the data from the user mode to the buffers \r
ULONG CopySize = pBufferDescriptor->BufferSize - sizeof msg_hdr_bsdh;\r
CopySize = min(CopySize, pWspSendIn->BufferSize - Coppied);\r
goto Cleanup;\r
}\r
}\r
- ASSERT(Locked == true);\r
+ \r
rc = m_Lock.Unlock();\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_Lock.Unlock() failed rc = 0x%x\n", rc ));\r
goto Cleanup;\r
}\r
- \r
- m_SendBufferPool.AllowOthersToGet();\r
- \r
+\r
Cleanup:\r
if (NT_SUCCESS(rc) ) {\r
- pWspSendOut->Errno = 0;\r
- ASSERT(pWspSendIn->BufferSize == Coppied);\r
- pWspSendOut->NumberOfBytesSent = Coppied;\r
+ ASSERT((rc == STATUS_SUCCESS) || (rc == STATUS_PENDING));\r
+ if (rc != STATUS_PENDING) {\r
+ pWspSendOut->Errno = 0;\r
+ ASSERT(pWspSendIn->BufferSize == Coppied);\r
+ pWspSendOut->NumberOfBytesSent = Coppied;\r
+ }\r
} else {\r
// Make sure that we have the error setted\r
+ Shutdown();\r
ASSERT(pWspSendOut->Errno != 0); // BUGBUG: Need to make sure that this\r
+ if(pWspSendOut->Errno == 0) {\r
+ // Some default value\r
+ pWspSendOut->Errno = WSAENOBUFS;\r
+ }\r
SDP_PRINT(SDP_WARN, SDP_SOCKET, ("this = 0x%p rc = 0x%x\n",this, rc));\r
// is indeed the case.\r
}\r
goto Cleanup;\r
} \r
\r
- rc = g_pSdpDriver->m_pSdpArp->DestPortGidFromMac(pWspConnectIn->DestMac, &DestPortGid);\r
+ rc = g_pSdpDriver->m_pSdpArp->DestPortGidFromMac(m_SrcPortGuid, pWspConnectIn->DestMac, &DestPortGid);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_pSdpArp->DestPortGidFromIP failed rc = 0x%x\n", rc ));\r
pWspConnectOut->Errno = WSAENETUNREACH; // BUGBUG: verify this error\r
SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p state = %s \n",this, SS2String(m_state)));\r
OBJECT_ATTRIBUTES attr;\r
HANDLE ThreadHandle;\r
-\r
+ bool sleep = false;\r
+restart:\r
+ \r
+ if (sleep) {\r
+ Sleep(1*1000*1000);//???????\r
+ }\r
+ sleep = true;\r
\r
if (!m_Lock.Lock()) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to lock this = 0x%p \n",this));\r
goto Cleanup;\r
}\r
\r
+\r
+ //?????????\r
+ if (m_SendBufferPool.m_UserPackets.Size() > 0) {\r
+ m_Lock.Unlock();\r
+ goto restart;\r
+ }\r
+\r
// This will force that no more calls will be allowed\r
ASSERT(m_CloseSocketCalled == FALSE); // If this is not the case \r
// We shouldn't be able to take the lock\r
m_pCloseSocketThread = NULL; // Will be delated when the callback thread is deleted\r
\r
rc = m_Lock.Unlock();\r
- if (rc == STATUS_SHUTDOWN_IN_PROGRESS) {\r
+ if (rc == STATUS_HANDLES_CLOSED) {\r
// shutdown in progress is fine since we have started the shutdown ...\r
rc = STATUS_SUCCESS;\r
}\r
\r
int MaxMessageSize = min(m_hello_ack.hah.l_rcv_size, MAX_SEND_BUFFER_SIZE);\r
\r
- rc = m_SendBufferPool.Init(MAX_SEND_PACKETS, QP_ATTRIB_SQ_DEPTH, MaxMessageSize, m_pd, m_qp, m_lkey, this);\r
+ rc = m_SendBufferPool.Init(MAX_SEND_PACKETS, SDP_QP_ATTRIB_SQ_DEPTH, MaxMessageSize, m_pd, m_qp, m_lkey, this);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_SendBufferPool.Init failed rc = 0x%x\n", rc ));\r
goto Cleanup;\r
WspSocketIn SocketInParam;\r
WspSocketOut SocketOutParam;\r
SocketInParam.dwFlags = 0; \r
- rc = pNewSocket->Init(&SocketInParam, &SocketOutParam);\r
+ rc = pNewSocket->Init(&SocketInParam, &SocketOutParam, m_pSdpUserFile);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("pNewSocket.Init() failed rc = 0x%x\n", rc ));\r
goto ErrorLocked;\r
// We will now call init on the sender and the reciever\r
int MaxMessageSize = min(msg_hello->hh.l_rcv_size, MAX_SEND_BUFFER_SIZE);\r
\r
- rc = pNewSocket->m_SendBufferPool.Init(MAX_SEND_PACKETS, QP_ATTRIB_SQ_DEPTH, MaxMessageSize, pNewSocket->m_pd, pNewSocket->m_qp, pNewSocket->m_lkey, pNewSocket);\r
+ rc = pNewSocket->m_SendBufferPool.Init(MAX_SEND_PACKETS, SDP_QP_ATTRIB_SQ_DEPTH, MaxMessageSize, pNewSocket->m_pd, pNewSocket->m_qp, pNewSocket->m_lkey, pNewSocket);\r
if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_SendBufferPool.Init failed rc = 0x%x\n", rc ));\r
goto ErrorLocked;\r
\r
\r
// Take the lock and verify the state\r
- Locked = m_Lock.Lock();\r
+ rc = m_Lock.LockRc();\r
// BUGBUG: It seems that even when the lock fails we should send\r
// drep\r
- if (!Locked) {\r
+ if (!NT_SUCCESS(rc)) {\r
SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_Lock.Lock failed rc = 0x%x\n", rc ));\r
goto Cleanup;\r
}\r
{\r
SDP_PRINT(SDP_DEBUG, SDP_SOCKET, ("called this =0x%p\n", this));\r
NTSTATUS rc = STATUS_SUCCESS, rc1 = STATUS_SUCCESS, rc2 = STATUS_SUCCESS;\r
+ AssertLocked();\r
ib_api_status_t ib_status;\r
ib_wc_t *p_wc, *p_free;\r
size_t i;\r
BufferDescriptor *pBufferDescriptor = NULL;\r
\r
- for( i = 0; i < QP_ATTRIB_SQ_DEPTH; i++ ) {\r
+ for( i = 0; i < SDP_QP_ATTRIB_SQ_DEPTH; i++ ) {\r
m_SendComplitionWC[i].p_next = &m_SendComplitionWC[i + 1];\r
}\r
- m_SendComplitionWC[QP_ATTRIB_SQ_DEPTH - 1].p_next = NULL;\r
+ m_SendComplitionWC[SDP_QP_ATTRIB_SQ_DEPTH - 1].p_next = NULL;\r
\r
do \r
{\r
}\r
\r
/* Allocate send CQ. */\r
- cq_create.size = QP_ATTRIB_SQ_DEPTH;\r
+ cq_create.size = SDP_QP_ATTRIB_SQ_DEPTH;\r
cq_create.pfn_comp_cb = SdpSocket::__send_cb1;\r
\r
ib_status = ib_create_cq(\r
qp_create.rq_depth = QP_ATTRIB_RQ_DEPTH;\r
qp_create.rq_sge = QP_ATTRIB_RQ_SGE; /* To support buffers spanning pages. */\r
qp_create.h_rq_cq = m_rcq;\r
- qp_create.sq_depth = QP_ATTRIB_SQ_DEPTH;\r
+ qp_create.sq_depth = SDP_QP_ATTRIB_SQ_DEPTH;\r
//TODO: Figure out the right number of SGE entries for sends.\r
qp_create.sq_sge = QP_ATTRIB_SQ_SGE;\r
qp_create.h_sq_cq = m_scq;\r
cm_req->pfn_cm_rep_cb = cm_rep_callback;\r
}\r
\r
+\r
+VOID SdpSocket::UsersThreadCallBack(bool Send)\r
+{\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
+\r
+ if (!m_Lock.Lock()) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to lock this = 0x%p \n",this));\r
+ // Error is ignored, as it is a callback path, socket is already at an error state\r
+ goto Cleanup;\r
+ }\r
+ if (Send) {\r
+ InitializeListHead(&m_CallBackRequestList);\r
+ rc = m_SendBufferPool.UsersThreadCallBack();\r
+ if (!NT_SUCCESS(rc)) { \r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_SendBufferPool.UsersThreadCallBack failed this = 0x%p, rc = 0x%x \n",\r
+ this, rc));\r
+ m_Lock.Unlock(); // Error is ignored, as this is already an error path\r
+ Shutdown();\r
+ goto Cleanup;\r
+ }\r
+ \r
+ }\r
+\r
+ rc = m_Lock.Unlock(); // Error is ignored, as it is a callback path \r
+ if (!NT_SUCCESS(rc)) { \r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("m_Lock.Unlock failed this = 0x%p, rc = 0x%x \n",\r
+ this, rc));\r
+ Shutdown();\r
+ goto Cleanup;\r
+ }\r
+\r
+Cleanup:\r
+ return;\r
+}\r
+\r
// static\r
VOID SdpSocket::ShutdownCB(VOID* pContext)\r
{\r
delete m_pCloseSocketThread;\r
m_pCloseSocketThread = NULL;\r
}\r
- \r
\r
// Now that all ibal operations have finished we can free the memory\r
m_SendBufferPool.ShutDown();\r
m_RecvBufferPool.ShutDown();\r
\r
+ if (m_pSdpUserFile != NULL) {\r
+ m_pSdpUserFile->RemoveSocket(this);\r
+ m_pSdpUserFile->Release();\r
+ m_pSdpUserFile = NULL;\r
+ }\r
\r
/*\r
Memory reagion probably cleans when the other handles are closed\r
\r
const int MAX_SEND_BUFFER_SIZE = 1*4096; // This is the maximum send packet size\r
\r
-// BUGBUG: Check why changing this param crushes the system\r
const int MAX_RECV_BUFFER_SIZE = 1*4096; // This is the maximum send packet size\r
const int MAX_SEND_PACKETS = 200; // This is the maximum number of packets allocated per send\r
const int MAX_RECV_PACKETS = 200; // This is the maximum number of packets allocated per send\r
\r
\r
-const short QP_ATTRIB_SQ_DEPTH = 64;\r
+const short SDP_QP_ATTRIB_SQ_DEPTH = 64;\r
const short QP_ATTRIB_SQ_SGE = 1; /* Set based on inline data requirements */\r
//#define QP_ATTRIB_RESPONDER_RESOURCES 4\r
const short QP_ATTRIB_INITIATOR_DEPTH = 4;\r
KEVENT m_ShutdownCompleteEvent;\r
KEVENT m_DisconectSentEvent;\r
\r
- ib_wc_t m_SendComplitionWC[QP_ATTRIB_SQ_DEPTH];\r
+ ib_wc_t m_SendComplitionWC[SDP_QP_ATTRIB_SQ_DEPTH];\r
ib_wc_t m_RecvComplitionWC[QP_ATTRIB_RQ_DEPTH];\r
\r
// The following three falgs are used to shutdown a socket\r
bool m_ShutdownCalled;\r
bool m_DisconnectConnectionRecieved;\r
\r
- ThreadHandle* m_pCloseSocketThread; \r
+ ThreadHandle* m_pCloseSocketThread;\r
+\r
+ SdpUserFile *m_pSdpUserFile;\r
\r
static VOID __send_cb1(\r
IN const ib_cq_handle_t h_cq,\r
RecvPool m_RecvBufferPool;\r
ConnectionList m_ConnectionList;\r
\r
+ LIST_ENTRY m_CallBackRequestList;// Used by the call back request thread to hold the request\r
+\r
\r
SdpSocket();\r
\r
\r
NTSTATUS Init(\r
WspSocketIn *pSocketInParam, \r
- WspSocketOut *pSocketOutParam\r
+ WspSocketOut *pSocketOutParam,\r
+ SdpUserFile *pSdpUserFile\r
);\r
\r
NTSTATUS WSPConnect(\r
\r
NTSTATUS WSPSend(\r
WspSendIn *pWspSendIn,\r
- WspSendOut *pWspSendOut\r
+ WspSendOut *pWspSendOut,\r
+ IRP *pIrp \r
); \r
\r
NTSTATUS WSPRecv(\r
USHORT DestPort\r
);\r
\r
+ NTSTATUS RequestCallBack() {\r
+ AssertLocked();\r
+ ASSERT(IsListEmpty(&m_CallBackRequestList));\r
+ return m_pSdpUserFile->RequestCallBack(&m_CallBackRequestList);\r
+ }\r
+\r
+ VOID UsersThreadCallBack(bool Send);\r
+\r
VOID CmRepCallback(IN ib_cm_rep_rec_t *p_cm_rep_rec);\r
VOID CmReqCallback(IN ib_cm_req_rec_t *p_cm_req_rec);\r
VOID CmRtuCallback(IN ib_cm_rtu_rec_t *p_cm_rtu_rec);\r
{\r
InitializeListHead(&m_SocketsList);\r
m_shutdown = false;\r
+ m_NumberOfUserThreads = 0;\r
}\r
\r
NTSTATUS SdpUserFile::Init()\r
{\r
- KeInitializeSpinLock(&m_Lock);\r
InitializeListHead(&m_SocketsList);\r
+ KeInitializeEvent(&m_UsersCallEvent, SynchronizationEvent , FALSE );\r
m_shutdown = false;\r
-\r
+ KeInitializeSpinLock(&m_Lock);\r
return STATUS_SUCCESS;\r
}\r
\r
void SdpUserFile::Shutdown()\r
{ \r
+ SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("Called this = 0x%p \n",this));\r
// go over the entire list, and release it's objects\r
CSpinLockWrapper Lock(m_Lock);\r
Lock.Lock();\r
Lock.Unlock();\r
return;\r
}\r
+ m_shutdown = true;\r
+\r
+ // Go over the list of callbacks that you have to make and remove \r
+ // them.\r
+ while (m_UsersCallList.Size() > 0) {\r
+ PLIST_ENTRY pTemp = m_UsersCallList.RemoveHeadList();\r
+ SdpSocket * pSdpSocket = CONTAINING_RECORD(pTemp, SdpSocket , m_CallBackRequestList);\r
+\r
+ // Don't call release with the lock being hold\r
+ Lock.Unlock();\r
+ pSdpSocket->Release();\r
+ // It seems that we shoule be protected by the m_shutdown\r
+ // flag, but will take the lock just in case\r
+ Lock.Lock();\r
+ }\r
+ \r
while (!IsListEmpty(&m_SocketsList)) {\r
PLIST_ENTRY pTemp = RemoveHeadList(&m_SocketsList);\r
SdpSocket *pSdpSocket = CONTAINING_RECORD(pTemp, SdpSocket, m_UserFileList );\r
// It seems that we shoule be protected by the m_shutdown\r
// flag, but will take the lock just in case\r
Lock.Lock();\r
-\r
}\r
+ \r
Lock.Unlock();\r
+ // Free the users thread\r
+ KePulseEvent(&m_UsersCallEvent,IO_NO_INCREMENT ,FALSE); \r
}\r
\r
NTSTATUS SdpUserFile::AddSocket(SdpSocket *pSdpSocket)\r
return pSdpSocket;\r
}\r
\r
+NTSTATUS \r
+SdpUserFile::RequestCallBack(LIST_ENTRY *pList)\r
+{\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
+ CSpinLockWrapper Lock(m_Lock);\r
+ SdpSocket *pSdpSocket = NULL;\r
+ \r
+ pSdpSocket = CONTAINING_RECORD(pList, SdpSocket , m_CallBackRequestList);\r
+ // Take the lock and add the wanted event\r
+ Lock.Lock();\r
+ if (m_shutdown) {\r
+ Lock.Unlock();\r
+ return STATUS_SHUTDOWN_IN_PROGRESS;\r
+ }\r
+ pSdpSocket->AddRef();\r
\r
+ ASSERT(IsListEmpty(pList));\r
+ m_UsersCallList.InsertTailList(pList);\r
+\r
+ Lock.Unlock();\r
+ // Make sure someone tries to read our objects\r
+ KeSetEvent(&m_UsersCallEvent,IO_NETWORK_INCREMENT ,FALSE);\r
+ return rc;\r
+\r
+}\r
+\r
+/*\r
+ This function is being called by a thread that reaches us from \r
+ the user, and is responisble for copying data from user buffers\r
+ to kernel memory.\r
+\r
+ Only in the case of shutdown, the thread will exit.\r
+ Since we only do the cleanup of the SdpUserFile on IRP_MJ_CLOSE\r
+ there is no feer of working on a removed object.\r
+*/\r
+\r
+NTSTATUS \r
+SdpUserFile::UsersThread()\r
+{\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
+ CSpinLockWrapper Lock(m_Lock);\r
+ LIST_ENTRY *item = NULL;\r
+ SdpSocket *pSdpSocket = NULL;\r
+ bool ShutdownCalled = false; // This will only change from false\r
+ // to true\r
+ long NumberOfThreads = InterlockedIncrement(&m_NumberOfUserThreads);\r
+ if(NumberOfThreads != 1) {\r
+ // It seems that more than one uesr is here, don't let him\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("More than one user thread !!! \n"));\r
+ ASSERT(FALSE);\r
+ return STATUS_ACCESS_DENIED;\r
+ }\r
+ \r
+ int count = 0; \r
+ while (true) {\r
+ // Take the lock, and see the state:\r
+ Lock.Lock();\r
+ ShutdownCalled = m_shutdown;\r
+ // Process all data that exists\r
+ if(m_UsersCallList.Size() > 0) {\r
+ item = m_UsersCallList.RemoveHeadList();\r
+ pSdpSocket = CONTAINING_RECORD(item, SdpSocket , m_CallBackRequestList);\r
+\r
+ Lock.Unlock();\r
+\r
+ // Do the call back \r
+ if (!ShutdownCalled) {\r
+ pSdpSocket->UsersThreadCallBack(true);\r
+ } else {\r
+ //Currently, we don't call on shutdown.\r
+ }\r
+\r
+ // Release everything\r
+ pSdpSocket->Release();\r
+ continue;\r
+ }\r
+ if (ShutdownCalled) {\r
+ // Is there some other thread that is hidding ? Shouldn't happen\r
+ // but we can't trust the user\r
+ KePulseEvent(&m_UsersCallEvent,IO_NO_INCREMENT ,FALSE);\r
+ Lock.Unlock();\r
+ return STATUS_SUCCESS;\r
+ }\r
+ // Wait for a new event to arrive\r
+ Lock.Unlock();\r
+ rc = MyKeWaitForSingleObject(&m_UsersCallEvent, UserRequest, UserMode, TRUE, NULL);\r
+ \r
+ if (rc == STATUS_USER_APC ) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Worker thread has recieved a user APC, shuting down the process \n"));\r
+ Shutdown();\r
+ return STATUS_SUCCESS;\r
+ }\r
+ }\r
+\r
+}\r
#ifndef _SDP_USER_FILE_H\r
#define _SDP_USER_FILE_H\r
\r
-\r
-\r
class SdpUserFile : public RefCountImpl {\r
private: \r
KSPIN_LOCK m_Lock;\r
\r
// BUGBUG: Use something more effiecent for this storage\r
LIST_ENTRY m_SocketsList; \r
- \r
+\r
+ LinkedList m_UsersCallList; // This list holds all the requests of users for callback\r
+ KEVENT m_UsersCallEvent; // The users thread waits on this event\r
+\r
+ volatile long m_NumberOfUserThreads;// Make sure that there is only one user thread\r
+\r
public:\r
\r
SdpUserFile();\r
\r
VOID RemoveSocket(SdpSocket *pSdpSocket);\r
\r
+// VOID MoveSocketT(SdpSocket *pSdpSocket);\r
+\r
+ NTSTATUS RequestCallBack(LIST_ENTRY *pList);\r
+\r
+ NTSTATUS UsersThread();\r
+\r
};\r
\r
#endif //_SDP_USER_FILE_H\r
1) Clean error path.\r
\r
send:\r
- 1) On send: implmeant some kind of a negal algorithm.\r
- 2) On send: Create some kind of mechanism that will allow to recieve complitions on more than\r
+ 1) implmeant some kind of a negal algorithm.\r
+ 2) Create some kind of mechanism that will allow to recieve complitions on more than\r
one send.\r
- 3) If possibale, post more than one send.\r
- 4) Consider copying big packets from the DPC handler, instead of using the users thread\r
- for the copy\r
+ 3) If possibale, post more than one send, at a time\r
+ 4) [Critical] Use refferance count when queing the socket in an IRP structure.\r
\r
recv:\r
1) Find and fix the race when the socket is being initialized\r
Check the ArpCache problems (on a native windows machine) and decide what to do.\r
\r
\r
+Overlapped IO:\r
+1) Split to two types of overlapped operations\r
+2) Use referance counting on our type? If not, make sure that the life time of objects is well.\r
+3) Replace InterlockedIncrement with _InterlockedIncrement\r
+4) Make sure that in UserFile module, operations can start only when there is a user mode thread\r
+ that is already waiting.\r
+\r
+\r
USER MODE:\r
\r
* Check the lifetime of the SdpSocket (when is it deleted and so)??\r