Leaked source code of windows server 2003
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.

2962 lines
67 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. ntVdm netWare (Vw) IPX/SPX Functions
  7. Vw: The peoples' network
  8. Contains various utility routines
  9. Contents:
  10. GetInternetAddress
  11. GetMaxPacketSize
  12. RetrieveEcb
  13. RetrieveXEcb
  14. (AllocateXecb)
  15. (DeallocateXecb)
  16. ScheduleEvent
  17. ScanTimerList
  18. CancelTimerEvent
  19. CancelTimedEvents
  20. CancelAsyncEvent
  21. CancelSocketEvent
  22. CancelConnectionEvent
  23. QueueEcb
  24. DequeueEcb
  25. CancelSocketQueue
  26. CancelConnectionQueue
  27. AbortQueue
  28. AbortConnectionEvent
  29. StartIpxSend
  30. GetIoBuffer
  31. (ReleaseIoBuffer)
  32. GatherData
  33. ScatterData
  34. IpxReceiveFirst
  35. IpxReceiveNext
  36. (IpxSendFirst)
  37. IpxSendNext
  38. (QueueReceiveRequest)
  39. (DequeueReceiveRequest)
  40. (QueueSendRequest)
  41. (DequeueSendRequest)
  42. CompleteOrQueueIo
  43. CompleteIo
  44. CompleteOrQueueEcb
  45. CompleteEcb
  46. (QueueAsyncCompletion)
  47. EsrCallback
  48. VWinEsrCallback
  49. FifoAddHead
  50. FifoAdd
  51. FifoRemove
  52. FifoNext
  53. Author:
  54. Richard L Firth (rfirth) 30-Sep-1993
  55. Environment:
  56. User-mode Win32
  57. Revision History:
  58. 30-Sep-1993 rfirth
  59. Created
  60. --*/
  61. #include "vw.h"
  62. #pragma hdrstop
  63. //
  64. // private routine prototypes
  65. //
  66. PRIVATE
  67. LPXECB
  68. AllocateXecb(
  69. VOID
  70. );
  71. PRIVATE
  72. VOID
  73. DeallocateXecb(
  74. IN LPXECB pXecb
  75. );
  76. PRIVATE
  77. VOID
  78. ReleaseIoBuffer(
  79. IN LPXECB pXecb
  80. );
  81. PRIVATE
  82. VOID
  83. IpxSendFirst(
  84. IN LPXECB pXecb,
  85. IN LPSOCKET_INFO pSocketInfo
  86. );
  87. PRIVATE
  88. VOID
  89. QueueReceiveRequest(
  90. IN LPXECB pXecb,
  91. IN LPSOCKET_INFO pSocketInfo
  92. );
  93. PRIVATE
  94. LPXECB
  95. DequeueReceiveRequest(
  96. IN LPXECB pXecb,
  97. IN LPSOCKET_INFO pSocketInfo
  98. );
  99. PRIVATE
  100. VOID
  101. QueueSendRequest(
  102. IN LPXECB pXecb,
  103. IN LPSOCKET_INFO pSocketInfo
  104. );
  105. PRIVATE
  106. LPXECB
  107. DequeueSendRequest(
  108. IN LPXECB pXecb,
  109. IN LPSOCKET_INFO pSocketInfo
  110. );
  111. PRIVATE
  112. VOID
  113. QueueAsyncCompletion(
  114. IN LPXECB pXecb,
  115. IN BYTE CompletionCode
  116. );
  117. //
  118. // private data
  119. //
  120. //
  121. // TimerList - singly-linked list of timed events, in order of duration
  122. //
  123. PRIVATE LPXECB TimerList = NULL;
  124. //
  125. // AsyncCompletionQueue - keeps list of completed ECBs awaiting removal via
  126. // ESR callback
  127. //
  128. PRIVATE FIFO AsyncCompletionQueue = {NULL, NULL};
  129. //
  130. // sort-of-private data (matches not-really-global data in other modules)
  131. //
  132. //
  133. // SerializationCritSec - grab this when manipulating SOCKET_INFO list
  134. //
  135. CRITICAL_SECTION SerializationCritSec;
  136. //
  137. // AsyncCritSec - grab this when manipulating AsyncCompletionQueue
  138. //
  139. CRITICAL_SECTION AsyncCritSec;
  140. //
  141. // functions
  142. //
  143. int
  144. GetInternetAddress(
  145. IN OUT LPSOCKADDR_IPX InternetAddress
  146. )
  147. /*++
  148. Routine Description:
  149. Gets the node and net numbers for this station
  150. Arguments:
  151. InternetAddress - pointer to SOCKADDR_IPX structure to fill with internetwork
  152. address for this station
  153. Return Value:
  154. int
  155. Success - 0
  156. Failure - SOCKET_ERROR
  157. --*/
  158. {
  159. SOCKET s;
  160. int rc;
  161. int structureLength = sizeof(*InternetAddress);
  162. s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
  163. if (s != INVALID_SOCKET) {
  164. //
  165. // make dynamic binding (socket number = 0)
  166. //
  167. ZeroMemory(InternetAddress, structureLength);
  168. InternetAddress->sa_family = AF_IPX;
  169. rc = bind(s, (LPSOCKADDR)InternetAddress, structureLength);
  170. if (rc != SOCKET_ERROR) {
  171. rc = getsockname(s, (LPSOCKADDR)InternetAddress, &structureLength);
  172. if (rc) {
  173. IPXDBGPRINT((__FILE__, __LINE__,
  174. FUNCTION_ANY,
  175. IPXDBG_LEVEL_ERROR,
  176. "GetInternetAddress: getsockname() returns %d\n",
  177. WSAGetLastError()
  178. ));
  179. }
  180. } else {
  181. IPXDBGPRINT((__FILE__, __LINE__,
  182. FUNCTION_ANY,
  183. IPXDBG_LEVEL_ERROR,
  184. "GetInternetAddress: bind() returns %d\n",
  185. WSAGetLastError()
  186. ));
  187. }
  188. closesocket(s);
  189. } else {
  190. IPXDBGPRINT((__FILE__, __LINE__,
  191. FUNCTION_ANY,
  192. IPXDBG_LEVEL_ERROR,
  193. "GetInternetAddress: socket() returns %d\n",
  194. WSAGetLastError()
  195. ));
  196. rc = SOCKET_ERROR;
  197. }
  198. return rc;
  199. }
  200. int
  201. GetMaxPacketSize(
  202. OUT LPWORD MaxPacketSize
  203. )
  204. /*++
  205. Routine Description:
  206. Returns the maximum packet allowed by the underlying transport
  207. Arguments:
  208. MaxPacketSize - pointer to returned maximum packet size
  209. Return Value:
  210. int
  211. Success - 0
  212. Failure - SOCKET_ERROR
  213. --*/
  214. {
  215. SOCKET s;
  216. int maxLen, maxLenSize = sizeof(maxLen);
  217. int rc;
  218. SOCKADDR_IPX ipxAddr;
  219. s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
  220. if (s != SOCKET_ERROR) {
  221. //
  222. // set socket to 0 - causes any applicable address to be bound
  223. //
  224. ZeroMemory(&ipxAddr, sizeof(ipxAddr));
  225. ipxAddr.sa_family = AF_IPX;
  226. rc = bind(s, (LPSOCKADDR)&ipxAddr, sizeof(ipxAddr));
  227. if (rc != SOCKET_ERROR) {
  228. rc = getsockopt(s,
  229. NSPROTO_IPX,
  230. IPX_MAXSIZE,
  231. (char FAR*)&maxLen,
  232. &maxLenSize
  233. );
  234. if (rc != SOCKET_ERROR) {
  235. //
  236. // IPX_MAXSIZE always returns the amount of data that can be
  237. // transmitted in a single frame. 16-bit IPX/SPX requires that
  238. // the IPX header length be included in the data size
  239. //
  240. maxLen += IPX_HEADER_LENGTH;
  241. } else {
  242. IPXDBGPRINT((__FILE__, __LINE__,
  243. FUNCTION_ANY,
  244. IPXDBG_LEVEL_ERROR,
  245. "GetMaxPacketSize: getsockopt() returns %d\n",
  246. WSAGetLastError()
  247. ));
  248. }
  249. } else {
  250. IPXDBGPRINT((__FILE__, __LINE__,
  251. FUNCTION_ANY,
  252. IPXDBG_LEVEL_ERROR,
  253. "GetMaxPacketSize: bind() returns %d\n",
  254. WSAGetLastError()
  255. ));
  256. }
  257. closesocket(s);
  258. } else {
  259. IPXDBGPRINT((__FILE__, __LINE__,
  260. FUNCTION_ANY,
  261. IPXDBG_LEVEL_ERROR,
  262. "GetMaxPacketSize: socket() returns %d\n",
  263. WSAGetLastError()
  264. ));
  265. rc = SOCKET_ERROR;
  266. }
  267. *MaxPacketSize = (rc != SOCKET_ERROR) ? maxLen : MAXIMUM_IPX_PACKET_LENGTH;
  268. return rc;
  269. }
  270. LPXECB
  271. RetrieveEcb(
  272. IN BYTE EcbType
  273. )
  274. /*++
  275. Routine Description:
  276. Returns pointer to 32-bit extended ECB structure which contains flat pointer
  277. to IPX or AES ECB in VDM memory
  278. We allocate the extended ECB for 3 reasons:
  279. 1. Avoids 16-bit app scribbling over our control fields
  280. 2. Don't have to make unaligned references to all fields (still need some)
  281. 3. Don't have enough space in AES ECB to remember all the stuff we need
  282. However, we do update the 16-bit ECB's LinkAddress field. We use this as a
  283. pointer to the 32-bit XECB we allocate in this routine. This just saves us
  284. having to traverse all the lists looking for the address of the 16-bit ECB
  285. (which we could still do as a fall-back)
  286. Arguments:
  287. EcbType - type of ECB - AES, IPX or SPX
  288. Return Value:
  289. LPXECB - 32-bit pointer to extended ECB structure
  290. --*/
  291. {
  292. WORD segment;
  293. WORD offset;
  294. LPECB pEcb;
  295. segment = IPX_GET_ECB_SEGMENT();
  296. offset = IPX_GET_ECB_OFFSET();
  297. pEcb = (LPIPX_ECB)POINTER_FROM_WORDS(segment, offset, sizeof(IPX_ECB));
  298. return RetrieveXEcb(EcbType, pEcb, (ECB_ADDRESS)MAKELONG(offset,segment));
  299. }
  300. LPXECB
  301. RetrieveXEcb(
  302. IN BYTE EcbType,
  303. LPECB pEcb,
  304. ECB_ADDRESS EcbAddress
  305. )
  306. /*++
  307. Routine Description:
  308. worker for RetrieveEcb, callable from windows functions (ex DOS parms)
  309. Arguments:
  310. EcbType - type of ECB - AES, IPX or SPX
  311. pEcb - pointer to the 16-bit ECB
  312. EcbAddress - address (seg:off in DWORD) of 16-bit ECB
  313. Return Value:
  314. LPXECB
  315. --*/
  316. {
  317. LPXECB pXecb;
  318. if (pEcb) {
  319. //
  320. // tommye - MS 30525
  321. // Make sure the pEcb is valid - we'll go ahead
  322. // and do this before we alloc the XEcb.
  323. //
  324. try {
  325. BYTE x;
  326. // Just deref the ptr to make sure it is okay
  327. x = pEcb->InUse;
  328. } except(1) {
  329. //
  330. // bad pointer: bogus ECB
  331. //
  332. return NULL;
  333. }
  334. //
  335. // allocate and fill-in 32-bit extended ECB structure. If can't allocate
  336. // then return NULL
  337. //
  338. pXecb = AllocateXecb();
  339. if (pXecb) {
  340. pXecb->Ecb = pEcb;
  341. pXecb->EcbAddress = EcbAddress;
  342. pXecb->EsrAddress = pEcb->EsrAddress;
  343. //
  344. // set flags - IPX/AES, SPX, protect-mode
  345. //
  346. pXecb->Flags |= (((EcbType == ECB_TYPE_IPX) || (EcbType == ECB_TYPE_SPX))
  347. ? XECB_FLAG_IPX
  348. : XECB_FLAG_AES)
  349. | ((EcbType == ECB_TYPE_SPX) ? XECB_FLAG_SPX : 0)
  350. | ((getMSW() & MSW_PE) ? XECB_FLAG_PROTMODE : 0);
  351. //
  352. // this XECB is not yet on a queue
  353. //
  354. pXecb->QueueId = NO_QUEUE;
  355. //
  356. // mark the 16-bit ECB as being used. We use an undefined value to
  357. // make sure it gets set/reset in the right places
  358. //
  359. pEcb->InUse = ECB_IU_TEMPORARY;
  360. //
  361. // use the LinkAddress field in the 16-bit ECB to point to the XECB.
  362. // We use this when cancelling the ECB
  363. //
  364. pEcb->LinkAddress = pXecb;
  365. //
  366. // AES and IPX ECBs have different sizes and different layouts
  367. //
  368. if ((EcbType == ECB_TYPE_IPX) || (EcbType == ECB_TYPE_SPX)) {
  369. pXecb->SocketNumber = pEcb->SocketNumber;
  370. }
  371. }
  372. } else {
  373. pXecb = NULL;
  374. }
  375. return pXecb;
  376. }
  377. PRIVATE
  378. LPXECB
  379. AllocateXecb(
  380. VOID
  381. )
  382. /*++
  383. Routine Description:
  384. Allocate an XECB; zero it; set the reference count to 1
  385. Arguments:
  386. None.
  387. Return Value:
  388. LPXECB
  389. --*/
  390. {
  391. LPXECB pXecb;
  392. pXecb = (LPXECB)LocalAlloc(LPTR, sizeof(*pXecb));
  393. if (pXecb) {
  394. pXecb->RefCount = 1;
  395. }
  396. return pXecb;
  397. }
  398. PRIVATE
  399. VOID
  400. DeallocateXecb(
  401. IN LPXECB pXecb
  402. )
  403. /*++
  404. Routine Description:
  405. decrement the XECB reference count (while holding SerializationCritSec). If
  406. goes to 0 then free the structure (else other thread is also holding pointer
  407. to XECB)
  408. Arguments:
  409. pXecb - XECB to deallocate
  410. Return Value:
  411. None.
  412. --*/
  413. {
  414. RequestMutex();
  415. --pXecb->RefCount;
  416. if (!pXecb->RefCount) {
  417. #if DBG
  418. FillMemory(pXecb, sizeof(*pXecb), 0xFF);
  419. #endif
  420. FREE_OBJECT(pXecb);
  421. }
  422. ReleaseMutex();
  423. }
  424. VOID
  425. ScheduleEvent(
  426. IN LPXECB pXecb,
  427. IN WORD Ticks
  428. )
  429. /*++
  430. Routine Description:
  431. Adds an ECB to the TimerList, ordered by Ticks. The value of Ticks cannot
  432. be zero
  433. Assumes 1. Ticks != 0
  434. 2. pXecb->Next is already NULL (as result of LocalAlloc(LPTR,...)
  435. Arguments:
  436. pXecb - pointer to XECB describing IPX or AES ECB to queue
  437. Ticks - number of ticks to elapse before ECB is cooked
  438. Return Value:
  439. None.
  440. --*/
  441. {
  442. ASSERT(Ticks);
  443. ASSERT(pXecb->Next == NULL);
  444. RequestMutex();
  445. if (!TimerList) {
  446. TimerList = pXecb;
  447. } else {
  448. if (TimerList->Ticks > Ticks) {
  449. TimerList->Ticks -= Ticks;
  450. pXecb->Next = TimerList;
  451. TimerList = pXecb;
  452. } else {
  453. LPXECB previous = (LPXECB)TimerList;
  454. LPXECB this = previous->Next;
  455. Ticks -= TimerList->Ticks;
  456. while (this && Ticks > this->Ticks) {
  457. Ticks -= this->Ticks;
  458. previous = this;
  459. this = this->Next;
  460. }
  461. previous->Next = pXecb;
  462. pXecb->Next = this;
  463. }
  464. }
  465. pXecb->Ticks = Ticks;
  466. pXecb->QueueId = TIMER_QUEUE;
  467. ReleaseMutex();
  468. }
  469. VOID
  470. ScanTimerList(
  471. VOID
  472. )
  473. /*++
  474. Routine Description:
  475. Called once per tick. Decrements the tick count of the ECB at the head of
  476. the list. If it goes to zero, completes the ECB and any subsequent ECBs
  477. which whose tick count would go to zero
  478. Arguments:
  479. None.
  480. Return Value:
  481. None.
  482. --*/
  483. {
  484. LPXECB pXecb;
  485. RequestMutex();
  486. pXecb = TimerList;
  487. if (pXecb) {
  488. //
  489. // Decrement if not already zero. Can be zero because the ECB at the
  490. // front of the list could have been Cancelled. This makes sure we
  491. // do not wrap around to 0xFFFF !!!
  492. //
  493. if (pXecb->Ticks != 0)
  494. --pXecb->Ticks;
  495. if (!pXecb->Ticks) {
  496. //
  497. // complete all ECBs that would go to 0 on this tick
  498. //
  499. while (pXecb->Ticks <= 1) {
  500. TimerList = pXecb->Next;
  501. IPXDBGPRINT((__FILE__, __LINE__,
  502. FUNCTION_ANY,
  503. IPXDBG_LEVEL_INFO,
  504. "ScanTimerList: ECB %04x:%04x is done\n",
  505. HIWORD(pXecb->EcbAddress),
  506. LOWORD(pXecb->EcbAddress)
  507. ));
  508. CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
  509. pXecb = TimerList;
  510. if (!pXecb) {
  511. break;
  512. }
  513. }
  514. }
  515. }
  516. ReleaseMutex();
  517. }
  518. BYTE
  519. CancelTimerEvent(
  520. IN LPXECB pXecb
  521. )
  522. /*++
  523. Routine Description:
  524. Cancels a pending event on the timer list
  525. Arguments:
  526. pXecb - pointer to XECB to cancel
  527. Return Value:
  528. BYTE
  529. Success - IPX_SUCCESS
  530. Failure - IPX_ECB_NOT_IN_USE
  531. --*/
  532. {
  533. LPXECB listptr;
  534. LPXECB previous = (LPXECB)&TimerList;
  535. BYTE status;
  536. RequestMutex();
  537. listptr = TimerList;
  538. while (listptr && listptr != pXecb) {
  539. previous = listptr;
  540. listptr = listptr->Next;
  541. }
  542. if (listptr) {
  543. //
  544. // take the XECB out of the list and complete the ECB (in VDM memory).
  545. // Does not generate a call-back to the ESR. When CompleteEcb returns,
  546. // the XECB has been deallocated
  547. //
  548. previous->Next = listptr->Next;
  549. ASSERT(pXecb->RefCount == 2);
  550. --pXecb->RefCount;
  551. CompleteEcb(pXecb, ECB_CC_CANCELLED);
  552. status = IPX_SUCCESS;
  553. } else {
  554. status = IPX_ECB_NOT_IN_USE;
  555. }
  556. ReleaseMutex();
  557. return status;
  558. }
  559. VOID
  560. CancelTimedEvents(
  561. IN WORD SocketNumber,
  562. IN WORD Owner,
  563. IN DWORD TaskId
  564. )
  565. /*++
  566. Routine Description:
  567. traverses the TimerList cancelling any IPX or AES events owned by any of
  568. SocketNumber, Owner or TaskId
  569. Assumes valid SocketNumber, Owner or TaskId cannot be 0
  570. Arguments:
  571. SocketNumber - owning socket of IPX events to cancel
  572. Owner - owning DOS PDB
  573. TaskID - owning Windows Task ID
  574. Return Value:
  575. None.
  576. --*/
  577. {
  578. LPXECB pXecb;
  579. LPXECB prev = (LPXECB)&TimerList;
  580. LPXECB next;
  581. RequestMutex();
  582. pXecb = TimerList;
  583. while (pXecb) {
  584. next = pXecb->Next;
  585. if ((SocketNumber && (pXecb->SocketNumber == SocketNumber))
  586. || (Owner && !(pXecb->Flags & XECB_FLAG_IPX) && (pXecb->Owner == Owner))
  587. || (TaskId && (pXecb->TaskId == TaskId))) {
  588. prev->Next = next;
  589. IPXDBGPRINT((__FILE__, __LINE__,
  590. FUNCTION_ANY,
  591. IPXDBG_LEVEL_INFO,
  592. "CancelTimedEvents: cancelling ECB %08x (%04x:%04x)\n",
  593. pXecb,
  594. HIWORD(pXecb->EcbAddress),
  595. LOWORD(pXecb->EcbAddress)
  596. ));
  597. CompleteEcb(pXecb, ECB_CC_CANCELLED);
  598. }
  599. else
  600. {
  601. prev = pXecb ;
  602. }
  603. pXecb = next;
  604. }
  605. ReleaseMutex();
  606. }
  607. BYTE
  608. CancelAsyncEvent(
  609. IN LPXECB pXecb
  610. )
  611. /*++
  612. Routine Description:
  613. Called to cancel an event currently on the async completion list. We don't
  614. cancel these events - just return 0xF9 (ECB cannot be cancelled). It is a
  615. race to see who gets there first - us with the cancel, or the ESR callback.
  616. In this case it is fairly immaterial
  617. Arguments:
  618. pXecb - pointer to XECB to cancel (ignored)
  619. Return Value:
  620. BYTE - IPX_CANNOT_CANCEL
  621. --*/
  622. {
  623. //
  624. // we call DeallocateXecb to reduce the reference count. If the other thread
  625. // really tried to deallocate it in the short time we've been looking at it
  626. // on the cancel path, the call will finish up what the other thread started
  627. //
  628. DeallocateXecb(pXecb);
  629. return IPX_CANNOT_CANCEL;
  630. }
  631. BYTE
  632. CancelSocketEvent(
  633. IN LPXECB pXecb
  634. )
  635. /*++
  636. Routine Description:
  637. Called to cancel a pending send or listen from a socket queue. Request can
  638. be IPX or SPX. If IPX event, then the ECB is on either the SendQueue or
  639. ListenQueue. If SPX, it may be on a CONNECTION_INFO ConnectQueue,
  640. AcceptQueue, SendQueue or ListenQueue, or if it is an
  641. SPXListenForSequencedPacket request that is still in the pool then it may
  642. be on the owning SOCKET_INFO ListenQueue
  643. Arguments:
  644. pXecb - pointer to XECB describing ECB to cancel
  645. Return Value:
  646. BYTE - IPX_SUCCESS
  647. --*/
  648. {
  649. LPXECB ptr;
  650. LPVOID pObject;
  651. RequestMutex();
  652. pObject = pXecb->OwningObject;
  653. switch (pXecb->QueueId) {
  654. case SOCKET_LISTEN_QUEUE:
  655. if (pXecb->Flags & XECB_FLAG_SPX) {
  656. ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->ListenQueue);
  657. } else {
  658. ptr = DequeueReceiveRequest(pXecb, (LPSOCKET_INFO)pObject);
  659. }
  660. break;
  661. case SOCKET_SEND_QUEUE:
  662. if (pXecb->Flags & XECB_FLAG_SPX) {
  663. ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->SendQueue);
  664. } else {
  665. ptr = DequeueSendRequest(pXecb, (LPSOCKET_INFO)pObject);
  666. }
  667. break;
  668. case SOCKET_HEADER_QUEUE: // SPX only
  669. if (pXecb->Flags & XECB_FLAG_SPX) {
  670. ptr = DequeueEcb(pXecb, &((LPSOCKET_INFO)pObject)->HeaderQueue);
  671. } else {
  672. ASSERT(FALSE);
  673. }
  674. break;
  675. }
  676. ReleaseMutex();
  677. if (ptr) {
  678. CompleteIo(ptr, ECB_CC_CANCELLED);
  679. }
  680. return IPX_SUCCESS;
  681. }
  682. BYTE
  683. CancelConnectionEvent(
  684. IN LPXECB pXecb
  685. )
  686. /*++
  687. Routine Description:
  688. Cancels a pending SPXListenForConnection or SPXListenForSequencedPacket, the
  689. only cancellable SPX requests
  690. Arguments:
  691. pXecb - pointer to SPX XECB to cancel
  692. Return Value:
  693. BYTE - IPX_SUCCESS
  694. --*/
  695. {
  696. LPXECB ptr;
  697. LPVOID pObject;
  698. LPXECB_QUEUE pQueue;
  699. RequestMutex();
  700. pObject = pXecb->OwningObject;
  701. switch (pXecb->QueueId) {
  702. case CONNECTION_ACCEPT_QUEUE:
  703. pQueue = &((LPCONNECTION_INFO)pObject)->AcceptQueue;
  704. break;
  705. case CONNECTION_LISTEN_QUEUE:
  706. pQueue = &((LPCONNECTION_INFO)pObject)->ListenQueue;
  707. break;
  708. }
  709. ptr = DequeueEcb(pXecb, pQueue);
  710. ReleaseMutex();
  711. if (ptr) {
  712. CompleteIo(ptr, ECB_CC_CANCELLED);
  713. }
  714. return IPX_SUCCESS;
  715. }
  716. VOID
  717. QueueEcb(
  718. IN LPXECB pXecb,
  719. IN LPXECB_QUEUE Queue,
  720. IN QUEUE_ID QueueId
  721. )
  722. /*++
  723. Routine Description:
  724. Adds an XECB to a queue and sets the queue identifier in the XECB.
  725. Arguments:
  726. pXecb - pointer to XECB to queue
  727. Queue - pointer to queue to add XECB to (at tail)
  728. QueueId - identifies Queue
  729. Return Value:
  730. None.
  731. --*/
  732. {
  733. LPVOID owningObject = NULL;
  734. #define CONTAINER_STRUCTURE(p, t, f) (LPVOID)(((LPBYTE)(p)) - (UINT_PTR)(&((t)0)->f))
  735. pXecb->QueueId = QueueId;
  736. switch (QueueId) {
  737. case SOCKET_LISTEN_QUEUE:
  738. if (Queue->Tail && (Queue->Tail->Length < pXecb->Length)) {
  739. FifoAddHead((LPFIFO)Queue, (LPFIFO)pXecb);
  740. } else {
  741. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  742. }
  743. owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, ListenQueue);
  744. break;
  745. case SOCKET_SEND_QUEUE:
  746. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  747. owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, SendQueue);
  748. break;
  749. case SOCKET_HEADER_QUEUE:
  750. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  751. owningObject = CONTAINER_STRUCTURE(Queue, LPSOCKET_INFO, HeaderQueue);
  752. break;
  753. case CONNECTION_CONNECT_QUEUE:
  754. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  755. owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, ConnectQueue);
  756. break;
  757. case CONNECTION_ACCEPT_QUEUE:
  758. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  759. owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, AcceptQueue);
  760. break;
  761. case CONNECTION_SEND_QUEUE:
  762. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  763. owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, SendQueue);
  764. break;
  765. case CONNECTION_LISTEN_QUEUE:
  766. FifoAdd((LPFIFO)Queue, (LPFIFO)pXecb);
  767. owningObject = CONTAINER_STRUCTURE(Queue, LPCONNECTION_INFO, ListenQueue);
  768. break;
  769. }
  770. pXecb->OwningObject = owningObject;
  771. }
  772. LPXECB
  773. DequeueEcb(
  774. IN LPXECB pXecb,
  775. IN LPXECB_QUEUE Queue
  776. )
  777. /*++
  778. Routine Description:
  779. Removes pXecb from Queue and resets the XECB queue identifier (to NO_QUEUE)
  780. Arguments:
  781. pXecb - pointer to XECB to remove
  782. Queue - queue from which to remove pXecb
  783. Return Value:
  784. LPXECB
  785. pointer to removed XECB
  786. --*/
  787. {
  788. LPXECB p;
  789. p = (LPXECB)FifoRemove((LPFIFO)Queue, (LPFIFO)pXecb);
  790. pXecb->QueueId = NO_QUEUE;
  791. pXecb->OwningObject = NULL;
  792. return pXecb;
  793. }
  794. VOID
  795. CancelSocketQueue(
  796. IN LPXECB_QUEUE pXecbQueue
  797. )
  798. /*++
  799. Routine Description:
  800. Cancels all pending ECBs on a SOCKET_INFO queue
  801. Arguments:
  802. pXecbQueue - pointer to (socket/connection) queue
  803. Return Value:
  804. None.
  805. --*/
  806. {
  807. LPXECB ptr;
  808. while (ptr = pXecbQueue->Head) {
  809. CancelSocketEvent(ptr);
  810. }
  811. }
  812. VOID
  813. CancelConnectionQueue(
  814. IN LPXECB_QUEUE pXecbQueue
  815. )
  816. /*++
  817. Routine Description:
  818. Cancels all pending ECBs on a CONNECTION_INFO queue
  819. Arguments:
  820. pXecbQueue - pointer to XECB queue on CONNECTION_INFO
  821. Return Value:
  822. None.
  823. --*/
  824. {
  825. LPXECB ptr;
  826. while (ptr = pXecbQueue->Head) {
  827. CancelConnectionEvent(ptr);
  828. }
  829. }
  830. VOID
  831. AbortQueue(
  832. IN LPXECB_QUEUE pXecbQueue,
  833. IN BYTE CompletionCode
  834. )
  835. /*++
  836. Routine Description:
  837. Aborts or terminates an ECB queue from a CONNECTION_INFO structure
  838. Arguments:
  839. pXecbQueue - pointer to queue
  840. CompletionCode - to put in aborted/terminated ECBs
  841. Return Value:
  842. None.
  843. --*/
  844. {
  845. LPXECB ptr;
  846. while (ptr = pXecbQueue->Head) {
  847. AbortConnectionEvent(ptr, CompletionCode);
  848. }
  849. }
  850. VOID
  851. AbortConnectionEvent(
  852. IN LPXECB pXecb,
  853. IN BYTE CompletionCode
  854. )
  855. /*++
  856. Routine Description:
  857. Aborts a connection ECB
  858. Arguments:
  859. pXecb - pointer to SPX XECB to cancel
  860. CompletionCode - value to put in ECB
  861. Return Value:
  862. None.
  863. --*/
  864. {
  865. LPXECB ptr;
  866. LPCONNECTION_INFO pConnectionInfo;
  867. LPXECB_QUEUE pQueue;
  868. pConnectionInfo = (LPCONNECTION_INFO)pXecb->OwningObject;
  869. switch (pXecb->QueueId) {
  870. case CONNECTION_CONNECT_QUEUE:
  871. pQueue = &pConnectionInfo->ConnectQueue;
  872. break;
  873. case CONNECTION_ACCEPT_QUEUE:
  874. pQueue = &pConnectionInfo->AcceptQueue;
  875. break;
  876. case CONNECTION_SEND_QUEUE:
  877. pQueue = &pConnectionInfo->SendQueue;
  878. break;
  879. case CONNECTION_LISTEN_QUEUE:
  880. pQueue = &pConnectionInfo->ListenQueue;
  881. break;
  882. }
  883. ptr = DequeueEcb(pXecb, pQueue);
  884. if (ptr) {
  885. IPXDBGPRINT((__FILE__, __LINE__,
  886. FUNCTION_ANY,
  887. IPXDBG_LEVEL_INFO,
  888. "AbortConnectionEvent: Aborting ECB %04x:%04x\n",
  889. HIWORD(pXecb->EcbAddress),
  890. LOWORD(pXecb->EcbAddress)
  891. ));
  892. SPX_ECB_CONNECTION_ID(ptr->Ecb) = pConnectionInfo->ConnectionId;
  893. CompleteOrQueueIo(ptr, CompletionCode);
  894. }
  895. }
  896. VOID
  897. StartIpxSend(
  898. IN LPXECB pXecb,
  899. IN LPSOCKET_INFO pSocketInfo
  900. )
  901. /*++
  902. Routine Description:
  903. Starts a send operation for IPXSendPacket(). Allocates a send buffer if
  904. the ECB has >1 fragment else uses a pointer to the single fragment buffer
  905. in 16-bit address space
  906. Fills in various fields in the ECB and IPX header
  907. Assumes: 1. By the time this function is called, we already know we have
  908. a valid non-zero fragment count and the first fragment is
  909. big enough to hold an IPX packet header
  910. When this function terminates, the ECB is either completed or queued
  911. Arguments:
  912. pXecb - pointer to XECB describing ECB to use for sending
  913. pSocketInfo - pointer to SOCKET_INFO structure
  914. Return Value:
  915. None.
  916. --*/
  917. {
  918. BOOL success;
  919. int packetLength = 0;
  920. LPFRAGMENT pFragment;
  921. int fragmentCount;
  922. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  923. IPXDBGPRINT((__FILE__, __LINE__,
  924. FUNCTION_ANY,
  925. IPXDBG_LEVEL_INFO,
  926. "StartIpxSend: %d frag(s), 1: address=%x (%04x:%04x), len=%04x\n",
  927. READ_WORD(&pEcb->FragmentCount),
  928. GET_FAR_POINTER(&(ECB_FRAGMENT(pEcb, 0)->Address), IS_PROT_MODE(pXecb)),
  929. GET_SELECTOR(&(ECB_FRAGMENT(pEcb, 0)->Address)),
  930. GET_OFFSET(&(ECB_FRAGMENT(pEcb, 0)->Address)),
  931. READ_WORD(&(ECB_FRAGMENT(pEcb, 0)->Length))
  932. ));
  933. //
  934. // mark the ECB as being used by IPX (for send)
  935. //
  936. pEcb->InUse = ECB_IU_SENDING;
  937. //
  938. // the total send buffer size cannot exceed the maximum packet size
  939. //
  940. fragmentCount = (int)pEcb->FragmentCount;
  941. ASSERT(fragmentCount);
  942. pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
  943. while (fragmentCount--) {
  944. packetLength += pFragment->Length;
  945. ++pFragment;
  946. }
  947. if (packetLength <= MyMaxPacketSize) {
  948. success = GetIoBuffer(pXecb, TRUE, IPX_HEADER_LENGTH);
  949. if (success) {
  950. LPIPX_PACKET pPacket = (LPIPX_PACKET)GET_FAR_POINTER(
  951. &(ECB_FRAGMENT(pEcb, 0)->Address),
  952. IS_PROT_MODE(pXecb)
  953. );
  954. //
  955. // fill in the following fields in the IPX header:
  956. //
  957. // Checksum
  958. // Length
  959. // TransportControl
  960. // Source (network, node, socket)
  961. //
  962. // Does real IPX modify these fields in app memory?
  963. // If so, does the app expect modified fields?
  964. // If not, we need to always copy then modify memory,
  965. // even if only 1 fragment
  966. //
  967. pPacket->Checksum = 0xFFFF;
  968. pPacket->Length = L2BW((WORD)packetLength);
  969. pPacket->TransportControl = 0;
  970. CopyMemory((LPBYTE)&pPacket->Source,
  971. &MyInternetAddress.sa_netnum,
  972. sizeof(MyInternetAddress.sa_netnum)
  973. + sizeof(MyInternetAddress.sa_nodenum)
  974. );
  975. pPacket->Source.Socket = pSocketInfo->SocketNumber;
  976. //
  977. // if we allocated a buffer then there is >1 fragment. Collect them
  978. //
  979. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  980. GatherData(pXecb, IPX_HEADER_LENGTH);
  981. }
  982. //
  983. // initiate the send. IPX_ECB_BUFFER32(pEcb) points to the data to send,
  984. // IPX_ECB_LENGTH32(pEcb) is the size of data to send
  985. //
  986. IpxSendFirst(pXecb, pSocketInfo);
  987. } else {
  988. //
  989. // couldn't allocate a buffer? Comes under the heading of
  990. // hardware error?
  991. //
  992. CompleteEcb(pXecb, ECB_CC_HARDWARE_ERROR);
  993. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  994. KillSocket(pSocketInfo);
  995. }
  996. }
  997. } else {
  998. //
  999. // packet larger than MyMaxPacketSize
  1000. //
  1001. CompleteOrQueueEcb(pXecb, ECB_CC_BAD_REQUEST);
  1002. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  1003. KillSocket(pSocketInfo);
  1004. }
  1005. }
  1006. }
  1007. BOOL
  1008. GetIoBuffer(
  1009. IN OUT LPXECB pXecb,
  1010. IN BOOL Send,
  1011. IN WORD HeaderLength
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Allocate a buffer based on the ECB fragment list. If there is only 1 fragment
  1016. we use the address of the buffer in the VDM. If >1 fragment, we allocate a
  1017. 32-bit buffer large enough to hold all the 16-bit fragments
  1018. We trim the buffer requirement for a send buffer: we do not send the IPX/SPX
  1019. header with the data: it will be provided by the transport
  1020. Assumes: 1. If called for a send buffer, the first fragment has already
  1021. been verified as >= HeaderLength
  1022. Arguments:
  1023. pXecb - pointer to XECB which points to IPX_ECB containing fragment
  1024. list to allocate buffer for
  1025. Send - TRUE if this request is to get a send buffer
  1026. HeaderLength - length of the (untransmitted) header portion
  1027. Return Value:
  1028. BOOL
  1029. TRUE - Buffer allocated, XECB updated with address, length and flags
  1030. FALSE - either ECB contains bad fragment descriptor list or we
  1031. couldn't allocate a buffer
  1032. --*/
  1033. {
  1034. WORD fragmentCount;
  1035. WORD bufferLength = 0;
  1036. LPBYTE bufferPointer = NULL;
  1037. WORD flags = 0;
  1038. int i;
  1039. int fragIndex = 0; // index of fragment address to use if no allocation required
  1040. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  1041. fragmentCount = READ_WORD(&pEcb->FragmentCount);
  1042. for (i = 0; i < (int)fragmentCount; ++i) {
  1043. bufferLength += ECB_FRAGMENT(pEcb, i)->Length;
  1044. }
  1045. if (bufferLength) {
  1046. //
  1047. // exclude the IPX header from send buffer. If the first send fragment
  1048. // contains only the IPX header, reduce the fragment count by 1
  1049. //
  1050. if (Send) {
  1051. bufferLength -= HeaderLength;
  1052. if (ECB_FRAGMENT(pEcb, 0)->Length == HeaderLength) {
  1053. --fragmentCount;
  1054. fragIndex = 1;
  1055. }
  1056. }
  1057. if (bufferLength) {
  1058. if (fragmentCount > 1) {
  1059. bufferPointer = AllocateBuffer(bufferLength);
  1060. if (bufferPointer) {
  1061. flags = XECB_FLAG_BUFFER_ALLOCATED;
  1062. } else {
  1063. //
  1064. // need a buffer; failed to allocate it
  1065. //
  1066. return FALSE;
  1067. }
  1068. } else {
  1069. //
  1070. // fragmentCount must be 1 (else bufferLength would be 0)
  1071. //
  1072. bufferPointer = GET_FAR_POINTER(
  1073. &ECB_FRAGMENT(pEcb, fragIndex)->Address,
  1074. IS_PROT_MODE(pXecb)
  1075. );
  1076. if (Send && !fragIndex) {
  1077. //
  1078. // if we are allocating a send buffer AND there is only 1
  1079. // fragment AND it is the first fragment then the one and
  1080. // only fragment must contain the IPX header and the data.
  1081. // Advance the data pointer past the IPX header
  1082. //
  1083. bufferPointer += HeaderLength;
  1084. }
  1085. }
  1086. } else {
  1087. //
  1088. // sending 0 bytes!!!
  1089. //
  1090. }
  1091. } else {
  1092. //
  1093. // fragments but no buffer length? Sounds like a malformed packet
  1094. //
  1095. return FALSE;
  1096. }
  1097. //
  1098. // bufferPointer is either the address of a buffer in 32-bit memory which
  1099. // must be gather/scattered when the I/O operation completes, or it is the
  1100. // address of a single fragment buffer in 16-bit memory. In the former case
  1101. // flags is ECB_ALLOCATE_32 and the latter 0
  1102. //
  1103. pXecb->Buffer = pXecb->Data = bufferPointer;
  1104. pXecb->Length = bufferLength;
  1105. pXecb->Flags |= flags;
  1106. return TRUE;
  1107. }
  1108. PRIVATE
  1109. VOID
  1110. ReleaseIoBuffer(
  1111. IN LPXECB pXecb
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Deallocates I/O buffer attached to XECB and zaps associated XECB fields
  1116. Arguments:
  1117. pXecb - pointer to XECB owning buffer to be released
  1118. Return Value:
  1119. None.
  1120. --*/
  1121. {
  1122. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1123. DeallocateBuffer(pXecb->Buffer);
  1124. pXecb->Buffer = pXecb->Data = NULL;
  1125. pXecb->Flags &= ~XECB_FLAG_BUFFER_ALLOCATED;
  1126. }
  1127. }
  1128. VOID
  1129. GatherData(
  1130. IN LPXECB pXecb,
  1131. IN WORD HeaderLength
  1132. )
  1133. /*++
  1134. Routine Description:
  1135. Copies data from fragmented 16-bit memory into single 32-bit memory buffer.
  1136. Used to send data. We exclude the IPX header: this information is supplied
  1137. by the transport
  1138. Assumes: 1. The fragment descriptor list has been verified: we know that
  1139. the first fragment contains at least the IPX header
  1140. Arguments:
  1141. pXecb - pointer to XECB structure. The following IPX_ECB and XECB
  1142. fields must contain coherent values:
  1143. IPX_ECB.FragmentCount
  1144. XECB.Buffer
  1145. HeaderLength - length of the (untransmitted) header portion
  1146. Return Value:
  1147. None.
  1148. --*/
  1149. {
  1150. int fragmentCount;
  1151. WORD length;
  1152. ULPBYTE pData16;
  1153. ULPBYTE pData32;
  1154. LPFRAGMENT pFragment;
  1155. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  1156. fragmentCount = (int)pEcb->FragmentCount;
  1157. pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
  1158. pData32 = pXecb->Buffer;
  1159. //
  1160. // if the 1st fragment contains more than the IPX/SPX header, copy the data
  1161. // after the header
  1162. //
  1163. if (pFragment->Length > HeaderLength) {
  1164. LPBYTE fragAddr = GET_FAR_POINTER(&pFragment->Address,
  1165. IS_PROT_MODE(pXecb)
  1166. );
  1167. length = pFragment->Length - HeaderLength;
  1168. CopyMemory((LPVOID)pData32,
  1169. fragAddr + HeaderLength,
  1170. length
  1171. );
  1172. pData32 += length;
  1173. }
  1174. //
  1175. // copy subsequent fragments
  1176. //
  1177. ++pFragment;
  1178. while (--fragmentCount) {
  1179. pData16 = GET_FAR_POINTER(&pFragment->Address, IS_PROT_MODE(pXecb));
  1180. if (pData16 == NULL) {
  1181. break;
  1182. }
  1183. length = pFragment->Length;
  1184. CopyMemory((PVOID)pData32, (CONST VOID*)pData16, (ULONG)length);
  1185. pData32 += length;
  1186. ++pFragment;
  1187. }
  1188. }
  1189. VOID
  1190. ScatterData(
  1191. IN LPXECB pXecb
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. Copies data from 32-bit memory to 16-bit. The data must be fragmented if
  1196. this function has been called (i.e. we determined there were >1 fragments
  1197. and allocated a single 32-bit buffer to cover them)
  1198. Arguments:
  1199. pXecb - pointer to XECB containing 32-bit buffer info
  1200. Return Value:
  1201. None.
  1202. --*/
  1203. {
  1204. int fragmentCount;
  1205. int length;
  1206. WORD length16;
  1207. WORD length32;
  1208. ULPBYTE pData16;
  1209. ULPBYTE pData32;
  1210. LPFRAGMENT pFragment;
  1211. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  1212. fragmentCount = (int)pEcb->FragmentCount;
  1213. pFragment = (LPFRAGMENT)&(ECB_FRAGMENT(pEcb, 0)->Address);
  1214. pData32 = pXecb->Buffer;
  1215. length32 = pXecb->Length;
  1216. while (length32) {
  1217. pData16 = GET_FAR_POINTER(&pFragment->Address, IS_PROT_MODE(pXecb));
  1218. if (pData16 == NULL) {
  1219. break;
  1220. }
  1221. length16 = pFragment->Length;
  1222. length = min(length16, length32);
  1223. CopyMemory((PVOID)pData16, (CONST VOID*)pData32, (ULONG)length);
  1224. pData32 += length;
  1225. length32 -= (WORD) length;
  1226. ++pFragment;
  1227. --fragmentCount;
  1228. ASSERT(fragmentCount >= 0);
  1229. }
  1230. }
  1231. VOID
  1232. IpxReceiveFirst(
  1233. IN LPXECB pXecb,
  1234. IN LPSOCKET_INFO pSocketInfo
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. Performs a receive against a non-blocking socket. This is the first
  1239. receive call for this ECB. If the receive completes immediately with data
  1240. or an error that isn't WSAEWOULDBLOCK then the ECB is completed. If the
  1241. receives completes with a WSAEWOULDBLOCK error then the request is queued
  1242. for deferred processing by the AES thread
  1243. Unlike send, receives are not serialized. If there are already receives
  1244. pending against the socket there could be a clash between this function
  1245. and IpxReceiveNext(), called from the AES thread. In this case, we expect
  1246. Winsock to do the right thing and serialize the callers
  1247. Arguments:
  1248. pXecb - pointer to XECB describing receive ECB
  1249. pSocketInfo - pointer to socket structure
  1250. Return Value:
  1251. None.
  1252. --*/
  1253. {
  1254. SOCKADDR_IPX from;
  1255. int fromLen = sizeof(from);
  1256. int rc;
  1257. BYTE status;
  1258. BOOL error;
  1259. rc = recvfrom(pSocketInfo->Socket,
  1260. (char FAR*)pXecb->Buffer,
  1261. (int)pXecb->Length,
  1262. 0, // flags
  1263. (LPSOCKADDR)&from,
  1264. &fromLen
  1265. );
  1266. if (rc != SOCKET_ERROR) {
  1267. error = FALSE;
  1268. status = ECB_CC_SUCCESS;
  1269. } else {
  1270. error = TRUE;
  1271. rc = WSAGetLastError();
  1272. if (rc == WSAEWOULDBLOCK) {
  1273. RequestMutex();
  1274. QueueReceiveRequest(pXecb, pSocketInfo);
  1275. ReleaseMutex();
  1276. } else if (rc == WSAEMSGSIZE) {
  1277. error = FALSE;
  1278. status = ECB_CC_BAD_REQUEST;
  1279. rc = pXecb->Length;
  1280. } else {
  1281. IPXDBGPRINT((__FILE__, __LINE__,
  1282. FUNCTION_ANY,
  1283. IPXDBG_LEVEL_ERROR,
  1284. "IpxReceiveFirst: recvfrom() returns %d (buflen=%d)\n",
  1285. rc,
  1286. pXecb->Length
  1287. ));
  1288. CompleteOrQueueIo(pXecb, ECB_CC_BAD_REQUEST);
  1289. }
  1290. }
  1291. if (!error) {
  1292. //
  1293. // rc = bytes received, or 0 = connection terminated (even for DGRAM?)
  1294. //
  1295. IPXDBGPRINT((__FILE__, __LINE__,
  1296. FUNCTION_ANY,
  1297. IPXDBG_LEVEL_INFO,
  1298. "IpxReceiveFirst: bytes received = %d (%x)\n",
  1299. rc,
  1300. rc
  1301. ));
  1302. /*
  1303. VwDumpEcb(pXecb->Ecb,
  1304. HIWORD(pXecb->EcbAddress),
  1305. LOWORD(pXecb->EcbAddress),
  1306. FALSE,
  1307. TRUE,
  1308. TRUE,
  1309. IS_PROT_MODE(pXecb)
  1310. );
  1311. */
  1312. IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
  1313. //
  1314. // if the receive buffers are fragmented, copy the data to 16-bit memory
  1315. // (else single buffer: its already there (dude))
  1316. //
  1317. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1318. //
  1319. // update the ECB_LENGTH32 field to reflect the amount of data received
  1320. //
  1321. pXecb->Length = (WORD)rc;
  1322. ScatterData(pXecb);
  1323. //
  1324. // we have finished with the 32-bit buffer: deallocate it
  1325. //
  1326. ReleaseIoBuffer(pXecb);
  1327. }
  1328. //
  1329. // update the ImmediateAddress field in the ECB with the node address
  1330. // of the sender
  1331. //
  1332. CopyMemory(pXecb->Ecb->ImmediateAddress, from.sa_nodenum, sizeof(from.sa_nodenum));
  1333. //
  1334. // if this ECB has a non-NULL ESR then queue for asynchronous completion
  1335. // else complete immediately (app must poll InUse field)
  1336. //
  1337. CompleteOrQueueEcb(pXecb, status);
  1338. }
  1339. }
  1340. VOID
  1341. IpxReceiveNext(
  1342. IN LPSOCKET_INFO pSocketInfo
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. Attempts to complete an IPXListenForPacket request that has been deferred due
  1347. to the fact the socket was blocked.
  1348. The ECB containing all the receive information is at the head of the
  1349. ListenQueue on pSocketInfo
  1350. We can use any queued listen ECB, but it just so happens we use the one at
  1351. the head of the FIFO
  1352. Note: SerializationCritSec is held when this function is called.
  1353. Arguments:
  1354. pSocketInfo - pointer to SOCKET_INFO structure with pending IPX send request
  1355. Return Value:
  1356. None.
  1357. --*/
  1358. {
  1359. LPXECB pXecb;
  1360. SOCKADDR_IPX from;
  1361. int fromLen = sizeof(from);
  1362. int rc;
  1363. BYTE status;
  1364. BOOL error;
  1365. ASSERT(pSocketInfo);
  1366. pXecb = (LPXECB)pSocketInfo->ListenQueue.Head;
  1367. ASSERT(pXecb);
  1368. rc = recvfrom(pSocketInfo->Socket,
  1369. (char FAR*)pXecb->Buffer,
  1370. (int)pXecb->Length,
  1371. 0, // flags
  1372. (LPSOCKADDR)&from,
  1373. &fromLen
  1374. );
  1375. if (rc != SOCKET_ERROR) {
  1376. error = FALSE;
  1377. status = ECB_CC_SUCCESS;
  1378. } else {
  1379. error = TRUE;
  1380. rc = WSAGetLastError();
  1381. if (rc == WSAEMSGSIZE) {
  1382. error = FALSE;
  1383. status = ECB_CC_BAD_REQUEST;
  1384. rc = pXecb->Length;
  1385. } else if (rc != WSAEWOULDBLOCK) {
  1386. DequeueReceiveRequest(pXecb, pSocketInfo);
  1387. IPXDBGPRINT((__FILE__, __LINE__,
  1388. FUNCTION_ANY,
  1389. IPXDBG_LEVEL_ERROR,
  1390. "IpxReceiveNext: recvfrom() returns %d\n",
  1391. rc
  1392. ));
  1393. CompleteOrQueueIo(pXecb, ECB_CC_CANCELLED);
  1394. }
  1395. }
  1396. if (!error) {
  1397. /*
  1398. VwDumpEcb(pXecb->Ecb,
  1399. HIWORD(pXecb->EcbAddress),
  1400. LOWORD(pXecb->EcbAddress),
  1401. FALSE,
  1402. TRUE,
  1403. TRUE,
  1404. IS_PROT_MODE(pXecb)
  1405. );
  1406. */
  1407. //
  1408. // data received. Remove ECB from queue
  1409. //
  1410. DequeueReceiveRequest(pXecb, pSocketInfo);
  1411. //
  1412. // rc = bytes received, or 0 = connection terminated (even for DGRAM?)
  1413. //
  1414. IPXDBGPRINT((__FILE__, __LINE__,
  1415. FUNCTION_ANY,
  1416. IPXDBG_LEVEL_INFO,
  1417. "IpxReceiveNext: ECB %04x:%04x bytes received = %d (%x)\n",
  1418. HIWORD(pXecb->EcbAddress),
  1419. LOWORD(pXecb->EcbAddress),
  1420. rc,
  1421. rc
  1422. ));
  1423. IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
  1424. //
  1425. // if the receive buffers are fragmented, copy the data to 16-bit memory
  1426. // (else single buffer: its already there (dude))
  1427. //
  1428. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1429. //
  1430. // update the IPX_ECB_LENGTH32 field to reflect the amount of data received
  1431. //
  1432. pXecb->Length = (WORD)rc;
  1433. ScatterData(pXecb);
  1434. ReleaseIoBuffer(pXecb);
  1435. }
  1436. //
  1437. // update the ImmediateAddress field in the ECB with the node address
  1438. // of the sender
  1439. //
  1440. CopyMemory(pXecb->Ecb->ImmediateAddress,
  1441. from.sa_nodenum,
  1442. sizeof(from.sa_nodenum)
  1443. );
  1444. //
  1445. // if this ECB has a non-NULL ESR then queue for asynchronous completion
  1446. // else complete immediately (app must poll InUse field)
  1447. //
  1448. CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
  1449. }
  1450. }
  1451. PRIVATE
  1452. VOID
  1453. IpxSendFirst(
  1454. IN LPXECB pXecb,
  1455. IN LPSOCKET_INFO pSocketInfo
  1456. )
  1457. /*++
  1458. Routine Description:
  1459. Tries to send an IPX packet. This is the first attempt to send the packet
  1460. described in the ECB. If the send succeeds or fails with an error other
  1461. than WSAEWOULDBLOCK we complete the ECB. If the send attempt fails because
  1462. the transport can't accept the request at this time, we queue it for later
  1463. when the AES thread will attempt to send it.
  1464. If there is already a send being attempted then we just queue this request
  1465. and let AES handle it in IpxSendNext()
  1466. Arguments:
  1467. pXecb - pointer to XECB
  1468. pSocketInfo - pointer to SOCKET_INFO structure
  1469. Return Value:
  1470. None.
  1471. --*/
  1472. {
  1473. RequestMutex();
  1474. if (pSocketInfo->Flags & SOCKET_FLAG_SENDING) {
  1475. IPXDBGPRINT((__FILE__, __LINE__,
  1476. FUNCTION_ANY,
  1477. IPXDBG_LEVEL_INFO,
  1478. "IpxSendFirst: queueing ECB %04x:%04x\n",
  1479. HIWORD(pXecb->EcbAddress),
  1480. LOWORD(pXecb->EcbAddress)
  1481. ));
  1482. QueueSendRequest(pXecb, pSocketInfo);
  1483. } else {
  1484. SOCKADDR_IPX to;
  1485. LPIPX_PACKET pPacket;
  1486. int length;
  1487. int rc;
  1488. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  1489. int type;
  1490. /*
  1491. VwDumpEcb(pXecb->Ecb,
  1492. HIWORD(pXecb->EcbAddress),
  1493. LOWORD(pXecb->EcbAddress),
  1494. FALSE,
  1495. TRUE,
  1496. TRUE,
  1497. IS_PROT_MODE(pXecb)
  1498. );
  1499. */
  1500. length = (int)pXecb->Length;
  1501. //
  1502. // the first fragment holds the destination address info
  1503. //
  1504. pPacket = (LPIPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pEcb, 0)->Address,
  1505. IS_PROT_MODE(pXecb)
  1506. );
  1507. to.sa_family = AF_IPX;
  1508. //
  1509. // copy the destination net number as a DWORD (4 bytes) from the
  1510. // destination network address structure in the IPX packet header
  1511. //
  1512. *(ULPDWORD)&to.sa_netnum[0] = *(ULPDWORD)&pPacket->Destination.Net[0];
  1513. //
  1514. // copy the immediate (destination) node number as a DWORD (4 bytes) and
  1515. // a WORD (2 bytes) from the Destination network address structure in
  1516. // the IPX packet header. pPacket is an unaligned pointer, so we are
  1517. // safe
  1518. //
  1519. *(ULPDWORD)&to.sa_nodenum[0] = *(ULPDWORD)&pPacket->Destination.Node[0];
  1520. *(LPWORD)&to.sa_nodenum[4] = *(ULPWORD)&pPacket->Destination.Node[4];
  1521. //
  1522. // copy the destination socket number from the IPX packet header as a
  1523. // WORD (2 bytes). Again, the aligned pointer will save us
  1524. //
  1525. to.sa_socket = pPacket->Destination.Socket;
  1526. type = (int)pPacket->PacketType;
  1527. rc = setsockopt(pSocketInfo->Socket,
  1528. NSPROTO_IPX,
  1529. IPX_PTYPE,
  1530. (char FAR*)&type,
  1531. sizeof(type)
  1532. );
  1533. if (rc) {
  1534. IPXDBGPRINT((__FILE__, __LINE__,
  1535. FUNCTION_ANY,
  1536. IPXDBG_LEVEL_ERROR,
  1537. "IpxSendFirst: setsockopt(IPX_PTYPE) returns %d\n",
  1538. WSAGetLastError()
  1539. ));
  1540. }
  1541. rc = sendto(pSocketInfo->Socket,
  1542. (char FAR*)pXecb->Buffer,
  1543. length,
  1544. 0, // flags
  1545. (LPSOCKADDR)&to,
  1546. sizeof(to)
  1547. );
  1548. if (rc == length) {
  1549. //
  1550. // all data sent
  1551. //
  1552. IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
  1553. CompleteOrQueueIo(pXecb, ECB_CC_SUCCESS);
  1554. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  1555. KillSocket(pSocketInfo);
  1556. }
  1557. } else if (rc == SOCKET_ERROR) {
  1558. rc = WSAGetLastError();
  1559. if (rc == WSAEWOULDBLOCK) {
  1560. IPXDBGPRINT((__FILE__, __LINE__,
  1561. FUNCTION_ANY,
  1562. IPXDBG_LEVEL_INFO,
  1563. "IpxSendFirst: queueing ECB %04x:%04x (after sendto)\n",
  1564. HIWORD(pXecb->EcbAddress),
  1565. LOWORD(pXecb->EcbAddress)
  1566. ));
  1567. QueueSendRequest(pXecb, pSocketInfo);
  1568. } else {
  1569. IPXDBGPRINT((__FILE__, __LINE__,
  1570. FUNCTION_ANY,
  1571. IPXDBG_LEVEL_ERROR,
  1572. "IpxSendFirst: sendto() returns %d\n",
  1573. rc
  1574. ));
  1575. CompleteIo(pXecb, ECB_CC_UNDELIVERABLE);
  1576. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  1577. KillSocket(pSocketInfo);
  1578. }
  1579. }
  1580. } else {
  1581. //
  1582. // send should send all the data or return an error
  1583. //
  1584. IPXDBGPRINT((__FILE__, __LINE__,
  1585. FUNCTION_ANY,
  1586. IPXDBG_LEVEL_FATAL,
  1587. "IpxSendFirst: sendto() returns unexpected %d (length = %d)\n",
  1588. rc,
  1589. length
  1590. ));
  1591. }
  1592. }
  1593. ReleaseMutex();
  1594. }
  1595. VOID
  1596. IpxSendNext(
  1597. IN LPSOCKET_INFO pSocketInfo
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. Attempts to complete an IPXSendPacket request that has been deferred due
  1602. to the fact the socket was blocked.
  1603. The ECB containing all the send information is at the head of the SendQueue
  1604. on pSocketInfo
  1605. The SendQueue is serialized in FIFO order
  1606. Note: SerializationCritSec is held when this function is called.
  1607. Arguments:
  1608. pSocketInfo - pointer to SOCKET_INFO structure with pending IPX send request
  1609. Return Value:
  1610. None.
  1611. --*/
  1612. {
  1613. SOCKADDR_IPX to;
  1614. LPIPX_PACKET pPacket;
  1615. int length;
  1616. int rc;
  1617. LPXECB pXecb;
  1618. LPIPX_ECB pEcb;
  1619. int type;
  1620. pXecb = (LPXECB)pSocketInfo->SendQueue.Head;
  1621. pEcb = (LPIPX_ECB)pXecb->Ecb;
  1622. ASSERT(pXecb);
  1623. ASSERT(pEcb);
  1624. /*
  1625. VwDumpEcb(pXecb->Ecb,
  1626. HIWORD(pXecb->EcbAddress),
  1627. LOWORD(pXecb->EcbAddress),
  1628. FALSE,
  1629. TRUE,
  1630. TRUE,
  1631. IS_PROT_MODE(pXecb)
  1632. );
  1633. */
  1634. length = (int)pXecb->Length;
  1635. //
  1636. // even though we have a 32-bit pointer to the IPX packet buffer which
  1637. // may be in 16- or 32-bit memory, we still need unaligned access
  1638. //
  1639. pPacket = (LPIPX_PACKET)pXecb->Buffer;
  1640. to.sa_family = AF_IPX;
  1641. //
  1642. // copy the destination net number as a DWORD (4 bytes) from the
  1643. // destination network address structure in the IPX packet header
  1644. //
  1645. *(ULPDWORD)&to.sa_netnum[0] = *(ULPDWORD)&pPacket->Destination.Net[0];
  1646. //
  1647. // copy the immediate (destination) node number as a DWORD (4 bytes) and
  1648. // a WORD (2 bytes) from the Destination network address structure in
  1649. // the IPX packet header. pPacket is an unaligned pointer, so we are
  1650. // safe
  1651. //
  1652. *(ULPDWORD)&to.sa_nodenum[0] = *(ULPDWORD)&pPacket->Destination.Node[0];
  1653. *(LPWORD)&to.sa_nodenum[4] = *(ULPWORD)&pPacket->Destination.Node[4];
  1654. //
  1655. // copy the destination socket number from the IPX packet header as a
  1656. // WORD (2 bytes). Again, the aligned pointer will save us
  1657. //
  1658. to.sa_socket = pPacket->Destination.Socket;
  1659. type = (int)pPacket->PacketType;
  1660. rc = setsockopt(pSocketInfo->Socket,
  1661. NSPROTO_IPX,
  1662. IPX_PTYPE,
  1663. (char FAR*)&type,
  1664. sizeof(type)
  1665. );
  1666. if (rc) {
  1667. IPXDBGPRINT((__FILE__, __LINE__,
  1668. FUNCTION_ANY,
  1669. IPXDBG_LEVEL_ERROR,
  1670. "IpxSendNext: setsockopt(IPX_PTYPE) returns %d\n",
  1671. WSAGetLastError()
  1672. ));
  1673. }
  1674. rc = sendto(pSocketInfo->Socket,
  1675. (char FAR*)pPacket,
  1676. length,
  1677. 0, // flags
  1678. (LPSOCKADDR)&to,
  1679. sizeof(to)
  1680. );
  1681. if (rc == length) {
  1682. //
  1683. // all data sent - dequeue it
  1684. //
  1685. IPXDUMPDATA((pXecb->Buffer, 0, 0, FALSE, (WORD)rc));
  1686. DequeueEcb(pXecb, &pSocketInfo->SendQueue);
  1687. if (pXecb->EsrAddress) {
  1688. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1689. ReleaseIoBuffer(pXecb);
  1690. }
  1691. QueueAsyncCompletion(pXecb, ECB_CC_SUCCESS);
  1692. } else {
  1693. CompleteIo(pXecb, ECB_CC_SUCCESS);
  1694. }
  1695. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  1696. KillSocket(pSocketInfo);
  1697. }
  1698. } else if (rc == SOCKET_ERROR) {
  1699. //
  1700. // if the socket is still blocked, there's nothing to do - just leave
  1701. // the request hanging around till next time
  1702. //
  1703. rc = WSAGetLastError();
  1704. if (rc != WSAEWOULDBLOCK) {
  1705. DequeueSendRequest(pXecb, pSocketInfo);
  1706. IPXDBGPRINT((__FILE__, __LINE__,
  1707. FUNCTION_ANY,
  1708. IPXDBG_LEVEL_ERROR,
  1709. "IpxSendNext: sendto() returns %d\n",
  1710. rc
  1711. ));
  1712. CompleteIo(pXecb, ECB_CC_UNDELIVERABLE);
  1713. if (pSocketInfo->Flags & SOCKET_FLAG_TEMPORARY) {
  1714. KillSocket(pSocketInfo);
  1715. }
  1716. }
  1717. } else {
  1718. //
  1719. // send should send all the data or return an error
  1720. //
  1721. IPXDBGPRINT((__FILE__, __LINE__,
  1722. FUNCTION_ANY,
  1723. IPXDBG_LEVEL_FATAL,
  1724. "IpxSendNext: sendto() returns unexpected %d (length = %d)\n",
  1725. rc,
  1726. length
  1727. ));
  1728. }
  1729. }
  1730. PRIVATE
  1731. VOID
  1732. QueueReceiveRequest(
  1733. IN LPXECB pXecb,
  1734. IN LPSOCKET_INFO pSocketInfo
  1735. )
  1736. /*++
  1737. Routine Description:
  1738. Add a listen XECB to queue of listen XECBs on a SOCKET_INFO structure
  1739. Arguments:
  1740. pXecb - pointer to listen XECB to queue
  1741. pSocketInfo - pointer to SOCKET_INFO structure
  1742. Return Value:
  1743. None.
  1744. --*/
  1745. {
  1746. QueueEcb(pXecb, &pSocketInfo->ListenQueue, SOCKET_LISTEN_QUEUE);
  1747. ++pSocketInfo->PendingListens;
  1748. pSocketInfo->Flags |= SOCKET_FLAG_LISTENING;
  1749. }
  1750. PRIVATE
  1751. LPXECB
  1752. DequeueReceiveRequest(
  1753. IN LPXECB pXecb,
  1754. IN LPSOCKET_INFO pSocketInfo
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. Remove a listen XECB from queue of listen XECBs on a SOCKET_INFO structure
  1759. Arguments:
  1760. pXecb - pointer to listen XECB to dequeue
  1761. pSocketInfo - pointer to SOCKET_INFO structure
  1762. Return Value:
  1763. LPXECB
  1764. --*/
  1765. {
  1766. LPXECB ptr;
  1767. ptr = (LPXECB)DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
  1768. if (ptr) {
  1769. ASSERT(ptr == pXecb);
  1770. --pSocketInfo->PendingListens;
  1771. if (!pSocketInfo->PendingListens) {
  1772. pSocketInfo->Flags &= ~SOCKET_FLAG_LISTENING;
  1773. }
  1774. pXecb->Ecb->InUse = ECB_IU_AWAITING_PROCESSING;
  1775. }
  1776. return ptr;
  1777. }
  1778. PRIVATE
  1779. VOID
  1780. QueueSendRequest(
  1781. IN LPXECB pXecb,
  1782. IN LPSOCKET_INFO pSocketInfo
  1783. )
  1784. /*++
  1785. Routine Description:
  1786. Add a send XECB to queue of send XECBs on a SOCKET_INFO structure
  1787. Arguments:
  1788. pXecb - pointer to send XECB to queue
  1789. pSocketInfo - pointer to SOCKET_INFO structure
  1790. Return Value:
  1791. None.
  1792. --*/
  1793. {
  1794. QueueEcb(pXecb, &pSocketInfo->SendQueue, SOCKET_SEND_QUEUE);
  1795. ++pSocketInfo->PendingSends;
  1796. pSocketInfo->Flags |= SOCKET_FLAG_SENDING;
  1797. pXecb->Ecb->InUse = ECB_IU_SEND_QUEUED;
  1798. }
  1799. PRIVATE
  1800. LPXECB
  1801. DequeueSendRequest(
  1802. IN LPXECB pXecb,
  1803. IN LPSOCKET_INFO pSocketInfo
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Remove a send XECB from queue of send XECBs on a SOCKET_INFO structure
  1808. Arguments:
  1809. pXecb - pointer to send XECB to dequeue
  1810. pSocketInfo - pointer to SOCKET_INFO structure
  1811. Return Value:
  1812. LPXECB
  1813. --*/
  1814. {
  1815. LPXECB ptr;
  1816. ptr = (LPXECB)DequeueEcb(pXecb, &pSocketInfo->SendQueue);
  1817. if (ptr) {
  1818. ASSERT(ptr == pXecb);
  1819. --pSocketInfo->PendingSends;
  1820. if (!pSocketInfo->PendingSends) {
  1821. pSocketInfo->Flags &= ~SOCKET_FLAG_SENDING;
  1822. }
  1823. pXecb->Ecb->InUse = ECB_IU_AWAITING_PROCESSING;
  1824. }
  1825. return ptr;
  1826. }
  1827. VOID
  1828. CompleteOrQueueIo(
  1829. IN LPXECB pXecb,
  1830. IN BYTE CompletionCode
  1831. )
  1832. /*++
  1833. Routine Description:
  1834. Returns any allocated buffer resource then completes or queues the ECB
  1835. Arguments:
  1836. pXecb - pointer to XECB structure
  1837. CompletionCode - value to put in CompletionCode field
  1838. Return Value:
  1839. None.
  1840. --*/
  1841. {
  1842. //
  1843. // if we allocated a buffer, free it
  1844. //
  1845. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1846. ReleaseIoBuffer(pXecb);
  1847. }
  1848. CompleteOrQueueEcb(pXecb, CompletionCode);
  1849. }
  1850. VOID
  1851. CompleteIo(
  1852. IN LPXECB pXecb,
  1853. IN BYTE CompletionCode
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. Completes a send/receive request by returning any allocated buffer resource
  1858. and setting the ECB InUse and CompletionCode fields
  1859. Arguments:
  1860. pXecb - pointer to XECB structure
  1861. CompletionCode - value to put in CompletionCode field
  1862. Return Value:
  1863. None.
  1864. --*/
  1865. {
  1866. //
  1867. // if we allocated a buffer, free it
  1868. //
  1869. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1870. ReleaseIoBuffer(pXecb);
  1871. }
  1872. CompleteEcb(pXecb, CompletionCode);
  1873. }
  1874. VOID
  1875. CompleteOrQueueEcb(
  1876. IN LPXECB pXecb,
  1877. IN BYTE CompletionCode
  1878. )
  1879. /*++
  1880. Routine Description:
  1881. Queues an XECB for completion by ESR or completes it now
  1882. Arguments:
  1883. pXecb - pointer to XECB describing ECB to complete
  1884. CompletionCode - value to put in ECB CompletionCode field
  1885. Return Value:
  1886. None.
  1887. --*/
  1888. {
  1889. if (pXecb->EsrAddress) {
  1890. QueueAsyncCompletion(pXecb, CompletionCode);
  1891. } else {
  1892. CompleteIo(pXecb, CompletionCode);
  1893. }
  1894. }
  1895. VOID
  1896. CompleteEcb(
  1897. IN LPXECB pXecb,
  1898. IN BYTE CompletionCode
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. Sets the CompletionCode field in the ECB and sets the InUse field to 0.
  1903. Deallocates the XECB structure
  1904. Arguments:
  1905. pXecb - pointer to XECB describing ECB in 16-bit memory to update
  1906. CompletionCode - value to put in CompletionCode field
  1907. Return Value:
  1908. None.
  1909. --*/
  1910. {
  1911. LPIPX_ECB pEcb = (LPIPX_ECB)pXecb->Ecb;
  1912. IPXDBGPRINT((__FILE__, __LINE__,
  1913. FUNCTION_ANY,
  1914. IPXDBG_LEVEL_INFO,
  1915. "CompleteEcb: completing ECB @%04x:%04x w/ %02x\n",
  1916. HIWORD(pXecb->EcbAddress),
  1917. LOWORD(pXecb->EcbAddress),
  1918. CompletionCode
  1919. ));
  1920. //
  1921. // if this is really an AES ECB then CompletionCode is actually the first
  1922. // byte of the AES workspace. It shouldn't matter that we write into this
  1923. // field - we are supposed to own it
  1924. //
  1925. pEcb->CompletionCode = CompletionCode;
  1926. pEcb->InUse = ECB_IU_NOT_IN_USE;
  1927. //
  1928. // reset the LinkAddress field. This means we have completed the ECB
  1929. //
  1930. pEcb->LinkAddress = NULL;
  1931. //
  1932. // finally, deallocate the XECB. This mustn't have any allocated resources
  1933. // (like a buffer)
  1934. //
  1935. DeallocateXecb(pXecb);
  1936. }
  1937. PRIVATE
  1938. VOID
  1939. QueueAsyncCompletion(
  1940. IN LPXECB pXecb,
  1941. IN BYTE CompletionCode
  1942. )
  1943. /*++
  1944. Routine Description:
  1945. Add an XECB to the (serialized) async completion queue and raise a simulated
  1946. hardware interrupt in the VDM.
  1947. The interrupt will cause the VDM to start executing at the ISR in the TSR
  1948. which will call-back to find the address for the ESR, then execute it
  1949. Arguments:
  1950. pXecb - pointer to XECB describing IPX or AES ECB to add to async
  1951. completion list
  1952. CompletionCode - the ECB in VDM memory will be updated with this completion
  1953. code
  1954. Return Value:
  1955. None.
  1956. --*/
  1957. {
  1958. IPXDBGPRINT((__FILE__, __LINE__,
  1959. FUNCTION_ANY,
  1960. IPXDBG_LEVEL_INFO,
  1961. "QueueAsyncCompletion: completing ECB @%04x:%04x w/ %02x\n",
  1962. HIWORD(pXecb->EcbAddress),
  1963. LOWORD(pXecb->EcbAddress),
  1964. CompletionCode
  1965. ));
  1966. pXecb->Ecb->CompletionCode = CompletionCode;
  1967. pXecb->QueueId = ASYNC_COMPLETION_QUEUE;
  1968. EnterCriticalSection(&AsyncCritSec);
  1969. FifoAdd(&AsyncCompletionQueue, (LPFIFO)pXecb);
  1970. LeaveCriticalSection(&AsyncCritSec);
  1971. IPXDBGPRINT((__FILE__, __LINE__,
  1972. FUNCTION_ANY,
  1973. IPXDBG_LEVEL_INFO,
  1974. "QueueAsyncCompletion: ECB @ %04x:%04x ESR @ %04x:%04x\n",
  1975. HIWORD(pXecb->EcbAddress),
  1976. LOWORD(pXecb->EcbAddress),
  1977. HIWORD(pXecb->EsrAddress),
  1978. LOWORD(pXecb->EsrAddress)
  1979. ));
  1980. VDDSimulateInterrupt(Ica, IcaLine, 1);
  1981. }
  1982. VOID
  1983. EsrCallback(
  1984. VOID
  1985. )
  1986. /*++
  1987. Routine Description:
  1988. Callback function from within 16-bit TSR ESR function. Returns the address
  1989. of the next completed ECB in ES:SI
  1990. Any allocated resources (e.g. 32-bit buffer) must have been freed by the
  1991. time the ESR callback happens
  1992. Arguments:
  1993. None.
  1994. Return Value:
  1995. None.
  1996. --*/
  1997. {
  1998. WORD segment = 0;
  1999. WORD offset = 0;
  2000. BYTE flags = 0;
  2001. VWinEsrCallback( &segment, &offset, &flags );
  2002. setES(segment);
  2003. setSI(offset);
  2004. setAL(flags);
  2005. }
  2006. VOID
  2007. VWinEsrCallback(
  2008. WORD *pSegment,
  2009. WORD *pOffset,
  2010. BYTE *pFlags
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. Callback function from within 16-bit function. Returns the address
  2015. of the next completed ECB
  2016. Any allocated resources (e.g. 32-bit buffer) must have been freed by the
  2017. time the ESR callback happens
  2018. Arguments:
  2019. None.
  2020. Return Value:
  2021. None.
  2022. --*/
  2023. {
  2024. LPXECB pXecb;
  2025. EnterCriticalSection(&AsyncCritSec);
  2026. pXecb = AsyncCompletionQueue.Head;
  2027. if (pXecb) {
  2028. WORD msw = getMSW();
  2029. if ((msw & MSW_PE) ^ IS_PROT_MODE(pXecb)) {
  2030. IPXDBGPRINT((__FILE__, __LINE__,
  2031. FUNCTION_ANY,
  2032. IPXDBG_LEVEL_INFO,
  2033. "EsrCallback: ECB @ %04x:%04x NOT for this proc mode (%d)\n",
  2034. HIWORD(pXecb->EcbAddress),
  2035. LOWORD(pXecb->EcbAddress),
  2036. msw & MSW_PE
  2037. ));
  2038. pXecb = NULL;
  2039. } else {
  2040. pXecb = (LPXECB)FifoNext(&AsyncCompletionQueue);
  2041. }
  2042. } else {
  2043. IPXDBGPRINT((__FILE__, __LINE__,
  2044. FUNCTION_ANY,
  2045. IPXDBG_LEVEL_FATAL,
  2046. "EsrCallback: no ECBs on AsyncCompletionQueue!\n"
  2047. ));
  2048. }
  2049. LeaveCriticalSection(&AsyncCritSec);
  2050. if (pXecb) {
  2051. IPXDBGPRINT((__FILE__, __LINE__,
  2052. FUNCTION_ANY,
  2053. IPXDBG_LEVEL_INFO,
  2054. "EsrCallback: ECB @ %04x:%04x ESR @ %04x:%04x\n",
  2055. HIWORD(pXecb->EcbAddress),
  2056. LOWORD(pXecb->EcbAddress),
  2057. HIWORD(pXecb->EsrAddress),
  2058. LOWORD(pXecb->EsrAddress)
  2059. ));
  2060. *pSegment = HIWORD(pXecb->EcbAddress);
  2061. *pOffset = LOWORD(pXecb->EcbAddress);
  2062. pXecb->Ecb->LinkAddress = NULL;
  2063. pXecb->Ecb->InUse = ECB_IU_NOT_IN_USE;
  2064. *pFlags = (BYTE)((pXecb->Flags & XECB_FLAG_IPX) ? ECB_TYPE_IPX : ECB_TYPE_AES);
  2065. DeallocateXecb(pXecb);
  2066. setCF(0);
  2067. } else {
  2068. setCF(1);
  2069. }
  2070. }
  2071. VOID
  2072. FifoAddHead(
  2073. IN LPFIFO pFifo,
  2074. IN LPFIFO pElement
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. Adds an element to the head of a (single-linked) FIFO list
  2079. Arguments:
  2080. pFifo - pointer to FIFO structure
  2081. pElement - pointer to (FIFO) element to add to list
  2082. Return Value:
  2083. None.
  2084. --*/
  2085. {
  2086. if (!pFifo->Head) {
  2087. pFifo->Head = pFifo->Tail = pElement;
  2088. pElement->Head = NULL;
  2089. } else {
  2090. pElement->Head = pFifo->Head;
  2091. pFifo->Head = pElement;
  2092. }
  2093. }
  2094. VOID
  2095. FifoAdd(
  2096. IN LPFIFO pFifo,
  2097. IN LPFIFO pElement
  2098. )
  2099. /*++
  2100. Routine Description:
  2101. Adds an element to the tail of a (single-linked) FIFO list
  2102. Arguments:
  2103. pFifo - pointer to FIFO structure
  2104. pElement - pointer to (FIFO) element to add to list
  2105. Return Value:
  2106. None.
  2107. --*/
  2108. {
  2109. if (!pFifo->Head) {
  2110. pFifo->Head = pFifo->Tail = pElement;
  2111. } else {
  2112. ((LPFIFO)pFifo->Tail)->Head = pElement;
  2113. }
  2114. pFifo->Tail = pElement;
  2115. pElement->Head = NULL;
  2116. }
  2117. LPFIFO
  2118. FifoRemove(
  2119. IN LPFIFO pFifo,
  2120. IN LPFIFO pElement
  2121. )
  2122. /*++
  2123. Routine Description:
  2124. Removes an element from a (single-linked) FIFO list
  2125. Arguments:
  2126. pFifo - pointer to FIFO structure
  2127. pElement - pointer to (FIFO) element to remove (single-linked)
  2128. Return Value:
  2129. PFIFO
  2130. NULL - pElement not on list
  2131. !NULL - pElement removed from list
  2132. --*/
  2133. {
  2134. LPFIFO p;
  2135. LPFIFO prev = (LPFIFO)pFifo;
  2136. p = (LPFIFO)pFifo->Head;
  2137. while (p && (p != pElement)) {
  2138. prev = p;
  2139. p = p->Head;
  2140. }
  2141. if (p) {
  2142. prev->Head = p->Head;
  2143. if (pFifo->Head == NULL) {
  2144. pFifo->Tail = NULL;
  2145. } else if (pFifo->Tail == p) {
  2146. pFifo->Tail = prev;
  2147. }
  2148. }
  2149. return p;
  2150. }
  2151. LPFIFO
  2152. FifoNext(
  2153. IN LPFIFO pFifo
  2154. )
  2155. /*++
  2156. Routine Description:
  2157. Remove element at head of FIFO queue
  2158. Arguments:
  2159. pFifo - pointer to FIFO
  2160. Return Value:
  2161. LPFIFO
  2162. NULL - nothing on queue
  2163. !NULL - removed element
  2164. --*/
  2165. {
  2166. LPFIFO p;
  2167. LPFIFO prev = (LPFIFO)pFifo;
  2168. p = (LPFIFO)pFifo->Head;
  2169. if (p) {
  2170. pFifo->Head = p->Head;
  2171. if (!pFifo->Head) {
  2172. pFifo->Tail = NULL;
  2173. }
  2174. }
  2175. return p;
  2176. }