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.

716 lines
18 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. pppread.c
  5. Abstract:
  6. Author:
  7. Thomas J. Dimitri (TommyD) 08-May-1992
  8. Environment:
  9. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  10. Revision History:
  11. --*/
  12. #include "asyncall.h"
  13. NTSTATUS
  14. AsyncSLIPCompletionRoutine(
  15. IN PDEVICE_OBJECT DeviceObject,
  16. IN PIRP Irp,
  17. IN PVOID Context);
  18. NTSTATUS
  19. AsyncWaitMaskCompletionRoutine(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PIRP Irp,
  22. IN PVOID Context);
  23. NTSTATUS
  24. AsyncPPPWaitMask(
  25. IN PASYNC_INFO Info)
  26. /*++
  27. Assumption -- 0 length frames are not sent (this includes headers)!!!
  28. Also, this is NOT a synchronous operation. It is always asynchronous.
  29. Routine Description:
  30. This service writes Length bytes of data from the caller's Buffer to the
  31. "port" handle. It is assumed that the handle uses non-buffered IO.
  32. --*/
  33. {
  34. NTSTATUS status;
  35. PIRP irp;
  36. PASYNC_FRAME pFrame;
  37. PASYNC_ADAPTER pAdapter=Info->Adapter;
  38. pFrame=Info->AsyncFrame;
  39. irp =
  40. IoAllocateIrp(Info->DeviceObject->StackSize, (BOOLEAN)FALSE);
  41. InitSerialIrp(irp,
  42. Info,
  43. IOCTL_SERIAL_WAIT_ON_MASK,
  44. sizeof(ULONG));
  45. irp->AssociatedIrp.SystemBuffer=&pFrame->WaitMask;
  46. IoSetCompletionRoutine(
  47. irp, // irp to use
  48. AsyncWaitMaskCompletionRoutine, // routine to call when irp is done
  49. Info, // context to pass routine
  50. TRUE, // call on success
  51. TRUE, // call on error
  52. TRUE); // call on cancel
  53. //
  54. // Now simply invoke the driver at its dispatch entry with the IRP.
  55. //
  56. status = IoCallDriver(Info->DeviceObject, irp);
  57. //
  58. // Status for a local serial driver should be
  59. // STATUS_SUCCESS since the irp should complete
  60. // immediately because there are no read timeouts.
  61. //
  62. // For a remote serial driver, it will pend.
  63. //
  64. return(status);
  65. }
  66. NTSTATUS
  67. AsyncPPPCompletionRoutine(
  68. IN PDEVICE_OBJECT DeviceObject,
  69. IN PIRP Irp,
  70. IN PVOID Context)
  71. /*++
  72. This is the IO Completion routine for ReadFrame.
  73. --*/
  74. {
  75. NTSTATUS status;
  76. PASYNC_INFO pInfo;
  77. ULONG bytesReceived;
  78. PASYNC_FRAME pFrame;
  79. PUCHAR frameStart, frameEnd;
  80. USHORT crcData;
  81. PUCHAR frameEnd2,frameStart2;
  82. ULONG bitMask;
  83. LONG bytesWanted;
  84. DeviceObject; // prevent compiler warnings
  85. status = Irp->IoStatus.Status;
  86. bytesReceived=(ULONG)Irp->IoStatus.Information;
  87. IoFreeIrp(Irp);
  88. pInfo=Context;
  89. pFrame=pInfo->AsyncFrame;
  90. switch (status) {
  91. case STATUS_SUCCESS:
  92. pFrame=pInfo->AsyncFrame;
  93. //
  94. // Any bytes to process? This can happen if
  95. // the WaitMask completes late and by the time
  96. // we process the read, another event character has come
  97. // in.
  98. //
  99. if (bytesReceived==0) {
  100. break;
  101. }
  102. //
  103. // Update num of bytes read total for this frame
  104. //
  105. pInfo->BytesRead = bytesReceived = pInfo->BytesRead + bytesReceived;
  106. //
  107. // Set frameEnd to last byte processed. Initially,
  108. // we have processed nothing (i.e. processed up to
  109. // the start of the first byte).
  110. //
  111. frameStart=pFrame->Frame + PPP_PADDING;
  112. PROCESS_FRAME:
  113. //
  114. // Now we have actuallyRead bytes unused
  115. // Also, we may have a complete frame.
  116. //
  117. while (*frameStart == PPP_FLAG_BYTE && --bytesReceived) {
  118. frameStart++;
  119. }
  120. //
  121. // If we reach here, there is only a start FLAG...
  122. //
  123. if (bytesReceived == 0) {
  124. break;
  125. }
  126. //
  127. // frameEnd is set to the first byte not yet processed.
  128. // If we are starting out, that is the first byte!
  129. //
  130. frameEnd=frameStart;
  131. //
  132. // Assume the start of the frame has the PPP_FLAG_BYTE
  133. // Look for the second PPP_FLAG_BYTE (end of frame)
  134. //
  135. while (*frameEnd != PPP_FLAG_BYTE && --bytesReceived) {
  136. frameEnd++;
  137. }
  138. //
  139. // At this point...
  140. // frameStart = beginning PPP_FLAG_BYTE seen
  141. // frameEnd = end PPP_FLAG_BYTE
  142. // bytesReceived = bytes after frameEnd not processed
  143. //
  144. //
  145. // if bytesReceived is 0, we ran out of space before hitting
  146. // the END flag. We will have to wait for the next round
  147. //
  148. // NOTE: if BytesRead gets too high we trash the frame
  149. // because we could not find the FLAG_BYTE
  150. //
  151. if (bytesReceived==0) {
  152. break;
  153. }
  154. if (*(pFrame->Frame+PPP_PADDING) != PPP_FLAG_BYTE) {
  155. //
  156. // We had garbage at the start. Remove the garbage.
  157. //
  158. pInfo->SerialStats.AlignmentErrors++;
  159. //
  160. // Tell the transport above us that we dropped a packet
  161. // Hopefully, it will quickly resync.
  162. //
  163. AsyncIndicateFragment(
  164. pInfo,
  165. WAN_ERROR_ALIGNMENT);
  166. goto NEXT_PPP_FRAME;
  167. }
  168. //
  169. // Length of frame is frameEnd - frameStart
  170. //
  171. bytesWanted = (LONG)(frameEnd - frameStart);
  172. bitMask = pInfo->Adapter->WanInfo.DesiredACCM;
  173. frameEnd2 = frameStart2 = frameStart;
  174. //
  175. // Replace back all control chars, ESC, and FLAG chars
  176. //
  177. while (bytesWanted-- > 0) {
  178. if ((*frameEnd2=*frameStart2++) == PPP_ESC_BYTE) {
  179. //
  180. // We have not run the CRC check yet!!
  181. // We have be careful about sending bytesWanted
  182. // back to -1 on corrupted data
  183. //
  184. bytesWanted--;
  185. *frameEnd2 = (*frameStart2++ ^ 0x20);
  186. }
  187. frameEnd2++;
  188. }
  189. if (*frameStart2 != PPP_FLAG_BYTE) {
  190. DbgTracef(-2,("BAD PPP FRAME at 0x%.8x 0x%.8x\n", frameStart, frameEnd2));
  191. }
  192. //
  193. // if CRC-16, get 16 bit CRC from end of frame
  194. //
  195. frameEnd2 -= 2;
  196. //
  197. // Little endian assumptions for CRC
  198. //
  199. crcData=(USHORT)frameEnd2[0]+(USHORT)(frameEnd2[1] << 8);
  200. crcData ^= 0xFFFF;
  201. //
  202. // Change the bytesWanted field to what it normally is
  203. // without the byte stuffing (length of frame between flags)
  204. // Note that it can be -1 if only one byte was
  205. // found in between the flag bytes
  206. //
  207. bytesWanted = (LONG)(frameEnd2 - frameStart);
  208. //
  209. // If we get some sort of garbage inbetween
  210. // the PPP flags, we just assume it is noise and
  211. // discard it. We don't record a PPP CRC error just
  212. // an alignment error.
  213. //
  214. if (bytesWanted < 3) {
  215. pInfo->SerialStats.AlignmentErrors++;
  216. //
  217. // Tell the transport above us that we dropped a packet
  218. // Hopefully, it will quickly resync.
  219. //
  220. AsyncIndicateFragment(pInfo, WAN_ERROR_ALIGNMENT);
  221. goto NEXT_PPP_FRAME;
  222. }
  223. //
  224. // get CRC from FLAG byte to FLAG byte
  225. //
  226. if (crcData != CalcCRCPPP(frameStart, bytesWanted)) {
  227. DbgTracef(0,("---CRC check failed on control char frame!\n"));
  228. //
  229. // Record the CRC error
  230. //
  231. pInfo->SerialStats.CRCErrors++;
  232. //
  233. // Tell the transport above us that we dropped a packet
  234. // Hopefully, it will quickly resync.
  235. //
  236. AsyncIndicateFragment(
  237. pInfo,
  238. WAN_ERROR_CRC);
  239. goto NEXT_PPP_FRAME;
  240. }
  241. /*
  242. for ( i = 0; (i < (ULONG)bytesWanted) && (i < 48); i++ )
  243. {
  244. if ( (i & 15) == 0 )
  245. DbgTracef(-1, ("\nrx:\t") );
  246. DbgTracef(-1, ("%.2x ", frameStart[i]) );
  247. }
  248. DbgTracef(-1, ("\n") );
  249. */
  250. {
  251. KIRQL irql;
  252. NDIS_STATUS Status;
  253. PASYNC_ADAPTER Adapter = pInfo->Adapter;
  254. KeRaiseIrql( (KIRQL)DISPATCH_LEVEL, &irql );
  255. //
  256. // Tell the transport above (or really RasHub) that the connection
  257. // is now up. We have a new link speed, frame size, quality of service
  258. //
  259. NdisMWanIndicateReceive(&Status,
  260. Adapter->MiniportHandle,
  261. pInfo->NdisLinkContext,
  262. frameStart, // ptr to start of packet
  263. bytesWanted); // Total packet length - header
  264. NdisMWanIndicateReceiveComplete(Adapter->MiniportHandle,
  265. pInfo->NdisLinkContext);
  266. KeLowerIrql( irql );
  267. }
  268. NEXT_PPP_FRAME:
  269. //
  270. // if bytesReceived == 0 no frame was found
  271. // thus we must keep the current frame and continue
  272. // processing
  273. //
  274. if (bytesReceived) {
  275. //
  276. // Calculate how much of what we received
  277. // just got passed up as a frame and move the
  278. // rest to the beginning.
  279. //
  280. frameStart=pFrame->Frame + PPP_PADDING;
  281. frameEnd2=frameStart + pInfo->BytesRead;
  282. pInfo->BytesRead =
  283. bytesReceived = (ULONG)(frameEnd2-frameEnd);
  284. ASYNC_MOVE_MEMORY(
  285. frameStart, // dest
  286. frameEnd, // src
  287. bytesReceived); // length
  288. //
  289. // Need at least four bytes for a frame to exist
  290. //
  291. if (bytesReceived > 3) {
  292. goto PROCESS_FRAME;
  293. }
  294. }
  295. break;
  296. case STATUS_PENDING:
  297. DbgTracef(0,("---ASYNC: Status PENDING on read\n"));
  298. case STATUS_CANCELLED:
  299. // else this is an anomally!
  300. DbgTracef(-2,("---ASYNC: Status cancelled on read for unknown reason!!\n"));
  301. default:
  302. #if DBG
  303. DbgPrint ("AsyncPPPCompletionRoutine: status == %x, no more reads\n", status) ;
  304. #endif
  305. return(STATUS_MORE_PROCESSING_REQUIRED);
  306. }
  307. //
  308. // Here we are at the end of processing this IRP so we go
  309. // ahead and post another read from the serial port.
  310. //
  311. AsyncPPPWaitMask(pInfo);
  312. // We return STATUS_MORE_PROCESSING_REQUIRED so that the
  313. // IoCompletionRoutine will stop working on the IRP.
  314. return(STATUS_MORE_PROCESSING_REQUIRED);
  315. }
  316. NTSTATUS
  317. AsyncPPPRead(
  318. IN PASYNC_INFO Info)
  319. /*++
  320. Assumption -- 0 length frames are not sent (this includes headers)!!!
  321. Also, this is NOT a synchronous operation. It is always asynchronous.
  322. MUST use non-paged pool to read!!!
  323. Routine Description:
  324. This service writes Length bytes of data from the caller's Buffer to the
  325. "port" handle. It is assumed that the handle uses non-buffered IO.
  326. --*/
  327. {
  328. NTSTATUS status;
  329. PIRP irp;
  330. PDEVICE_OBJECT deviceObject=Info->DeviceObject;
  331. PFILE_OBJECT fileObject=Info->FileObject;
  332. PIO_STACK_LOCATION irpSp;
  333. PASYNC_FRAME pFrame;
  334. PASYNC_ADAPTER pAdapter=Info->Adapter;
  335. PIO_COMPLETION_ROUTINE routine;
  336. pFrame=Info->AsyncFrame;
  337. //
  338. // check if this port is closing down or already closed
  339. //
  340. if (Info->PortState == PORT_CLOSING ||
  341. Info->PortState == PORT_CLOSED) {
  342. if (Info->PortState == PORT_CLOSED) {
  343. DbgTracef(-2,("ASYNC: Port closed - but still reading on it!\n"));
  344. }
  345. //
  346. // Acknowledge that the port is closed
  347. //
  348. KeSetEvent(&Info->ClosingEvent, // Event
  349. 1, // Priority
  350. (BOOLEAN)FALSE); // Wait (does not follow)
  351. //
  352. // Ok, if this happens, we are shutting down. Stop
  353. // posting reads. Don't make it try to deallocate the irp!
  354. //
  355. return(STATUS_MORE_PROCESSING_REQUIRED);
  356. }
  357. //
  358. // Has our stack counter reached its max?
  359. //
  360. if ( Info->ReadStackCounter > 1 ) {
  361. //
  362. // Send off the worker thread to compress this frame
  363. //
  364. ExInitializeWorkItem(&pFrame->WorkItem,
  365. (PWORKER_THREAD_ROUTINE) AsyncPPPRead, Info);
  366. //
  367. // reset stack counter since we are scheduling
  368. // a worker thread
  369. //
  370. Info->ReadStackCounter=0;
  371. //
  372. // We choose to be nice and use delayed.
  373. //
  374. ExQueueWorkItem(&pFrame->WorkItem, DelayedWorkQueue);
  375. return NDIS_STATUS_PENDING;
  376. }
  377. //
  378. // One more stack used up.
  379. //
  380. Info->ReadStackCounter++;
  381. // get irp from frame (each frame has an irp allocate with it)
  382. irp =
  383. IoAllocateIrp(Info->DeviceObject->StackSize, (BOOLEAN)FALSE);
  384. // Setup this irp with defaults
  385. AsyncSetupIrp(pFrame, irp);
  386. //
  387. // If we've read all the bytes we can and we still do not
  388. // have a frame, we trash our buffer and start over
  389. // again.
  390. //
  391. if (Info->BytesRead >= (DEFAULT_EXPANDED_PPP_MAX_FRAME_SIZE - PPP_PADDING)) {
  392. Info->SerialStats.BufferOverrunErrors++;
  393. //
  394. // Tell the transport above us that we dropped a packet
  395. // Hopefully, it will quickly resync.
  396. //
  397. AsyncIndicateFragment(Info, WAN_ERROR_BUFFEROVERRUN);
  398. Info->BytesRead=0;
  399. }
  400. irp->AssociatedIrp.SystemBuffer =
  401. pFrame->Frame + Info->BytesRead + PPP_PADDING;
  402. //
  403. // Get a pointer to the stack location for the first driver. This will be
  404. // used to pass the original function codes and parameters.
  405. //
  406. irpSp = IoGetNextIrpStackLocation(irp);
  407. irpSp->MajorFunction = IRP_MJ_READ;
  408. irpSp->FileObject = fileObject;
  409. if (fileObject->Flags & FO_WRITE_THROUGH) {
  410. irpSp->Flags = SL_WRITE_THROUGH;
  411. }
  412. //
  413. // If this write operation is to be performed without any caching, set the
  414. // appropriate flag in the IRP so no caching is performed.
  415. //
  416. irp->Flags |= IRP_READ_OPERATION;
  417. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  418. irp->Flags |= IRP_NOCACHE;
  419. }
  420. //
  421. // Copy the caller's parameters to the service-specific portion of the
  422. // IRP.
  423. //
  424. irpSp->Parameters.Read.Length =
  425. DEFAULT_EXPANDED_PPP_MAX_FRAME_SIZE - Info->BytesRead - PPP_PADDING;
  426. irpSp->Parameters.Read.Key = 0; // we don't use a key
  427. irpSp->Parameters.Read.ByteOffset = fileObject->CurrentByteOffset;
  428. if ( Info->GetLinkInfo.SendFramingBits & SLIP_FRAMING ) {
  429. routine=AsyncSLIPCompletionRoutine;
  430. } else {
  431. routine=AsyncPPPCompletionRoutine;
  432. }
  433. IoSetCompletionRoutine(
  434. irp, // irp to use
  435. routine, // routine to call when irp is done
  436. Info, // context to pass routine
  437. TRUE, // call on success
  438. TRUE, // call on error
  439. TRUE); // call on cancel
  440. //
  441. // We DO NOT insert the packet at the head of the IRP list for the thread.
  442. // because we do NOT really have an IoCompletionRoutine that does
  443. // anything with the thread.
  444. //
  445. //
  446. // Now simply invoke the driver at its dispatch entry with the IRP.
  447. //
  448. status = IoCallDriver(deviceObject, irp);
  449. //
  450. // unroll the stack counter
  451. //
  452. if ( Info->ReadStackCounter > 0 ) {
  453. Info->ReadStackCounter--;
  454. }
  455. //
  456. // Status for a local serial driver should be
  457. // STATUS_SUCCESS since the irp should complete
  458. // immediately because there are no read timeouts.
  459. //
  460. // For a remote serial driver, it will pend.
  461. //
  462. return(status);
  463. }
  464. NTSTATUS
  465. AsyncWaitMaskCompletionRoutine(
  466. IN PDEVICE_OBJECT DeviceObject,
  467. IN PIRP Irp,
  468. IN PVOID Context)
  469. /*++
  470. This is the IO Completion routine for ReadFrame.
  471. --*/
  472. {
  473. NTSTATUS status;
  474. PASYNC_INFO pInfo=Context;
  475. PASYNC_FRAME pFrame;
  476. DeviceObject; // avoid compiler warnings
  477. status = Irp->IoStatus.Status;
  478. pFrame=pInfo->AsyncFrame;
  479. IoFreeIrp(Irp);
  480. // check if this port is closing down or already closed
  481. if (pInfo->PortState == PORT_CLOSING ||
  482. pInfo->PortState == PORT_CLOSED) {
  483. if (pInfo->PortState == PORT_CLOSED) {
  484. DbgTracef(-2,("ASYNC: Port closed - but still reading on it!\n"));
  485. }
  486. //
  487. // Acknowledge that the port is closed
  488. //
  489. KeSetEvent(
  490. &pInfo->ClosingEvent, // Event
  491. 1, // Priority
  492. (BOOLEAN)FALSE); // Wait (does not follow)
  493. DbgTracef(1,("ASYNC: PPP no longer holds the wait_on_mask\n"));
  494. //
  495. // Ok, if this happens, we are shutting down. Stop
  496. // posting reads. Don't make it try to deallocate the irp!
  497. //
  498. return(STATUS_MORE_PROCESSING_REQUIRED);
  499. }
  500. // wait failed
  501. //
  502. if (status != STATUS_SUCCESS) {
  503. pInfo->PortState = PORT_FRAMING;
  504. return(STATUS_MORE_PROCESSING_REQUIRED);
  505. }
  506. //
  507. // Send off a irp to check comm status
  508. // of this port (because we suspect a problem).
  509. //
  510. if (pFrame->WaitMask & SERIAL_EV_ERR) {
  511. AsyncCheckCommStatus(pInfo);
  512. }
  513. //
  514. // Check if RLSD or DSR changed state.
  515. // If so, we probably have to complete and IRP
  516. //
  517. if (pFrame->WaitMask & (SERIAL_EV_RLSD | SERIAL_EV_DSR)) {
  518. TryToCompleteDDCDIrp(pInfo);
  519. }
  520. #if DBG
  521. if (status == STATUS_INVALID_PARAMETER) {
  522. DbgPrint("ASYNC: PPP BAD WAIT MASK! Irp is at 0x%.8x\n",Irp);
  523. DbgBreakPoint();
  524. }
  525. #endif
  526. //
  527. // If we have some more bytes (specifically the event character)
  528. // in the buffer, let's process those new bytes
  529. //
  530. if (pFrame->WaitMask & (SERIAL_EV_RXFLAG | SERIAL_EV_RX80FULL)) {
  531. //
  532. // Read current buffer and try to process a frame
  533. //
  534. AsyncPPPRead(pInfo);
  535. } else {
  536. //
  537. // Set another WaitMask call
  538. //
  539. AsyncPPPWaitMask(pInfo);
  540. }
  541. // We return STATUS_MORE_PROCESSING_REQUIRED so that the
  542. // IoCompletionRoutine will stop working on the IRP.
  543. return(STATUS_MORE_PROCESSING_REQUIRED);
  544. }