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.

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