1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2000-2001 Boris Popov 5 * 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/condvar.h> 31 #include <sys/kernel.h> 32 #include <sys/lock.h> 33 #include <sys/malloc.h> 34 #include <sys/mbuf.h> 35 #include <sys/poll.h> 36 #include <sys/proc.h> 37 #include <sys/protosw.h> 38 #include <sys/signalvar.h> 39 #include <sys/socket.h> 40 #include <sys/socketvar.h> 41 #include <sys/sx.h> 42 #include <sys/sysctl.h> 43 #include <sys/systm.h> 44 #include <sys/uio.h> 45 46 #include <net/if.h> 47 #include <net/route.h> 48 #include <net/vnet.h> 49 50 #include <netinet/in.h> 51 #include <netinet/tcp.h> 52 53 #include <sys/mchain.h> 54 55 #include <netsmb/netbios.h> 56 57 #include <netsmb/smb.h> 58 #include <netsmb/smb_conn.h> 59 #include <netsmb/smb_tran.h> 60 #include <netsmb/smb_trantcp.h> 61 #include <netsmb/smb_subr.h> 62 63 #define M_NBDATA M_PCB 64 65 static int smb_tcpsndbuf = NB_SNDQ - 1; 66 static int smb_tcprcvbuf = NB_RCVQ - 1; 67 68 SYSCTL_DECL(_net_smb); 69 SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, ""); 70 SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, ""); 71 72 #define nb_sosend(so,m,flags,td) sosend(so, NULL, 0, m, 0, flags, td) 73 74 static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 75 u_int8_t *rpcodep, struct thread *td); 76 static int smb_nbst_disconnect(struct smb_vc *vcp, struct thread *td); 77 78 static int 79 nb_setsockopt_int(struct socket *so, int level, int name, int val) 80 { 81 struct sockopt sopt; 82 int error; 83 84 bzero(&sopt, sizeof(sopt)); 85 sopt.sopt_level = level; 86 sopt.sopt_name = name; 87 sopt.sopt_val = &val; 88 sopt.sopt_valsize = sizeof(val); 89 CURVNET_SET(so->so_vnet); 90 error = sosetopt(so, &sopt); 91 CURVNET_RESTORE(); 92 return error; 93 } 94 95 static int 96 nb_intr(struct nbpcb *nbp, struct proc *p) 97 { 98 return 0; 99 } 100 101 static int 102 nb_upcall(struct socket *so, void *arg, int waitflag) 103 { 104 struct nbpcb *nbp = arg; 105 106 if (arg == NULL || nbp->nbp_selectid == NULL) 107 return (SU_OK); 108 wakeup(nbp->nbp_selectid); 109 return (SU_OK); 110 } 111 112 static int 113 nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len) 114 { 115 u_int32_t *p = mtod(m, u_int32_t *); 116 117 *p = htonl((len & 0x1FFFF) | (type << 24)); 118 return 0; 119 } 120 121 static int 122 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) 123 { 124 int error; 125 u_char seglen, *cp; 126 127 cp = snb->snb_name; 128 if (*cp == 0) 129 return EINVAL; 130 NBDEBUG("[%s]\n", cp); 131 for (;;) { 132 seglen = (*cp) + 1; 133 error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM); 134 if (error) 135 return error; 136 if (seglen == 1) 137 break; 138 cp += seglen; 139 } 140 return 0; 141 } 142 143 static int 144 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct thread *td) 145 { 146 struct socket *so; 147 int error, s; 148 149 error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, 150 td->td_ucred, td); 151 if (error) 152 return error; 153 nbp->nbp_tso = so; 154 SOCKBUF_LOCK(&so->so_rcv); 155 soupcall_set(so, SO_RCV, nb_upcall, nbp); 156 SOCKBUF_UNLOCK(&so->so_rcv); 157 so->so_rcv.sb_timeo = (5 * SBT_1S); 158 so->so_snd.sb_timeo = (5 * SBT_1S); 159 error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf); 160 if (error) 161 goto bad; 162 nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1); 163 nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1); 164 SOCKBUF_LOCK(&so->so_rcv); 165 so->so_rcv.sb_flags &= ~SB_NOINTR; 166 SOCKBUF_UNLOCK(&so->so_rcv); 167 SOCKBUF_LOCK(&so->so_snd); 168 so->so_snd.sb_flags &= ~SB_NOINTR; 169 SOCKBUF_UNLOCK(&so->so_snd); 170 error = soconnect(so, (struct sockaddr*)to, td); 171 if (error) 172 goto bad; 173 s = splnet(); 174 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 175 tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz); 176 if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && 177 (error = nb_intr(nbp, td->td_proc)) != 0) { 178 so->so_state &= ~SS_ISCONNECTING; 179 splx(s); 180 goto bad; 181 } 182 } 183 if (so->so_error) { 184 error = so->so_error; 185 so->so_error = 0; 186 splx(s); 187 goto bad; 188 } 189 splx(s); 190 return 0; 191 bad: 192 smb_nbst_disconnect(nbp->nbp_vc, td); 193 return error; 194 } 195 196 static int 197 nbssn_rq_request(struct nbpcb *nbp, struct thread *td) 198 { 199 struct mbchain *mbp; 200 struct mdchain *mdp; 201 struct mbuf *m0; 202 struct timeval tv; 203 struct sockaddr_in sin; 204 u_short port; 205 u_int8_t rpcode; 206 int error, rplen; 207 208 mbp = malloc(sizeof(struct mbchain), M_NBDATA, M_WAITOK); 209 mdp = malloc(sizeof(struct mbchain), M_NBDATA, M_WAITOK); 210 error = mb_init(mbp); 211 if (error) { 212 free(mbp, M_NBDATA); 213 free(mdp, M_NBDATA); 214 return error; 215 } 216 mb_put_uint32le(mbp, 0); 217 nb_put_name(mbp, nbp->nbp_paddr); 218 nb_put_name(mbp, nbp->nbp_laddr); 219 nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); 220 error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, td); 221 if (!error) { 222 nbp->nbp_state = NBST_RQSENT; 223 } 224 mb_detach(mbp); 225 mb_done(mbp); 226 free(mbp, M_NBDATA); 227 if (error) { 228 free(mdp, M_NBDATA); 229 return error; 230 } 231 TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo); 232 error = selsocket(nbp->nbp_tso, POLLIN, &tv, td); 233 if (error == EWOULDBLOCK) { /* Timeout */ 234 NBDEBUG("initial request timeout\n"); 235 free(mdp, M_NBDATA); 236 return ETIMEDOUT; 237 } 238 if (error) { /* restart or interrupt */ 239 free(mdp, M_NBDATA); 240 return error; 241 } 242 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, td); 243 if (error) { 244 NBDEBUG("recv() error %d\n", error); 245 free(mdp, M_NBDATA); 246 return error; 247 } 248 /* 249 * Process NETBIOS reply 250 */ 251 if (m0) 252 md_initm(mdp, m0); 253 error = 0; 254 do { 255 if (rpcode == NB_SSN_POSRESP) { 256 nbp->nbp_state = NBST_SESSION; 257 nbp->nbp_flags |= NBF_CONNECTED; 258 break; 259 } 260 if (rpcode != NB_SSN_RTGRESP) { 261 error = ECONNABORTED; 262 break; 263 } 264 if (rplen != 6) { 265 error = ECONNABORTED; 266 break; 267 } 268 md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); 269 md_get_uint16(mdp, &port); 270 sin.sin_port = port; 271 nbp->nbp_state = NBST_RETARGET; 272 smb_nbst_disconnect(nbp->nbp_vc, td); 273 error = nb_connect_in(nbp, &sin, td); 274 if (!error) 275 error = nbssn_rq_request(nbp, td); 276 if (error) { 277 smb_nbst_disconnect(nbp->nbp_vc, td); 278 break; 279 } 280 } while(0); 281 if (m0) 282 md_done(mdp); 283 free(mdp, M_NBDATA); 284 return error; 285 } 286 287 static int 288 nbssn_recvhdr(struct nbpcb *nbp, int *lenp, 289 u_int8_t *rpcodep, int flags, struct thread *td) 290 { 291 struct socket *so = nbp->nbp_tso; 292 struct uio auio; 293 struct iovec aio; 294 u_int32_t len; 295 int error; 296 297 aio.iov_base = (caddr_t)&len; 298 aio.iov_len = sizeof(len); 299 auio.uio_iov = &aio; 300 auio.uio_iovcnt = 1; 301 auio.uio_segflg = UIO_SYSSPACE; 302 auio.uio_rw = UIO_READ; 303 auio.uio_offset = 0; 304 auio.uio_resid = sizeof(len); 305 auio.uio_td = td; 306 CURVNET_SET(so->so_vnet); 307 error = soreceive(so, (struct sockaddr **)NULL, &auio, 308 (struct mbuf **)NULL, (struct mbuf **)NULL, &flags); 309 CURVNET_RESTORE(); 310 if (error) 311 return error; 312 if (auio.uio_resid > 0) { 313 SMBSDEBUG("short reply\n"); 314 return EPIPE; 315 } 316 len = ntohl(len); 317 *rpcodep = (len >> 24) & 0xFF; 318 len &= 0x1ffff; 319 if (len > SMB_MAXPKTLEN) { 320 SMBERROR("packet too long (%d)\n", len); 321 return EFBIG; 322 } 323 *lenp = len; 324 return 0; 325 } 326 327 static int 328 nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 329 u_int8_t *rpcodep, struct thread *td) 330 { 331 struct socket *so = nbp->nbp_tso; 332 struct uio auio; 333 struct mbuf *m, *tm, *im; 334 u_int8_t rpcode; 335 int len, resid; 336 int error, rcvflg; 337 338 if (so == NULL) 339 return ENOTCONN; 340 341 if (mpp) 342 *mpp = NULL; 343 m = NULL; 344 for(;;) { 345 /* 346 * Poll for a response header. 347 * If we don't have one waiting, return. 348 */ 349 len = 0; 350 rpcode = 0; 351 error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, td); 352 if ((so->so_state & (SS_ISDISCONNECTING | SS_ISDISCONNECTED)) || 353 (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { 354 nbp->nbp_state = NBST_CLOSED; 355 NBDEBUG("session closed by peer\n"); 356 return ECONNRESET; 357 } 358 if (error) 359 return error; 360 if (len == 0 && nbp->nbp_state != NBST_SESSION) 361 break; 362 /* no data, try again */ 363 if (rpcode == NB_SSN_KEEPALIVE) 364 continue; 365 366 /* 367 * Loop, blocking, for data following the response header. 368 * 369 * Note that we can't simply block here with MSG_WAITALL for the 370 * entire response size, as it may be larger than the TCP 371 * slow-start window that the sender employs. This will result 372 * in the sender stalling until the delayed ACK is sent, then 373 * resuming slow-start, resulting in very poor performance. 374 * 375 * Instead, we never request more than NB_SORECEIVE_CHUNK 376 * bytes at a time, resulting in an ack being pushed by 377 * the TCP code at the completion of each call. 378 */ 379 resid = len; 380 while (resid > 0) { 381 tm = NULL; 382 rcvflg = MSG_WAITALL; 383 bzero(&auio, sizeof(auio)); 384 auio.uio_resid = min(resid, NB_SORECEIVE_CHUNK); 385 auio.uio_td = td; 386 resid -= auio.uio_resid; 387 /* 388 * Spin until we have collected everything in 389 * this chunk. 390 */ 391 do { 392 rcvflg = MSG_WAITALL; 393 CURVNET_SET(so->so_vnet); 394 error = soreceive(so, (struct sockaddr **)NULL, 395 &auio, &tm, (struct mbuf **)NULL, &rcvflg); 396 CURVNET_RESTORE(); 397 } while (error == EWOULDBLOCK || error == EINTR || 398 error == ERESTART); 399 if (error) 400 goto out; 401 /* short return guarantees unhappiness */ 402 if (auio.uio_resid > 0) { 403 SMBERROR("packet is shorter than expected\n"); 404 error = EPIPE; 405 goto out; 406 } 407 /* append received chunk to previous chunk(s) */ 408 if (m == NULL) { 409 m = tm; 410 } else { 411 /* 412 * Just glue the new chain on the end. 413 * Consumer will pullup as required. 414 */ 415 for (im = m; im->m_next != NULL; im = im->m_next) 416 ; 417 im->m_next = tm; 418 } 419 } 420 /* got a session/message packet? */ 421 if (nbp->nbp_state == NBST_SESSION && 422 rpcode == NB_SSN_MESSAGE) 423 break; 424 /* drop packet and try for another */ 425 NBDEBUG("non-session packet %x\n", rpcode); 426 if (m) { 427 m_freem(m); 428 m = NULL; 429 } 430 } 431 432 out: 433 if (error) { 434 if (m) 435 m_freem(m); 436 return error; 437 } 438 if (mpp) 439 *mpp = m; 440 else 441 m_freem(m); 442 *lenp = len; 443 *rpcodep = rpcode; 444 return 0; 445 } 446 447 /* 448 * SMB transport interface 449 */ 450 static int 451 smb_nbst_create(struct smb_vc *vcp, struct thread *td) 452 { 453 struct nbpcb *nbp; 454 455 nbp = malloc(sizeof *nbp, M_NBDATA, M_WAITOK); 456 bzero(nbp, sizeof *nbp); 457 nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */ 458 nbp->nbp_state = NBST_CLOSED; 459 nbp->nbp_vc = vcp; 460 nbp->nbp_sndbuf = smb_tcpsndbuf; 461 nbp->nbp_rcvbuf = smb_tcprcvbuf; 462 vcp->vc_tdata = nbp; 463 return 0; 464 } 465 466 static int 467 smb_nbst_done(struct smb_vc *vcp, struct thread *td) 468 { 469 struct nbpcb *nbp = vcp->vc_tdata; 470 471 if (nbp == NULL) 472 return ENOTCONN; 473 smb_nbst_disconnect(vcp, td); 474 if (nbp->nbp_laddr) 475 free(nbp->nbp_laddr, M_SONAME); 476 if (nbp->nbp_paddr) 477 free(nbp->nbp_paddr, M_SONAME); 478 free(nbp, M_NBDATA); 479 return 0; 480 } 481 482 static int 483 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) 484 { 485 struct nbpcb *nbp = vcp->vc_tdata; 486 struct sockaddr_nb *snb; 487 int error, slen; 488 489 NBDEBUG("\n"); 490 error = EINVAL; 491 do { 492 if (nbp->nbp_flags & NBF_LOCADDR) 493 break; 494 /* 495 * It is possible to create NETBIOS name in the kernel, 496 * but nothing prevents us to do it in the user space. 497 */ 498 if (sap == NULL) 499 break; 500 slen = sap->sa_len; 501 if (slen < NB_MINSALEN) 502 break; 503 snb = (struct sockaddr_nb*)sodupsockaddr(sap, M_WAITOK); 504 if (snb == NULL) { 505 error = ENOMEM; 506 break; 507 } 508 nbp->nbp_laddr = snb; 509 nbp->nbp_flags |= NBF_LOCADDR; 510 error = 0; 511 } while(0); 512 return error; 513 } 514 515 static int 516 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) 517 { 518 struct nbpcb *nbp = vcp->vc_tdata; 519 struct sockaddr_in sin; 520 struct sockaddr_nb *snb; 521 struct timespec ts1, ts2; 522 int error, slen; 523 524 NBDEBUG("\n"); 525 if (nbp->nbp_tso != NULL) 526 return EISCONN; 527 if (nbp->nbp_laddr == NULL) 528 return EINVAL; 529 slen = sap->sa_len; 530 if (slen < NB_MINSALEN) 531 return EINVAL; 532 if (nbp->nbp_paddr) { 533 free(nbp->nbp_paddr, M_SONAME); 534 nbp->nbp_paddr = NULL; 535 } 536 snb = (struct sockaddr_nb*)sodupsockaddr(sap, M_WAITOK); 537 if (snb == NULL) 538 return ENOMEM; 539 nbp->nbp_paddr = snb; 540 sin = snb->snb_addrin; 541 getnanotime(&ts1); 542 error = nb_connect_in(nbp, &sin, td); 543 if (error) 544 return error; 545 getnanotime(&ts2); 546 timespecsub(&ts2, &ts1, &ts2); 547 if (ts2.tv_sec == 0) { 548 ts2.tv_sec = 1; 549 ts2.tv_nsec = 0; 550 } 551 timespecadd(&ts2, &ts2, &nbp->nbp_timo); 552 timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); 553 timespecadd(&nbp->nbp_timo, &ts2, &nbp->nbp_timo); /* * 4 */ 554 error = nbssn_rq_request(nbp, td); 555 if (error) 556 smb_nbst_disconnect(vcp, td); 557 return error; 558 } 559 560 static int 561 smb_nbst_disconnect(struct smb_vc *vcp, struct thread *td) 562 { 563 struct nbpcb *nbp = vcp->vc_tdata; 564 struct socket *so; 565 566 if (nbp == NULL || nbp->nbp_tso == NULL) 567 return ENOTCONN; 568 if ((so = nbp->nbp_tso) != NULL) { 569 nbp->nbp_flags &= ~NBF_CONNECTED; 570 nbp->nbp_tso = (struct socket *)NULL; 571 soshutdown(so, 2); 572 soclose(so); 573 } 574 if (nbp->nbp_state != NBST_RETARGET) { 575 nbp->nbp_state = NBST_CLOSED; 576 } 577 return 0; 578 } 579 580 static int 581 smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct thread *td) 582 { 583 struct nbpcb *nbp = vcp->vc_tdata; 584 int error; 585 586 if (nbp->nbp_state != NBST_SESSION) { 587 error = ENOTCONN; 588 goto abort; 589 } 590 M_PREPEND(m0, 4, M_WAITOK); 591 nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4); 592 error = nb_sosend(nbp->nbp_tso, m0, 0, td); 593 return error; 594 abort: 595 if (m0) 596 m_freem(m0); 597 return error; 598 } 599 600 static int 601 smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct thread *td) 602 { 603 struct nbpcb *nbp = vcp->vc_tdata; 604 u_int8_t rpcode; 605 int error, rplen; 606 607 nbp->nbp_flags |= NBF_RECVLOCK; 608 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, td); 609 nbp->nbp_flags &= ~NBF_RECVLOCK; 610 return error; 611 } 612 613 static void 614 smb_nbst_timo(struct smb_vc *vcp) 615 { 616 return; 617 } 618 619 static void 620 smb_nbst_intr(struct smb_vc *vcp) 621 { 622 struct nbpcb *nbp = vcp->vc_tdata; 623 624 if (nbp == NULL || nbp->nbp_tso == NULL) 625 return; 626 sorwakeup(nbp->nbp_tso); 627 sowwakeup(nbp->nbp_tso); 628 } 629 630 static int 631 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 632 { 633 struct nbpcb *nbp = vcp->vc_tdata; 634 635 switch (param) { 636 case SMBTP_SNDSZ: 637 *(int*)data = nbp->nbp_sndbuf; 638 break; 639 case SMBTP_RCVSZ: 640 *(int*)data = nbp->nbp_rcvbuf; 641 break; 642 case SMBTP_TIMEOUT: 643 *(struct timespec*)data = nbp->nbp_timo; 644 break; 645 default: 646 return EINVAL; 647 } 648 return 0; 649 } 650 651 static int 652 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 653 { 654 struct nbpcb *nbp = vcp->vc_tdata; 655 656 switch (param) { 657 case SMBTP_SELECTID: 658 nbp->nbp_selectid = data; 659 break; 660 default: 661 return EINVAL; 662 } 663 return 0; 664 } 665 666 /* 667 * Check for fatal errors 668 */ 669 static int 670 smb_nbst_fatal(struct smb_vc *vcp, int error) 671 { 672 switch (error) { 673 case ENOTCONN: 674 case ENETRESET: 675 case ECONNABORTED: 676 return 1; 677 } 678 return 0; 679 } 680 681 struct smb_tran_desc smb_tran_nbtcp_desc = { 682 SMBT_NBTCP, 683 smb_nbst_create, smb_nbst_done, 684 smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect, 685 smb_nbst_send, smb_nbst_recv, 686 smb_nbst_timo, smb_nbst_intr, 687 smb_nbst_getparam, smb_nbst_setparam, 688 smb_nbst_fatal 689 }; 690