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.

699 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. sh_irp.c
  5. Abstract:
  6. This source file contains the functions that convert between NT IRPs
  7. and STREAMS messages.
  8. Most functions in this module are based on identically named routines
  9. in the SpiderStreams emulator source, stremul/msgrtns.c.
  10. Author:
  11. Eric Chin (ericc) August 16, 1991
  12. Revision History:
  13. --*/
  14. #include "sh_inc.h"
  15. /*
  16. * Local (Private) Functions
  17. */
  18. STATIC void
  19. mp_buf_free(
  20. IN char *p
  21. );
  22. STATIC int
  23. mptoirp(
  24. IN mblk_t *mp,
  25. IN PIRP irp
  26. );
  27. VOID
  28. SHpGenReply(
  29. IN PIRP irp,
  30. IN int retval,
  31. IN int MyErrno
  32. )
  33. /*++
  34. Routine Description:
  35. This function is called to complete IRPs that convey generic STREAMS
  36. API's: ioctl(I_FDINSERT), ioctl(I_STR), putmsg(), ....
  37. By generic, we mean it returns a return value and possible an errno.
  38. Arguments:
  39. irp - irp to complete
  40. retval - return value of the ioctl(,I_FDINSERT,) or putmsg()
  41. errno - POSIX error value, if any
  42. Return Value:
  43. none.
  44. --*/
  45. {
  46. PSTRM_ARGS_OUT outptr;
  47. PIO_STACK_LOCATION pIrpSp;
  48. IF_STRMDBG(CALL) {
  49. STRMTRACE(("SHEAD: SHpGenReply(irp = %lx, %lx, %lx) entered\n",
  50. irp, retval, MyErrno));
  51. }
  52. pIrpSp = IoGetCurrentIrpStackLocation(irp);
  53. // Check size of output buffer.
  54. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STRM_ARGS_OUT))
  55. {
  56. shortreply(irp, STATUS_BUFFER_TOO_SMALL, 0);
  57. return;
  58. }
  59. //
  60. // have IopCompleteRequest() copy the following back to the user's
  61. // output buffer, laid out as:
  62. //
  63. // typedef struct _STRM_ARGS_OUT_ { // generic return parameters
  64. // int a_retval; // return value
  65. // int a_errno; // errno if retval == -1
  66. //
  67. // } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
  68. //
  69. outptr = (PSTRM_ARGS_OUT) irp->AssociatedIrp.SystemBuffer;
  70. outptr->a_retval = retval;
  71. outptr->a_errno = MyErrno;
  72. shortreply(irp, STATUS_SUCCESS, sizeof(STRM_ARGS_OUT));
  73. IF_STRMDBG(CALL) {
  74. STRMTRACE(("SHEAD: SHpGenReply(irp = %lx) done\n", irp));
  75. }
  76. return;
  77. } // SHpGenReply
  78. int
  79. iocreply(
  80. IN mblk_t *mp,
  81. IN PIRP irp
  82. )
  83. /*++
  84. Routine Description:
  85. This function sends the reply to an M_IOCTL message back to the user,
  86. reverting a STREAMS message into an NT irp. It is loosely based on the
  87. SpiderStreams functions, iocreply() and mptomsg(), in stremul/msgrtns.c.
  88. It should be called after the appropriate routine has taken the message
  89. off the queue. If it fails to send a message, it returns a negative
  90. value.
  91. Acquire the lock of ms->e_strm before calling, and release it afterwards !!
  92. Arguments:
  93. mp - pointer to the message to reply to
  94. irp - pointer to the IRP
  95. Return Value:
  96. -1 - no message is ready to be sent to the user
  97. -2 - failed to send a message to the user
  98. --*/
  99. {
  100. mblk_t *tmp;
  101. int length;
  102. char *outbuf;
  103. int *pretval;
  104. int nbytes = 0;
  105. struct iocblk *iocp;
  106. struct strioctl *striop;
  107. IF_STRMDBG(CALL) {
  108. STRMTRACE(("SHEAD: iocreply(mp = %lx, irp = %lx) entered\n", mp, irp));
  109. }
  110. if (!mp) {
  111. return(-1);
  112. }
  113. outbuf = irp->AssociatedIrp.SystemBuffer;
  114. pretval = (int *) outbuf;
  115. *pretval = 0;
  116. switch (mp->b_datap->db_type) {
  117. /*
  118. * for ioctl(I_STR), arrange the return parameters contiguously in outbuf
  119. * in the format:
  120. *
  121. * int return value (required)
  122. * union {
  123. * int errno; (required)
  124. * struct strioctl; (ic_cmd is not valid !!)
  125. * }
  126. * int (required)
  127. * int (required)
  128. * ic_dp buffer (optional)
  129. */
  130. case M_IOCACK:
  131. iocp = (struct iocblk *) mp->b_rptr;
  132. *pretval = iocp->ioc_rval;
  133. striop = (struct strioctl *) ((int *) outbuf + 1);
  134. striop->ic_len = 0;
  135. outbuf = (char *) (striop + 1) + 2 * sizeof(int);
  136. for (tmp = mp->b_cont; tmp; tmp = tmp->b_cont) {
  137. ASSERT(tmp->b_datap->db_type == M_DATA);
  138. length = (int)(tmp->b_wptr - tmp->b_rptr);
  139. ASSERT(length >= 0);
  140. striop->ic_len += length;
  141. RtlCopyMemory(outbuf, tmp->b_rptr, length);
  142. outbuf += length;
  143. }
  144. nbytes = (int) ( outbuf - (char *) irp->AssociatedIrp.SystemBuffer );
  145. break;
  146. case M_IOCNAK:
  147. iocp = (struct iocblk *) mp->b_rptr;
  148. *pretval = -1;
  149. *(pretval + 1) = iocp->ioc_error;
  150. nbytes = 2 * sizeof(int);
  151. break;
  152. default:
  153. ASSERT(0); /* shouldn't come here */
  154. }
  155. shortreply(irp, STATUS_SUCCESS, nbytes);
  156. freemsg(mp);
  157. IF_STRMDBG(CALL) {
  158. STRMTRACE(("SHEAD: iocreply(irp = %lx) nbytes = %lx, completed ok\n",
  159. irp, nbytes));
  160. }
  161. return(0);
  162. } // iocreply
  163. mblk_t *
  164. irptomp(
  165. IN PIRP irp,
  166. IN int pri,
  167. IN int ctlsize,
  168. IN int datasize,
  169. IN char *mbuf
  170. )
  171. /*++
  172. Routine Description:
  173. This function converts the buffers associated with an NT irp into a
  174. STREAMS message. It is based on the SpiderSTREAMS routine, msgtomp().
  175. The first block of the message created is either an M_PROTO or M_DATA
  176. block. To make it M_PCPROTO, M_IOCTL, ..., set it yourself after
  177. this function returns !!
  178. Arguments:
  179. irp - pointer to the IRP.
  180. pri - buffer allocation priority. BPRI_LO, BPRI_MED or BPRI_HI.
  181. ctlsize - length of control part message
  182. datasize - length of data part of message
  183. mbuf - pointer to a contiguous chunk containing first the control
  184. part of the message, if any, and then the data part.
  185. Return Value:
  186. pointer to the resulting STREAMS message, or NULL if unsuccessful.
  187. --*/
  188. {
  189. unsigned char *extra;
  190. mblk_t *mp = (mblk_t *) NULL;
  191. mblk_t *cmp = (mblk_t *) NULL;
  192. frtn_t fr_rtn;
  193. IF_STRMDBG(CALL) {
  194. STRMTRACE(("SHEAD: irptomp(clen, dlen, mbuf = %lx, %lx, %lx) entered\n",
  195. ctlsize, datasize, mbuf));
  196. }
  197. /*
  198. * special case for constructing a zero length message.
  199. */
  200. if ((max(ctlsize, 0) + max(datasize, 0)) == 0) {
  201. mp = allocb(0, pri);
  202. if (!mp) {
  203. IF_STRMDBG(TERSE) {
  204. STRMTRACE(("SHEAD: irptomp(), allocb of 0 failed\n"));
  205. }
  206. return((mblk_t *) NULL);
  207. }
  208. ASSERT(mp->b_datap->db_type == M_DATA);
  209. if (ctlsize != -1) {
  210. mp->b_datap->db_type = M_PROTO;
  211. }
  212. ASSERT(mp->b_wptr == mp->b_rptr);
  213. return(mp);
  214. }
  215. fr_rtn.free_func = mp_buf_free;
  216. if (ctlsize >= 0) {
  217. if (ctlsize) {
  218. extra = ExAllocatePool(NonPagedPool, ctlsize);
  219. if (!extra) {
  220. return((mblk_t *) NULL);
  221. }
  222. RtlCopyMemory(extra, mbuf, ctlsize);
  223. fr_rtn.free_arg = (char *) extra;
  224. cmp = esballoc(extra, ctlsize, pri, &fr_rtn);
  225. }
  226. else {
  227. cmp = allocb(0, pri);
  228. }
  229. if (!cmp) {
  230. IF_STRMDBG(TERSE) {
  231. STRMTRACE(("SHEAD: irptomp(), esballoc %x failed\n", ctlsize));
  232. }
  233. return((mblk_t *) NULL);
  234. }
  235. ASSERT(cmp->b_datap->db_type == M_DATA);
  236. cmp->b_datap->db_type = M_PROTO;
  237. ASSERT(cmp->b_wptr == cmp->b_rptr);
  238. cmp->b_wptr += ctlsize;
  239. }
  240. if (datasize >= 0) {
  241. if (datasize) {
  242. extra = ExAllocatePool(NonPagedPool, datasize);
  243. if (!extra) {
  244. if (cmp) {
  245. freemsg(cmp);
  246. }
  247. return((mblk_t *) NULL);
  248. }
  249. RtlCopyMemory(extra,
  250. (ctlsize <= 0) ? mbuf : mbuf + ctlsize, datasize);
  251. fr_rtn.free_arg = (char *) extra;
  252. mp = esballoc(extra, datasize, pri, &fr_rtn);
  253. }
  254. else {
  255. mp = allocb(0, pri);
  256. }
  257. if (!mp) {
  258. IF_STRMDBG(TERSE) {
  259. STRMTRACE(("SHEAD: irptomp(), esballoc %x failed\n", ctlsize));
  260. }
  261. if (cmp) {
  262. freemsg(cmp);
  263. }
  264. return((mblk_t *) NULL);
  265. }
  266. ASSERT(mp->b_datap->db_type == M_DATA);
  267. ASSERT(mp->b_wptr == mp->b_rptr);
  268. mp->b_wptr += datasize;
  269. }
  270. if (cmp) {
  271. cmp->b_cont = mp;
  272. mp = cmp;
  273. }
  274. IF_STRMDBG(CALL) {
  275. STRMTRACE(("SHEAD: irptomp(mbuf = %lx) returns, mp = %lx\n", mbuf, mp));
  276. }
  277. return(mp);
  278. } // irptomp
  279. STATIC void
  280. mp_buf_free(
  281. IN char *p
  282. )
  283. {
  284. IF_STRMDBG(CALL) {
  285. STRMTRACE(("SHEAD: mp_buf_free(%lx) entered\n", p));
  286. }
  287. if (p) {
  288. ExFreePool(p);
  289. }
  290. IF_STRMDBG(CALL) {
  291. STRMTRACE(("SHEAD: mp_buf_free(%lx) completed\n", p));
  292. }
  293. return;
  294. } // mp_buf_free
  295. STATIC int
  296. mptoirp(
  297. IN mblk_t *mp,
  298. IN PIRP irp
  299. )
  300. /*++
  301. Routine Description:
  302. This function converts a STREAMS message into an NT irp. It is based
  303. on the SpiderStreams routine, mptomsg(), in stremul/msgrtns.c.
  304. It should be called after the appropriate routine has taken the message
  305. off the queue. If it fails to send a message, it returns a negative
  306. value.
  307. The caller must free the STREAMS message, mp. This function doesn't !!
  308. Arguments:
  309. mp
  310. irp
  311. Return Value:
  312. number of bytes copied back to user space, or a negative value if
  313. unsuccessful.
  314. --*/
  315. {
  316. char *outbuf;
  317. int *pretval;
  318. int length, nbytes;
  319. struct strbuf *strbufp;
  320. IF_STRMDBG(CALL) {
  321. STRMTRACE(("SHEAD: mptoirp(mp = %lx, irp = %lx) entered\n", mp, irp));
  322. }
  323. /*
  324. * for getmsg(), arrange the return parameters contiguously in outbuf
  325. * in the format:
  326. *
  327. * int return value (required)
  328. * flags / errno (required)
  329. * struct strbuf ctrlbuf (required)
  330. * struct strbuf databuf (required)
  331. * ctrl buffer (optional)
  332. * data buffer (optional)
  333. */
  334. outbuf = irp->AssociatedIrp.SystemBuffer;
  335. pretval = (int *) outbuf;
  336. strbufp = (struct strbuf *) (pretval + 2); /* struct strbuf ctrlbuf */
  337. outbuf = (char *) (strbufp + 2); /* ctrl buffer */
  338. /*
  339. * ensure that the return value is copied back to the user-level runtime.
  340. * It was zeroed in ShDispGetmsg(), and the MORECTL, MOREDATA bits may
  341. * have set by st_getmsg().
  342. */
  343. nbytes = 2 * sizeof(int);
  344. switch (mp->b_datap->db_type) {
  345. case M_PCPROTO:
  346. *(pretval + 1) = RS_HIPRI; /* flags */
  347. goto doproto;
  348. case M_PROTO:
  349. *(pretval + 1) = 0; /* flags */
  350. doproto:
  351. length = (int)(mp->b_wptr - mp->b_rptr);
  352. if (strbufp->maxlen < length) {
  353. length = strbufp->maxlen;
  354. *pretval |= MORECTL;
  355. }
  356. strbufp->len = length;
  357. RtlCopyMemory(outbuf, mp->b_rptr, strbufp->len);
  358. mp = mp->b_cont;
  359. goto dodata;
  360. case M_DATA:
  361. *(pretval + 1) = 0; /* flags */
  362. strbufp->len = 0; /* ctrlbuf->len */
  363. dodata:
  364. outbuf += strbufp->len;
  365. (++strbufp)->len = 0;
  366. for (; mp; mp = mp->b_cont) {
  367. ASSERT(mp->b_datap->db_type == M_DATA);
  368. length = (int)(mp->b_wptr - mp->b_rptr);
  369. ASSERT(length >= 0);
  370. if (strbufp->maxlen < length) {
  371. length = strbufp->maxlen;
  372. *pretval |= MOREDATA;
  373. }
  374. RtlCopyMemory(outbuf, mp->b_rptr, length);
  375. outbuf += length;
  376. strbufp->len += length;
  377. if ((strbufp->maxlen -= length) == 0) {
  378. break;
  379. }
  380. }
  381. nbytes = (int)( outbuf - (char *) irp->AssociatedIrp.SystemBuffer );
  382. break;
  383. default:
  384. IF_STRMDBG(TERSE) {
  385. STRMTRACE(("SHEAD: mptoirp(), unexpected db_type = %x\n",
  386. mp->b_datap->db_type));
  387. }
  388. ASSERT(0); /* shouldn't come here */
  389. KeBugCheck(STREAMS_INTERNAL_ERROR);
  390. break;
  391. }
  392. /*
  393. * no matter what, we always pass back the return value and the flags
  394. * to the user-level runtime.
  395. */
  396. ASSERT(nbytes >= 2 * sizeof(int));
  397. shortreply(irp, STATUS_SUCCESS, nbytes);
  398. IF_STRMDBG(CALL) {
  399. STRMTRACE(("SHEAD: mptoirp(irp = %lx), %lx, completed\n", irp, nbytes));
  400. }
  401. return(nbytes);
  402. } // mptoirp
  403. int
  404. msgreply(
  405. IN STREAM_ENDPOINT *ms,
  406. IN PIRP irp
  407. )
  408. /*++
  409. Routine Description:
  410. This function gets a STREAMS message to complete an IRP representing
  411. a getmsg(). It is based on the SpiderStreams emulator function of the
  412. same name.
  413. Lock the stream, ms->e_strm, before calling this function, and unlock
  414. it after this function returns !!
  415. Arguments:
  416. ms - stream endpoint from whose read queue to get the message from
  417. irp - IRP to complete
  418. Return Value:
  419. 0 - successful completion
  420. -1 - no message is ready to be sent to the user
  421. -2 - failed to send a message to the user
  422. --*/
  423. {
  424. int ret;
  425. mblk_t *mp;
  426. int more = 0;
  427. struct strbuf *strbufp;
  428. int ctlsize, datasize, flags, *pretval, remains;
  429. /*
  430. * the arguments are marshalled in one contiguous chunk, laid out as:
  431. *
  432. * an unused int (required)
  433. * flags (required)
  434. * struct strbuf ctrlbuf (required)
  435. * struct strbuf databuf (required)
  436. */
  437. pretval = (int *) irp->AssociatedIrp.SystemBuffer;
  438. flags = * (pretval + 1);
  439. strbufp = (struct strbuf *) (pretval + 2);
  440. ctlsize = strbufp->maxlen;
  441. datasize = (++strbufp)->maxlen;
  442. /*
  443. * st_getmsg() may set MORECTL and/or MOREDATA in *pretval; we must
  444. * return it to the user-level runtime !!
  445. */
  446. ret = st_getmsg(ms->e_strm, ctlsize, datasize, &flags, pretval,
  447. &mp, &remains);
  448. if (ret) {
  449. ASSERT(0);
  450. shortreply(irp, STATUS_SUCCESS, 0);
  451. return(0);
  452. }
  453. if (!mp) {
  454. return(-1);
  455. }
  456. //
  457. // Unlike SpiderSTREAMS, our mptoirp() function never fails !! Hence
  458. // the assertion.
  459. //
  460. if (mptoirp(mp, irp) < 0) {
  461. ASSERT(0);
  462. st_putback(ms->e_strm, mp, remains);
  463. return(-2);
  464. }
  465. /*
  466. * Spider frees mp by chasing mp->b_next. Why ?
  467. */
  468. ASSERT(!(mp->b_next));
  469. freemsg(mp);
  470. return(0);
  471. } // msgreply
  472. int
  473. shortreply(
  474. IN PIRP irp,
  475. IN int status,
  476. IN int nbytes
  477. )
  478. /*++
  479. Routine Description:
  480. This function completes an IRP, and arranges for return parameters,
  481. if any, to be copied.
  482. Although somewhat a misnomer, this function is named after a similar
  483. function in the SpiderSTREAMS emulator.
  484. Arguments:
  485. irp - pointer to the IRP to complete
  486. status - completion status of the IRP
  487. nbytes - number of bytes to return
  488. Return Value:
  489. number of bytes copied back to the user.
  490. --*/
  491. {
  492. CCHAR priboost;
  493. IF_STRMDBG(CALL) {
  494. STRMTRACE((
  495. "SHEAD: shortreply(irp, status, nbytes = %lx, %lx, %lx) entered\n",
  496. irp, status, nbytes));
  497. }
  498. //
  499. // set the irp's cancel routine to NULL, or the system may bugcheck
  500. // with the bugcode, CANCEL_STATE_IN_COMPLETED_IRP !!
  501. //
  502. // ref: IoCancelIrp(), ...\ntos\io\iosubs.c.
  503. //
  504. //
  505. IoAcquireCancelSpinLock(&irp->CancelIrql);
  506. IoSetCancelRoutine(irp, NULL);
  507. IoReleaseCancelSpinLock(irp->CancelIrql);
  508. //
  509. // irp->IoStatus.Information is meaningful only for STATUS_SUCCESS
  510. //
  511. ASSERT(!nbytes || (status == STATUS_SUCCESS));
  512. irp->IoStatus.Information = nbytes;
  513. irp->IoStatus.Status = status;
  514. priboost = (CCHAR) ((status == STATUS_SUCCESS) ?
  515. IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
  516. IoCompleteRequest(irp, priboost);
  517. return(nbytes);
  518. } // shortreply