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