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_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $ 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/autoconf.h> 40 #include <sys/sysmacros.h> 41 #include <sys/sunddi.h> 42 #include <sys/kmem.h> 43 #include <sys/proc.h> 44 #include <sys/protosw.h> 45 #include <sys/socket.h> 46 #include <sys/poll.h> 47 #include <sys/stream.h> 48 #include <sys/strsubr.h> 49 #include <sys/strsun.h> 50 #include <sys/stropts.h> 51 #include <sys/cmn_err.h> 52 #include <sys/tihdr.h> 53 #include <sys/tiuser.h> 54 #include <sys/t_kuser.h> 55 #include <sys/priv.h> 56 57 #include <net/if.h> 58 #include <net/route.h> 59 60 #include <netinet/in.h> 61 #include <netinet/tcp.h> 62 63 #ifdef APPLE 64 #include <sys/smb_apple.h> 65 #else 66 #include <netsmb/smb_osdep.h> 67 #endif 68 69 #include <netsmb/mchain.h> 70 #include <netsmb/netbios.h> 71 72 #include <netsmb/smb.h> 73 #include <netsmb/smb_conn.h> 74 #include <netsmb/smb_subr.h> 75 #include <netsmb/smb_tran.h> 76 #include <netsmb/smb_trantcp.h> 77 78 /* 79 * SMB messages are up to 64K. 80 * Let's leave room for two. 81 */ 82 static int smb_tcpsndbuf = 0x20000; 83 static int smb_tcprcvbuf = 0x20000; 84 85 static dev_t smb_tcp_dev; 86 87 static int nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp, 88 uint8_t *rpcodep, struct proc *p); 89 static int nb_disconnect(struct nbpcb *nbp); 90 91 static int 92 nb_wait_ack(TIUSER *tiptr, t_scalar_t ack_prim, int fmode) 93 { 94 int msgsz; 95 union T_primitives *pptr; 96 mblk_t *bp; 97 ptrdiff_t diff; 98 int error; 99 100 /* 101 * wait for ack 102 */ 103 bp = NULL; 104 if ((error = tli_recv(tiptr, &bp, fmode)) != 0) 105 return (error); 106 107 /*LINTED*/ 108 diff = MBLKL(bp); 109 ASSERT(diff == (ptrdiff_t)((int)diff)); 110 msgsz = (int)diff; 111 112 if (msgsz < sizeof (int)) { 113 freemsg(bp); 114 return (EPROTO); 115 } 116 117 /*LINTED*/ 118 pptr = (union T_primitives *)bp->b_rptr; 119 if (pptr->type == ack_prim) 120 error = 0; /* Success */ 121 else if (pptr->type == T_ERROR_ACK) { 122 if (pptr->error_ack.TLI_error == TSYSERR) 123 error = pptr->error_ack.UNIX_error; 124 else 125 error = t_tlitosyserr(pptr->error_ack.TLI_error); 126 } else 127 error = EPROTO; 128 129 freemsg(bp); 130 return (error); 131 } 132 133 /* 134 * Internal set sockopt for int-sized options. 135 * Is there a common Solaris function for this? 136 * Code from uts/common/rpc/clnt_cots.c 137 */ 138 static int 139 nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val) 140 { 141 int fmode; 142 mblk_t *mp; 143 struct opthdr *opt; 144 struct T_optmgmt_req *tor; 145 int *valp; 146 int error, mlen; 147 148 mlen = (sizeof (struct T_optmgmt_req) + 149 sizeof (struct opthdr) + sizeof (int)); 150 if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error))) 151 return (error); 152 153 mp->b_datap->db_type = M_PROTO; 154 /*LINTED*/ 155 tor = (struct T_optmgmt_req *)mp->b_wptr; 156 tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 157 tor->MGMT_flags = T_NEGOTIATE; 158 tor->OPT_length = sizeof (struct opthdr) + sizeof (int); 159 tor->OPT_offset = sizeof (struct T_optmgmt_req); 160 mp->b_wptr += sizeof (struct T_optmgmt_req); 161 162 /*LINTED*/ 163 opt = (struct opthdr *)mp->b_wptr; 164 opt->level = level; 165 opt->name = name; 166 opt->len = sizeof (int); 167 mp->b_wptr += sizeof (struct opthdr); 168 169 /* LINTED */ 170 valp = (int *)mp->b_wptr; 171 *valp = val; 172 mp->b_wptr += sizeof (int); 173 174 fmode = tiptr->fp->f_flag; 175 if ((error = tli_send(tiptr, mp, fmode)) != 0) 176 return (error); 177 178 fmode = 0; /* need to block */ 179 error = nb_wait_ack(tiptr, T_OPTMGMT_ACK, fmode); 180 return (error); 181 } 182 183 /* 184 * Get mblks into *mpp until the data length is at least mlen. 185 * Note that *mpp may already contain a fragment. 186 * 187 * If we ever have to wait more than 15 sec. to read a message, 188 * return ETIME. (Caller will declare the VD dead.) 189 */ 190 static int 191 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen) 192 { 193 mblk_t *im, *tm; 194 union T_primitives *pptr; 195 size_t dlen; 196 int events, fmode, timo, waitflg; 197 int error = 0; 198 199 /* 200 * Get the first message (fragment) if 201 * we don't already have a left-over. 202 */ 203 dlen = msgdsize(*mpp); /* *mpp==null is OK */ 204 while (dlen < mlen) { 205 206 /* 207 * I think we still want this to return ETIME 208 * if nothing arrives for SMB_NBTIMO (15) sec. 209 * so we can report "server not responding". 210 * We _could_ just block here now that our 211 * IOD is just a reader. 212 */ 213 #if 1 214 /* Wait with timeout... */ 215 events = 0; 216 waitflg = READWAIT; 217 timo = SEC_TO_TICK(SMB_NBTIMO); 218 error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events); 219 if (!error && !events) 220 error = ETIME; 221 if (error) 222 break; 223 /* file mode for recv is: */ 224 fmode = FNDELAY; /* non-blocking */ 225 #else 226 fmode = 0; /* normal (blocking) */ 227 #endif 228 229 /* Get some more... */ 230 tm = NULL; 231 error = tli_recv(nbp->nbp_tiptr, &tm, fmode); 232 if (error == EAGAIN) 233 continue; 234 if (error) 235 break; 236 237 /* 238 * Normally get M_DATA messages here, 239 * but have to check for other types. 240 */ 241 switch (tm->b_datap->db_type) { 242 case M_DATA: 243 break; 244 case M_PROTO: 245 case M_PCPROTO: 246 /*LINTED*/ 247 pptr = (union T_primitives *)tm->b_rptr; 248 switch (pptr->type) { 249 case T_DATA_IND: 250 /* remove 1st mblk, keep the rest. */ 251 im = tm->b_cont; 252 tm->b_cont = NULL; 253 freeb(tm); 254 tm = im; 255 break; 256 case T_DISCON_IND: 257 /* Peer disconnected. */ 258 NBDEBUG("T_DISCON_IND: reason=%d", 259 pptr->discon_ind.DISCON_reason); 260 goto discon; 261 case T_ORDREL_IND: 262 /* Peer disconnecting. */ 263 NBDEBUG("T_ORDREL_IND"); 264 goto discon; 265 case T_OK_ACK: 266 switch (pptr->ok_ack.CORRECT_prim) { 267 case T_DISCON_REQ: 268 NBDEBUG("T_OK_ACK/T_DISCON_REQ"); 269 goto discon; 270 default: 271 NBDEBUG("T_OK_ACK/prim=%d", 272 pptr->ok_ack.CORRECT_prim); 273 goto discon; 274 } 275 default: 276 NBDEBUG("M_PROTO/type=%d", pptr->type); 277 goto discon; 278 } 279 break; /* M_PROTO, M_PCPROTO */ 280 281 default: 282 NBDEBUG("unexpected msg type=%d", 283 tm->b_datap->db_type); 284 /*FALLTHROUGH*/ 285 discon: 286 /* 287 * The connection is no longer usable. 288 * Drop this message and disconnect. 289 * 290 * Note: nb_disconnect only does t_snddis 291 * on the first call, but does important 292 * cleanup and state change on any call. 293 */ 294 freemsg(tm); 295 nb_disconnect(nbp); 296 return (ENOTCONN); 297 } 298 299 /* 300 * If we have a data message, append it to 301 * the previous chunk(s) and update dlen 302 */ 303 if (!tm) 304 continue; 305 if (*mpp == NULL) { 306 *mpp = tm; 307 } else { 308 /* Append */ 309 for (im = *mpp; im->b_cont; im = im->b_cont) 310 ; 311 im->b_cont = tm; 312 } 313 dlen += msgdsize(tm); 314 } 315 316 return (error); 317 } 318 319 /* 320 * Send a T_DISCON_REQ (disconnect) 321 */ 322 static int 323 nb_snddis(TIUSER *tiptr) 324 { 325 mblk_t *mp; 326 struct T_discon_req *dreq; 327 int error, fmode, mlen; 328 329 mlen = sizeof (struct T_discon_req); 330 if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error))) 331 return (error); 332 333 mp->b_datap->db_type = M_PROTO; 334 /*LINTED*/ 335 dreq = (struct T_discon_req *)mp->b_wptr; 336 dreq->PRIM_type = T_DISCON_REQ; 337 dreq->SEQ_number = -1; 338 mp->b_wptr += sizeof (struct T_discon_req); 339 340 fmode = tiptr->fp->f_flag; 341 if ((error = tli_send(tiptr, mp, fmode)) != 0) 342 return (error); 343 344 #if 0 /* Now letting the IOD recv this. */ 345 fmode = 0; /* need to block */ 346 error = nb_wait_ack(tiptr, T_OK_ACK, fmode); 347 #endif 348 return (error); 349 } 350 351 #ifdef APPLE 352 static int 353 nb_intr(struct nbpcb *nbp, struct proc *p) 354 { 355 return (0); 356 } 357 #endif 358 359 /* 360 * Stuff the NetBIOS header into space already prepended. 361 */ 362 static int 363 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len) 364 { 365 uint32_t *p; 366 367 len &= 0x1FFFF; 368 len |= (type << 24); 369 370 /*LINTED*/ 371 p = (uint32_t *)m->b_rptr; 372 *p = htonl(len); 373 return (0); 374 } 375 376 /* 377 * Note: Moved name encoding into here. 378 */ 379 static int 380 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) 381 { 382 int i, len; 383 uchar_t ch, *p; 384 385 /* 386 * Do the NetBIOS "first-level encoding" here. 387 * (RFC1002 explains this wierdness...) 388 * See similar code in smbfs library: 389 * lib/libsmbfs/smb/nb_name.c 390 * 391 * Here is what we marshall: 392 * uint8_t NAME_LENGTH (always 32) 393 * uint8_t ENCODED_NAME[32] 394 * uint8_t SCOPE_LENGTH 395 * XXX Scope should follow here, then another null, 396 * if and when we support NetBIOS scopes. 397 */ 398 len = 1 + (2 * NB_NAMELEN) + 1; 399 400 p = mb_reserve(mbp, len); 401 if (!p) 402 return (ENOSR); 403 404 /* NAME_LENGTH */ 405 *p++ = (2 * NB_NAMELEN); 406 407 /* ENCODED_NAME */ 408 for (i = 0; i < NB_NAMELEN; i++) { 409 ch = (uchar_t)snb->snb_name[i]; 410 *p++ = 'A' + ((ch >> 4) & 0xF); 411 *p++ = 'A' + ((ch) & 0xF); 412 } 413 414 /* SCOPE_LENGTH */ 415 *p++ = 0; 416 417 return (0); 418 } 419 420 static int 421 nb_tcpopen(struct nbpcb *nbp, struct proc *p) 422 { 423 TIUSER *tiptr; 424 int err, oflags = FREAD|FWRITE; 425 cred_t *cr = p->p_cred; 426 427 if (!smb_tcp_dev) { 428 smb_tcp_dev = makedevice( 429 clone_major, ddi_name_to_major("tcp")); 430 } 431 432 /* 433 * This magic arranges for our network endpoint 434 * to have the right "label" for operation in a 435 * "trusted extensions" environment. 436 */ 437 if (is_system_labeled()) { 438 cr = crdup(cr); 439 (void) setpflags(NET_MAC_AWARE, 1, cr); 440 } else { 441 crhold(cr); 442 } 443 err = t_kopen(NULL, smb_tcp_dev, oflags, &tiptr, cr); 444 crfree(cr); 445 if (err) 446 return (err); 447 448 /* Note: I_PUSH "timod" is done by t_kopen */ 449 450 /* Save the TPI handle we use everywhere. */ 451 nbp->nbp_tiptr = tiptr; 452 453 /* 454 * Internal ktli calls need the "fmode" flags 455 * from the t_kopen call. XXX: Not sure if the 456 * flags have the right bits set, or if we 457 * always want the same block/non-block flags. 458 * XXX: Look into this... 459 */ 460 nbp->nbp_fmode = tiptr->fp->f_flag; 461 return (0); 462 } 463 464 /*ARGSUSED*/ 465 static int 466 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p) 467 { 468 int error; 469 TIUSER *tiptr = NULL; 470 struct t_call call; 471 472 tiptr = nbp->nbp_tiptr; 473 if (tiptr == NULL) 474 return (EBADF); 475 if (nbp->nbp_flags & NBF_CONNECTED) 476 return (EISCONN); 477 478 /* 479 * Set various socket/TCP options. 480 * Failures here are not fatal - 481 * just log a complaint. 482 * 483 * We don't need these two: 484 * SO_RCVTIMEO, SO_SNDTIMEO 485 */ 486 487 error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF, 488 nbp->nbp_sndbuf); 489 if (error) 490 NBDEBUG("nb_connect_in: set SO_SNDBUF"); 491 492 error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF, 493 nbp->nbp_rcvbuf); 494 if (error) 495 NBDEBUG("nb_connect_in: set SO_RCVBUF"); 496 497 error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1); 498 if (error) 499 NBDEBUG("nb_connect_in: set SO_KEEPALIVE"); 500 501 error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1); 502 if (error) 503 NBDEBUG("nb_connect_in: set TCP_NODELAY"); 504 505 /* Do local bind (any address) */ 506 if ((error = t_kbind(tiptr, NULL, NULL)) != 0) { 507 NBDEBUG("nb_connect_in: bind local"); 508 return (error); 509 } 510 511 /* 512 * Setup (snd)call address (connect to). 513 * Just pass NULL for the (rcv)call. 514 */ 515 bzero(&call, sizeof (call)); 516 call.addr.len = sizeof (*to); 517 call.addr.buf = (char *)to; 518 /* call.opt - none */ 519 /* call.udata -- XXX: Should put NB session req here! */ 520 521 /* Send the connect, wait... */ 522 error = t_kconnect(tiptr, &call, NULL); 523 if (error) { 524 NBDEBUG("nb_connect_in: connect %d error", error); 525 /* 526 * XXX: t_kconnect returning EPROTO here instead of ETIMEDOUT 527 * here. Temporarily return ETIMEDOUT error if we get EPROTO. 528 */ 529 if (error == EPROTO) 530 error = ETIMEDOUT; 531 } else { 532 mutex_enter(&nbp->nbp_lock); 533 nbp->nbp_flags |= NBF_CONNECTED; 534 mutex_exit(&nbp->nbp_lock); 535 } 536 537 return (error); 538 } 539 540 static int 541 nbssn_rq_request(struct nbpcb *nbp, struct proc *p) 542 { 543 struct mbchain mb, *mbp = &mb; 544 struct mdchain md, *mdp = &md; 545 mblk_t *m0; 546 struct sockaddr_in sin; 547 ushort_t port; 548 uint8_t rpcode; 549 int error, rplen; 550 551 error = mb_init(mbp); 552 if (error) 553 return (error); 554 555 /* 556 * Put a zero for the 4-byte NetBIOS header, 557 * then let nb_sethdr() overwrite it. 558 */ 559 mb_put_uint32le(mbp, 0); 560 nb_put_name(mbp, nbp->nbp_paddr); 561 nb_put_name(mbp, nbp->nbp_laddr); 562 nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); 563 564 m0 = mb_detach(mbp); 565 error = tli_send(nbp->nbp_tiptr, m0, nbp->nbp_fmode); 566 m0 = NULL; /* Note: _always_ consumed by tli_send */ 567 mb_done(mbp); 568 if (error) 569 return (error); 570 571 nbp->nbp_state = NBST_RQSENT; 572 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p); 573 if (error == EWOULDBLOCK) { /* Timeout */ 574 NBDEBUG("initial request timeout\n"); 575 return (ETIMEDOUT); 576 } 577 if (error) { 578 NBDEBUG("recv() error %d\n", error); 579 return (error); 580 } 581 /* 582 * Process NETBIOS reply 583 */ 584 if (m0) 585 md_initm(mdp, m0); 586 587 error = 0; 588 if (rpcode == NB_SSN_POSRESP) { 589 mutex_enter(&nbp->nbp_lock); 590 nbp->nbp_state = NBST_SESSION; 591 mutex_exit(&nbp->nbp_lock); 592 goto out; 593 } 594 if (rpcode != NB_SSN_RTGRESP) { 595 error = ECONNABORTED; 596 goto out; 597 } 598 if (rplen != 6) { 599 error = ECONNABORTED; 600 goto out; 601 } 602 md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); 603 md_get_uint16(mdp, &port); 604 sin.sin_port = port; 605 nbp->nbp_state = NBST_RETARGET; 606 nb_disconnect(nbp); 607 error = nb_connect_in(nbp, &sin, p); 608 if (!error) 609 error = nbssn_rq_request(nbp, p); 610 if (error) { 611 nb_disconnect(nbp); 612 } 613 614 out: 615 if (m0) 616 md_done(mdp); 617 return (error); 618 } 619 620 /* 621 * Wait for up to 15 sec. for the next packet. 622 * Often return ETIME and do nothing else. 623 * When a packet header is available, check 624 * the header and get the length, but don't 625 * consume it. No side effects here except 626 * for the pullupmsg call. 627 */ 628 static int 629 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep) 630 { 631 uint32_t len, *hdr; 632 int error; 633 634 /* 635 * Get the first message (fragment) if 636 * we don't already have a left-over. 637 */ 638 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len)); 639 if (error) 640 return (error); 641 642 if (!pullupmsg(nbp->nbp_frag, sizeof (len))) 643 return (ENOSR); 644 645 /* 646 * Check the NetBIOS header. 647 * (NOT consumed here) 648 */ 649 /*LINTED*/ 650 hdr = (uint32_t *)nbp->nbp_frag->b_rptr; 651 652 len = ntohl(*hdr); 653 if ((len >> 16) & 0xFE) { 654 NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len); 655 return (EPIPE); 656 } 657 *rpcodep = (len >> 24) & 0xFF; 658 switch (*rpcodep) { 659 case NB_SSN_MESSAGE: 660 case NB_SSN_REQUEST: 661 case NB_SSN_POSRESP: 662 case NB_SSN_NEGRESP: 663 case NB_SSN_RTGRESP: 664 case NB_SSN_KEEPALIVE: 665 break; 666 default: 667 NBDEBUG("bad nb header received 0x%x (bogus type)\n", len); 668 return (EPIPE); 669 } 670 len &= 0x1ffff; 671 if (len > SMB_MAXPKTLEN) { 672 NBDEBUG("packet too long (%d)\n", len); 673 return (EFBIG); 674 } 675 *lenp = len; 676 return (0); 677 } 678 679 /* 680 * Receive a NetBIOS message. This may block to wait for the entire 681 * message to arrive. The caller knows there is (or should be) a 682 * message to be read. When we receive and drop a keepalive or 683 * zero-length message, return EAGAIN so the caller knows that 684 * something was received. This avoids false triggering of the 685 * "server not responding" state machine. 686 */ 687 /*ARGSUSED*/ 688 static int 689 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp, 690 uint8_t *rpcodep, struct proc *p) 691 { 692 TIUSER *tiptr = nbp->nbp_tiptr; 693 mblk_t *m0; 694 uint8_t rpcode; 695 int error; 696 size_t rlen, len; 697 698 /* We should be the only reader. */ 699 ASSERT(nbp->nbp_flags & NBF_RECVLOCK); 700 701 if (tiptr == NULL) 702 return (EBADF); 703 if (mpp) { 704 if (*mpp) { 705 NBDEBUG("*mpp not 0 - leak?"); 706 } 707 *mpp = NULL; 708 } 709 m0 = NULL; 710 711 /* 712 * Get the NetBIOS header (not consumed yet) 713 */ 714 error = nbssn_peekhdr(nbp, &len, &rpcode); 715 if (error) { 716 if (error != ETIME) 717 NBDEBUG("peekhdr, error=%d\n", error); 718 return (error); 719 } 720 NBDEBUG("Have pkt, type=0x%x len=0x%x\n", 721 (int)rpcode, (int)len); 722 723 /* 724 * Block here waiting for the whole packet to arrive. 725 * If we get a timeout, return without side effects. 726 * The data length we wait for here includes both the 727 * NetBIOS header and the payload. 728 */ 729 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4); 730 if (error) { 731 NBDEBUG("getmsg(body), error=%d\n", error); 732 return (error); 733 } 734 735 /* 736 * We now have an entire NetBIOS message. 737 * Trim off the NetBIOS header and consume it. 738 * Note: _peekhdr has done pullupmsg for us, 739 * so we know it's safe to advance b_rptr. 740 */ 741 m0 = nbp->nbp_frag; 742 m0->b_rptr += 4; 743 744 /* 745 * There may be more data after the message 746 * we're about to return, in which case we 747 * split it and leave the remainder. 748 */ 749 rlen = msgdsize(m0); 750 ASSERT(rlen >= len); 751 nbp->nbp_frag = NULL; 752 if (rlen > len) 753 nbp->nbp_frag = m_split(m0, len, 1); 754 755 if (nbp->nbp_state != NBST_SESSION) { 756 /* 757 * No session is established. 758 * Return whatever packet we got. 759 */ 760 goto out; 761 } 762 763 /* 764 * A session is established; the only packets 765 * we should see are session message and 766 * keep-alive packets. Drop anything else. 767 */ 768 switch (rpcode) { 769 770 case NB_SSN_KEEPALIVE: 771 /* 772 * It's a keepalive. Discard any data in it 773 * (there's not supposed to be any, but that 774 * doesn't mean some server won't send some) 775 */ 776 if (len) 777 NBDEBUG("Keepalive with data %d\n", (int)len); 778 error = EAGAIN; 779 break; 780 781 case NB_SSN_MESSAGE: 782 /* 783 * Session message. Does it have any data? 784 */ 785 if (len == 0) { 786 /* 787 * No data - treat as keepalive (drop). 788 */ 789 error = EAGAIN; 790 break; 791 } 792 /* 793 * Yes, has data. Return it. 794 */ 795 error = 0; 796 break; 797 798 default: 799 /* 800 * Drop anything else. 801 */ 802 NBDEBUG("non-session packet %x\n", rpcode); 803 error = EAGAIN; 804 break; 805 } 806 807 out: 808 if (error) { 809 if (m0) 810 m_freem(m0); 811 return (error); 812 } 813 if (mpp) 814 *mpp = m0; 815 else 816 m_freem(m0); 817 *lenp = (int)len; 818 *rpcodep = rpcode; 819 return (0); 820 } 821 822 /* 823 * SMB transport interface 824 */ 825 static int 826 smb_nbst_create(struct smb_vc *vcp, struct proc *p) 827 { 828 struct nbpcb *nbp; 829 int error; 830 831 nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP); 832 833 /* 834 * We don't keep reference counts or otherwise 835 * prevent nbp->nbp_tiptr from going away, so 836 * do the TLI open here and keep it until the 837 * last ref calls smb_nbst_done. 838 * This does t_kopen (open endpoint) 839 */ 840 error = nb_tcpopen(nbp, p); 841 if (error) { 842 kmem_free(nbp, sizeof (*nbp)); 843 return (error); 844 } 845 846 nbp->nbp_timo.tv_sec = SMB_NBTIMO; 847 nbp->nbp_state = NBST_CLOSED; /* really IDLE */ 848 nbp->nbp_vc = vcp; 849 nbp->nbp_sndbuf = smb_tcpsndbuf; 850 nbp->nbp_rcvbuf = smb_tcprcvbuf; 851 mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL); 852 vcp->vc_tdata = nbp; 853 return (0); 854 } 855 856 /*ARGSUSED*/ 857 static int 858 smb_nbst_done(struct smb_vc *vcp, struct proc *p) 859 { 860 struct nbpcb *nbp = vcp->vc_tdata; 861 862 if (nbp == NULL) 863 return (ENOTCONN); 864 vcp->vc_tdata = NULL; 865 866 /* 867 * Don't really need to disconnect here, 868 * because the close following will do it. 869 * But it's harmless. 870 */ 871 if (nbp->nbp_flags & NBF_CONNECTED) 872 nb_disconnect(nbp); 873 if (nbp->nbp_tiptr) 874 t_kclose(nbp->nbp_tiptr, 1); 875 if (nbp->nbp_laddr) 876 smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr); 877 if (nbp->nbp_paddr) 878 smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr); 879 mutex_destroy(&nbp->nbp_lock); 880 kmem_free(nbp, sizeof (*nbp)); 881 return (0); 882 } 883 884 /*ARGSUSED*/ 885 static int 886 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) 887 { 888 struct nbpcb *nbp = vcp->vc_tdata; 889 struct sockaddr_nb *snb; 890 int error; 891 892 NBDEBUG("\n"); 893 error = EINVAL; 894 895 if (nbp->nbp_flags & NBF_LOCADDR) 896 goto out; 897 898 /* 899 * Null name is an "anonymous" (NULL) bind request. 900 * (Let the transport pick a local name.) 901 * This transport does not support NULL bind. 902 */ 903 if (sap == NULL) 904 goto out; 905 906 /*LINTED*/ 907 snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap); 908 if (snb == NULL) { 909 error = ENOMEM; 910 goto out; 911 } 912 mutex_enter(&nbp->nbp_lock); 913 nbp->nbp_laddr = snb; 914 nbp->nbp_flags |= NBF_LOCADDR; 915 mutex_exit(&nbp->nbp_lock); 916 error = 0; 917 918 out: 919 return (error); 920 } 921 922 static int 923 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) 924 { 925 struct nbpcb *nbp = vcp->vc_tdata; 926 struct sockaddr_in sin; 927 struct sockaddr_nb *snb; 928 struct timespec ts1, ts2; 929 int error; 930 931 NBDEBUG("\n"); 932 if (nbp->nbp_tiptr == NULL) 933 return (EBADF); 934 if (nbp->nbp_laddr == NULL) 935 return (EINVAL); 936 937 /* 938 * Note: nbssn_rq_request() will call nbssn_recv(), 939 * so set the RECVLOCK flag here. Otherwise we'll 940 * hit an ASSERT for this flag in nbssn_recv(). 941 */ 942 mutex_enter(&nbp->nbp_lock); 943 if (nbp->nbp_flags & NBF_RECVLOCK) { 944 NBDEBUG("attempt to reenter session layer!\n"); 945 mutex_exit(&nbp->nbp_lock); 946 return (EWOULDBLOCK); 947 } 948 nbp->nbp_flags |= NBF_RECVLOCK; 949 mutex_exit(&nbp->nbp_lock); 950 951 /*LINTED*/ 952 snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap); 953 if (snb == NULL) { 954 error = ENOMEM; 955 goto out; 956 } 957 if (nbp->nbp_paddr) 958 smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr); 959 nbp->nbp_paddr = snb; 960 961 /* Setup the remote IP address. */ 962 bzero(&sin, sizeof (sin)); 963 sin.sin_family = AF_INET; 964 sin.sin_port = htons(SMB_TCP_PORT); 965 sin.sin_addr.s_addr = snb->snb_ipaddr; 966 967 /* 968 * For our general timeout we use the greater of 969 * the default (15 sec) and 4 times the time it 970 * took for the first round trip. We used to use 971 * just the latter, but sometimes if the first 972 * round trip is very fast the subsequent 4 sec 973 * timeouts are simply too short. 974 */ 975 gethrestime(&ts1); 976 error = nb_connect_in(nbp, &sin, p); 977 if (error) 978 goto out; 979 gethrestime(&ts2); 980 timespecsub(&ts2, &ts1); 981 timespecadd(&ts2, &ts2); 982 timespecadd(&ts2, &ts2); /* * 4 */ 983 /*CSTYLED*/ 984 if (timespeccmp(&ts2, (&(nbp->nbp_timo)), >)) 985 nbp->nbp_timo = ts2; 986 error = nbssn_rq_request(nbp, p); 987 if (error) 988 nb_disconnect(nbp); 989 out: 990 mutex_enter(&nbp->nbp_lock); 991 nbp->nbp_flags &= ~NBF_RECVLOCK; 992 mutex_exit(&nbp->nbp_lock); 993 994 return (error); 995 } 996 997 /*ARGSUSED*/ 998 static int 999 smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p) 1000 { 1001 struct nbpcb *nbp = vcp->vc_tdata; 1002 1003 if (nbp == NULL) 1004 return (ENOTCONN); 1005 1006 return (nb_disconnect(nbp)); 1007 } 1008 1009 static int 1010 nb_disconnect(struct nbpcb *nbp) 1011 { 1012 TIUSER *tiptr; 1013 int save_flags; 1014 1015 tiptr = nbp->nbp_tiptr; 1016 if (tiptr == NULL) 1017 return (EBADF); 1018 1019 mutex_enter(&nbp->nbp_lock); 1020 save_flags = nbp->nbp_flags; 1021 nbp->nbp_flags &= ~NBF_CONNECTED; 1022 if (nbp->nbp_frag) { 1023 freemsg(nbp->nbp_frag); 1024 nbp->nbp_frag = NULL; 1025 } 1026 mutex_exit(&nbp->nbp_lock); 1027 1028 if (save_flags & NBF_CONNECTED) 1029 nb_snddis(tiptr); 1030 1031 if (nbp->nbp_state != NBST_RETARGET) { 1032 nbp->nbp_state = NBST_CLOSED; /* really IDLE */ 1033 } 1034 return (0); 1035 } 1036 1037 /* 1038 * Always consume the message. 1039 * (On error too!) 1040 */ 1041 /*ARGSUSED*/ 1042 static int 1043 smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p) 1044 { 1045 struct nbpcb *nbp = vcp->vc_tdata; 1046 ptrdiff_t diff; 1047 uint32_t mlen; 1048 int error; 1049 1050 if (nbp == NULL || nbp->nbp_tiptr == NULL) { 1051 error = EBADF; 1052 goto errout; 1053 } 1054 1055 /* 1056 * Get the message length, which 1057 * does NOT include the NetBIOS header 1058 */ 1059 mlen = msgdsize(m); 1060 1061 /* 1062 * Normally, mb_init() will have left space 1063 * for us to prepend the NetBIOS header in 1064 * the data block of the first mblk. 1065 * However, we have to check in case other 1066 * code did not leave this space, or if the 1067 * message is from dupmsg (db_ref > 1) 1068 * 1069 * If don't find room in the first data block, 1070 * we have to allocb a new message and link it 1071 * on the front of the chain. We try not to 1072 * do this becuase it's less efficient. Also, 1073 * some network drivers will apparently send 1074 * each mblk in the chain as separate frames. 1075 * (That's arguably a driver bug.) 1076 */ 1077 1078 /* LINTED */ 1079 diff = MBLKHEAD(m); 1080 if (diff == 4 && DB_REF(m) == 1) { 1081 /* We can use the first dblk. */ 1082 m->b_rptr -= 4; 1083 } else { 1084 /* Link a new mblk on the head. */ 1085 mblk_t *m0; 1086 1087 /* M_PREPEND */ 1088 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error); 1089 if (!m0) 1090 goto errout; 1091 1092 m0->b_wptr += 4; 1093 m0->b_cont = m; 1094 m = m0; 1095 } 1096 1097 nb_sethdr(m, NB_SSN_MESSAGE, mlen); 1098 error = tli_send(nbp->nbp_tiptr, m, 0); 1099 return (error); 1100 1101 errout: 1102 if (m) 1103 m_freem(m); 1104 return (error); 1105 } 1106 1107 1108 static int 1109 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p) 1110 { 1111 struct nbpcb *nbp = vcp->vc_tdata; 1112 uint8_t rpcode; 1113 int error, rplen; 1114 1115 mutex_enter(&nbp->nbp_lock); 1116 if (nbp->nbp_flags & NBF_RECVLOCK) { 1117 NBDEBUG("attempt to reenter session layer!\n"); 1118 mutex_exit(&nbp->nbp_lock); 1119 return (EWOULDBLOCK); 1120 } 1121 nbp->nbp_flags |= NBF_RECVLOCK; 1122 mutex_exit(&nbp->nbp_lock); 1123 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p); 1124 mutex_enter(&nbp->nbp_lock); 1125 nbp->nbp_flags &= ~NBF_RECVLOCK; 1126 mutex_exit(&nbp->nbp_lock); 1127 return (error); 1128 } 1129 1130 /* 1131 * Wait for up to "ticks" clock ticks for input on vcp. 1132 * Returns zero if input is available, otherwise ETIME 1133 * indicating time expired, or other error codes. 1134 */ 1135 /*ARGSUSED*/ 1136 static int 1137 smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p) 1138 { 1139 int error; 1140 int events = 0; 1141 int waitflg = READWAIT; 1142 struct nbpcb *nbp = vcp->vc_tdata; 1143 1144 error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events); 1145 if (!error && !events) 1146 error = ETIME; 1147 1148 return (error); 1149 } 1150 1151 static int 1152 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 1153 { 1154 struct nbpcb *nbp = vcp->vc_tdata; 1155 1156 switch (param) { 1157 case SMBTP_SNDSZ: 1158 *(int *)data = nbp->nbp_sndbuf; 1159 break; 1160 case SMBTP_RCVSZ: 1161 *(int *)data = nbp->nbp_rcvbuf; 1162 break; 1163 case SMBTP_TIMEOUT: 1164 *(struct timespec *)data = nbp->nbp_timo; 1165 break; 1166 #ifdef SMBTP_SELECTID 1167 case SMBTP_SELECTID: 1168 *(void **)data = nbp->nbp_selectid; 1169 break; 1170 #endif 1171 #ifdef SMBTP_UPCALL 1172 case SMBTP_UPCALL: 1173 *(void **)data = nbp->nbp_upcall; 1174 break; 1175 #endif 1176 default: 1177 return (EINVAL); 1178 } 1179 return (0); 1180 } 1181 1182 /*ARGSUSED*/ 1183 static int 1184 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 1185 { 1186 return (EINVAL); 1187 } 1188 1189 /* 1190 * Check for fatal errors 1191 */ 1192 /*ARGSUSED*/ 1193 static int 1194 smb_nbst_fatal(struct smb_vc *vcp, int error) 1195 { 1196 switch (error) { 1197 case ENOTCONN: 1198 case ENETRESET: 1199 case ECONNABORTED: 1200 case EPIPE: 1201 return (1); 1202 } 1203 return (0); 1204 } 1205 1206 1207 struct smb_tran_desc smb_tran_nbtcp_desc = { 1208 SMBT_NBTCP, 1209 smb_nbst_create, 1210 smb_nbst_done, 1211 smb_nbst_bind, 1212 smb_nbst_connect, 1213 smb_nbst_disconnect, 1214 smb_nbst_send, 1215 smb_nbst_recv, 1216 smb_nbst_poll, 1217 smb_nbst_getparam, 1218 smb_nbst_setparam, 1219 smb_nbst_fatal, 1220 {NULL, NULL} 1221 }; 1222