1 /* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 /* 41 * various SMB requests. Most of the routines merely packs data into mbufs. 42 */ 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kmem.h> 46 #include <sys/proc.h> 47 #include <sys/lock.h> 48 #include <sys/socket.h> 49 #include <sys/uio.h> 50 #include <sys/random.h> 51 #include <sys/note.h> 52 #include <sys/cmn_err.h> 53 54 #include <netsmb/smb_osdep.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_conn.h> 58 #include <netsmb/smb_rq.h> 59 #include <netsmb/smb_subr.h> 60 #include <netsmb/smb_tran.h> 61 62 /* 63 * Largest size to use with LARGE_READ/LARGE_WRITE. 64 * Specs say up to 64k data bytes, but Windows traffic 65 * uses 60k... no doubt for some good reason. 66 * (Probably to keep 4k block alignment.) 67 * XXX: Move to smb.h maybe? 68 */ 69 #define SMB_MAX_LARGE_RW_SIZE (60*1024) 70 71 /* 72 * Default timeout values, all in seconds. 73 * Make these tunable (only via mdb for now). 74 */ 75 int smb_timo_notice = 15; 76 int smb_timo_default = 30; /* was SMB_DEFRQTIMO */ 77 int smb_timo_open = 45; 78 int smb_timo_read = 45; 79 int smb_timo_write = 60; /* was SMBWRTTIMO */ 80 int smb_timo_append = 90; 81 82 static int smb_smb_read(struct smb_share *ssp, uint16_t fid, 83 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 84 static int smb_smb_write(struct smb_share *ssp, uint16_t fid, 85 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 86 87 static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, 88 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 89 static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, 90 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 91 92 int 93 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 94 { 95 struct smb_vc *vcp; 96 struct smb_rq *rqp = NULL; 97 struct mbchain *mbp; 98 struct mdchain *mdp; 99 char *pbuf, *unc_name = NULL; 100 int error, tlen, plen, unc_len; 101 uint16_t bcnt, options; 102 uint8_t wc; 103 104 vcp = SSTOVC(ssp); 105 106 /* 107 * Make this a "VC-level" request, so it will have 108 * rqp->sr_share == NULL, and smb_iod_sendrq() 109 * will send it with TID = SMB_TID_UNKNOWN 110 * 111 * This also serves to bypass the wait for 112 * share state changes, which this call is 113 * trying to carry out. 114 */ 115 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX, 116 scred, &rqp); 117 if (error) 118 return (error); 119 120 /* 121 * Build the UNC name, i.e. "//server/share" 122 * but with backslashes of course. 123 * size math: three slashes, one null. 124 */ 125 unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); 126 unc_name = kmem_alloc(unc_len, KM_SLEEP); 127 (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", 128 vcp->vc_srvname, ssp->ss_name); 129 130 /* 131 * The password is now pre-computed in the 132 * user-space helper process. 133 */ 134 plen = ssp->ss_pwlen; 135 pbuf = ssp->ss_pass; 136 137 /* 138 * Build the request. 139 */ 140 mbp = &rqp->sr_rq; 141 smb_rq_wstart(rqp); 142 mb_put_uint8(mbp, 0xff); 143 mb_put_uint8(mbp, 0); 144 mb_put_uint16le(mbp, 0); 145 mb_put_uint16le(mbp, 0); /* Flags */ 146 mb_put_uint16le(mbp, plen); 147 smb_rq_wend(rqp); 148 smb_rq_bstart(rqp); 149 150 /* Tree connect password, if any */ 151 error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM); 152 if (error) 153 goto out; 154 155 /* UNC resource name */ 156 error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE); 157 if (error) 158 goto out; 159 160 /* 161 * Put the type string (always ASCII), 162 * including the null. 163 */ 164 tlen = strlen(ssp->ss_type_req) + 1; 165 error = mb_put_mem(mbp, ssp->ss_type_req, tlen, MB_MSYSTEM); 166 if (error) 167 goto out; 168 169 smb_rq_bend(rqp); 170 171 /* 172 * Run the request. 173 * 174 * Using NOINTR_RECV because we don't want to risk 175 * missing a successful tree connect response, 176 * which would "leak" Tree IDs. 177 */ 178 rqp->sr_flags |= SMBR_NOINTR_RECV; 179 error = smb_rq_simple(rqp); 180 SMBSDEBUG("%d\n", error); 181 if (error) 182 goto out; 183 184 /* 185 * Parse the TCON response 186 */ 187 smb_rq_getreply(rqp, &mdp); 188 md_get_uint8(mdp, &wc); 189 if (wc != 3) { 190 error = EBADRPC; 191 goto out; 192 } 193 md_get_uint16le(mdp, NULL); /* AndX cmd */ 194 md_get_uint16le(mdp, NULL); /* AndX off */ 195 md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ 196 error = md_get_uint16le(mdp, &bcnt); /* byte count */ 197 if (error) 198 goto out; 199 200 /* 201 * Get the returned share type string, 202 * i.e. "IPC" or whatever. Don't care 203 * if we get an error reading the type. 204 */ 205 tlen = sizeof (ssp->ss_type_ret); 206 bzero(ssp->ss_type_ret, tlen--); 207 if (tlen > bcnt) 208 tlen = bcnt; 209 md_get_mem(mdp, ssp->ss_type_ret, tlen, MB_MSYSTEM); 210 211 /* Success! */ 212 SMB_SS_LOCK(ssp); 213 ssp->ss_tid = rqp->sr_rptid; 214 ssp->ss_vcgenid = vcp->vc_genid; 215 ssp->ss_options = options; 216 ssp->ss_flags |= SMBS_CONNECTED; 217 SMB_SS_UNLOCK(ssp); 218 219 out: 220 if (unc_name) 221 kmem_free(unc_name, unc_len); 222 smb_rq_done(rqp); 223 return (error); 224 } 225 226 int 227 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 228 { 229 struct smb_vc *vcp; 230 struct smb_rq *rqp; 231 int error; 232 233 if (ssp->ss_tid == SMB_TID_UNKNOWN) 234 return (0); 235 236 /* 237 * Build this as a "VC-level" request, so it will 238 * avoid testing the _GONE flag on the share, 239 * which has already been set at this point. 240 * Add the share pointer "by hand" below, so 241 * smb_iod_sendrq will plug in the TID. 242 */ 243 vcp = SSTOVC(ssp); 244 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 245 if (error) 246 return (error); 247 rqp->sr_share = ssp; /* by hand */ 248 249 smb_rq_wstart(rqp); 250 smb_rq_wend(rqp); 251 smb_rq_bstart(rqp); 252 smb_rq_bend(rqp); 253 254 /* 255 * Run this with a relatively short timeout. (5 sec.) 256 * We don't really care about the result here, but we 257 * do need to make sure we send this out, or we could 258 * "leak" active tree IDs on interrupt or timeout. 259 * The NOINTR_SEND flag makes this request immune to 260 * interrupt or timeout until the send is done. 261 * Also, don't reconnect for this, of course! 262 */ 263 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); 264 error = smb_rq_simple_timed(rqp, 5); 265 SMBSDEBUG("%d\n", error); 266 smb_rq_done(rqp); 267 ssp->ss_tid = SMB_TID_UNKNOWN; 268 return (error); 269 } 270 271 /* 272 * Common function for read/write with UIO. 273 * Called by netsmb smb_usr_rw, 274 * smbfs_readvnode, smbfs_writevnode 275 */ 276 int 277 smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw, 278 uio_t *uiop, smb_cred_t *scred, int timo) 279 { 280 struct smb_vc *vcp = SSTOVC(ssp); 281 ssize_t save_resid; 282 uint32_t len, rlen, maxlen; 283 int error = 0; 284 int (*iofun)(struct smb_share *, uint16_t, uint32_t *, 285 uio_t *, smb_cred_t *, int); 286 287 /* 288 * Determine which function to use, 289 * and the transfer size per call. 290 */ 291 if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) { 292 /* 293 * Using NT LM 0.12, so readx, writex. 294 * Make sure we can represent the offset. 295 */ 296 if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 && 297 (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) 298 return (EFBIG); 299 300 if (rw == UIO_READ) { 301 iofun = smb_smb_readx; 302 if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) 303 maxlen = SMB_MAX_LARGE_RW_SIZE; 304 else 305 maxlen = vcp->vc_rxmax; 306 } else { /* UIO_WRITE */ 307 iofun = smb_smb_writex; 308 if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) 309 maxlen = SMB_MAX_LARGE_RW_SIZE; 310 else 311 maxlen = vcp->vc_wxmax; 312 } 313 } else { 314 /* 315 * Using the old SMB_READ and SMB_WRITE so 316 * we're limited to 32-bit offsets, etc. 317 * XXX: Someday, punt the old dialects. 318 */ 319 if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) 320 return (EFBIG); 321 322 if (rw == UIO_READ) { 323 iofun = smb_smb_read; 324 maxlen = vcp->vc_rxmax; 325 } else { /* UIO_WRITE */ 326 iofun = smb_smb_write; 327 maxlen = vcp->vc_wxmax; 328 } 329 } 330 331 save_resid = uiop->uio_resid; 332 while (uiop->uio_resid > 0) { 333 /* Lint: uio_resid may be 64-bits */ 334 rlen = len = (uint32_t)min(maxlen, uiop->uio_resid); 335 error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo); 336 337 /* 338 * Note: the iofun called uio_update, so 339 * not doing that here as one might expect. 340 * 341 * Quit the loop either on error, or if we 342 * transferred less then requested. 343 */ 344 if (error || (rlen < len)) 345 break; 346 347 timo = 0; /* only first I/O should wait */ 348 } 349 if (error && (save_resid != uiop->uio_resid)) { 350 /* 351 * Stopped on an error after having 352 * successfully transferred data. 353 * Suppress this error. 354 */ 355 SMBSDEBUG("error %d suppressed\n", error); 356 error = 0; 357 } 358 359 return (error); 360 } 361 362 static int 363 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 364 uio_t *uiop, smb_cred_t *scred, int timo) 365 { 366 struct smb_rq *rqp; 367 struct mbchain *mbp; 368 struct mdchain *mdp; 369 int error; 370 uint32_t offlo, offhi, rlen; 371 uint16_t lenhi, lenlo, off, doff; 372 uint8_t wc; 373 374 lenhi = (uint16_t)(*lenp >> 16); 375 lenlo = (uint16_t)*lenp; 376 offhi = (uint32_t)(uiop->uio_loffset >> 32); 377 offlo = (uint32_t)uiop->uio_loffset; 378 379 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 380 if (error) 381 return (error); 382 smb_rq_getrequest(rqp, &mbp); 383 smb_rq_wstart(rqp); 384 mb_put_uint8(mbp, 0xff); /* no secondary command */ 385 mb_put_uint8(mbp, 0); /* MBZ */ 386 mb_put_uint16le(mbp, 0); /* offset to secondary */ 387 mb_put_uint16le(mbp, fid); 388 mb_put_uint32le(mbp, offlo); /* offset (low part) */ 389 mb_put_uint16le(mbp, lenlo); /* MaxCount */ 390 mb_put_uint16le(mbp, 1); /* MinCount */ 391 /* (only indicates blocking) */ 392 mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */ 393 mb_put_uint16le(mbp, lenlo); /* Remaining ("obsolete") */ 394 mb_put_uint32le(mbp, offhi); /* offset (high part) */ 395 smb_rq_wend(rqp); 396 smb_rq_bstart(rqp); 397 smb_rq_bend(rqp); 398 399 if (timo == 0) 400 timo = smb_timo_read; 401 error = smb_rq_simple_timed(rqp, timo); 402 if (error) 403 goto out; 404 405 smb_rq_getreply(rqp, &mdp); 406 error = md_get_uint8(mdp, &wc); 407 if (error) 408 goto out; 409 if (wc != 12) { 410 error = EBADRPC; 411 goto out; 412 } 413 md_get_uint8(mdp, NULL); 414 md_get_uint8(mdp, NULL); 415 md_get_uint16le(mdp, NULL); 416 md_get_uint16le(mdp, NULL); 417 md_get_uint16le(mdp, NULL); /* data compaction mode */ 418 md_get_uint16le(mdp, NULL); 419 md_get_uint16le(mdp, &lenlo); /* data len ret. */ 420 md_get_uint16le(mdp, &doff); /* data offset */ 421 md_get_uint16le(mdp, &lenhi); 422 rlen = (lenhi << 16) | lenlo; 423 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 424 error = md_get_uint16le(mdp, NULL); /* ByteCount */ 425 if (error) 426 goto out; 427 /* 428 * Does the data offset indicate padding? 429 * The current offset is a constant, found 430 * by counting the md_get_ calls above. 431 */ 432 off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ 433 if (doff > off) /* pad byte(s)? */ 434 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); 435 if (rlen == 0) { 436 *lenp = rlen; 437 goto out; 438 } 439 /* paranoid */ 440 if (rlen > *lenp) { 441 SMBSDEBUG("bad server! rlen %d, len %d\n", 442 rlen, *lenp); 443 rlen = *lenp; 444 } 445 error = md_get_uio(mdp, uiop, rlen); 446 if (error) 447 goto out; 448 449 /* Success */ 450 *lenp = rlen; 451 452 out: 453 smb_rq_done(rqp); 454 return (error); 455 } 456 457 static int 458 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 459 uio_t *uiop, smb_cred_t *scred, int timo) 460 { 461 struct smb_rq *rqp; 462 struct mbchain *mbp; 463 struct mdchain *mdp; 464 int error; 465 uint32_t offlo, offhi, rlen; 466 uint16_t lenhi, lenlo; 467 uint8_t wc; 468 469 lenhi = (uint16_t)(*lenp >> 16); 470 lenlo = (uint16_t)*lenp; 471 offhi = (uint32_t)(uiop->uio_loffset >> 32); 472 offlo = (uint32_t)uiop->uio_loffset; 473 474 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 475 if (error) 476 return (error); 477 smb_rq_getrequest(rqp, &mbp); 478 smb_rq_wstart(rqp); 479 mb_put_uint8(mbp, 0xff); /* no secondary command */ 480 mb_put_uint8(mbp, 0); /* MBZ */ 481 mb_put_uint16le(mbp, 0); /* offset to secondary */ 482 mb_put_uint16le(mbp, fid); 483 mb_put_uint32le(mbp, offlo); /* offset (low part) */ 484 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 485 mb_put_uint16le(mbp, 0); /* !write-thru */ 486 mb_put_uint16le(mbp, 0); 487 mb_put_uint16le(mbp, lenhi); 488 mb_put_uint16le(mbp, lenlo); 489 mb_put_uint16le(mbp, 64); /* data offset from header start */ 490 mb_put_uint32le(mbp, offhi); /* offset (high part) */ 491 smb_rq_wend(rqp); 492 smb_rq_bstart(rqp); 493 494 mb_put_uint8(mbp, 0); /* pad byte */ 495 error = mb_put_uio(mbp, uiop, *lenp); 496 if (error) 497 goto out; 498 smb_rq_bend(rqp); 499 if (timo == 0) 500 timo = smb_timo_write; 501 error = smb_rq_simple_timed(rqp, timo); 502 if (error) 503 goto out; 504 smb_rq_getreply(rqp, &mdp); 505 error = md_get_uint8(mdp, &wc); 506 if (error) 507 goto out; 508 if (wc != 6) { 509 error = EBADRPC; 510 goto out; 511 } 512 md_get_uint8(mdp, NULL); /* andx cmd */ 513 md_get_uint8(mdp, NULL); /* reserved */ 514 md_get_uint16le(mdp, NULL); /* andx offset */ 515 md_get_uint16le(mdp, &lenlo); /* data len ret. */ 516 md_get_uint16le(mdp, NULL); /* remaining */ 517 error = md_get_uint16le(mdp, &lenhi); 518 if (error) 519 goto out; 520 521 /* Success */ 522 rlen = (lenhi << 16) | lenlo; 523 *lenp = rlen; 524 525 out: 526 smb_rq_done(rqp); 527 return (error); 528 } 529 530 static int 531 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 532 uio_t *uiop, smb_cred_t *scred, int timo) 533 { 534 struct smb_rq *rqp; 535 struct mbchain *mbp; 536 struct mdchain *mdp; 537 int error; 538 uint32_t off32; 539 uint16_t bc, cnt, dlen, rcnt, todo; 540 uint8_t wc; 541 542 ASSERT(uiop->uio_loffset <= UINT32_MAX); 543 off32 = (uint32_t)uiop->uio_loffset; 544 ASSERT(*lenp <= UINT16_MAX); 545 cnt = (uint16_t)*lenp; 546 /* This next is an "estimate" of planned reads. */ 547 todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); 548 549 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 550 if (error) 551 return (error); 552 smb_rq_getrequest(rqp, &mbp); 553 smb_rq_wstart(rqp); 554 mb_put_uint16le(mbp, fid); 555 mb_put_uint16le(mbp, cnt); 556 mb_put_uint32le(mbp, off32); 557 mb_put_uint16le(mbp, todo); 558 smb_rq_wend(rqp); 559 smb_rq_bstart(rqp); 560 smb_rq_bend(rqp); 561 562 if (timo == 0) 563 timo = smb_timo_read; 564 error = smb_rq_simple_timed(rqp, timo); 565 if (error) 566 goto out; 567 smb_rq_getreply(rqp, &mdp); 568 error = md_get_uint8(mdp, &wc); 569 if (error) 570 goto out; 571 if (wc != 5) { 572 error = EBADRPC; 573 goto out; 574 } 575 md_get_uint16le(mdp, &rcnt); /* ret. count */ 576 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ 577 md_get_uint16le(mdp, &bc); /* byte count */ 578 md_get_uint8(mdp, NULL); /* buffer format */ 579 error = md_get_uint16le(mdp, &dlen); /* data len */ 580 if (error) 581 goto out; 582 if (dlen < rcnt) { 583 SMBSDEBUG("oops: dlen=%d rcnt=%d\n", 584 (int)dlen, (int)rcnt); 585 rcnt = dlen; 586 } 587 if (rcnt == 0) { 588 *lenp = 0; 589 goto out; 590 } 591 /* paranoid */ 592 if (rcnt > cnt) { 593 SMBSDEBUG("bad server! rcnt %d, cnt %d\n", 594 (int)rcnt, (int)cnt); 595 rcnt = cnt; 596 } 597 error = md_get_uio(mdp, uiop, (int)rcnt); 598 if (error) 599 goto out; 600 601 /* success */ 602 *lenp = (int)rcnt; 603 604 out: 605 smb_rq_done(rqp); 606 return (error); 607 } 608 609 static int 610 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 611 uio_t *uiop, smb_cred_t *scred, int timo) 612 { 613 struct smb_rq *rqp; 614 struct mbchain *mbp; 615 struct mdchain *mdp; 616 int error; 617 uint32_t off32; 618 uint16_t cnt, rcnt, todo; 619 uint8_t wc; 620 621 ASSERT(uiop->uio_loffset <= UINT32_MAX); 622 off32 = (uint32_t)uiop->uio_loffset; 623 ASSERT(*lenp <= UINT16_MAX); 624 cnt = (uint16_t)*lenp; 625 /* This next is an "estimate" of planned writes. */ 626 todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); 627 628 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 629 if (error) 630 return (error); 631 smb_rq_getrequest(rqp, &mbp); 632 smb_rq_wstart(rqp); 633 mb_put_uint16le(mbp, fid); 634 mb_put_uint16le(mbp, cnt); 635 mb_put_uint32le(mbp, off32); 636 mb_put_uint16le(mbp, todo); 637 smb_rq_wend(rqp); 638 smb_rq_bstart(rqp); 639 mb_put_uint8(mbp, SMB_DT_DATA); 640 mb_put_uint16le(mbp, cnt); 641 642 error = mb_put_uio(mbp, uiop, *lenp); 643 if (error) 644 goto out; 645 smb_rq_bend(rqp); 646 if (timo == 0) 647 timo = smb_timo_write; 648 error = smb_rq_simple_timed(rqp, timo); 649 if (error) 650 goto out; 651 smb_rq_getreply(rqp, &mdp); 652 error = md_get_uint8(mdp, &wc); 653 if (error) 654 goto out; 655 if (wc != 1) { 656 error = EBADRPC; 657 goto out; 658 } 659 error = md_get_uint16le(mdp, &rcnt); 660 if (error) 661 goto out; 662 *lenp = rcnt; 663 664 out: 665 smb_rq_done(rqp); 666 return (error); 667 } 668 669 670 static u_int32_t smbechoes = 0; 671 672 int 673 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) 674 { 675 struct smb_rq *rqp; 676 struct mbchain *mbp; 677 int error; 678 679 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); 680 if (error) 681 return (error); 682 mbp = &rqp->sr_rq; 683 smb_rq_wstart(rqp); 684 mb_put_uint16le(mbp, 1); /* echo count */ 685 smb_rq_wend(rqp); 686 smb_rq_bstart(rqp); 687 mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes)); 688 smb_rq_bend(rqp); 689 /* 690 * Note: the IOD calls this, so 691 * this request must not wait for 692 * connection state changes, etc. 693 */ 694 rqp->sr_flags |= SMBR_NORECONNECT; 695 error = smb_rq_simple_timed(rqp, timo); 696 SMBSDEBUG("%d\n", error); 697 smb_rq_done(rqp); 698 return (error); 699 } 700