Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
8.0 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. Contains the rcv packet routines
  7. Author:
  8. Stefan Solomon 07/06/1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. // nr of receive work items (receive packets) posted
  14. ULONG RcvPostedCount;
  15. // nr of send worl items posted
  16. ULONG SendPostedCount;
  17. // high and low water marks for the current count of posted rcv packets
  18. #define RCV_POSTED_LOW_WATER_MARK 8
  19. #define RCV_POSTED_HIGH_WATER_MARK 16
  20. ULONG RcvPostedLowWaterMark = RCV_POSTED_LOW_WATER_MARK;
  21. ULONG RcvPostedHighWaterMark = RCV_POSTED_HIGH_WATER_MARK;
  22. // current count of rcv packets completed and waiting processing
  23. ULONG RcvProcessingCount;
  24. // limit on the number of rcv packets completed and waiting processing
  25. #define MAX_RCV_PROCESSING 1000;
  26. ULONG MaxRcvProcessing = MAX_RCV_PROCESSING;
  27. /*++
  28. Function: OpenRipSocket
  29. Descr:
  30. --*/
  31. DWORD
  32. OpenRipSocket(VOID)
  33. {
  34. USHORT ripsocket;
  35. PUTUSHORT2SHORT(&ripsocket, IPX_RIP_SOCKET);
  36. if((RipSocketHandle = CreateSocketPort(ripsocket)) == INVALID_HANDLE_VALUE) {
  37. Trace(INIT_TRACE, "CreateSocketPort FAILED!\n");
  38. IF_LOG(EVENTLOG_ERROR_TYPE) {
  39. RouterLogErrorA (RipEventLogHdl,
  40. ROUTERLOG_IPXRIP_RIP_SOCKET_IN_USE,
  41. 0, NULL, GetLastError ());
  42. }
  43. return ERROR_CAN_NOT_COMPLETE;
  44. }
  45. return NO_ERROR;
  46. }
  47. /*++
  48. Function: CloseRipSocket
  49. Descr:
  50. --*/
  51. DWORD
  52. CloseRipSocket(VOID)
  53. {
  54. DWORD rc;
  55. rc = DeleteSocketPort(RipSocketHandle);
  56. Trace(INIT_TRACE, "IpxRip: DeleteSocketPort rc = %d\n", rc);
  57. return rc;
  58. }
  59. /*++
  60. Function: StartReceiver
  61. Descr: Starts allocating and posting receive
  62. work items until it reaches the low water mark.
  63. --*/
  64. VOID
  65. StartReceiver(VOID)
  66. {
  67. PWORK_ITEM wip;
  68. DWORD rc;
  69. // init RcvProcessingCount
  70. RcvProcessingCount = 0;
  71. ACQUIRE_QUEUES_LOCK;
  72. while(RcvPostedCount < RcvPostedLowWaterMark) {
  73. if((wip = AllocateWorkItem(RECEIVE_PACKET_TYPE)) == NULL) {
  74. // !!! log something
  75. break;
  76. }
  77. if((rc = ReceiveSubmit(wip)) != NO_ERROR) {
  78. FreeWorkItem(wip);
  79. break;
  80. }
  81. }
  82. RELEASE_QUEUES_LOCK;
  83. }
  84. /*++
  85. Function: RepostRcvPackets
  86. Descr: invoked in the rcv thread when signaled that rcv pkts are
  87. available in the repostrcvpackets queue.
  88. Dequeues all available packets and either reposts them up to
  89. high water mark or frees them if enough reposted
  90. --*/
  91. VOID
  92. RepostRcvPackets(VOID)
  93. {
  94. PWORK_ITEM wip;
  95. PLIST_ENTRY lep;
  96. DWORD rc;
  97. ACQUIRE_QUEUES_LOCK;
  98. while(!IsListEmpty(&RepostRcvPacketsQueue))
  99. {
  100. RcvProcessingCount--;
  101. lep = RemoveHeadList(&RepostRcvPacketsQueue);
  102. wip = CONTAINING_RECORD(lep, WORK_ITEM, Linkage);
  103. // if the protocol is stopping OR
  104. // enough rcv packets posted (i.e. posted up to high water mark, discard
  105. // the rcv packet
  106. if(((RipOperState != OPER_STATE_STARTING) &&
  107. (RipOperState != OPER_STATE_UP)) ||
  108. (RcvPostedCount >= RcvPostedHighWaterMark)) {
  109. // discard the received wi and don't repost
  110. FreeWorkItem(wip);
  111. }
  112. else
  113. {
  114. if((rc = ReceiveSubmit(wip)) != NO_ERROR) {
  115. FreeWorkItem(wip);
  116. }
  117. }
  118. }
  119. RELEASE_QUEUES_LOCK;
  120. }
  121. /*++
  122. Function: ReceiveComplete
  123. Descr: invoked in the io completion thread when a receive packet has completed.
  124. if the number of receive packets waiting to be processed is below
  125. the limit then
  126. Enqueues the received packet work item in the WorkersQueue.
  127. Finally, it reposts a new receive packet if below the low water mark.
  128. --*/
  129. VOID
  130. ReceiveComplete(PWORK_ITEM wip)
  131. {
  132. PWORK_ITEM newwip;
  133. DWORD rc;
  134. PUCHAR reservedp;
  135. reservedp = wip->AddressReserved.Reserved;
  136. wip->AdapterIndex = GetNicId(reservedp);
  137. ACQUIRE_QUEUES_LOCK;
  138. InterlockedDecrement(&RcvPostedCount);
  139. if(wip->IoCompletionStatus != NO_ERROR) {
  140. Trace(RECEIVE_TRACE, "Receive posted failed with error 0x%x\n",
  141. wip->IoCompletionStatus);
  142. }
  143. // if the protocol is stopping all the receive work items will get discarded
  144. if((RipOperState != OPER_STATE_STARTING) &&
  145. (RipOperState != OPER_STATE_UP)) {
  146. // discard the received wi and don't repost
  147. FreeWorkItem(wip);
  148. RELEASE_QUEUES_LOCK;
  149. return;
  150. }
  151. // if completed with error or too many waiting to be processed,
  152. // then repost the same
  153. if((wip->IoCompletionStatus != NO_ERROR) ||
  154. (RcvProcessingCount >= MaxRcvProcessing)) {
  155. // repost if below water mark
  156. if(RcvPostedCount < RcvPostedLowWaterMark) {
  157. if((rc = ReceiveSubmit(wip)) != NO_ERROR) {
  158. FreeWorkItem(wip);
  159. }
  160. }
  161. else
  162. {
  163. // enough posted already
  164. FreeWorkItem(wip);
  165. }
  166. RELEASE_QUEUES_LOCK;
  167. return;
  168. }
  169. //
  170. //** Process the received packet **
  171. //
  172. // first repost a new receive packet if below water mark
  173. if(RcvPostedCount < RcvPostedLowWaterMark) {
  174. if((newwip = AllocateWorkItem(RECEIVE_PACKET_TYPE)) == NULL) {
  175. Trace(RECEIVE_TRACE, "ReceiveComplete: Cannot allocate receive packet\n");
  176. }
  177. else
  178. {
  179. // repost the new receive packet and increment the ref count
  180. if((rc = ReceiveSubmit(newwip)) != NO_ERROR) {
  181. FreeWorkItem(newwip);
  182. }
  183. }
  184. }
  185. RcvProcessingCount++;
  186. RELEASE_QUEUES_LOCK;
  187. ProcessWorkItem(wip);
  188. }
  189. /*++
  190. Function: SendComplete
  191. Descr: invoked in the worker thread APC when a send packet has completed
  192. --*/
  193. VOID
  194. SendComplete(PWORK_ITEM wip)
  195. {
  196. InterlockedDecrement(&SendPostedCount);
  197. // if this is a regular send packet, discard it
  198. if(wip->Type == SEND_PACKET_TYPE) {
  199. FreeWorkItem(wip);
  200. return;
  201. }
  202. // time stamp and enqueue in the workers queue for further processing
  203. wip->TimeStamp = GetTickCount();
  204. ProcessWorkItem(wip);
  205. }
  206. /*++
  207. Function: EnqueueRcvPacketToRepostQueue
  208. Descr: take queues lock
  209. enqueues rcv packet in repost queue
  210. signals repost queue event
  211. rel queues lock
  212. --*/
  213. VOID
  214. EnqueueRcvPacketToRepostQueue(PWORK_ITEM wip)
  215. {
  216. ACQUIRE_QUEUES_LOCK;
  217. InsertTailList(&RepostRcvPacketsQueue, &wip->Linkage);
  218. RELEASE_QUEUES_LOCK;
  219. SetEvent(WorkerThreadObjects[REPOST_RCV_PACKETS_EVENT]);
  220. }
  221. /*++
  222. Function: ReceiveSubmit
  223. Descr: posts a receive packet work item for receive
  224. increments the receive count
  225. --*/
  226. DWORD
  227. ReceiveSubmit(PWORK_ITEM wip)
  228. {
  229. DWORD rc;
  230. wip->Overlapped.hEvent = NULL;
  231. rc = IpxRecvPacket(RipSocketHandle,
  232. wip->Packet,
  233. MAX_PACKET_LEN,
  234. &wip->AddressReserved,
  235. &wip->Overlapped,
  236. NULL);
  237. if(rc != NO_ERROR) {
  238. Trace(RECEIVE_TRACE, "Failed to submit receive error 0x%x\n", rc);
  239. }
  240. else
  241. {
  242. InterlockedIncrement(&RcvPostedCount);
  243. }
  244. return rc;
  245. }
  246. /*++
  247. Function: SendSubmit
  248. Descr: posts a send packet work item for send to the adapter index
  249. specified by the work item
  250. increments the send statistics for the interface specified
  251. by the work item
  252. Remark: >> called with the interface lock held <<
  253. --*/
  254. DWORD
  255. SendSubmit(PWORK_ITEM wip)
  256. {
  257. DWORD rc;
  258. USHORT SendPacketLength;
  259. // increment the send statistics. Note that we still hold the if lock here
  260. wip->icbp->IfStats.RipIfOutputPackets++;
  261. // get the length from the packet to send
  262. SendPacketLength = GETSHORT2USHORT(&SendPacketLength, wip->Packet + IPXH_LENGTH);
  263. wip->Overlapped.hEvent = NULL;
  264. rc = IpxSendPacket(RipSocketHandle,
  265. wip->AdapterIndex,
  266. wip->Packet,
  267. (ULONG)SendPacketLength,
  268. &wip->AddressReserved,
  269. &wip->Overlapped,
  270. NULL);
  271. if(rc != NO_ERROR) {
  272. Trace(SEND_TRACE, "Failed to send the packet on if %d error 0x%x\n",
  273. wip->icbp->InterfaceIndex,
  274. rc);
  275. }
  276. else
  277. {
  278. InterlockedIncrement(&SendPostedCount);
  279. }
  280. return rc;
  281. }
  282. /*++
  283. Function: IfRefSendSubmit
  284. Descr: send a work item and increment the interface ref count
  285. Remark: >> called with the interface lock held <<
  286. --*/
  287. DWORD
  288. IfRefSendSubmit(PWORK_ITEM wip)
  289. {
  290. DWORD rc;
  291. if((rc = SendSubmit(wip)) == NO_ERROR) {
  292. wip->icbp->RefCount++;
  293. }
  294. return rc;
  295. }