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.

856 lines
21 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. s_ioctl.c
  5. Abstract:
  6. This module implements the s_ioctl() operation used by the
  7. socket library.
  8. Author:
  9. Eric Chin (ericc) July 26, 1991
  10. Revision History:
  11. Sam Patton (sampa) August 13, 1991
  12. changed errno to {get|set}lasterror
  13. --*/
  14. #include "common.h"
  15. //
  16. // BUGBUG: Remove this structure when eric implements
  17. // neither I/O. Right now, it is needed because sockets allocates
  18. // the space for this structure in an ioctl call.
  19. //
  20. /*
  21. * IOCTL structure - this structure is the format of the M_IOCTL message type.
  22. */
  23. struct iocblk {
  24. int ioc_cmd; /* ioctl command type */
  25. unsigned short ioc_uid; /* effective uid of user */
  26. unsigned short ioc_gid; /* effective gid of user */
  27. unsigned int ioc_id; /* ioctl id */
  28. unsigned int ioc_count; /* count of bytes in data field */
  29. int ioc_error; /* error code */
  30. int ioc_rval; /* return value */
  31. };
  32. //
  33. // BUGBUG:
  34. // The max amount of data that any module in the stream can return in an
  35. // M_IOCACK message should probably be queried from the Stream Head driver.
  36. //
  37. #define MAX_DATA_AMOUNT 0x1000
  38. //
  39. // Declaration of Local Functions
  40. //
  41. static int
  42. s_debug(
  43. IN HANDLE fd,
  44. IN OUT struct strdebug *dbgbufp
  45. );
  46. static int
  47. s_fdinsert(
  48. IN HANDLE fd,
  49. IN struct strfdinsert *iblk
  50. );
  51. static int
  52. s_link(
  53. IN HANDLE fd,
  54. IN HANDLE fd2
  55. );
  56. static int
  57. s_push(
  58. IN HANDLE fd,
  59. IN char *name
  60. );
  61. static int
  62. s_sioctl(
  63. IN HANDLE fd,
  64. IN OUT struct strioctl *iocp
  65. );
  66. static int
  67. s_unlink(
  68. IN HANDLE fd,
  69. IN int muxid
  70. );
  71. int
  72. s_ioctl(
  73. IN HANDLE fd,
  74. IN int cmd,
  75. IN OUT void *arg OPTIONAL
  76. )
  77. /*++
  78. Routine Description:
  79. This procedure is called to perform a STREAMS ioctl() on a stream
  80. as defined in streamio(7) of the Unix Programmer's Guide: STREAMS.
  81. Arguments:
  82. fd - NT file handle
  83. command - ioctl command code
  84. arg - command-dependent arg, usually a pointer to some structure
  85. Return Value:
  86. 0 if successful, -1 otherwise.
  87. --*/
  88. {
  89. switch (cmd) {
  90. case I_STR:
  91. return(s_sioctl(fd, (struct strioctl *) arg));
  92. case I_DEBUG:
  93. return(s_debug(fd, (struct strdebug *) arg));
  94. case I_FDINSERT:
  95. return(s_fdinsert(fd, (struct strfdinsert *) arg));
  96. case I_PUSH:
  97. return(s_push(fd, (char *) arg));
  98. case I_LINK:
  99. return(s_link(fd, (HANDLE) arg));
  100. case I_UNLINK:
  101. return(s_unlink(fd, (int) ((ULONG_PTR)arg)));
  102. default:
  103. SetLastError(EINVAL);
  104. return(-1);
  105. }
  106. }
  107. static int
  108. s_debug(
  109. IN HANDLE fd,
  110. IN OUT struct strdebug *dbgbufp
  111. )
  112. /*++
  113. Routine Description:
  114. This procedure performs an I_DEBUG ioctl command on a stream.
  115. Arguments:
  116. fd - NT file handle
  117. dbgbufp - pointer to a strdebug structure
  118. Return Value:
  119. 0 if successful, -1 otherwise.
  120. --*/
  121. {
  122. char *tmp;
  123. char *chunk;
  124. NTSTATUS status;
  125. int chunksz, retval;
  126. IO_STATUS_BLOCK iosb;
  127. if (dbgbufp == NULL) {
  128. SetLastError(EINVAL);
  129. return(-1);
  130. }
  131. chunksz = sizeof(int) + sizeof(struct strdebug);
  132. if (!(chunk = (char *) LocalAlloc(LMEM_FIXED, chunksz))) {
  133. SetLastError(ENOSPC);
  134. return(-1);
  135. }
  136. //
  137. // marshall the arguments into one contiguous chunk, laid out as:
  138. //
  139. // union {
  140. // struct {
  141. // int s_code; // I_DEBUG
  142. // struct strdebug dbgbuf;
  143. // } in;
  144. //
  145. // struct {
  146. // int s_retval;
  147. // int s_errno;
  148. // } out;
  149. // };
  150. //
  151. * ((int *) chunk) = I_DEBUG;
  152. tmp = chunk + sizeof(int);
  153. memcpy(tmp, dbgbufp, sizeof(struct strdebug));
  154. status = NtDeviceIoControlFile(
  155. fd,
  156. NULL, // Event
  157. NULL, // ApcRoutine
  158. NULL, // ApcContext
  159. &iosb, // IoStatusBlock
  160. IOCTL_STREAMS_IOCTL, // IoControlCode
  161. (PVOID) chunk, // InputBuffer
  162. chunksz, // InputBufferSize
  163. (PVOID) chunk, // OutputBuffer
  164. chunksz); // OutputBufferSize
  165. if (status == STATUS_PENDING) {
  166. status =
  167. NtWaitForSingleObject(
  168. fd,
  169. TRUE,
  170. NULL);
  171. }
  172. if (!NT_SUCCESS(status)) {
  173. LocalFree((HANDLE) chunk);
  174. SetLastError(MapNtToPosixStatus(status));
  175. return(-1);
  176. }
  177. //
  178. // the Stream Head driver returned values in one chunk, laid out as:
  179. //
  180. // int return value (required)
  181. // int errno; (required)
  182. //
  183. retval = * (int *) chunk;
  184. if (retval == -1) {
  185. SetLastError(* (int *) (chunk + sizeof(int)));
  186. }
  187. LocalFree((HANDLE) chunk);
  188. return(retval);
  189. }
  190. int
  191. s_fdinsert(
  192. IN HANDLE fd,
  193. IN struct strfdinsert *iblk
  194. )
  195. /*++
  196. Routine Description:
  197. This function performs an ioctl(I_FDINSERT) on a stream, which is a
  198. special form of putmsg().
  199. This function is synchronous, in the NT sense: it blocks until the API
  200. completes.
  201. Arguments:
  202. fd - NT file handle
  203. iblk - pointer to a strfdinsert structure
  204. Return Value:
  205. 0 if successful, -1 otherwise.
  206. --*/
  207. {
  208. char *tmp;
  209. NTSTATUS status;
  210. int chunksz, retval;
  211. IO_STATUS_BLOCK iosb;
  212. PSTRM_ARGS_OUT oparm;
  213. PPUTMSG_ARGS_IN chunk;
  214. if (!iblk) {
  215. SetLastError(EINVAL);
  216. return(-1);
  217. }
  218. if (iblk->ctlbuf.len <= 0) {
  219. SetLastError(ERANGE);
  220. return(-1);
  221. }
  222. //
  223. // iblk->databuf.len may be -1, to indicate no data buffer.
  224. //
  225. chunksz = sizeof(PUTMSG_ARGS_IN) - 1 +
  226. iblk->ctlbuf.len + max(iblk->databuf.len, 0);
  227. if (!(chunk = (PPUTMSG_ARGS_IN) LocalAlloc(LMEM_FIXED, chunksz))) {
  228. SetLastError(ENOSPC);
  229. return(-1);
  230. }
  231. //
  232. // marshall the arguments into one contiguous chunk. However, for
  233. // commonality with putmsg(), we rearrange the strfdinsert structure
  234. // as below:
  235. //
  236. // typedef struct _PUTMSG_ARGS_IN_ {
  237. // int a_iocode; // I_FDINSERT
  238. // long a_flags; // 0 | RS_HIPRI
  239. // struct strbuf a_ctlbuf; // (required)
  240. // struct strbuf a_databuf; // (required)
  241. // HANDLE a_insert.i_fildes; // (required)
  242. // int a_offset; // (optional)
  243. // char a_stuff[1]; // s_ctlbuf.buf (required)
  244. // // s_databuf.buf (optional)
  245. // } PUTMSG_ARGS_IN, *PPUTMSG_ARGS_IN;
  246. //
  247. //
  248. chunk->a_iocode = I_FDINSERT;
  249. chunk->a_flags = iblk->flags;
  250. chunk->a_ctlbuf = iblk->ctlbuf; // structure copy
  251. chunk->a_databuf = iblk->databuf; // structure copy
  252. chunk->a_insert.i_fildes = iblk->fildes;
  253. chunk->a_offset = iblk->offset;
  254. tmp = (char *) chunk->a_stuff;
  255. assert(iblk->ctlbuf.len > 0);
  256. memcpy(tmp, iblk->ctlbuf.buf, iblk->ctlbuf.len);
  257. tmp += iblk->ctlbuf.len;
  258. if (iblk->databuf.len > 0) {
  259. memcpy(tmp, iblk->databuf.buf, iblk->databuf.len);
  260. }
  261. ASSERT(chunksz >= sizeof(STRM_ARGS_OUT));
  262. status = NtDeviceIoControlFile(
  263. fd, // Handle
  264. NULL, // Event
  265. NULL, // ApcRoutine
  266. NULL, // ApcContext
  267. &iosb, // IoStatusBlock
  268. IOCTL_STREAMS_IOCTL, // IoControlCode
  269. (PVOID) chunk, // InputBuffer
  270. chunksz, // InputBufferSize
  271. (PVOID) chunk, // OutputBuffer
  272. chunksz); // OutputBufferSize
  273. if (status == STATUS_PENDING) {
  274. status = NtWaitForSingleObject(
  275. fd, // Handle
  276. TRUE, // Alertable
  277. NULL); // Timeout
  278. }
  279. if (!NT_SUCCESS(status)) {
  280. LocalFree(chunk);
  281. SetLastError(MapNtToPosixStatus(status));
  282. return(-1);
  283. }
  284. //
  285. // the return parameters from the Stream Head Driver are laid out as:
  286. //
  287. // typedef struct _STRM_ARGS_OUT_ { // generic return parameters
  288. // int a_retval; // return value
  289. // int a_errno; // errno if retval == -1
  290. //
  291. // } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
  292. //
  293. //
  294. oparm = (PSTRM_ARGS_OUT) chunk;
  295. retval = oparm->a_retval;
  296. if (retval == -1) {
  297. SetLastError(oparm->a_errno);
  298. }
  299. LocalFree(chunk);
  300. return(retval);
  301. } // s_fdinsert
  302. static int
  303. s_link(
  304. IN HANDLE fd,
  305. IN HANDLE fd2
  306. )
  307. /*++
  308. Routine Description:
  309. This procedure performs an I_LINK ioctl command on a stream.
  310. Arguments:
  311. fd - NT file handle to upstream driver
  312. fd2 - NT file handle to downstream driver
  313. Return Value:
  314. multiplexor id number, or -1 if unsuccessful
  315. --*/
  316. {
  317. char *chunk;
  318. NTSTATUS status;
  319. int chunksz, retval;
  320. IO_STATUS_BLOCK iosb;
  321. chunksz = sizeof(int) + sizeof(HANDLE);
  322. if (!(chunk = (char *) LocalAlloc(LMEM_FIXED, chunksz))) {
  323. SetLastError(ENOSPC);
  324. return(-1);
  325. }
  326. //
  327. // marshall the arguments into one contiguous chunk, laid out as:
  328. //
  329. // union {
  330. // struct {
  331. // int s_code; // I_LINK
  332. //
  333. // union {
  334. // HANDLE l_fd2;
  335. // } s_link;
  336. // } in;
  337. //
  338. // struct {
  339. // int s_retval;
  340. // int s_errno;
  341. // } out;
  342. // };
  343. //
  344. * ((int *) chunk) = I_LINK;
  345. * (PHANDLE) ((int *) chunk + 1) = fd2;
  346. status = NtDeviceIoControlFile(
  347. fd,
  348. NULL, // Event
  349. NULL, // ApcRoutine
  350. NULL, // ApcContext
  351. &iosb, // IoStatusBlock
  352. IOCTL_STREAMS_IOCTL, // IoControlCode
  353. (PVOID) chunk, // InputBuffer
  354. chunksz, // InputBufferSize
  355. (PVOID) chunk, // OutputBuffer
  356. chunksz); // OutputBufferSize
  357. if (status == STATUS_PENDING) {
  358. status =
  359. NtWaitForSingleObject(
  360. fd,
  361. TRUE,
  362. NULL);
  363. }
  364. if (!NT_SUCCESS(status)) {
  365. LocalFree((HANDLE) chunk);
  366. SetLastError(MapNtToPosixStatus(status));
  367. return(-1);
  368. }
  369. //
  370. // the Stream Head driver returned values in one chunk, laid out as:
  371. //
  372. // union {
  373. // struct {
  374. // int s_code; // I_LINK
  375. //
  376. // union {
  377. // HANDLE l_fd2;
  378. // } s_link;
  379. // } in;
  380. //
  381. // struct {
  382. // int s_retval;
  383. // int s_errno;
  384. // } out;
  385. // };
  386. //
  387. if ((retval = * (int *) chunk) == -1) {
  388. SetLastError(* (int *) (chunk + sizeof(int)));
  389. }
  390. LocalFree((HANDLE) chunk);
  391. return(retval);
  392. }
  393. static int
  394. s_push(
  395. IN HANDLE fd,
  396. IN char *name
  397. )
  398. /*++
  399. Routine Description:
  400. This procedure performs an I_LINK ioctl command on a stream.
  401. Arguments:
  402. fd - NT file handle to stream
  403. name - name of STREAMS module to be pushed
  404. Return Value:
  405. 0 if successful, -1 otherwise
  406. --*/
  407. {
  408. char *chunk;
  409. NTSTATUS status;
  410. int chunksz, retval;
  411. IO_STATUS_BLOCK iosb;
  412. chunksz = (int)(max(2 * sizeof(int), sizeof(int) + strlen(name) + 1));
  413. if (!(chunk = (char *) LocalAlloc(LMEM_FIXED, chunksz))) {
  414. SetLastError(ENOSPC);
  415. return(-1);
  416. }
  417. //
  418. // marshall the arguments into one contiguous chunk, laid out as:
  419. //
  420. // union {
  421. // struct {
  422. // int s_code; // I_PUSH
  423. //
  424. // union {
  425. // char p_name[1];
  426. // } s_push;
  427. // } in;
  428. //
  429. // struct {
  430. // int s_retval;
  431. // int s_errno;
  432. // } out;
  433. // };
  434. //
  435. * ((int *) chunk) = I_PUSH;
  436. strcpy(chunk + sizeof(int), name);
  437. status = NtDeviceIoControlFile(
  438. fd,
  439. NULL, // Event
  440. NULL, // ApcRoutine
  441. NULL, // ApcContext
  442. &iosb, // IoStatusBlock
  443. IOCTL_STREAMS_IOCTL, // IoControlCode
  444. (PVOID) chunk, // InputBuffer
  445. chunksz, // InputBufferSize
  446. (PVOID) chunk, // OutputBuffer
  447. chunksz); // OutputBufferSize
  448. if (status == STATUS_PENDING) {
  449. status =
  450. NtWaitForSingleObject(
  451. fd,
  452. TRUE,
  453. NULL);
  454. }
  455. if (!NT_SUCCESS(status)) {
  456. LocalFree((HANDLE) chunk);
  457. SetLastError(MapNtToPosixStatus(status));
  458. return(-1);
  459. }
  460. //
  461. // the Stream Head driver returned values in one chunk, laid out as:
  462. //
  463. // union {
  464. // struct {
  465. // int s_code; // I_LINK
  466. // } in;
  467. //
  468. // struct {
  469. // int s_retval;
  470. // int s_errno;
  471. // } out;
  472. // };
  473. //
  474. if ((retval = * (int *) chunk) == -1) {
  475. SetLastError(* (int *) (chunk + sizeof(int)));
  476. }
  477. LocalFree((HANDLE) chunk);
  478. return(retval);
  479. }
  480. static int
  481. s_sioctl(
  482. IN HANDLE fd,
  483. IN OUT struct strioctl *iocp
  484. )
  485. /*++
  486. Routine Description:
  487. This procedure performs an ioctl(I_STR) on a stream.
  488. Arguments:
  489. fd - NT file handle
  490. iocp - pointer to a strioctl structure
  491. Return Value:
  492. 0 if successful, -1 otherwise.
  493. --*/
  494. {
  495. NTSTATUS status;
  496. int chunksz, retval;
  497. IO_STATUS_BLOCK iosb;
  498. PISTR_ARGS_INOUT chunk;
  499. union outparms {
  500. ISTR_ARGS_INOUT o_ok;
  501. STRM_ARGS_OUT o_bad;
  502. } *oparm;
  503. if (!iocp || (iocp->ic_len < 0)) {
  504. SetLastError(EINVAL);
  505. return(-1);
  506. }
  507. chunksz = sizeof(ISTR_ARGS_INOUT) + max(iocp->ic_len, MAX_DATA_AMOUNT);
  508. chunk = (PISTR_ARGS_INOUT) LocalAlloc(LMEM_FIXED, chunksz);
  509. if (!chunk) {
  510. SetLastError(ENOSPC);
  511. return(-1);
  512. }
  513. //
  514. // marshall the arguments into one contiguous chunk, laid out as:
  515. //
  516. // typedef struct _ISTR_ARGS_INOUT { // ioctl(I_STR)
  517. // int a_iocode; // I_STR
  518. // struct strioctl a_strio; // (required)
  519. // int a_unused[2]; // (required) BUGBUG
  520. // char a_stuff[1]; // (optional)
  521. //
  522. // } ISTR_ARGS_INOUT, *PISTR_ARGS_INOUT;
  523. //
  524. //
  525. // An optimizing compiler will warn that the assertion below contains
  526. // unreachable code. Ignore the warning.
  527. //
  528. assert((char *) chunk->a_stuff - (char *) &(chunk->a_strio) >=
  529. sizeof(struct iocblk));
  530. chunk->a_iocode = I_STR;
  531. memcpy(&(chunk->a_strio), iocp, sizeof(struct strioctl));
  532. if (iocp->ic_len >= 0) {
  533. memcpy(&(chunk->a_stuff), iocp->ic_dp, iocp->ic_len);
  534. }
  535. status = NtDeviceIoControlFile(
  536. fd, // Handle
  537. NULL, // Event
  538. NULL, // ApcRoutine
  539. NULL, // ApcContext
  540. &iosb, // IoStatusBlock
  541. IOCTL_STREAMS_IOCTL, // IoControlCode
  542. (PVOID) chunk, // InputBuffer
  543. chunksz, // InputBufferSize
  544. (PVOID) chunk, // OutputBuffer
  545. chunksz); // OutputBufferSize
  546. if (status == STATUS_PENDING) {
  547. status = NtWaitForSingleObject(
  548. fd, // Handle
  549. TRUE, // Alertable
  550. NULL); // Timeout
  551. }
  552. if (!NT_SUCCESS(status)) {
  553. LocalFree(chunk);
  554. SetLastError(MapNtToPosixStatus(status));
  555. return(-1);
  556. }
  557. //
  558. // if there was an error, the return parameters from the Stream Head
  559. // Driver are laid out as:
  560. //
  561. // typedef struct _STRM_ARGS_OUT_ { // generic return parameters
  562. // int a_retval; // return value
  563. // int a_errno; // errno if retval == -1
  564. //
  565. // } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
  566. //
  567. //
  568. oparm = (union outparms *) chunk;
  569. retval = oparm->o_bad.a_retval;
  570. if (retval == -1) {
  571. SetLastError(oparm->o_bad.a_errno);
  572. LocalFree(chunk);
  573. return(retval);
  574. }
  575. //
  576. // if there wasn't an error, the return parameters from the Stream Head
  577. // Driver are laid out as:
  578. //
  579. // typedef struct _ISTR_ARGS_INOUT { // ioctl(I_STR)
  580. // int a_iocode; // return value
  581. // struct strioctl a_strio; // (required)
  582. // int a_unused[2];
  583. // char a_stuff[1]; // (optional)
  584. //
  585. // } ISTR_ARGS_INOUT, *PISTR_ARGS_INOUT;
  586. //
  587. // However, a_iocode now holds the return value.
  588. //
  589. //
  590. if (iocp && iocp->ic_dp) {
  591. iocp->ic_len = oparm->o_ok.a_strio.ic_len;
  592. if (iocp->ic_len >= 0) {
  593. memcpy(iocp->ic_dp, oparm->o_ok.a_stuff, iocp->ic_len);
  594. }
  595. }
  596. LocalFree(chunk);
  597. return(retval);
  598. } // s_sioctl
  599. static int
  600. s_unlink(
  601. IN HANDLE fd,
  602. IN int muxid
  603. )
  604. /*++
  605. Routine Description:
  606. This procedure performs an I_UNLINK ioctl command on a stream.
  607. Arguments:
  608. fd - NT file handle to upstream driver
  609. muxid - STREAMS multiplexor id of the lower stream
  610. Return Value:
  611. 0 on success, or -1 on failure
  612. --*/
  613. {
  614. int chunk[2];
  615. NTSTATUS status;
  616. int chunksz, retval;
  617. IO_STATUS_BLOCK iosb;
  618. //
  619. // marshall the arguments into one contiguous chunk, laid out as:
  620. //
  621. // union {
  622. // struct {
  623. // int s_code; // I_UNLINK
  624. //
  625. // union {
  626. // int l_muxid;
  627. // } s_unlink;
  628. // } in;
  629. //
  630. // struct {
  631. // int s_retval;
  632. // int s_errno;
  633. // } out;
  634. // };
  635. //
  636. chunk[0] = I_UNLINK;
  637. chunk[1] = muxid;
  638. chunksz = sizeof(chunk);
  639. status = NtDeviceIoControlFile(
  640. fd, // Handle
  641. NULL, // Event
  642. NULL, // ApcRoutine
  643. NULL, // ApcContext
  644. &iosb, // IoStatusBlock
  645. IOCTL_STREAMS_IOCTL, // IoControlCode
  646. (PVOID) chunk, // InputBuffer
  647. chunksz, // InputBufferSize
  648. (PVOID) chunk, // OutputBuffer
  649. chunksz); // OutputBufferSize
  650. if (status == STATUS_PENDING) {
  651. status =
  652. NtWaitForSingleObject(
  653. fd,
  654. TRUE,
  655. NULL);
  656. }
  657. if (!NT_SUCCESS(status)) {
  658. SetLastError(MapNtToPosixStatus(status));
  659. return(-1);
  660. }
  661. //
  662. // the Stream Head driver returned values in one chunk, laid out as:
  663. //
  664. // union {
  665. // struct {
  666. // int s_code; // I_UNLINK
  667. //
  668. // union {
  669. // HANDLE l_fd2;
  670. // } s_link;
  671. // } in;
  672. //
  673. // struct {
  674. // int s_retval;
  675. // int s_errno;
  676. // } out;
  677. // };
  678. //
  679. if ((retval = chunk[0]) == -1) {
  680. SetLastError(chunk[1]);
  681. }
  682. return(retval);
  683. } // s_unlink