1/* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/kernel.h> 39#include <sys/malloc.h> 40#include <sys/kpi_mbuf.h> 41#include <sys/proc.h> 42#include <sys/socket.h> 43#include <sys/uio.h> 44#include <sys/sysctl.h> 45 46#include <net/if.h> 47#include <net/route.h> 48 49#include <netinet/in.h> 50#include <netinet/tcp.h> 51 52#include <sys/smb_apple.h> 53 54#include <sys/mchain.h> 55 56#include <netsmb/netbios.h> 57 58#include <netsmb/smb.h> 59#include <netsmb/smb_2.h> 60#include <netsmb/smb_conn.h> 61#include <netsmb/smb_rq.h> 62#include <netsmb/smb_tran.h> 63#include <netsmb/smb_trantcp.h> 64#include <netsmb/smb_subr.h> 65 66#include <netsmb/smb_sleephandler.h> 67 68#define M_NBDATA M_PCB 69 70static uint32_t smb_tcpsndbuf = 4 * 1024 * 1024; /* SMBX srvr starts at 4 MB */ 71static uint32_t smb_tcprcvbuf = 4 * 1024 * 1024; 72 73SYSCTL_DECL(_net_smb_fs); 74SYSCTL_INT(_net_smb_fs, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, ""); 75SYSCTL_INT(_net_smb_fs, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, ""); 76 77static int nbssn_recv(struct nbpcb *nbp, mbuf_t *mpp, int *lenp, uint8_t *rpcodep, 78 struct timespec *wait_time); 79static int smb_nbst_disconnect(struct smb_vc *vcp); 80 81static int 82nb_setsockopt_int(socket_t so, int level, int name, int val) 83{ 84 return (sock_setsockopt(so, level, name, &val, (int)sizeof(val))); 85} 86 87static void 88nb_upcall(socket_t so, void *arg, int waitflag) 89{ 90#pragma unused(so, waitflag) 91 struct nbpcb *nbp = (struct nbpcb *)arg; 92 93 /* sanity check make sure everything seems ok */ 94 if ((so == NULL) || (nbp == NULL) || (nbp->nbp_tso == NULL) || (nbp->nbp_tso != so)) { 95#ifdef SMB_DEBUG 96 /* Don't log if nbp_tso is null we could be getting called after a disconnect */ 97 if (nbp && nbp->nbp_tso) { 98 SMBDEBUG("UPCALLED: so = %p nbp = %p nbp->nbp_tso = %p\n", so, nbp, (nbp) ? nbp->nbp_tso : NULL); 99 } 100#endif // SMB_DEBUG 101 return; 102 } 103 104 lck_mtx_lock(&nbp->nbp_lock); 105 106 nbp->nbp_flags |= NBF_UPCALLED; 107 /* 108 * If there's an upcall, pass it the selectid, 109 * otherwise wakeup on the selectid 110 */ 111 if (nbp->nbp_upcall) { 112 nbp->nbp_upcall(nbp->nbp_selectid); 113 } else if (nbp->nbp_selectid) 114 wakeup(nbp->nbp_selectid); 115 lck_mtx_unlock(&nbp->nbp_lock); 116 return; 117} 118 119static int 120nb_sethdr(struct nbpcb *nbp, mbuf_t m, uint8_t type, uint32_t len) 121{ 122 uint32_t *p = mbuf_data(m); 123 124 if (nbp->nbp_flags & NBF_NETBIOS) { 125 /* NetBIOS connection the length field is 17 bits */ 126 *p = htonl((len & SMB_MAXPKTLEN) | (type << 24)); 127 } else { 128 /* NetBIOS-less connection the length field is 24 bits */ 129 *p = htonl((len & SMB_LARGE_MAXPKTLEN) | (type << 24)); 130 } 131 132 return (0); 133} 134 135static int 136nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) 137{ 138 int error; 139 u_char seglen, *cp; 140 141 cp = snb->snb_name; 142 if (*cp == 0) 143 return (EINVAL); 144 NBDEBUG("[%s]\n", cp); 145 for (;;) { 146 seglen = (*cp) + 1; 147 error = mb_put_mem(mbp, (const char *)cp, seglen, MB_MSYSTEM); 148 if (error) 149 return (error); 150 if (seglen == 1) 151 break; 152 cp += seglen; 153 } 154 return (0); 155} 156 157static int tcp_connect(struct nbpcb *nbp, struct sockaddr *to) 158{ 159 socket_t so; 160 int error; 161 struct timeval tv; 162 int optlen; 163 uint32_t bufsize, default_size; 164 165 error = sock_socket(to->sa_family, SOCK_STREAM, IPPROTO_TCP, nb_upcall, nbp, &so); 166 if (error) 167 return (error); 168 169 nbp->nbp_tso = so; 170 tv.tv_sec = SMBSBTIMO; 171 tv.tv_usec = 0; 172 error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, (int)sizeof(tv)); 173 if (error) 174 goto bad; 175 176 error = sock_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &tv, (int)sizeof(tv)); 177 if (error) 178 goto bad; 179 180 sock_getsockopt(so, SOL_SOCKET, SO_RCVBUF, &nbp->nbp_rcvchunk, &optlen); 181 if (error) { 182 goto bad; 183 } 184 /* Max size we want to read off the buffer at a time, always half the socket size */ 185 nbp->nbp_rcvchunk /= 2; 186 /* Never let it go below 8K */ 187 if (nbp->nbp_rcvchunk < NB_SORECEIVE_CHUNK) { 188 nbp->nbp_rcvchunk = NB_SORECEIVE_CHUNK; 189 } 190 191 /* 192 * The default socket buffer size can vary depending on system pressure. 193 * Set SO_SNDBUF as large as we can get. 194 */ 195 bufsize = nbp->nbp_sndbuf; 196 optlen = sizeof(bufsize); 197 error = sock_getsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, &optlen); 198 if (error) { 199 /* Not sure what else we can do here, should never happen */ 200 SMBERROR("sock_getsockopt failed %d\n", error); 201 goto bad; 202 } 203 default_size = bufsize; 204 205 if (bufsize < nbp->nbp_sndbuf) { 206 do { 207 /* Not big enough, try to make it bigger */ 208 bufsize = nbp->nbp_sndbuf; 209 optlen = sizeof(bufsize); 210 error = sock_setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, optlen); 211 if ((error == 0) && (bufsize > 0x100000)) { 212 /* Currently, 1 MB seems to work fine */ 213 break; 214 } else { 215 /* Reduce by 64K and try again */ 216 nbp->nbp_sndbuf -= 0x10000; 217 } 218 } while (nbp->nbp_sndbuf >= 0x100000); 219 } 220 if (error) { 221 nbp->nbp_sndbuf = default_size; 222 } 223 else { 224 nbp->nbp_sndbuf = bufsize; 225 } 226 227 if (nbp->nbp_sndbuf < smb_tcpsndbuf) { 228 SMBWARNING("nbp_rcvbuf = %d nbp_sndbuf = %d\n", nbp->nbp_rcvbuf, nbp->nbp_sndbuf); 229 } 230 231 error = nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1); 232 if (error) 233 goto bad; 234 235 error = nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1); 236 if (error) 237 goto bad; 238 239 /* set SO_NOADDRERR to detect network changes ASAP */ 240 error = nb_setsockopt_int(so, SOL_SOCKET, SO_NOADDRERR, 1); 241 if (error) /* Should we error out if this fails? */ 242 goto bad; 243 244 /* just playin' it safe */ 245 nb_setsockopt_int(so, SOL_SOCKET, SO_UPCALLCLOSEWAIT, 1); 246 247 error = sock_nointerrupt(so, 0); 248 if (error) 249 goto bad; 250 251 error = sock_connect(so, (struct sockaddr*)to, MSG_DONTWAIT); 252 if (error && error != EINPROGRESS) 253 goto bad; 254 255 tv.tv_sec = 2; 256 tv.tv_usec = 0; 257 while ((error = sock_connectwait(so, &tv)) == EINPROGRESS) { 258 if ((error = smb_iod_nb_intr(nbp->nbp_vc))) 259 break; 260 } 261 if (!error) 262 return (0); 263 264bad: 265 smb_nbst_disconnect(nbp->nbp_vc); 266 return (error); 267} 268 269static int 270nbssn_rq_request(struct nbpcb *nbp) 271{ 272 struct mbchain mb, *mbp = &mb; 273 struct mdchain md, *mdp = &md; 274 mbuf_t m0; 275 struct sockaddr_in sin; 276 u_short port; 277 uint8_t rpcode; 278 int error, rplen; 279 280 error = mb_init(mbp); 281 if (error) 282 return (error); 283 mb_put_uint32le(mbp, 0); 284 nb_put_name(mbp, nbp->nbp_paddr); 285 nb_put_name(mbp, nbp->nbp_laddr); 286 nb_sethdr(nbp, mbp->mb_top, NB_SSN_REQUEST, (uint32_t)(mb_fixhdr(mbp) - 4)); 287 error = sock_sendmbuf(nbp->nbp_tso, NULL, (mbuf_t)mbp->mb_top, 0, NULL); 288 if (!error) 289 nbp->nbp_state = NBST_RQSENT; 290 mb_detach(mbp); 291 mb_done(mbp); 292 if (error) 293 return (error); 294 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, &nbp->nbp_timo); 295 if (error == EWOULDBLOCK) { /* Timeout */ 296 NBDEBUG("initial request timeout\n"); 297 return (ETIMEDOUT); 298 } 299 if (error) { 300 NBDEBUG("recv() error %d\n", error); 301 return (error); 302 } 303 /* 304 * Process NETBIOS reply 305 */ 306 if (m0) 307 md_initm(mdp, m0); 308 error = 0; 309 do { 310 if (rpcode == NB_SSN_POSRESP) { 311 lck_mtx_lock(&nbp->nbp_lock); 312 nbp->nbp_state = NBST_SESSION; 313 nbp->nbp_flags |= NBF_CONNECTED; 314 lck_mtx_unlock(&nbp->nbp_lock); 315 break; 316 } 317 if (rpcode != NB_SSN_RTGRESP) { 318 error = ECONNABORTED; 319 break; 320 } 321 if (rplen != 6) { 322 error = ECONNABORTED; 323 break; 324 } 325 md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); 326 md_get_uint16(mdp, &port); 327 sin.sin_port = port; 328 nbp->nbp_state = NBST_RETARGET; 329 smb_nbst_disconnect(nbp->nbp_vc); 330 error = tcp_connect(nbp, (struct sockaddr *)&sin); 331 if (!error) 332 error = nbssn_rq_request(nbp); 333 if (error) { 334 smb_nbst_disconnect(nbp->nbp_vc); 335 break; 336 } 337 } while(0); 338 if (m0) 339 md_done(mdp); 340 return (error); 341} 342 343static int nbssn_recvhdr(struct nbpcb *nbp, uint32_t *lenp, uint8_t *rpcodep, 344 struct timespec *wait_time) 345{ 346 struct iovec aio; 347 uint32_t len; 348 uint8_t *bytep; 349 int error; 350 size_t resid, recvdlen; 351 struct msghdr msg; 352 struct smbiod *iod = nbp->nbp_vc->vc_iod; 353 int flags = MSG_DONTWAIT; 354 355 resid = sizeof(len); 356 bytep = (uint8_t *)&len; 357 while (resid != 0) { 358 aio.iov_base = bytep; 359 aio.iov_len = resid; 360 bzero(&msg, sizeof(msg)); 361 msg.msg_iov = &aio; 362 msg.msg_iovlen = 1; 363 364 /* 365 * We are trying to read the nbt header which is 4 bytes long. The first 366 * time though the loop we set the flag to be MSG_DONTWAIT. Once we receive 367 * at least one byte then we will reset the flag to MSG_WAITALL. This means 368 * once we get part of the header we will only wait 5 seconds before giving 369 * up. 370 */ 371 error = sock_receive(nbp->nbp_tso, &msg, flags, &recvdlen); 372 /* 373 * If we have wait_time then we want to wait here for some amount of time 374 * that is determined by wait_time. 375 */ 376 if ((error == EWOULDBLOCK) && wait_time) { 377 lck_mtx_lock(&nbp->nbp_lock); 378 if (!(nbp->nbp_flags & NBF_UPCALLED)) 379 msleep(&iod->iod_flags, &nbp->nbp_lock, PWAIT, "nbssn", wait_time); 380 lck_mtx_unlock(&nbp->nbp_lock); 381 wait_time = 0; /* We are suppose to have some data waiting by now */ 382 flags = MSG_WAITALL; /* Wait for all four bytes */ 383 continue; 384 } 385 386 /* 387 * If we didn't get an error and recvdlen is zero then we have reached 388 * EOF. So the socket has the SS_CANTRCVMORE flag set. This means the other 389 * side has closed their side of the connection. 390 */ 391 if ((error == 0) && (recvdlen == 0) && resid) { 392 SMBWARNING("Server closed their side of the connection.\n"); 393 nbp->nbp_state = NBST_CLOSED; 394 error = EPIPE; 395 } 396 /* This should never happen, someday should we make it just a debug assert. */ 397 if ((error == 0) && (recvdlen > resid)) { 398 SMBERROR("Got more data than we asked for!\n"); 399 error = EPIPE; 400 } 401 /* The connect got closed */ 402 if (!sock_isconnected(nbp->nbp_tso)) { 403 nbp->nbp_state = NBST_CLOSED; 404 NBDEBUG("session closed by peer\n"); 405 error = EPIPE; 406 } 407 if (error) { 408 if ((error == EWOULDBLOCK) && resid && (resid < sizeof(len))) 409 SMBERROR("Timed out reading the nbt header: missing %ld bytes\n", resid); 410 return error; 411 } 412 413 /* 414 * At this point we have received some data, reset the flag to wait. We got 415 * part of the 4 byte length field only wait 5 seconds to get the rest. 416 */ 417 flags = MSG_WAITALL; 418 resid -= recvdlen; 419 bytep += recvdlen; 420 } 421 /* 422 * From http://support.microsoft.com/kb/204279 423 * 424 * Direct hosted "NetBIOS-less" SMB traffic uses port 445 (TCP and UDP). In 425 * this situation, a four-byte header precedes the SMB traffic. The first 426 * byte of this header is always 0x00, and the next three bytes are the 427 * length of the remaining data. 428 */ 429 len = ntohl(len); 430 *rpcodep = (len >> 24) & 0xFF; /* For port 445 this should be zero, NB_SSN_MESSAGE */ 431 if (nbp->nbp_flags & NBF_NETBIOS) { 432 /* Port 139, we can only use the first 17 bits for the length */ 433 if ((len >> 16) & 0xFE) { 434 SMBERROR("bad nb header received 0x%x (MBZ flag set)\n", len); 435 return (EPIPE); 436 } 437 len &= SMB_MAXPKTLEN; 438 } else { 439 /* "NetBIOS-less", we can only use the frist 24 bits for the length */ 440 len &= SMB_LARGE_MAXPKTLEN; 441 } 442 switch (*rpcodep) { 443 case NB_SSN_MESSAGE: 444 case NB_SSN_KEEPALIVE: /* Can "NetBIOS-less" have a keep alive, does hurt anything */ 445 break; 446 case NB_SSN_REQUEST: 447 case NB_SSN_POSRESP: 448 case NB_SSN_NEGRESP: 449 case NB_SSN_RTGRESP: 450 if (nbp->nbp_flags & NBF_NETBIOS) { 451 break; 452 } 453 default: 454 SMBERROR("bad nb header received 0x%x (bogus type)\n", len); 455 return (EPIPE); 456 } 457 *lenp = len; 458 return (0); 459} 460 461static int nbssn_recv(struct nbpcb *nbp, mbuf_t *mpp, int *lenp, uint8_t *rpcodep, 462 struct timespec *wait_time) 463{ 464 socket_t so = nbp->nbp_tso; 465 mbuf_t m; 466 mbuf_t tm; 467 uint8_t rpcode; 468 uint32_t len; 469 int32_t error; 470 size_t recvdlen, resid; 471 472 if (so == NULL) 473 return (ENOTCONN); 474 if (mpp) 475 *mpp = NULL; 476 m = NULL; 477 for(;;) { 478 /* 479 * Read the response header. 480 */ 481 lck_mtx_lock(&nbp->nbp_lock); 482 nbp->nbp_flags &= ~NBF_UPCALLED; 483 lck_mtx_unlock(&nbp->nbp_lock); 484 error = nbssn_recvhdr(nbp, &len, &rpcode, wait_time); 485 if (error) 486 return (error); 487 488 /* 489 * Loop, blocking, for data following the response header, if any. 490 * 491 * Note that we can't simply block here with MSG_WAITALL for the 492 * entire response size, as it may be larger than the TCP 493 * slow-start window that the sender employs. This will result 494 * in the sender stalling until the delayed ACK is sent, then 495 * resuming slow-start, resulting in very poor performance. 496 * 497 * Instead, we never request more than NB_SORECEIVE_CHUNK 498 * bytes at a time, resulting in an ack being pushed by 499 * the TCP code at the completion of each call. 500 */ 501 resid = len; 502 while (resid != 0) { 503 struct timespec tstart, tend; 504 tm = NULL; 505 /* 506 * We use to spin until we got a hard error, we no longer wait forever. 507 * We now limit how long we will block receiving any message. This timer only 508 * starts after we have read the 4 byte header length field. We then try to read 509 * the data in 8K chunks, if any read takes longer that 15 seconds we break the 510 * connection and give up. If we went to sleep then we reset our start timer to when we 511 * woke up. Now for the reason behind the fix. We have the message length, but looks 512 * like only part of the message has made it in. We went to sleep and the server 513 * broke the connect while we were still a sleep. Looks like we got the first 514 * ethernet packet but not the rest. We are in a loop waiting for the rest of the 515 * message. Since we can't send in this state there is no way for us to know that 516 * the connect is really down. 517 */ 518 nanouptime(&tstart); 519 do { 520 recvdlen = MIN(resid, nbp->nbp_rcvchunk); 521 error = sock_receivembuf(so, NULL, &tm, MSG_WAITALL, &recvdlen); 522 if (error == EAGAIN) { 523 nanouptime(&tend); 524 /* We fell asleep reset our timer to the wake up timer */ 525 if (tstart.tv_sec < gWakeTime.tv_sec) 526 tstart.tv_sec = gWakeTime.tv_sec; 527 /* Ok we have tried hard enough just break the connection and give up. */ 528 if (tend.tv_sec > (tstart.tv_sec + SMB_SB_RCVTIMEO)) { 529 error = EPIPE; 530 SMBERROR("Breaking connection, sock_receivembuf blocked for %d\n", (int)(tend.tv_sec - tstart.tv_sec)); 531 } 532 } 533 } while ((error == EAGAIN) || (error == EINTR) || (error == ERESTART)); 534 /* 535 * If we didn't get an error and recvdlen is zero then we have reached 536 * EOF. So the socket has the SS_CANTRCVMORE flag set. This means the other 537 * side has closed their side of the connection. 538 */ 539 if ((error == 0) && (recvdlen == 0) && resid) { 540 SMBWARNING("Server closed their side of the connection.\n"); 541 error = EPIPE; 542 } 543 /* 544 * This should never happen, someday should we make it just 545 * a debug assert. 546 */ 547 if ((error == 0) && (recvdlen > resid)) { 548 SMBERROR("Got more data than we asked for!\n"); 549 if (tm) 550 mbuf_freem(tm); 551 error = EPIPE; 552 } 553 if (error) 554 goto out; 555 556 resid -= recvdlen; 557 /* 558 * Append received chunk to previous chunk. Just glue 559 * the new chain on the end. Consumer will pullup as required. 560 */ 561 if (!m) { 562 m = (mbuf_t )tm; 563 m_fixhdr(m); /* Work around <15114764> */ 564 } else if (tm) { 565 mbuf_cat_internal(m, (mbuf_t )tm); 566 m_fixhdr(m); /* Work around <15114764> */ 567 } 568 } 569 570 /* 571 * If it's a keepalive, discard any data in it 572 * (there's not supposed to be any, but that 573 * doesn't mean some server won't send some) 574 * and get the next packet. 575 */ 576 if (rpcode == NB_SSN_KEEPALIVE) { 577 if (m) { 578 mbuf_freem(m); 579 m = NULL; 580 } 581 continue; 582 } 583 584 if (nbp->nbp_state != NBST_SESSION) { 585 /* 586 * No session is established. 587 * Return whatever packet we got. 588 */ 589 break; 590 } 591 592 /* 593 * A session is established; the only packets 594 * we should see are session message and 595 * keep-alive packets. 596 */ 597 if (rpcode == NB_SSN_MESSAGE) { 598 /* 599 * Session message. Does it have any data? 600 */ 601 if (!m) { 602 /* 603 * No - complain and continue. 604 */ 605 SMBERROR("empty session packet\n"); 606 continue; 607 } 608 609 /* 610 * Yes - return it to our caller. 611 */ 612 break; 613 } 614 615 /* 616 * Ignore other types of packets - drop packet 617 * and try for another. 618 */ 619 SMBERROR("non-session packet %x\n", rpcode); 620 if (m) { 621 mbuf_freem(m); 622 m = NULL; 623 } 624 } 625out: 626 if (error) { 627 if (m) 628 mbuf_freem(m); 629 return (error); 630 } 631 if (mpp) 632 *mpp = m; 633 else 634 mbuf_freem(m); 635 *lenp = len; 636 *rpcodep = rpcode; 637 return (0); 638} 639 640/* 641 * SMB transport interface 642 */ 643static int 644smb_nbst_create(struct smb_vc *vcp) 645{ 646 struct nbpcb *nbp; 647 648 SMB_MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK); 649 bzero(nbp, sizeof *nbp); 650 nbp->nbp_timo.tv_sec = SMB_NBTIMO; 651 nbp->nbp_state = NBST_CLOSED; 652 nbp->nbp_vc = vcp; 653 nbp->nbp_sndbuf = smb_tcpsndbuf; 654 nbp->nbp_rcvbuf = smb_tcprcvbuf; 655 lck_mtx_init(&nbp->nbp_lock, nbp_lck_group, nbp_lck_attr); 656 vcp->vc_tdata = nbp; 657 return (0); 658} 659 660static int 661smb_nbst_done(struct smb_vc *vcp) 662{ 663 struct nbpcb *nbp = vcp->vc_tdata; 664 665 if (nbp == NULL) 666 return (ENOTCONN); 667 smb_nbst_disconnect(vcp); 668 if (nbp->nbp_laddr) 669 SMB_FREE(nbp->nbp_laddr, M_SONAME); 670 if (nbp->nbp_paddr) 671 SMB_FREE(nbp->nbp_paddr, M_SONAME); 672 /* The vc_tdata is no longer valid */ 673 vcp->vc_tdata = NULL; 674 lck_mtx_destroy(&nbp->nbp_lock, nbp_lck_group); 675 SMB_FREE(nbp, M_NBDATA); 676 return (0); 677} 678 679static int 680smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap) 681{ 682 struct nbpcb *nbp = vcp->vc_tdata; 683 struct sockaddr_nb *snb; 684 int error, slen; 685 686 DBG_ASSERT(vcp->vc_tdata != NULL); 687 NBDEBUG("\n"); 688 error = EINVAL; 689 do { 690 if (nbp->nbp_flags & NBF_LOCADDR) 691 break; 692 /* 693 * It is possible to create NETBIOS name in the kernel, 694 * but nothing prevents us to do it in the user space. 695 */ 696 if (sap == NULL) 697 break; 698 slen = sap->sa_len; 699 if (slen < (int)NB_MINSALEN) 700 break; 701 snb = (struct sockaddr_nb*)smb_dup_sockaddr(sap, 1); 702 if (snb == NULL) { 703 error = ENOMEM; 704 break; 705 } 706 lck_mtx_lock(&nbp->nbp_lock); 707 nbp->nbp_laddr = snb; 708 nbp->nbp_flags |= NBF_LOCADDR; 709 lck_mtx_unlock(&nbp->nbp_lock); 710 error = 0; 711 } while(0); 712 return (error); 713} 714 715static int 716smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap) 717{ 718 struct nbpcb *nbp = vcp->vc_tdata; 719 struct sockaddr *so; 720 struct timespec ts1, ts2; 721 int error, slen; 722 723 NBDEBUG("\n"); 724 if (nbp == NULL) 725 return (EINVAL); 726 if (nbp->nbp_tso != NULL) 727 return (EISCONN); 728 if (sap->sa_family == AF_NETBIOS) { 729 if (nbp->nbp_laddr == NULL) 730 return (EINVAL); 731 slen = sap->sa_len; 732 if (slen < (int)NB_MINSALEN) 733 return (EINVAL); 734 if (nbp->nbp_paddr) { 735 SMB_FREE(nbp->nbp_paddr, M_SONAME); 736 nbp->nbp_paddr = NULL; 737 } 738 nbp->nbp_paddr = (struct sockaddr_nb*)smb_dup_sockaddr(sap, 1); 739 if (nbp->nbp_paddr == NULL) 740 return (ENOMEM); 741 so = (struct sockaddr*)&(nbp->nbp_paddr)->snb_addrin; 742 } else { 743 so = sap; 744 } 745 /* 746 * For our general timeout we use the greater of 747 * the default (15 sec) and 4 times the time it 748 * took for the first round trip. We used to use 749 * just the latter, but sometimes if the first 750 * round trip is very fast the subsequent 4 sec 751 * timeouts are simply too short. 752 */ 753 nanouptime(&ts1); 754 error = tcp_connect(nbp, so); 755 if (error) 756 return (error); 757 nanouptime(&ts2); 758 timespecsub(&ts2, &ts1); 759 timespecadd(&ts2, &ts2); 760 timespecadd(&ts2, &ts2); /* * 4 */ 761 if (timespeccmp(&ts2, &nbp->nbp_timo, >)) 762 nbp->nbp_timo = ts2; 763 /* If its not a NetBIOS connection, then we don't need to do a NetBIOS session connect */ 764 if (sap->sa_family != AF_NETBIOS) 765 nbp->nbp_state = NBST_SESSION; 766 else { 767 nbp->nbp_flags |= NBF_NETBIOS; 768 error = nbssn_rq_request(nbp); 769 if (error) 770 smb_nbst_disconnect(vcp); 771 } 772 return (error); 773} 774 775static int 776smb_nbst_disconnect(struct smb_vc *vcp) 777{ 778 struct nbpcb *nbp = vcp->vc_tdata; 779 socket_t so; 780 781 if (nbp == NULL || nbp->nbp_tso == NULL) 782 return (ENOTCONN); 783 if ((so = nbp->nbp_tso) != NULL) { 784 lck_mtx_lock(&nbp->nbp_lock); 785 nbp->nbp_flags &= ~NBF_CONNECTED; 786 nbp->nbp_tso = (socket_t) NULL; 787 lck_mtx_unlock(&nbp->nbp_lock); 788 sock_shutdown(so, 2); 789 sock_close(so); 790 } 791 if (nbp->nbp_state != NBST_RETARGET) { 792 nbp->nbp_state = NBST_CLOSED; 793 } 794 return (0); 795} 796 797static int 798smb_nbst_send(struct smb_vc *vcp, mbuf_t m0) 799{ 800 struct nbpcb *nbp = vcp->vc_tdata; 801 int error; 802 803 /* Should never happen, but just in case */ 804 DBG_ASSERT(nbp); 805 if ((nbp == NULL) || (nbp->nbp_state != NBST_SESSION)) { 806 error = ENOTCONN; 807 goto abort; 808 } 809 810 /* Add in the NetBIOS 4 byte header */ 811 if (mbuf_prepend(&m0, 4, MBUF_WAITOK)) 812 return (ENOBUFS); 813 nb_sethdr(nbp, m0, NB_SSN_MESSAGE, (uint32_t)(m_fixhdr(m0) - 4)); 814 error = sock_sendmbuf(nbp->nbp_tso, NULL, (mbuf_t)m0, 0, NULL); 815 return (error); 816abort: 817 if (m0) 818 mbuf_freem(m0); 819 return (error); 820} 821 822 823static int 824smb_nbst_recv(struct smb_vc *vcp, mbuf_t *mpp) 825{ 826 struct nbpcb *nbp = vcp->vc_tdata; 827 uint8_t rpcode, *hp; 828 int error, rplen; 829 830 /* Should never happen, but just in case */ 831 DBG_ASSERT(nbp); 832 if (nbp == NULL) 833 return (ENOTCONN); 834 835 lck_mtx_lock(&nbp->nbp_lock); 836 if (nbp->nbp_flags & NBF_RECVLOCK) { 837 SMBERROR("attempt to reenter session layer!\n"); 838 lck_mtx_unlock(&nbp->nbp_lock); 839 return (EWOULDBLOCK); 840 } 841 nbp->nbp_flags |= NBF_RECVLOCK; 842 lck_mtx_unlock(&nbp->nbp_lock); 843 844 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, NULL); 845 846 if (!error) { 847 /* Handle case when first mbuf is zero-length */ 848 error = mbuf_pullup(mpp, 1); 849 } 850 851 // Check for a transform header (encrypted msg) 852 if (!error) { 853 hp = mbuf_data(*mpp); 854 if (*hp == 0xfd) { 855 error = smb3_msg_decrypt(vcp, mpp); 856 } 857 } 858 859 if (error) { 860 *mpp = NULL; 861 } 862 863 lck_mtx_lock(&nbp->nbp_lock); 864 nbp->nbp_flags &= ~NBF_RECVLOCK; 865 lck_mtx_unlock(&nbp->nbp_lock); 866 return (error); 867} 868 869static void 870smb_nbst_timo(struct smb_vc *vcp) 871{ 872 #pragma unused(vcp) 873 return; 874} 875 876static int 877smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 878{ 879 struct nbpcb *nbp = vcp->vc_tdata; 880 881 /* Should never happen, but just in case */ 882 DBG_ASSERT(nbp); 883 if (nbp == NULL) 884 return (EINVAL); 885 switch (param) { 886 case SMBTP_SNDSZ: 887 *(uint32_t*)data = nbp->nbp_sndbuf; 888 break; 889 case SMBTP_RCVSZ: 890 *(uint32_t*)data = nbp->nbp_rcvbuf; 891 break; 892 case SMBTP_TIMEOUT: 893 *(struct timespec*)data = nbp->nbp_timo; 894 break; 895 case SMBTP_SELECTID: 896 *(void **)data = nbp->nbp_selectid; 897 break; 898 case SMBTP_UPCALL: 899 *(void **)data = nbp->nbp_upcall; 900 break; 901 default: 902 return (EINVAL); 903 } 904 return (0); 905} 906 907static int 908smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 909{ 910 struct nbpcb *nbp = vcp->vc_tdata; 911 912 /* Should never happen, but just in case */ 913 DBG_ASSERT(nbp); 914 if (nbp == NULL) 915 return (EINVAL); 916 switch (param) { 917 case SMBTP_SELECTID: 918 nbp->nbp_selectid = data; 919 break; 920 case SMBTP_UPCALL: 921 nbp->nbp_upcall = data; 922 break; 923 default: 924 return (EINVAL); 925 } 926 return (0); 927} 928 929/* 930 * Check for fatal errors 931 */ 932static int 933smb_nbst_fatal(struct smb_vc *vcp, int error) 934{ 935 struct nbpcb *nbp; 936 937 switch (error) { 938 case EHOSTDOWN: 939 case ENETUNREACH: 940 case ENOTCONN: 941 case ENETRESET: 942 case ECONNABORTED: 943 case EPIPE: 944 case EADDRNOTAVAIL: 945 return 1; 946 } 947 DBG_ASSERT(vcp); 948 nbp = vcp->vc_tdata; 949 if ((nbp == NULL) || (nbp->nbp_tso == NULL) || (! sock_isconnected(nbp->nbp_tso))) 950 return 1; 951 952 return (0); 953} 954 955struct smb_tran_desc smb_tran_nbtcp_desc = { 956 SMBT_NBTCP, 957 smb_nbst_create, smb_nbst_done, 958 smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect, 959 smb_nbst_send, smb_nbst_recv, 960 smb_nbst_timo, 961 smb_nbst_getparam, smb_nbst_setparam, 962 smb_nbst_fatal, 963 {NULL, NULL} 964}; 965