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.

875 lines
26 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-2000 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //** DGRAM.C - Common datagram protocol code.
  7. //
  8. // This file contains the code common to both UDP and Raw IP.
  9. //
  10. #include "precomp.h"
  11. #include "tdint.h"
  12. #include "addr.h"
  13. #include "dgram.h"
  14. #include "tlcommon.h"
  15. #include "info.h"
  16. #include "mdlpool.h"
  17. #include "pplasl.h"
  18. #define NO_TCP_DEFS 1
  19. #include "tcpdeb.h"
  20. extern HANDLE TcpRequestPool;
  21. CACHE_LINE_KSPIN_LOCK DGQueueLock;
  22. USHORT DGHeaderBufferSize;
  23. // Information for maintaining the DG Header structures and
  24. // pending queue.
  25. Queue DGHeaderPending;
  26. Queue DGDelayed;
  27. CTEEvent DGDelayedEvent;
  28. extern IPInfo LocalNetInfo;
  29. #include "tcp.h"
  30. #include "udp.h"
  31. HANDLE DgHeaderPool;
  32. //
  33. // All of the init code can be discarded.
  34. //
  35. #ifdef ALLOC_PRAGMA
  36. int InitDG(uint MaxHeaderSize);
  37. #pragma alloc_text(INIT, InitDG)
  38. #endif
  39. //* GetDGHeader - Get a DG header buffer.
  40. //
  41. // The get header buffer routine. Called with the SendReqLock held.
  42. //
  43. // Input: Nothing.
  44. //
  45. // Output: A pointer to an NDIS buffer, or NULL.
  46. //
  47. __inline
  48. PNDIS_BUFFER
  49. GetDGHeaderAtDpcLevel(UDPHeader **Header)
  50. {
  51. PNDIS_BUFFER Buffer;
  52. Buffer = MdpAllocateAtDpcLevel(DgHeaderPool, Header);
  53. if (Buffer) {
  54. ASSERT(*Header);
  55. #if BACK_FILL
  56. ASSERT(Buffer->ByteOffset >= 40);
  57. (ULONG_PTR)(*Header) += MAX_BACKFILL_HDR_SIZE;
  58. (ULONG_PTR)Buffer->MappedSystemVa += MAX_BACKFILL_HDR_SIZE;
  59. Buffer->ByteOffset += MAX_BACKFILL_HDR_SIZE;
  60. Buffer->MdlFlags |= MDL_NETWORK_HEADER;
  61. #endif
  62. }
  63. return Buffer;
  64. }
  65. PNDIS_BUFFER
  66. GetDGHeader(UDPHeader **Header)
  67. {
  68. #if MILLEN
  69. return GetDGHeaderAtDpcLevel(Header);
  70. #else
  71. KIRQL OldIrql;
  72. PNDIS_BUFFER Buffer;
  73. OldIrql = KeRaiseIrqlToDpcLevel();
  74. Buffer = GetDGHeaderAtDpcLevel(Header);
  75. KeLowerIrql(OldIrql);
  76. return Buffer;
  77. #endif
  78. }
  79. //* FreeDGHeader - Free a DG header buffer.
  80. //
  81. // The free header buffer routine. Called with the SendReqLock held.
  82. //
  83. // Input: Buffer to be freed.
  84. //
  85. // Output: Nothing.
  86. //
  87. __inline
  88. VOID
  89. FreeDGHeader(PNDIS_BUFFER FreedBuffer)
  90. {
  91. NdisAdjustBufferLength(FreedBuffer, DGHeaderBufferSize);
  92. #if BACK_FILL
  93. (ULONG_PTR)FreedBuffer->MappedSystemVa -= MAX_BACKFILL_HDR_SIZE;
  94. FreedBuffer->ByteOffset -= MAX_BACKFILL_HDR_SIZE;
  95. #endif
  96. MdpFree(FreedBuffer);
  97. }
  98. //* PutPendingQ - Put an address object on the pending queue.
  99. //
  100. // Called when we've experienced a header buffer out of resources condition,
  101. // and want to queue an AddrObj for later processing. We put the specified
  102. // address object on the DGHeaderPending queue, set the OOR flag and clear
  103. // the 'send request' flag. It is invariant in the system that the send
  104. // request flag and the OOR flag are not set at the same time.
  105. //
  106. // This routine assumes that the caller holds QueueingAO->ao_lock.
  107. //
  108. // Input: QueueingAO - Pointer to address object to be queued.
  109. //
  110. // Returns: Nothing.
  111. //
  112. void
  113. PutPendingQ(AddrObj * QueueingAO)
  114. {
  115. CTEStructAssert(QueueingAO, ao);
  116. if (!AO_OOR(QueueingAO)) {
  117. CLEAR_AO_REQUEST(QueueingAO, AO_SEND);
  118. SET_AO_OOR(QueueingAO);
  119. InterlockedEnqueueAtDpcLevel(&DGHeaderPending,
  120. &QueueingAO->ao_pendq,
  121. &DGQueueLock.Lock);
  122. }
  123. }
  124. //* GetDGSendReq - Get a DG send request.
  125. //
  126. // Called when someone wants to allocate a DG send request. We assume
  127. // the send request lock is held when we are called.
  128. //
  129. // Note: This routine and the corresponding free routine might
  130. // be good candidates for inlining.
  131. //
  132. // Input: Nothing.
  133. //
  134. // Returns: Pointer to the SendReq, or NULL if none.
  135. //
  136. __inline
  137. DGSendReq *
  138. GetDGSendReq()
  139. {
  140. DGSendReq *Request;
  141. LOGICAL FromList;
  142. Request = PplAllocate(TcpRequestPool, &FromList);
  143. if (Request != NULL) {
  144. #if DBG
  145. Request->dsr_sig = dsr_signature;
  146. #endif
  147. }
  148. return Request;
  149. }
  150. //* FreeDGSendReq - Free a DG send request.
  151. //
  152. // Called when someone wants to free a DG send request. It's assumed
  153. // that the caller holds the SendRequest lock.
  154. //
  155. // Input: SendReq - SendReq to be freed.
  156. //
  157. // Returns: Nothing.
  158. //
  159. __inline
  160. VOID
  161. FreeDGSendReq(DGSendReq *Request)
  162. {
  163. CTEStructAssert(Request, dsr);
  164. PplFree(TcpRequestPool, Request);
  165. }
  166. //* GetDGRcvReq - Get a DG receive request.
  167. //
  168. // Called when we need to get a DG receive request.
  169. //
  170. // Input: Nothing.
  171. //
  172. // Returns: Pointer to new request, or NULL if none.
  173. //
  174. __inline
  175. DGRcvReq *
  176. GetDGRcvReq()
  177. {
  178. DGRcvReq *Request;
  179. Request = ExAllocatePoolWithTag(NonPagedPool, sizeof(DGRcvReq), 'dPCT');
  180. #if DBG
  181. Request->drr_sig = drr_signature;
  182. #endif
  183. return Request;
  184. }
  185. //* FreeDGRcvReq - Free a DG rcv request.
  186. //
  187. // Called when someone wants to free a DG rcv request.
  188. //
  189. // Input: RcvReq - RcvReq to be freed.
  190. //
  191. // Returns: Nothing.
  192. //
  193. __inline
  194. VOID
  195. FreeDGRcvReq(DGRcvReq *Request)
  196. {
  197. CTEStructAssert(Request, drr);
  198. ExFreePool(Request);
  199. }
  200. //* DGDelayedEventProc - Handle a delayed event.
  201. //
  202. // This is the delayed event handler, used for out-of-resources conditions
  203. // on AddrObjs. We pull from the delayed queue, and is the addr obj is
  204. // not already busy we'll send the datagram.
  205. //
  206. // Input: Event - Pointer to the event structure.
  207. // Context - Nothing.
  208. //
  209. // Returns: Nothing
  210. //
  211. void
  212. DGDelayedEventProc(CTEEvent *Event, void *Context)
  213. {
  214. Queue* Item;
  215. AddrObj *SendingAO;
  216. DGSendProc SendProc;
  217. CTELockHandle AOHandle;
  218. while ((Item = InterlockedDequeueIfNotEmpty(&DGDelayed,
  219. &DGQueueLock.Lock)) != NULL) {
  220. SendingAO = STRUCT_OF(AddrObj, Item, ao_pendq);
  221. CTEStructAssert(SendingAO, ao);
  222. CTEGetLock(&SendingAO->ao_lock, &AOHandle);
  223. CLEAR_AO_OOR(SendingAO);
  224. if (!AO_BUSY(SendingAO)) {
  225. DGSendReq *SendReq;
  226. if (!EMPTYQ(&SendingAO->ao_sendq)) {
  227. DEQUEUE(&SendingAO->ao_sendq, SendReq, DGSendReq, dsr_q);
  228. CTEStructAssert(SendReq, dsr);
  229. ASSERT(SendReq->dsr_header != NULL);
  230. SendingAO->ao_usecnt++;
  231. SendProc = SendingAO->ao_dgsend;
  232. CTEFreeLock(&SendingAO->ao_lock, AOHandle);
  233. (*SendProc) (SendingAO, SendReq);
  234. DEREF_AO(SendingAO);
  235. } else {
  236. ASSERT(FALSE);
  237. CTEFreeLock(&SendingAO->ao_lock, AOHandle);
  238. }
  239. } else {
  240. SET_AO_REQUEST(SendingAO, AO_SEND);
  241. CTEFreeLock(&SendingAO->ao_lock, AOHandle);
  242. }
  243. }
  244. }
  245. //* DGSendComplete - DG send complete handler.
  246. //
  247. // This is the routine called by IP when a send completes. We
  248. // take the context passed back as a pointer to a SendRequest
  249. // structure, and complete the caller's send.
  250. //
  251. // Input: Context - Context we gave on send (really a
  252. // SendRequest structure).
  253. // BufferChain - Chain of buffers sent.
  254. //
  255. // Returns: Nothing.
  256. void
  257. DGSendComplete(void *Context, PNDIS_BUFFER BufferChain, IP_STATUS SendStatus)
  258. {
  259. DGSendReq *FinishedSR = (DGSendReq *) Context;
  260. CTELockHandle AOHandle;
  261. CTEReqCmpltRtn Callback; // Completion routine.
  262. PVOID CallbackContext; // User context.
  263. ushort SentSize;
  264. AddrObj *AO;
  265. Queue* Item;
  266. #if TRACE_EVENT
  267. PTDI_DATA_REQUEST_NOTIFY_ROUTINE CPCallBack;
  268. WMIData WMIInfo;
  269. #endif
  270. CTEStructAssert(FinishedSR, dsr);
  271. Callback = FinishedSR->dsr_rtn;
  272. CallbackContext = FinishedSR->dsr_context;
  273. SentSize = FinishedSR->dsr_size;
  274. // If there's nothing on the header pending queue, just free the
  275. // header buffer. Otherwise pull from the pending queue, give him the
  276. // resource, and schedule an event to deal with him.
  277. Item = InterlockedDequeueIfNotEmpty(&DGHeaderPending, &DGQueueLock.Lock);
  278. if (!Item) {
  279. FreeDGHeader(BufferChain);
  280. } else {
  281. AO = STRUCT_OF(AddrObj, Item, ao_pendq);
  282. CTEStructAssert(AO, ao);
  283. CTEGetLock(&AO->ao_lock, &AOHandle);
  284. if (!EMPTYQ(&AO->ao_sendq)) {
  285. DGSendReq *SendReq;
  286. PEEKQ(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
  287. if (!SendReq->dsr_header) {
  288. SendReq->dsr_header = BufferChain; // Give him this buffer.
  289. InterlockedEnqueueAtDpcLevel(&DGDelayed,
  290. &AO->ao_pendq,
  291. &DGQueueLock.Lock);
  292. CTEFreeLock(&AO->ao_lock, AOHandle);
  293. CTEScheduleEvent(&DGDelayedEvent, NULL);
  294. } else {
  295. CLEAR_AO_OOR(AO);
  296. CTEFreeLock(&AO->ao_lock, AOHandle);
  297. FreeDGHeader(BufferChain);
  298. }
  299. } else {
  300. // On the pending queue, but no sends!
  301. ASSERT(0);
  302. CLEAR_AO_OOR(AO);
  303. CTEFreeLock(&AO->ao_lock, AOHandle);
  304. }
  305. }
  306. #if TRACE_EVENT
  307. if (!(SendStatus == IP_GENERAL_FAILURE)) {
  308. WMIInfo.wmi_destaddr = FinishedSR->dsr_addr;
  309. WMIInfo.wmi_destport = FinishedSR->dsr_port;
  310. WMIInfo.wmi_srcaddr = FinishedSR->dsr_srcaddr;
  311. WMIInfo.wmi_srcport = FinishedSR->dsr_srcport;
  312. WMIInfo.wmi_context = FinishedSR->dsr_pid;
  313. WMIInfo.wmi_size = SentSize;
  314. CPCallBack = TCPCPHandlerRoutine;
  315. if (CPCallBack!=NULL) {
  316. ulong GroupType;
  317. GroupType = EVENT_TRACE_GROUP_UDPIP + EVENT_TRACE_TYPE_SEND ;
  318. (*CPCallBack)(GroupType, (PVOID)&WMIInfo, sizeof(WMIInfo), NULL);
  319. }
  320. }
  321. #endif
  322. FreeDGSendReq(FinishedSR);
  323. if (Callback != NULL) {
  324. if (SendStatus == IP_GENERAL_FAILURE)
  325. (*Callback) (CallbackContext, TDI_REQ_ABORTED, (uint) SentSize);
  326. else if (SendStatus == IP_PACKET_TOO_BIG)
  327. (*Callback) (CallbackContext, TDI_BUFFER_TOO_BIG, (uint) SentSize);
  328. else
  329. (*Callback) (CallbackContext, TDI_SUCCESS, (uint) SentSize);
  330. }
  331. }
  332. //
  333. // NT supports cancellation of DG send/receive requests.
  334. //
  335. #define TCP_DEBUG_SEND_DGRAM 0x00000100
  336. #define TCP_DEBUG_RECEIVE_DGRAM 0x00000200
  337. extern ULONG TCPDebug;
  338. VOID
  339. TdiCancelSendDatagram(
  340. AddrObj * SrcAO,
  341. PVOID Context,
  342. CTELockHandle inHandle
  343. )
  344. {
  345. CTELockHandle lockHandle;
  346. DGSendReq *sendReq = NULL;
  347. Queue *qentry;
  348. BOOLEAN found = FALSE;
  349. PTCP_CONTEXT tcpContext;
  350. PIO_STACK_LOCATION irpSp;
  351. VOID *CancelContext, *CancelID;
  352. PIRP Irp = Context;
  353. irpSp = IoGetCurrentIrpStackLocation(Irp);
  354. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  355. CTEStructAssert(SrcAO, ao);
  356. CTEGetLock(&SrcAO->ao_lock, &lockHandle);
  357. // Search the send list for the specified request.
  358. for (qentry = QNEXT(&(SrcAO->ao_sendq));
  359. qentry != &(SrcAO->ao_sendq);
  360. qentry = QNEXT(qentry)
  361. ) {
  362. sendReq = STRUCT_OF(DGSendReq, qentry, dsr_q);
  363. CTEStructAssert(sendReq, dsr);
  364. if (sendReq->dsr_context == Context) {
  365. //
  366. // Found it. Dequeue
  367. //
  368. REMOVEQ(qentry);
  369. found = TRUE;
  370. IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
  371. TCPTRACE((
  372. "TdiCancelSendDatagram: Dequeued item %lx\n",
  373. Context
  374. ));
  375. }
  376. break;
  377. }
  378. }
  379. CTEFreeLock(&SrcAO->ao_lock, lockHandle);
  380. CancelContext = Irp->Tail.Overlay.DriverContext[0];
  381. CancelID = Irp->Tail.Overlay.DriverContext[1];
  382. CTEFreeLock(&tcpContext->EndpointLock, inHandle);
  383. if (found) {
  384. //
  385. // Complete the request and free its resources.
  386. //
  387. (*sendReq->dsr_rtn) (sendReq->dsr_context, (uint) TDI_CANCELLED, 0);
  388. if (sendReq->dsr_header != NULL) {
  389. FreeDGHeader(sendReq->dsr_header);
  390. }
  391. FreeDGSendReq(sendReq);
  392. } else {
  393. //Now try calling ndis cancel routine to complete queued up packets
  394. //for this request
  395. (*LocalNetInfo.ipi_cancelpackets) (CancelContext, CancelID);
  396. }
  397. } // TdiCancelSendDatagram
  398. VOID
  399. TdiCancelReceiveDatagram(
  400. AddrObj * SrcAO,
  401. PVOID Context,
  402. CTELockHandle inHandle
  403. )
  404. {
  405. CTELockHandle lockHandle;
  406. DGRcvReq *rcvReq = NULL;
  407. Queue *qentry;
  408. BOOLEAN found = FALSE;
  409. PTCP_CONTEXT tcpContext;
  410. PIO_STACK_LOCATION irpSp;
  411. PIRP Irp = Context;
  412. irpSp = IoGetCurrentIrpStackLocation(Irp);
  413. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  414. CTEStructAssert(SrcAO, ao);
  415. CTEGetLock(&SrcAO->ao_lock, &lockHandle);
  416. // Search the send list for the specified request.
  417. for (qentry = QNEXT(&(SrcAO->ao_rcvq));
  418. qentry != &(SrcAO->ao_rcvq);
  419. qentry = QNEXT(qentry)
  420. ) {
  421. rcvReq = STRUCT_OF(DGRcvReq, qentry, drr_q);
  422. CTEStructAssert(rcvReq, drr);
  423. if (rcvReq->drr_context == Context) {
  424. //
  425. // Found it. Dequeue
  426. //
  427. REMOVEQ(qentry);
  428. found = TRUE;
  429. IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
  430. TCPTRACE((
  431. "TdiCancelReceiveDatagram: Dequeued item %lx\n",
  432. Context
  433. ));
  434. }
  435. break;
  436. }
  437. }
  438. CTEFreeLock(&SrcAO->ao_lock, lockHandle);
  439. CTEFreeLock(&tcpContext->EndpointLock, inHandle);
  440. if (found) {
  441. //
  442. // Complete the request and free its resources.
  443. //
  444. (*rcvReq->drr_rtn) (rcvReq->drr_context, (uint) TDI_CANCELLED, 0);
  445. FreeDGRcvReq(rcvReq);
  446. }
  447. } // TdiCancelReceiveDatagram
  448. //** TdiSendDatagram - TDI send datagram function.
  449. //
  450. // This is the user interface to the send datagram function. The
  451. // caller specified a request structure, a connection info
  452. // structure containing the address, and data to be sent.
  453. // This routine gets a DG Send request structure to manage the
  454. // send, fills the structure in, and calls DGSend to deal with
  455. // it.
  456. //
  457. // Input: Request - Pointer to request structure.
  458. // ConnInfo - Pointer to ConnInfo structure which points to
  459. // remote address.
  460. // DataSize - Size in bytes of data to be sent.
  461. // BytesSent - Pointer to where to return size sent.
  462. // Buffer - Pointer to buffer chain.
  463. //
  464. // Returns: Status of attempt to send.
  465. //
  466. TDI_STATUS
  467. TdiSendDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo1,
  468. uint DataSize, uint * BytesSent, PNDIS_BUFFER Buffer)
  469. {
  470. AddrObj *SrcAO; // Pointer to AddrObj for src.
  471. DGSendReq *SendReq; // Pointer to send req for this request.
  472. CTELockHandle Handle;
  473. TDI_STATUS ReturnValue = TDI_ADDR_INVALID;
  474. DGSendProc SendProc;
  475. PTDI_CONNECTION_INFORMATION ConnInfo;
  476. // First, get a send request. We do this first because of MP issues
  477. // if we port this to NT. We need to take the SendRequest lock before
  478. // we take the AddrObj lock, to prevent deadlock and also because
  479. // GetDGSendReq might yield, and the state of the AddrObj might
  480. // change on us, so we don't want to yield after we've validated
  481. // it.
  482. SendReq = GetDGSendReq();
  483. // Now get the lock on the AO, and make sure it's valid. We do this
  484. // to make sure we return the correct error code.
  485. SrcAO = Request->Handle.AddressHandle;
  486. if (SrcAO != NULL) {
  487. CTEStructAssert(SrcAO, ao);
  488. CTEGetLock(&SrcAO->ao_lock, &Handle);
  489. if (AO_VALID(SrcAO)) {
  490. ConnInfo = ConnInfo1;
  491. if ((ConnInfo1 == NULL) && AO_CONNUDP(SrcAO)) {
  492. ConnInfo = &SrcAO->ao_udpconn;
  493. }
  494. // Make sure the size is reasonable.
  495. if (DataSize <= SrcAO->ao_maxdgsize) {
  496. // The AddrObj is valid. Now fill the address into the send request,
  497. // if we've got one. If this works, we'll continue with the
  498. // send.
  499. if (SendReq != NULL) { // Got a send request.
  500. if (ConnInfo && GetAddress(ConnInfo->RemoteAddress, &SendReq->dsr_addr,
  501. &SendReq->dsr_port)) {
  502. SendReq->dsr_rtn = Request->RequestNotifyObject;
  503. SendReq->dsr_context = Request->RequestContext;
  504. SendReq->dsr_buffer = Buffer;
  505. SendReq->dsr_size = (ushort) DataSize;
  506. // We've filled in the send request. If the AO isn't
  507. // already busy, try to get a DG header buffer and send
  508. // this. If the AO is busy, or we can't get a buffer, queue
  509. // until later. We try to get the header buffer here, as
  510. // an optimazation to avoid having to retake the lock.
  511. if (!AO_OOR(SrcAO)) { // AO isn't out of resources
  512. if (!AO_BUSY(SrcAO)) { // or or busy
  513. UDPHeader *UH;
  514. SendReq->dsr_header = GetDGHeaderAtDpcLevel(&UH);
  515. if (SendReq->dsr_header != NULL) {
  516. REF_AO(SrcAO); // Lock out exclusive
  517. // activities.
  518. SendProc = SrcAO->ao_dgsend;
  519. CTEFreeLock(&SrcAO->ao_lock, Handle);
  520. // Allright, just send it.
  521. (*SendProc) (SrcAO, SendReq);
  522. // See if any pending requests occured during
  523. // the send. If so, call the request handler.
  524. DEREF_AO(SrcAO);
  525. return TDI_PENDING;
  526. } else {
  527. // We couldn't get a header buffer. Put this
  528. // guy on the pending queue, and then fall
  529. // through to the 'queue request' code.
  530. PutPendingQ(SrcAO);
  531. }
  532. } else {
  533. // AO is busy, set request for later
  534. SET_AO_REQUEST(SrcAO, AO_SEND);
  535. }
  536. }
  537. // AO is busy, or out of resources. Queue the send request
  538. // for later.
  539. SendReq->dsr_header = NULL;
  540. ENQUEUE(&SrcAO->ao_sendq, &SendReq->dsr_q);
  541. CTEFreeLock(&SrcAO->ao_lock, Handle);
  542. return TDI_PENDING;
  543. } else {
  544. // The remote address was invalid.
  545. ReturnValue = TDI_BAD_ADDR;
  546. }
  547. } else {
  548. // Send request was null, return no resources.
  549. ReturnValue = TDI_NO_RESOURCES;
  550. }
  551. } else {
  552. // Buffer was too big, return an error.
  553. ReturnValue = TDI_BUFFER_TOO_BIG;
  554. }
  555. } else {
  556. // The addr object is invalid, possibly because it's deleting.
  557. ReturnValue = TDI_ADDR_INVALID;
  558. }
  559. CTEFreeLock(&SrcAO->ao_lock, Handle);
  560. }
  561. if (SendReq != NULL)
  562. FreeDGSendReq(SendReq);
  563. return ReturnValue;
  564. }
  565. //** TdiReceiveDatagram - TDI receive datagram function.
  566. //
  567. // This is the user interface to the receive datagram function. The
  568. // caller specifies a request structure, a connection info
  569. // structure that acts as a filter on acceptable datagrams, a connection
  570. // info structure to be filled in, and other parameters. We get a DGRcvReq
  571. // structure, fill it in, and hang it on the AddrObj, where it will be removed
  572. // later by incomig datagram handler.
  573. //
  574. // Input: Request - Pointer to request structure.
  575. // ConnInfo - Pointer to ConnInfo structure which points to
  576. // remote address.
  577. // ReturnInfo - Pointer to ConnInfo structure to be filled in.
  578. // RcvSize - Total size in bytes receive buffer.
  579. // BytesRcvd - Pointer to where to return size received.
  580. // Buffer - Pointer to buffer chain.
  581. //
  582. // Returns: Status of attempt to receive.
  583. //
  584. TDI_STATUS
  585. TdiReceiveDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo,
  586. PTDI_CONNECTION_INFORMATION ReturnInfo, uint RcvSize, uint * BytesRcvd,
  587. PNDIS_BUFFER Buffer)
  588. {
  589. AddrObj *RcvAO; // AddrObj that is receiving.
  590. DGRcvReq *RcvReq; // Receive request structure.
  591. CTELockHandle AOHandle;
  592. uchar AddrValid;
  593. RcvReq = GetDGRcvReq();
  594. RcvAO = Request->Handle.AddressHandle;
  595. CTEStructAssert(RcvAO, ao);
  596. CTEGetLock(&RcvAO->ao_lock, &AOHandle);
  597. if (AO_VALID(RcvAO)) {
  598. IF_TCPDBG(TCP_DEBUG_RAW) {
  599. TCPTRACE(("posting receive on AO %lx\n", RcvAO));
  600. }
  601. if (RcvReq != NULL) {
  602. if (ConnInfo != NULL && ConnInfo->RemoteAddressLength != 0)
  603. AddrValid = GetAddress(ConnInfo->RemoteAddress,
  604. &RcvReq->drr_addr, &RcvReq->drr_port);
  605. else {
  606. AddrValid = TRUE;
  607. RcvReq->drr_addr = NULL_IP_ADDR;
  608. RcvReq->drr_port = 0;
  609. }
  610. if (AddrValid) {
  611. // Everything'd valid. Fill in the receive request and queue it.
  612. RcvReq->drr_conninfo = ReturnInfo;
  613. RcvReq->drr_rtn = Request->RequestNotifyObject;
  614. RcvReq->drr_context = Request->RequestContext;
  615. RcvReq->drr_buffer = Buffer;
  616. RcvReq->drr_size = (ushort) RcvSize;
  617. ENQUEUE(&RcvAO->ao_rcvq, &RcvReq->drr_q);
  618. CTEFreeLock(&RcvAO->ao_lock, AOHandle);
  619. return TDI_PENDING;
  620. } else {
  621. // Have an invalid filter address.
  622. CTEFreeLock(&RcvAO->ao_lock, AOHandle);
  623. FreeDGRcvReq(RcvReq);
  624. return TDI_BAD_ADDR;
  625. }
  626. } else {
  627. // Couldn't get a receive request.
  628. CTEFreeLock(&RcvAO->ao_lock, AOHandle);
  629. return TDI_NO_RESOURCES;
  630. }
  631. } else {
  632. // The AddrObj isn't valid.
  633. CTEFreeLock(&RcvAO->ao_lock, AOHandle);
  634. }
  635. // The AddrObj is invalid or non-existent.
  636. if (RcvReq != NULL)
  637. FreeDGRcvReq(RcvReq);
  638. return TDI_ADDR_INVALID;
  639. }
  640. //* DGFillIpPktInfo - Create an ancillary data object and fill in
  641. // IP_PKTINFO information.
  642. //
  643. // This is a helper function for the IP_PKTINFO socket option supported for
  644. // datagram sockets only. The caller provides the destination address as
  645. // specified in the IP header of the packet and the IP address of the local
  646. // interface the packet was delivered on. This routine will create the
  647. // proper ancillary data object and fill in the destination IP address
  648. // and the interface number of the local interface. The data object must
  649. // be freed by the caller.
  650. //
  651. // Input: DestAddr - Destination address from IP header of packet.
  652. // LocalAddr - IP address of local interface on which packet
  653. // arrived.
  654. // Size - Buffer that will be filled in with size in bytes
  655. // of the ancillary data object.
  656. //
  657. // Returns: NULL if unsuccessful, an ancillary data object for IP_PKTINFO
  658. // if successful.
  659. //
  660. PTDI_CMSGHDR
  661. DGFillIpPktInfo(IPAddr DestAddr, IPAddr LocalAddr, int *Size)
  662. {
  663. PTDI_CMSGHDR CmsgHdr;
  664. *Size = TDI_CMSG_SPACE(sizeof(IN_PKTINFO));
  665. CmsgHdr = ExAllocatePoolWithTag(NonPagedPool, *Size, 'uPCT');
  666. if (CmsgHdr) {
  667. IN_PKTINFO *pktinfo = (IN_PKTINFO*)TDI_CMSG_DATA(CmsgHdr);
  668. // Fill in the ancillary data object header information.
  669. TDI_INIT_CMSGHDR(CmsgHdr, IPPROTO_IP, IP_PKTINFO, sizeof(IN_PKTINFO));
  670. pktinfo->ipi_addr = DestAddr;
  671. // Get the index of the local interface on which the packet arrived.
  672. pktinfo->ipi_ifindex =
  673. (*LocalNetInfo.ipi_getifindexfromaddr) (LocalAddr,IF_CHECK_NONE);
  674. } else {
  675. *Size = 0;
  676. }
  677. return CmsgHdr;
  678. }
  679. #pragma BEGIN_INIT
  680. //* InitDG - Initialize the DG stuff.
  681. //
  682. // Called during init time to initalize the DG code. We initialize
  683. // our locks and request lists.
  684. //
  685. // Input: MaxHeaderSize - The maximum size of a datagram transport header,
  686. // not including the IP header.
  687. //
  688. // Returns: True if we succeed, False if we fail.
  689. //
  690. int
  691. InitDG(uint MaxHeaderSize)
  692. {
  693. CTEInitLock(&DGQueueLock.Lock);
  694. DGHeaderBufferSize = (USHORT)(MaxHeaderSize + LocalNetInfo.ipi_hsize);
  695. #if BACK_FILL
  696. DGHeaderBufferSize += MAX_BACKFILL_HDR_SIZE;
  697. #endif
  698. DgHeaderPool = MdpCreatePool (
  699. DGHeaderBufferSize,
  700. 'uhCT');
  701. if (!DgHeaderPool)
  702. {
  703. return FALSE;
  704. }
  705. INITQ(&DGHeaderPending);
  706. INITQ(&DGDelayed);
  707. CTEInitEvent(&DGDelayedEvent, DGDelayedEventProc);
  708. return TRUE;
  709. }
  710. #pragma END_INIT