1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This module provides the interface to NDR RPC. 28 */ 29 30 #include <sys/stat.h> 31 #include <sys/door.h> 32 #include <sys/door_data.h> 33 #include <sys/uio.h> 34 #include <sys/ksynch.h> 35 #include <smbsrv/smb_kproto.h> 36 #include <smbsrv/smb_xdr.h> 37 38 #define SMB_OPIPE_ISOPEN(OPIPE) \ 39 (((OPIPE)->p_hdr.dh_magic == SMB_OPIPE_HDR_MAGIC) && \ 40 ((OPIPE)->p_hdr.dh_fid)) 41 42 extern volatile uint32_t smb_fids; 43 44 static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 45 static char *smb_opipe_lookup(const char *); 46 static int smb_opipe_sethdr(smb_opipe_t *, uint32_t, uint32_t); 47 static int smb_opipe_exec(smb_opipe_t *); 48 static void smb_opipe_enter(smb_opipe_t *); 49 static void smb_opipe_exit(smb_opipe_t *); 50 51 static door_handle_t smb_opipe_door_hd = NULL; 52 static int smb_opipe_door_id = -1; 53 static uint64_t smb_opipe_door_ncall = 0; 54 static kmutex_t smb_opipe_door_mutex; 55 static kcondvar_t smb_opipe_door_cv; 56 57 static int smb_opipe_door_call(smb_opipe_t *); 58 static int smb_opipe_door_upcall(smb_opipe_t *); 59 60 smb_opipe_t * 61 smb_opipe_alloc(smb_server_t *sv) 62 { 63 smb_opipe_t *opipe; 64 65 opipe = kmem_cache_alloc(sv->si_cache_opipe, KM_SLEEP); 66 67 bzero(opipe, sizeof (smb_opipe_t)); 68 mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 69 cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 70 opipe->p_magic = SMB_OPIPE_MAGIC; 71 opipe->p_server = sv; 72 73 smb_llist_enter(&sv->sv_opipe_list, RW_WRITER); 74 smb_llist_insert_tail(&sv->sv_opipe_list, opipe); 75 smb_llist_exit(&sv->sv_opipe_list); 76 77 return (opipe); 78 } 79 80 void 81 smb_opipe_dealloc(smb_opipe_t *opipe) 82 { 83 smb_server_t *sv; 84 85 SMB_OPIPE_VALID(opipe); 86 sv = opipe->p_server; 87 SMB_SERVER_VALID(sv); 88 89 smb_llist_enter(&sv->sv_opipe_list, RW_WRITER); 90 smb_llist_remove(&sv->sv_opipe_list, opipe); 91 smb_llist_exit(&sv->sv_opipe_list); 92 93 opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC; 94 smb_event_destroy(opipe->p_event); 95 cv_destroy(&opipe->p_cv); 96 mutex_destroy(&opipe->p_mutex); 97 98 kmem_cache_free(sv->si_cache_opipe, opipe); 99 } 100 101 /* 102 * smb_opipe_open 103 * 104 * Open a well-known RPC named pipe. This routine should be called if 105 * a file open is requested on a share of type STYPE_IPC. 106 * If we recognize the pipe, we setup a new ofile. 107 * 108 * Returns 0 on success, Otherwise an NT status is returned to indicate 109 * an error. 110 */ 111 int 112 smb_opipe_open(smb_request_t *sr) 113 { 114 open_param_t *op = &sr->arg.open; 115 smb_ofile_t *of; 116 smb_opipe_t *opipe; 117 smb_doorhdr_t hdr; 118 smb_error_t err; 119 char *pipe_name; 120 121 if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL) 122 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 123 124 op->create_options = 0; 125 126 of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op, 127 SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 128 129 if (of == NULL) 130 return (err.status); 131 132 if (!smb_tree_is_connected(sr->tid_tree)) { 133 smb_ofile_close(of, 0); 134 smb_ofile_release(of); 135 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 136 } 137 138 op->dsize = 0x01000; 139 op->dattr = FILE_ATTRIBUTE_NORMAL; 140 op->ftype = SMB_FTYPE_MESG_PIPE; 141 op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 142 op->devstate = SMB_PIPE_READMODE_MESSAGE 143 | SMB_PIPE_TYPE_MESSAGE 144 | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 145 op->fileid = of->f_fid; 146 147 sr->smb_fid = of->f_fid; 148 sr->fid_ofile = of; 149 150 opipe = of->f_pipe; 151 smb_opipe_enter(opipe); 152 153 opipe->p_server = of->f_server; 154 opipe->p_name = pipe_name; 155 opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 156 157 /* 158 * p_data points to the offset within p_doorbuf at which 159 * data will be written or read. 160 */ 161 opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_doorhdr_xdr, &hdr); 162 163 if (smb_opipe_do_open(sr, opipe) != 0) { 164 /* 165 * On error, reset the header to clear the fid, 166 * which avoids confusion when smb_opipe_close() is 167 * called by smb_ofile_close(). 168 */ 169 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t)); 170 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 171 smb_opipe_exit(opipe); 172 smb_ofile_close(of, 0); 173 return (NT_STATUS_NO_MEMORY); 174 } 175 smb_opipe_exit(opipe); 176 return (NT_STATUS_SUCCESS); 177 } 178 179 /* 180 * smb_opipe_lookup 181 * 182 * Lookup a path to see if it's a well-known RPC named pipe that we support. 183 * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 184 * can be assumed, so all we need here are the service names. 185 * 186 * Returns a pointer to the pipe name (without any leading \'s) on success. 187 * Otherwise returns a null pointer. 188 */ 189 static char * 190 smb_opipe_lookup(const char *path) 191 { 192 static char *named_pipes[] = { 193 "lsass", 194 "LSARPC", 195 "NETLOGON", 196 "SAMR", 197 "SPOOLSS", 198 "SRVSVC", 199 "SVCCTL", 200 "WINREG", 201 "WKSSVC", 202 "EVENTLOG", 203 "NETDFS" 204 }; 205 206 const char *name; 207 int i; 208 209 if (path == NULL) 210 return (NULL); 211 212 name = path; 213 name += strspn(name, "\\"); 214 if (smb_strcasecmp(name, "PIPE", 4) == 0) { 215 path += 4; 216 name += strspn(name, "\\"); 217 } 218 219 for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 220 if (smb_strcasecmp(name, named_pipes[i], 0) == 0) 221 return (named_pipes[i]); 222 } 223 224 return (NULL); 225 } 226 227 /* 228 * Initialize the opipe header and context, and make the door call. 229 */ 230 static int 231 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 232 { 233 smb_netuserinfo_t *userinfo = &opipe->p_user; 234 smb_user_t *user = sr->uid_user; 235 uint8_t *buf = opipe->p_doorbuf; 236 uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 237 uint32_t len; 238 239 if ((opipe->p_event = smb_event_create()) == NULL) 240 return (-1); 241 242 smb_user_netinfo_init(user, userinfo); 243 len = xdr_sizeof(smb_netuserinfo_xdr, userinfo); 244 245 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t)); 246 opipe->p_hdr.dh_magic = SMB_OPIPE_HDR_MAGIC; 247 opipe->p_hdr.dh_flags = SMB_DF_SYSSPACE; 248 opipe->p_hdr.dh_fid = smb_event_txid(opipe->p_event); 249 250 if (smb_opipe_sethdr(opipe, SMB_OPIPE_OPEN, len) == -1) 251 return (-1); 252 253 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr); 254 buf += len; 255 buflen -= len; 256 257 if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1) 258 return (-1); 259 260 return (smb_opipe_door_call(opipe)); 261 } 262 263 /* 264 * smb_opipe_close 265 * 266 * Called whenever an IPC file/pipe is closed. 267 */ 268 void 269 smb_opipe_close(smb_ofile_t *of) 270 { 271 smb_opipe_t *opipe; 272 273 ASSERT(of); 274 ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 275 276 opipe = of->f_pipe; 277 SMB_OPIPE_VALID(opipe); 278 279 (void) smb_server_cancel_event(opipe->p_hdr.dh_fid); 280 smb_opipe_enter(opipe); 281 282 if (SMB_OPIPE_ISOPEN(opipe)) { 283 (void) smb_opipe_sethdr(opipe, SMB_OPIPE_CLOSE, 0); 284 (void) smb_opipe_door_call(opipe); 285 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t)); 286 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 287 } 288 289 smb_user_netinfo_fini(&opipe->p_user); 290 smb_opipe_exit(opipe); 291 } 292 293 static int 294 smb_opipe_sethdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 295 { 296 opipe->p_hdr.dh_op = cmd; 297 opipe->p_hdr.dh_txid = opipe->p_hdr.dh_fid; 298 opipe->p_hdr.dh_datalen = datalen; 299 opipe->p_hdr.dh_resid = 0; 300 opipe->p_hdr.dh_door_rc = EINVAL; 301 302 return (smb_doorhdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 303 SMB_OPIPE_DOOR_BUFSIZE)); 304 } 305 306 /* 307 * smb_opipe_transact 308 * 309 * This is the entry point for RPC bind and request transactions. 310 * The fid is an arbitrary id used to associate RPC requests with a 311 * particular binding handle. 312 * 313 * If the data to be returned is larger than the client expects, we 314 * return as much as the client can handle and report a buffer overflow 315 * warning, which informs the client that we have more data to return. 316 * The residual data remains in the pipe until the client claims it or 317 * closes the pipe. 318 */ 319 smb_sdrc_t 320 smb_opipe_transact(smb_request_t *sr, struct uio *uio) 321 { 322 smb_xa_t *xa; 323 smb_opipe_t *opipe; 324 struct mbuf *mhead; 325 int mdrcnt; 326 int nbytes; 327 int rc; 328 329 if ((rc = smb_opipe_write(sr, uio)) != 0) { 330 if (rc == EBADF) 331 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 332 ERRDOS, ERROR_INVALID_HANDLE); 333 else 334 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 335 ERRDOS, ERROR_INTERNAL_ERROR); 336 return (SDRC_ERROR); 337 } 338 339 opipe = sr->fid_ofile->f_pipe; 340 341 if ((rc = smb_opipe_exec(opipe)) != 0) { 342 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 343 ERRDOS, ERROR_INTERNAL_ERROR); 344 return (SDRC_ERROR); 345 } 346 347 xa = sr->r_xa; 348 mdrcnt = xa->smb_mdrcnt; 349 smb_opipe_enter(opipe); 350 351 if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 352 smb_opipe_exit(opipe); 353 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 354 ERRDOS, ERROR_INTERNAL_ERROR); 355 return (SDRC_ERROR); 356 } 357 358 rc = smb_opipe_door_call(opipe); 359 nbytes = opipe->p_hdr.dh_datalen; 360 361 if (rc != 0) { 362 smb_opipe_exit(opipe); 363 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 364 ERRDOS, ERROR_INTERNAL_ERROR); 365 return (SDRC_ERROR); 366 } 367 368 if (nbytes) { 369 mhead = smb_mbuf_get(opipe->p_data, nbytes); 370 xa->rep_data_mb.max_bytes = nbytes; 371 MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 372 } 373 374 if (opipe->p_hdr.dh_resid) { 375 /* 376 * The pipe contains more data than mdrcnt, warn the 377 * client that there is more data in the pipe. 378 * Typically, the client will call SmbReadX, which 379 * will call smb_opipe_read, to get the data. 380 */ 381 smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 382 ERRDOS, ERROR_MORE_DATA); 383 } 384 385 smb_opipe_exit(opipe); 386 return (SDRC_SUCCESS); 387 } 388 389 /* 390 * smb_opipe_write 391 * 392 * Write RPC request data to the pipe. The client should call smb_opipe_read 393 * to complete the exchange and obtain the RPC response. 394 * 395 * Returns 0 on success or an errno on failure. 396 */ 397 int 398 smb_opipe_write(smb_request_t *sr, struct uio *uio) 399 { 400 smb_opipe_t *opipe; 401 uint32_t buflen; 402 uint32_t len; 403 int rc; 404 405 ASSERT(sr->fid_ofile); 406 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 407 408 opipe = sr->fid_ofile->f_pipe; 409 SMB_OPIPE_VALID(opipe); 410 smb_opipe_enter(opipe); 411 412 if (!SMB_OPIPE_ISOPEN(opipe)) { 413 smb_opipe_exit(opipe); 414 return (EBADF); 415 } 416 417 rc = smb_opipe_sethdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 418 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr); 419 if (rc == -1 || len == 0) { 420 smb_opipe_exit(opipe); 421 return (ENOMEM); 422 } 423 424 buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 425 (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 426 427 rc = smb_opipe_door_call(opipe); 428 429 smb_opipe_exit(opipe); 430 return ((rc == 0) ? 0 : EIO); 431 } 432 433 /* 434 * smb_opipe_read 435 * 436 * This interface may be called because smb_opipe_transact could not return 437 * all of the data in the original transaction or to form the second half 438 * of a transaction set up using smb_opipe_write. Either way, we just need 439 * to read data from the pipe and return it. 440 * 441 * The response data is encoded into raw_data as required by the smb_read 442 * functions. The uio_resid value indicates the number of bytes read. 443 */ 444 int 445 smb_opipe_read(smb_request_t *sr, struct uio *uio) 446 { 447 smb_opipe_t *opipe; 448 struct mbuf *mhead; 449 uint32_t nbytes; 450 int rc; 451 452 ASSERT(sr->fid_ofile); 453 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 454 455 opipe = sr->fid_ofile->f_pipe; 456 SMB_OPIPE_VALID(opipe); 457 458 if ((rc = smb_opipe_exec(opipe)) != 0) 459 return (EIO); 460 461 smb_opipe_enter(opipe); 462 463 if (!SMB_OPIPE_ISOPEN(opipe)) { 464 smb_opipe_exit(opipe); 465 return (EBADF); 466 } 467 468 if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 469 smb_opipe_exit(opipe); 470 return (ENOMEM); 471 } 472 473 rc = smb_opipe_door_call(opipe); 474 nbytes = opipe->p_hdr.dh_datalen; 475 476 if (rc != 0 || nbytes > uio->uio_resid) { 477 smb_opipe_exit(opipe); 478 return (EIO); 479 } 480 481 if (nbytes) { 482 mhead = smb_mbuf_get(opipe->p_data, nbytes); 483 MBC_SETUP(&sr->raw_data, nbytes); 484 MBC_ATTACH_MBUF(&sr->raw_data, mhead); 485 uio->uio_resid -= nbytes; 486 } 487 488 smb_opipe_exit(opipe); 489 return (rc); 490 } 491 492 static int 493 smb_opipe_exec(smb_opipe_t *opipe) 494 { 495 uint32_t len; 496 int rc; 497 498 smb_opipe_enter(opipe); 499 500 rc = smb_opipe_sethdr(opipe, SMB_OPIPE_EXEC, 0); 501 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr); 502 if (rc == -1 || len == 0) { 503 smb_opipe_exit(opipe); 504 return (ENOMEM); 505 } 506 507 if ((rc = smb_opipe_door_call(opipe)) == 0) 508 rc = smb_event_wait(opipe->p_event); 509 510 smb_opipe_exit(opipe); 511 return (rc); 512 } 513 514 /* 515 * Named pipe I/O is serialized per fid to ensure that each request 516 * has exclusive opipe access for the duration of the request. 517 */ 518 static void 519 smb_opipe_enter(smb_opipe_t *opipe) 520 { 521 mutex_enter(&opipe->p_mutex); 522 523 while (opipe->p_busy) 524 cv_wait(&opipe->p_cv, &opipe->p_mutex); 525 526 opipe->p_busy = 1; 527 mutex_exit(&opipe->p_mutex); 528 } 529 530 /* 531 * Exit busy state. If we have exec'd an RPC, we may have 532 * to wait for notification that processing has completed. 533 */ 534 static void 535 smb_opipe_exit(smb_opipe_t *opipe) 536 { 537 mutex_enter(&opipe->p_mutex); 538 opipe->p_busy = 0; 539 cv_signal(&opipe->p_cv); 540 mutex_exit(&opipe->p_mutex); 541 } 542 543 /* 544 * opipe door client (to user space door server). 545 */ 546 void 547 smb_opipe_door_init(void) 548 { 549 mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 550 cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 551 } 552 553 void 554 smb_opipe_door_fini(void) 555 { 556 smb_opipe_door_close(); 557 cv_destroy(&smb_opipe_door_cv); 558 mutex_destroy(&smb_opipe_door_mutex); 559 } 560 561 /* 562 * Open the (user space) door. If the door is already open, 563 * close it first because the door-id has probably changed. 564 */ 565 int 566 smb_opipe_door_open(int door_id) 567 { 568 smb_opipe_door_close(); 569 570 mutex_enter(&smb_opipe_door_mutex); 571 smb_opipe_door_ncall = 0; 572 573 if (smb_opipe_door_hd == NULL) { 574 smb_opipe_door_id = door_id; 575 smb_opipe_door_hd = door_ki_lookup(door_id); 576 } 577 578 mutex_exit(&smb_opipe_door_mutex); 579 return ((smb_opipe_door_hd == NULL) ? -1 : 0); 580 } 581 582 /* 583 * Close the (user space) door. 584 */ 585 void 586 smb_opipe_door_close(void) 587 { 588 mutex_enter(&smb_opipe_door_mutex); 589 590 if (smb_opipe_door_hd != NULL) { 591 while (smb_opipe_door_ncall > 0) 592 cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 593 594 door_ki_rele(smb_opipe_door_hd); 595 smb_opipe_door_hd = NULL; 596 } 597 598 mutex_exit(&smb_opipe_door_mutex); 599 } 600 601 /* 602 * opipe door call interface. 603 * Door serialization and call reference accounting is handled here. 604 */ 605 static int 606 smb_opipe_door_call(smb_opipe_t *opipe) 607 { 608 int rc; 609 610 mutex_enter(&smb_opipe_door_mutex); 611 612 if (smb_opipe_door_hd == NULL) { 613 mutex_exit(&smb_opipe_door_mutex); 614 615 if (smb_opipe_door_open(smb_opipe_door_id) != 0) 616 return (-1); 617 618 mutex_enter(&smb_opipe_door_mutex); 619 } 620 621 ++smb_opipe_door_ncall; 622 mutex_exit(&smb_opipe_door_mutex); 623 624 rc = smb_opipe_door_upcall(opipe); 625 626 mutex_enter(&smb_opipe_door_mutex); 627 if ((--smb_opipe_door_ncall) == 0) 628 cv_signal(&smb_opipe_door_cv); 629 mutex_exit(&smb_opipe_door_mutex); 630 return (rc); 631 } 632 633 /* 634 * Door upcall wrapper - handles data marshalling. 635 * This function should only be called by smb_opipe_door_call. 636 */ 637 static int 638 smb_opipe_door_upcall(smb_opipe_t *opipe) 639 { 640 door_arg_t da; 641 smb_doorhdr_t hdr; 642 int i; 643 int rc; 644 645 da.data_ptr = (char *)opipe->p_doorbuf; 646 da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 647 da.desc_ptr = NULL; 648 da.desc_num = 0; 649 da.rbuf = (char *)opipe->p_doorbuf; 650 da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 651 652 for (i = 0; i < 3; ++i) { 653 if (smb_server_is_stopping()) 654 return (-1); 655 656 if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 657 NULL, SIZE_MAX, 0)) == 0) 658 break; 659 660 if (rc != EAGAIN && rc != EINTR) 661 return (-1); 662 } 663 664 /* Check for door_return(NULL, 0, NULL, 0) */ 665 if (rc != 0 || da.data_size == 0 || da.rsize == 0) 666 return (-1); 667 668 if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1) 669 return (-1); 670 671 if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) || 672 (hdr.dh_fid != opipe->p_hdr.dh_fid) || 673 (hdr.dh_op != opipe->p_hdr.dh_op) || 674 (hdr.dh_door_rc != 0) || 675 (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 676 return (-1); 677 } 678 679 opipe->p_hdr.dh_datalen = hdr.dh_datalen; 680 opipe->p_hdr.dh_resid = hdr.dh_resid; 681 return (0); 682 } 683