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.

664 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. sh_get.c
  5. Abstract:
  6. This source file contains those functions of the Stream Head Driver that
  7. deal with receiving messages from a stream.
  8. Author:
  9. Eric Chin (ericc) August 16, 1991
  10. Revision History:
  11. Notes:
  12. The read error state of a stream is represented by ms->e_rerror. Once
  13. set, this is never reset. This corresponds to the STREAMS semantics as
  14. defined by AT&T. Once a user is notified of a read error on a stream,
  15. about the only recourse is to close the stream.
  16. --*/
  17. #include "sh_inc.h"
  18. //
  19. // Local (Private) Functions
  20. //
  21. STATIC
  22. VOID
  23. cancel_get(
  24. IN PDEVICE_OBJECT device,
  25. IN PIRP irp
  26. );
  27. NTSTATUS
  28. do_getmsg(
  29. IN PIRP irp,
  30. IN PFILE_OBJECT pfileobj,
  31. IN int flags
  32. );
  33. NTSTATUS
  34. SHDispGetMsg(
  35. IN PIRP irp,
  36. IN PIO_STACK_LOCATION irpsp
  37. )
  38. /*++
  39. Routine Description:
  40. This routine implements the getmsg(2) API.
  41. Arguments:
  42. irp - pointer to the IRP representing this request
  43. irpsp - pointer to the IRP stack location for this request
  44. Return Value:
  45. An NT status code. Whatever the return value, this function will arrange
  46. for the IRP to be completed.
  47. --*/
  48. {
  49. int spl_level;
  50. NTSTATUS status;
  51. PSTREAM_ENDPOINT ms;
  52. int MyErrno, pri;
  53. PGETMSG_ARGS_INOUT inbuf;
  54. int ret;
  55. mblk_t *mp;
  56. int more = 0;
  57. struct strbuf *strbufp;
  58. int ctlsize, datasize, flags, *pretval, remains;
  59. ASSERT((irpsp->Parameters.DeviceIoControl.IoControlCode & 0x3) ==
  60. METHOD_BUFFERED);
  61. ms = (PSTREAM_ENDPOINT) irpsp->FileObject->FsContext;
  62. if (irpsp->Parameters.DeviceIoControl.InputBufferLength <
  63. sizeof(GETMSG_ARGS_INOUT) - 1) {
  64. IF_STRMDBG(TERSE) {
  65. STRMTRACE(("SHEAD: SHDispGetMsg(%lx) insufficient nbytes = %lx\n",
  66. irp, irpsp->Parameters.DeviceIoControl.InputBufferLength));
  67. }
  68. shortreply(irp, STATUS_INVALID_PARAMETER, 0);
  69. return(STATUS_INVALID_PARAMETER);
  70. }
  71. // Need to ensure that the output buffer is big enough.
  72. {
  73. int cbOut = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
  74. NTSTATUS LengthStatus = STATUS_INVALID_PARAMETER;
  75. if (cbOut >= (sizeof(GETMSG_ARGS_INOUT) - 1))
  76. {
  77. pretval = (int *) irp->AssociatedIrp.SystemBuffer;
  78. flags = * (pretval + 1);
  79. strbufp = (struct strbuf *) (pretval + 2);
  80. ctlsize = strbufp->maxlen;
  81. datasize = (++strbufp)->maxlen;
  82. cbOut -= (sizeof(GETMSG_ARGS_INOUT) - 1);
  83. if (cbOut >= ctlsize)
  84. {
  85. cbOut -= ctlsize;
  86. if (cbOut >= datasize)
  87. {
  88. // cbOut -= datasize;
  89. LengthStatus = STATUS_SUCCESS;
  90. }
  91. }
  92. }
  93. if (LengthStatus != STATUS_SUCCESS)
  94. {
  95. IF_STRMDBG(TERSE) {
  96. STRMTRACE(("SHEAD: SHDispGetMsg(%lx) outbuf insufficient nbytes = %lx\n",
  97. irp, irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  98. }
  99. shortreply(irp, LengthStatus, 0);
  100. return (LengthStatus);
  101. }
  102. }
  103. //
  104. // the caller marshalled the input arguments contiguously thus:
  105. //
  106. // typedef struct _GETMSG_ARGS_INOUT_ { // getmsg()
  107. // int a_retval; // ignore on input
  108. // long a_flags; // 0 or RS_HIPRI
  109. // struct strbuf a_ctlbuf; // (required)
  110. // struct strbuf a_databuf; // (required)
  111. // char a_stuff[1]; // a_ctlbuf.buf (optional)
  112. // // a_databuf.buf (optional)
  113. // } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
  114. //
  115. inbuf = (PGETMSG_ARGS_INOUT) irp->AssociatedIrp.SystemBuffer;
  116. IF_STRMDBG(VERBOSE) {
  117. STRMTRACE(("SHEAD: SHDispGetMsg(irp = %lx)\n", irp));
  118. }
  119. IoAcquireCancelSpinLock(&irp->CancelIrql);
  120. spl_level = lock_strm(ms->e_strm);
  121. if (ms->e_rerror) {
  122. MyErrno = ms->e_rerror;
  123. }
  124. else if (ms->e_linked) {
  125. MyErrno = EINVAL;
  126. }
  127. else {
  128. MyErrno = 0;
  129. }
  130. if (MyErrno) {
  131. IF_STRMDBG(TERSE) {
  132. STRMTRACE(("SHEAD: SHDispGetMsg() error = %d\n", MyErrno));
  133. }
  134. unlock_strm(ms->e_strm, spl_level);
  135. IoReleaseCancelSpinLock(irp->CancelIrql);
  136. SHpGenReply(irp, -1, MyErrno);
  137. return(STATUS_SUCCESS);
  138. }
  139. pri = (inbuf->a_flags == RS_HIPRI) ? QPCTL : 0;
  140. if (shready(ms->e_strm, pri)) {
  141. IF_STRMDBG(VERBOSE) {
  142. STRMTRACE(("SHEAD: SHDispGetMsg() stream's shready()\n"));
  143. }
  144. // The two lines below are replaced by the lines between the vvv/^^^'s
  145. // temp = msgreply(ms, irp);
  146. // ASSERT(temp == 0);
  147. // vvvvvvvv
  148. // vvvvvvvv
  149. /*
  150. * the arguments are marshalled in one contiguous chunk, laid out as:
  151. *
  152. * an unused int (required)
  153. * flags (required)
  154. * struct strbuf ctrlbuf (required)
  155. * struct strbuf databuf (required)
  156. */
  157. pretval = (int *) irp->AssociatedIrp.SystemBuffer;
  158. flags = * (pretval + 1);
  159. strbufp = (struct strbuf *) (pretval + 2);
  160. ctlsize = strbufp->maxlen;
  161. datasize = (++strbufp)->maxlen;
  162. /*
  163. * st_getmsg() may set MORECTL and/or MOREDATA in *pretval; we must
  164. * return it to the user-level runtime !!
  165. */
  166. ret = st_getmsg(ms->e_strm, ctlsize, datasize, &flags, pretval,
  167. &mp, &remains);
  168. ASSERT(!ret);
  169. ASSERT(mp);
  170. // ^^^^^^^^
  171. // ^^^^^^^^
  172. unlock_strm(ms->e_strm, spl_level);
  173. IoReleaseCancelSpinLock(irp->CancelIrql);
  174. // vvvvvvvv
  175. // vvvvvvvv
  176. mptoirp(mp, irp);
  177. freemsg(mp);
  178. // ^^^^^^^^
  179. // ^^^^^^^^
  180. return(STATUS_SUCCESS);
  181. }
  182. if (ms->e_hup) {
  183. IF_STRMDBG(TERSE) {
  184. STRMTRACE(("SHEAD: SHDispGetMsg() stream's was hung up\n"));
  185. }
  186. unlock_strm(ms->e_strm, spl_level);
  187. IoReleaseCancelSpinLock(irp->CancelIrql);
  188. SHpGenReply(irp, -1, EINTR);
  189. return(STATUS_SUCCESS);
  190. }
  191. //
  192. // enqueue this request in the waiting list of readers.
  193. //
  194. IoMarkIrpPending(irp);
  195. if (irp->Cancel) {
  196. unlock_strm(ms->e_strm, spl_level);
  197. IoSetCancelRoutine(irp, NULL);
  198. IoReleaseCancelSpinLock(irp->CancelIrql);
  199. shortreply(irp, STATUS_CANCELLED, 0);
  200. return(STATUS_CANCELLED);
  201. }
  202. status = SHAddPendingIrp(&(ms->e_readers), FALSE, irp, NULL);
  203. ASSERT(!shready(ms->e_strm, 0));
  204. unlock_strm(ms->e_strm, spl_level);
  205. if (status != STATUS_SUCCESS) {
  206. IF_STRMDBG(TERSE) {
  207. STRMTRACE(("SHEAD: SHDispGetMsg() failed to SHAddPendingIrp\n"));
  208. }
  209. IoReleaseCancelSpinLock(irp->CancelIrql);
  210. shortreply(irp, status, 0);
  211. return(status);
  212. }
  213. IoSetCancelRoutine(irp, cancel_get);
  214. IoReleaseCancelSpinLock(irp->CancelIrql);
  215. IF_STRMDBG(VERBOSE) {
  216. STRMTRACE(("SHEAD: SHDispGetMsg(irp = %lx) q_count = %ld\n",
  217. irp, RD(ms->e_strm->str_sq)->q_count ));
  218. }
  219. return(STATUS_PENDING);
  220. } // SHDispGetMsg
  221. int
  222. SHpStreamError(
  223. IN PLIST_ENTRY listhead,
  224. IN int error
  225. )
  226. /*++
  227. Routine Description:
  228. This routine completes the IRPs waiting on a stream when an M_ERROR or
  229. M_HANGUP arrives from downstream.
  230. Arguments:
  231. listhead - either e_readers, e_writers or e_ioctlers
  232. error - the POSIX error code to return
  233. Return Value:
  234. The number of pending IRPs that were completed.
  235. --*/
  236. {
  237. int count = 0;
  238. PLIST_ENTRY tmp;
  239. PWAITING_IRP item;
  240. IF_STRMDBG(TERSE) {
  241. STRMTRACE(("SHEAD: ShpStreamError() for M_HANGUP/M_ERROR\n"));
  242. }
  243. while (!IsListEmpty(listhead)) {
  244. tmp = RemoveHeadList(listhead);
  245. item = CONTAINING_RECORD(tmp,
  246. WAITING_IRP,
  247. w_list);
  248. SHpGenReply(item->w_irp, -1, error);
  249. ExFreePool(item);
  250. count++;
  251. }
  252. return(count);
  253. } // SHpStreamError
  254. STATIC
  255. VOID
  256. cancel_get(
  257. IN PDEVICE_OBJECT device,
  258. IN PIRP irp
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is called when a getmsg() is cancelled.
  263. It must release the cancel spinlock before returning !! The caller
  264. has already acquired the cancel spinlock. ref: IoCancelIrp().
  265. Arguments:
  266. device - pointer to the device object
  267. irp - pointer to the irp of this request
  268. Return Value:
  269. none.
  270. --*/
  271. {
  272. int spl_level;
  273. PLIST_ENTRY tmp;
  274. PWAITING_IRP item;
  275. PSTREAM_ENDPOINT ms;
  276. PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
  277. ASSERT(device == (PDEVICE_OBJECT) StreamDevice);
  278. ASSERT(irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
  279. ASSERT(irpsp->Parameters.DeviceIoControl.IoControlCode ==
  280. IOCTL_STREAMS_GETMSG);
  281. IF_STRMDBG(CALL) {
  282. STRMTRACE(("SHEAD: cancel_get(irp = %lx) entered\n", irp));
  283. }
  284. IoSetCancelRoutine(irp, NULL); /* unnecessary, but cheap */
  285. IoReleaseCancelSpinLock(irp->CancelIrql);
  286. ms = (PSTREAM_ENDPOINT) irpsp->FileObject->FsContext;
  287. spl_level = lock_strm(ms->e_strm);
  288. for (tmp = ms->e_readers.Flink; tmp != &ms->e_readers; tmp = tmp->Flink) {
  289. item = CONTAINING_RECORD(tmp,
  290. WAITING_IRP,
  291. w_list);
  292. if (irp != item->w_irp) {
  293. continue;
  294. }
  295. RemoveEntryList(&(item->w_list));
  296. unlock_strm(ms->e_strm, spl_level);
  297. ExFreePool(item);
  298. shortreply(irp, STATUS_CANCELLED, 0);
  299. IF_STRMDBG(CALL) {
  300. STRMTRACE(("SHEAD: cancel_get(irp = %lx) cancelled ok\n", irp));
  301. }
  302. return;
  303. }
  304. unlock_strm(ms->e_strm, spl_level);
  305. IF_STRMDBG(CALL) {
  306. STRMTRACE(("SHEAD: cancel_get(irp = %lx) not found\n", irp));
  307. }
  308. } // cancel_get
  309. void
  310. msgrdy(
  311. IN struct msg_strm *ms,
  312. IN int mtype
  313. )
  314. /*++
  315. Routine Description:
  316. This function is called by the Stream Head Driver when a message arrives
  317. at the read queue of the specified stream.
  318. Call this function with the stream endpoint locked !!
  319. Arguments:
  320. ms - pointer to the stream endpoint
  321. mtype - type of the STREAMS message
  322. Return Value:
  323. none.
  324. --*/
  325. {
  326. PIRP irp;
  327. int check, pri;
  328. PLIST_ENTRY tmp;
  329. PWAITING_IRP item;
  330. PGETMSG_ARGS_INOUT inbuf;
  331. IF_STRMDBG(CALL) {
  332. STRMTRACE(("SHEAD: msgrdy(ms = %lx, mtype = %x)\n", ms, mtype));
  333. }
  334. switch (mtype) {
  335. case M_DATA:
  336. case M_PROTO:
  337. if (ms->e_strm_flags & POLLIN) {
  338. ms->e_strm_flags &= ~POLLIN;
  339. KeReleaseSemaphore(
  340. &Poll_fired, // semaphore
  341. SEMAPHORE_INCREMENT, // priority increment
  342. 1, // adjustment
  343. FALSE // wait
  344. );
  345. }
  346. break;
  347. case M_PCPROTO:
  348. if (ms->e_strm_flags & POLLPRI) {
  349. ms->e_strm_flags &= ~POLLPRI;
  350. KeReleaseSemaphore(
  351. &Poll_fired, // semaphore
  352. SEMAPHORE_INCREMENT, // priority increment
  353. 1, // adjustment
  354. FALSE // wait
  355. );
  356. }
  357. break;
  358. case M_SIG:
  359. if (ms->e_strm_flags & POLLMSG) {
  360. ms->e_strm_flags &= ~POLLMSG;
  361. KeReleaseSemaphore(
  362. &Poll_fired, // semaphore
  363. SEMAPHORE_INCREMENT, // priority increment
  364. 1, // adjustment
  365. FALSE // wait
  366. );
  367. }
  368. break;
  369. default:
  370. IF_STRMDBG(TERSE) {
  371. STRMTRACE(("SHEAD: msgrdy(), msg type = %x unexpected\n", mtype));
  372. }
  373. ASSERT(0);
  374. }
  375. while (!IsListEmpty( &(ms->e_readers) )) {
  376. tmp = RemoveHeadList( &(ms->e_readers) );
  377. item = CONTAINING_RECORD(tmp,
  378. WAITING_IRP,
  379. w_list);
  380. irp = item->w_irp;
  381. //
  382. // get the RS_HIPRI flag, if any, from the irp.
  383. //
  384. inbuf = (PGETMSG_ARGS_INOUT) irp->AssociatedIrp.SystemBuffer;
  385. pri = (inbuf->a_flags == RS_HIPRI) ? QPCTL : 0;
  386. if (!shready(ms->e_strm, pri)) {
  387. InsertHeadList( &(ms->e_readers), &(item->w_list) );
  388. return;
  389. }
  390. check = msgreply(ms, irp);
  391. ASSERT(check == 0);
  392. ExFreePool(item);
  393. }
  394. IF_STRMDBG(CALL) {
  395. STRMTRACE(("SHEAD: msgrdy() completed ok\n"));
  396. }
  397. return;
  398. } // msgrdy
  399. void
  400. strmevent(
  401. IN STREAM_ENDPOINT *ms,
  402. IN int rerror,
  403. IN int werror,
  404. IN int t
  405. )
  406. /*++
  407. Routine Description:
  408. This function handles special messages that arrive at the stream head.
  409. It is based on the SpiderStreams function of the same name.
  410. Only M_ERROR and M_HANGUP messages are handled at present. M_ERROR is
  411. straightforward to deal with. The error status in the stream structure
  412. is set, and any pending requests failed.
  413. M_HANGUP is very similar, except that read requests are allowed to
  414. complete, and subsequent reads are treated as end of file, rather than
  415. an error condition.
  416. Arguments:
  417. ms - pointer to stream endpoint
  418. rerror - read queue error
  419. werror - write queue error
  420. t - type of STREAMS message
  421. Return Value:
  422. --*/
  423. {
  424. PIRP irp;
  425. int succeeded;
  426. IF_STRMDBG(CALL) {
  427. STRMTRACE(("SHEAD: strmevent(ms = %lx) entered\n", ms));
  428. }
  429. if (ms->TdiStreamPtr) {
  430. TdiStreamEvent(ms, rerror, werror, t);
  431. return;
  432. }
  433. if (rerror == NOERROR) {
  434. rerror = ms->e_rerror; // get current value
  435. }
  436. else {
  437. ms->e_rerror = rerror; // set read error status
  438. }
  439. if (werror == NOERROR) {
  440. werror = ms->e_werror; // get current value
  441. }
  442. else {
  443. ms->e_werror = werror; // set write error status
  444. }
  445. if ((rerror == 0) && (werror == 0)) { // errors zeroed out
  446. IF_STRMDBG(TERSE) {
  447. STRMTRACE(("SHEAD: strmevent(ms = %lx) [rw]error = 0\n", ms));
  448. }
  449. return;
  450. }
  451. switch (t) {
  452. case M_HANGUP:
  453. ms->e_hup = 1;
  454. break;
  455. default:
  456. ASSERT(0);
  457. /* fall through */
  458. case M_ERROR:
  459. break;
  460. }
  461. if (rerror) {
  462. SHpStreamError(&(ms->e_readers), rerror);
  463. }
  464. //
  465. // in response to an M_ERROR or M_HANGUP for the write-side, fail
  466. // any pending ioctl(), putmsg() or write() requests.
  467. //
  468. // If a pending ioctl() is being failed, don't forget to abort its
  469. // timeout !!
  470. //
  471. if (werror) {
  472. irp = ms->e_active_ioctl;
  473. if (irp) {
  474. ms->e_active_ioctl = NULL;
  475. succeeded = 1;
  476. if (irp->IoStatus.Information) {
  477. succeeded = untimeout((int)irp->IoStatus.Information);
  478. ASSERT((succeeded == 0) || (succeeded == 1));
  479. }
  480. if (succeeded) {
  481. SHpGenReply(irp, -1, werror);
  482. }
  483. }
  484. SHpStreamError(&(ms->e_ioctlers), werror);
  485. SHpStreamError(&(ms->e_writers), werror);
  486. }
  487. //
  488. // let poll()'ers know of the error/hangup
  489. //
  490. KeReleaseSemaphore(
  491. &Poll_fired, // semaphore
  492. SEMAPHORE_INCREMENT, // priority increment
  493. 1, // adjustment
  494. FALSE // wait
  495. );
  496. IF_STRMDBG(CALL) {
  497. STRMTRACE(("SHEAD: strmevent(ms = %lx) completed\n", ms));
  498. }
  499. return;
  500. } // strmevent