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 * $FreeBSD$ 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/mbuf.h> 39 #include <sys/proc.h> 40 #include <sys/protosw.h> 41 #include <sys/socket.h> 42 #include <sys/socketvar.h> 43 #include <sys/poll.h> 44 #include <sys/uio.h> 45 #include <sys/sysctl.h> 46 #include <sys/condvar.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 51 #include <netinet/in.h> 52 #include <netinet/tcp.h> 53 54 #include <sys/mchain.h> 55 56 #include <netsmb/netbios.h> 57 58 #include <netsmb/smb.h> 59 #include <netsmb/smb_conn.h> 60 #include <netsmb/smb_tran.h> 61 #include <netsmb/smb_trantcp.h> 62 #include <netsmb/smb_subr.h> 63 64 #define M_NBDATA M_PCB 65 66 static int smb_tcpsndbuf = 10 * 1024; 67 static int smb_tcprcvbuf = 10 * 1024; 68 69 SYSCTL_DECL(_net_smb); 70 SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, ""); 71 SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, ""); 72 73 #define nb_sosend(so,m,flags,p) (so)->so_proto->pr_usrreqs->pru_sosend( \ 74 so, NULL, 0, m, 0, flags, p) 75 76 static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 77 u_int8_t *rpcodep, struct proc *p); 78 static int smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p); 79 80 static int 81 nb_setsockopt_int(struct socket *so, int level, int name, int val) 82 { 83 struct sockopt sopt; 84 85 bzero(&sopt, sizeof(sopt)); 86 sopt.sopt_level = level; 87 sopt.sopt_name = name; 88 sopt.sopt_val = &val; 89 sopt.sopt_valsize = sizeof(val); 90 return sosetopt(so, &sopt); 91 } 92 93 static __inline int 94 nb_poll(struct nbpcb *nbp, int events, struct proc *p) 95 { 96 return nbp->nbp_tso->so_proto->pr_usrreqs->pru_sopoll(nbp->nbp_tso, 97 events, NULL, p); 98 } 99 100 static int 101 nbssn_rselect(struct nbpcb *nbp, struct timeval *tv, int events, struct proc *p) 102 { 103 struct timeval atv, rtv, ttv; 104 int timo, error; 105 106 if (tv) { 107 atv = *tv; 108 if (itimerfix(&atv)) { 109 error = EINVAL; 110 goto done_noproclock; 111 } 112 getmicrouptime(&rtv); 113 timevaladd(&atv, &rtv); 114 } 115 timo = 0; 116 PROC_LOCK(p); 117 p->p_flag |= P_SELECT; 118 PROC_UNLOCK(p); 119 error = nb_poll(nbp, events, p); 120 PROC_LOCK(p); 121 if (error) { 122 error = 0; 123 goto done; 124 } 125 if (tv) { 126 getmicrouptime(&rtv); 127 if (timevalcmp(&rtv, &atv, >=)) { 128 /* 129 * An event of our interest may occur during locking a process. 130 * In order to avoid missing the event that occured during locking 131 * the process, test P_SELECT and rescan file descriptors if 132 * necessary. 133 */ 134 if ((p->p_flag & P_SELECT) == 0) { 135 p->p_flag |= P_SELECT; 136 PROC_UNLOCK(p); 137 error = nb_poll(nbp, events, p); 138 PROC_LOCK(p); 139 } 140 goto done; 141 } 142 ttv = atv; 143 timevalsub(&ttv, &rtv); 144 timo = tvtohz(&ttv); 145 } 146 p->p_flag &= ~P_SELECT; 147 if (timo > 0) 148 error = cv_timedwait(&selwait, &p->p_mtx, timo); 149 else { 150 cv_wait(&selwait, &p->p_mtx); 151 error = 0; 152 } 153 154 done: 155 PROC_UNLOCK(p); 156 p->p_flag &= ~P_SELECT; 157 done_noproclock: 158 if (error == ERESTART) 159 return 0; 160 return error; 161 } 162 163 static int 164 nb_intr(struct nbpcb *nbp, struct proc *p) 165 { 166 return 0; 167 } 168 169 static void 170 nb_upcall(struct socket *so, void *arg, int waitflag) 171 { 172 struct nbpcb *nbp = arg; 173 174 if (arg == NULL || nbp->nbp_selectid == NULL) 175 return; 176 wakeup(nbp->nbp_selectid); 177 } 178 179 static int 180 nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len) 181 { 182 u_int32_t *p = mtod(m, u_int32_t *); 183 184 *p = htonl((len & 0x1FFFF) | (type << 24)); 185 return 0; 186 } 187 188 static int 189 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) 190 { 191 int error; 192 u_char seglen, *cp; 193 194 cp = snb->snb_name; 195 if (*cp == 0) 196 return EINVAL; 197 NBDEBUG("[%s]\n", cp); 198 for (;;) { 199 seglen = (*cp) + 1; 200 error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM); 201 if (error) 202 return error; 203 if (seglen == 1) 204 break; 205 cp += seglen; 206 } 207 return 0; 208 } 209 210 static int 211 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p) 212 { 213 struct socket *so; 214 int error, s; 215 216 error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, p); 217 if (error) 218 return error; 219 nbp->nbp_tso = so; 220 so->so_upcallarg = (caddr_t)nbp; 221 so->so_upcall = nb_upcall; 222 so->so_rcv.sb_flags |= SB_UPCALL; 223 so->so_rcv.sb_timeo = (5 * hz); 224 so->so_snd.sb_timeo = (5 * hz); 225 error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf); 226 if (error) 227 goto bad; 228 nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1); 229 nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1); 230 so->so_rcv.sb_flags &= ~SB_NOINTR; 231 so->so_snd.sb_flags &= ~SB_NOINTR; 232 error = soconnect(so, (struct sockaddr*)to, p); 233 if (error) 234 goto bad; 235 s = splnet(); 236 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 237 tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz); 238 if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && 239 (error = nb_intr(nbp, p)) != 0) { 240 so->so_state &= ~SS_ISCONNECTING; 241 splx(s); 242 goto bad; 243 } 244 } 245 if (so->so_error) { 246 error = so->so_error; 247 so->so_error = 0; 248 splx(s); 249 goto bad; 250 } 251 splx(s); 252 return 0; 253 bad: 254 smb_nbst_disconnect(nbp->nbp_vc, p); 255 return error; 256 } 257 258 static int 259 nbssn_rq_request(struct nbpcb *nbp, struct proc *p) 260 { 261 struct mbchain mb, *mbp = &mb; 262 struct mdchain md, *mdp = &md; 263 struct mbuf *m0; 264 struct timeval tv; 265 struct sockaddr_in sin; 266 u_short port; 267 u_int8_t rpcode; 268 int error, rplen; 269 270 error = mb_init(mbp); 271 if (error) 272 return error; 273 mb_put_uint32le(mbp, 0); 274 nb_put_name(mbp, nbp->nbp_paddr); 275 nb_put_name(mbp, nbp->nbp_laddr); 276 nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); 277 error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, p); 278 if (!error) { 279 nbp->nbp_state = NBST_RQSENT; 280 } 281 mb_detach(mbp); 282 mb_done(mbp); 283 if (error) 284 return error; 285 TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo); 286 error = nbssn_rselect(nbp, &tv, POLLIN, p); 287 if (error == EWOULDBLOCK) { /* Timeout */ 288 NBDEBUG("initial request timeout\n"); 289 return ETIMEDOUT; 290 } 291 if (error) /* restart or interrupt */ 292 return error; 293 error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p); 294 if (error) { 295 NBDEBUG("recv() error %d\n", error); 296 return error; 297 } 298 /* 299 * Process NETBIOS reply 300 */ 301 if (m0) 302 md_initm(mdp, m0); 303 error = 0; 304 do { 305 if (rpcode == NB_SSN_POSRESP) { 306 nbp->nbp_state = NBST_SESSION; 307 nbp->nbp_flags |= NBF_CONNECTED; 308 break; 309 } 310 if (rpcode != NB_SSN_RTGRESP) { 311 error = ECONNABORTED; 312 break; 313 } 314 if (rplen != 6) { 315 error = ECONNABORTED; 316 break; 317 } 318 md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); 319 md_get_uint16(mdp, &port); 320 sin.sin_port = port; 321 nbp->nbp_state = NBST_RETARGET; 322 smb_nbst_disconnect(nbp->nbp_vc, p); 323 error = nb_connect_in(nbp, &sin, p); 324 if (!error) 325 error = nbssn_rq_request(nbp, p); 326 if (error) { 327 smb_nbst_disconnect(nbp->nbp_vc, p); 328 break; 329 } 330 } while(0); 331 if (m0) 332 md_done(mdp); 333 return error; 334 } 335 336 static int 337 nbssn_recvhdr(struct nbpcb *nbp, int *lenp, 338 u_int8_t *rpcodep, int flags, struct proc *p) 339 { 340 struct socket *so = nbp->nbp_tso; 341 struct uio auio; 342 struct iovec aio; 343 u_int32_t len; 344 int error; 345 346 aio.iov_base = (caddr_t)&len; 347 aio.iov_len = sizeof(len); 348 auio.uio_iov = &aio; 349 auio.uio_iovcnt = 1; 350 auio.uio_segflg = UIO_SYSSPACE; 351 auio.uio_rw = UIO_READ; 352 auio.uio_offset = 0; 353 auio.uio_resid = sizeof(len); 354 auio.uio_procp = p; 355 error = so->so_proto->pr_usrreqs->pru_soreceive 356 (so, (struct sockaddr **)NULL, &auio, 357 (struct mbuf **)NULL, (struct mbuf **)NULL, &flags); 358 if (error) 359 return error; 360 if (auio.uio_resid > 0) { 361 SMBSDEBUG("short reply\n"); 362 return EPIPE; 363 } 364 len = ntohl(len); 365 *rpcodep = (len >> 24) & 0xFF; 366 len &= 0x1ffff; 367 if (len > SMB_MAXPKTLEN) { 368 SMBERROR("packet too long (%d)\n", len); 369 return EFBIG; 370 } 371 *lenp = len; 372 return 0; 373 } 374 375 static int 376 nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 377 u_int8_t *rpcodep, struct proc *p) 378 { 379 struct socket *so = nbp->nbp_tso; 380 struct uio auio; 381 struct mbuf *m; 382 u_int8_t rpcode; 383 int len; 384 int error, rcvflg; 385 386 if (so == NULL) 387 return ENOTCONN; 388 389 if (mpp) 390 *mpp = NULL; 391 for(;;) { 392 m = NULL; 393 error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, p); 394 if (so->so_state & 395 (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) { 396 nbp->nbp_state = NBST_CLOSED; 397 NBDEBUG("session closed by peer\n"); 398 return ECONNRESET; 399 } 400 if (error) 401 return error; 402 if (len == 0 && nbp->nbp_state != NBST_SESSION) 403 break; 404 if (rpcode == NB_SSN_KEEPALIVE) 405 continue; 406 bzero(&auio, sizeof(auio)); 407 auio.uio_resid = len; 408 auio.uio_procp = p; 409 do { 410 rcvflg = MSG_WAITALL; 411 error = so->so_proto->pr_usrreqs->pru_soreceive 412 (so, (struct sockaddr **)NULL, 413 &auio, &m, (struct mbuf **)NULL, &rcvflg); 414 } while (error == EWOULDBLOCK || error == EINTR || 415 error == ERESTART); 416 if (error) 417 break; 418 if (auio.uio_resid > 0) { 419 SMBERROR("packet is shorter than expected\n"); 420 error = EPIPE; 421 break; 422 } 423 if (nbp->nbp_state == NBST_SESSION && 424 rpcode == NB_SSN_MESSAGE) 425 break; 426 NBDEBUG("non-session packet %x\n", rpcode); 427 if (m) 428 m_freem(m); 429 } 430 if (error) { 431 if (m) 432 m_freem(m); 433 return error; 434 } 435 if (mpp) 436 *mpp = m; 437 else 438 m_freem(m); 439 *lenp = len; 440 *rpcodep = rpcode; 441 return 0; 442 } 443 444 /* 445 * SMB transport interface 446 */ 447 static int 448 smb_nbst_create(struct smb_vc *vcp, struct proc *p) 449 { 450 struct nbpcb *nbp; 451 452 MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK); 453 bzero(nbp, sizeof *nbp); 454 nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */ 455 nbp->nbp_state = NBST_CLOSED; 456 nbp->nbp_vc = vcp; 457 nbp->nbp_sndbuf = smb_tcpsndbuf; 458 nbp->nbp_rcvbuf = smb_tcprcvbuf; 459 vcp->vc_tdata = nbp; 460 return 0; 461 } 462 463 static int 464 smb_nbst_done(struct smb_vc *vcp, struct proc *p) 465 { 466 struct nbpcb *nbp = vcp->vc_tdata; 467 468 if (nbp == NULL) 469 return ENOTCONN; 470 smb_nbst_disconnect(vcp, p); 471 if (nbp->nbp_laddr) 472 free(nbp->nbp_laddr, M_SONAME); 473 if (nbp->nbp_paddr) 474 free(nbp->nbp_paddr, M_SONAME); 475 free(nbp, M_NBDATA); 476 return 0; 477 } 478 479 static int 480 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) 481 { 482 struct nbpcb *nbp = vcp->vc_tdata; 483 struct sockaddr_nb *snb; 484 int error, slen; 485 486 NBDEBUG("\n"); 487 error = EINVAL; 488 do { 489 if (nbp->nbp_flags & NBF_LOCADDR) 490 break; 491 /* 492 * It is possible to create NETBIOS name in the kernel, 493 * but nothing prevents us to do it in the user space. 494 */ 495 if (sap == NULL) 496 break; 497 slen = sap->sa_len; 498 if (slen < NB_MINSALEN) 499 break; 500 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1); 501 if (snb == NULL) { 502 error = ENOMEM; 503 break; 504 } 505 nbp->nbp_laddr = snb; 506 nbp->nbp_flags |= NBF_LOCADDR; 507 error = 0; 508 } while(0); 509 return error; 510 } 511 512 static int 513 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) 514 { 515 struct nbpcb *nbp = vcp->vc_tdata; 516 struct sockaddr_in sin; 517 struct sockaddr_nb *snb; 518 struct timespec ts1, ts2; 519 int error, slen; 520 521 NBDEBUG("\n"); 522 if (nbp->nbp_tso != NULL) 523 return EISCONN; 524 if (nbp->nbp_laddr == NULL) 525 return EINVAL; 526 slen = sap->sa_len; 527 if (slen < NB_MINSALEN) 528 return EINVAL; 529 if (nbp->nbp_paddr) { 530 free(nbp->nbp_paddr, M_SONAME); 531 nbp->nbp_paddr = NULL; 532 } 533 snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1); 534 if (snb == NULL) 535 return ENOMEM; 536 nbp->nbp_paddr = snb; 537 sin = snb->snb_addrin; 538 getnanotime(&ts1); 539 error = nb_connect_in(nbp, &sin, p); 540 if (error) 541 return error; 542 getnanotime(&ts2); 543 timespecsub(&ts2, &ts1); 544 if (ts2.tv_sec == 0 && ts2.tv_sec == 0) 545 ts2.tv_sec = 1; 546 nbp->nbp_timo = ts2; 547 timespecadd(&nbp->nbp_timo, &ts2); 548 timespecadd(&nbp->nbp_timo, &ts2); 549 timespecadd(&nbp->nbp_timo, &ts2); /* * 4 */ 550 error = nbssn_rq_request(nbp, p); 551 if (error) 552 smb_nbst_disconnect(vcp, p); 553 return error; 554 } 555 556 static int 557 smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p) 558 { 559 struct nbpcb *nbp = vcp->vc_tdata; 560 struct socket *so; 561 562 if (nbp == NULL || nbp->nbp_tso == NULL) 563 return ENOTCONN; 564 if ((so = nbp->nbp_tso) != NULL) { 565 nbp->nbp_flags &= ~NBF_CONNECTED; 566 nbp->nbp_tso = (struct socket *)NULL; 567 soshutdown(so, 2); 568 soclose(so); 569 } 570 if (nbp->nbp_state != NBST_RETARGET) { 571 nbp->nbp_state = NBST_CLOSED; 572 } 573 return 0; 574 } 575 576 static int 577 smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct proc *p) 578 { 579 struct nbpcb *nbp = vcp->vc_tdata; 580 int error; 581 582 if (nbp->nbp_state != NBST_SESSION) { 583 error = ENOTCONN; 584 goto abort; 585 } 586 M_PREPEND(m0, 4, M_WAITOK); 587 if (m0 == NULL) 588 return ENOBUFS; 589 nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4); 590 error = nb_sosend(nbp->nbp_tso, m0, 0, p); 591 return error; 592 abort: 593 if (m0) 594 m_freem(m0); 595 return error; 596 } 597 598 599 static int 600 smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct proc *p) 601 { 602 struct nbpcb *nbp = vcp->vc_tdata; 603 u_int8_t rpcode; 604 int error, rplen; 605 606 nbp->nbp_flags |= NBF_RECVLOCK; 607 error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p); 608 nbp->nbp_flags &= ~NBF_RECVLOCK; 609 return error; 610 } 611 612 static void 613 smb_nbst_timo(struct smb_vc *vcp) 614 { 615 return; 616 } 617 618 static void 619 smb_nbst_intr(struct smb_vc *vcp) 620 { 621 struct nbpcb *nbp = vcp->vc_tdata; 622 623 if (nbp == NULL || nbp->nbp_tso == NULL) 624 return; 625 sorwakeup(nbp->nbp_tso); 626 sowwakeup(nbp->nbp_tso); 627 } 628 629 static int 630 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 631 { 632 struct nbpcb *nbp = vcp->vc_tdata; 633 634 switch (param) { 635 case SMBTP_SNDSZ: 636 *(int*)data = nbp->nbp_sndbuf; 637 break; 638 case SMBTP_RCVSZ: 639 *(int*)data = nbp->nbp_rcvbuf; 640 break; 641 case SMBTP_TIMEOUT: 642 *(struct timespec*)data = nbp->nbp_timo; 643 break; 644 default: 645 return EINVAL; 646 } 647 return 0; 648 } 649 650 static int 651 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 652 { 653 struct nbpcb *nbp = vcp->vc_tdata; 654 655 switch (param) { 656 case SMBTP_SELECTID: 657 nbp->nbp_selectid = data; 658 break; 659 default: 660 return EINVAL; 661 } 662 return 0; 663 } 664 665 /* 666 * Check for fatal errors 667 */ 668 static int 669 smb_nbst_fatal(struct smb_vc *vcp, int error) 670 { 671 switch (error) { 672 case ENOTCONN: 673 case ENETRESET: 674 case ECONNABORTED: 675 return 1; 676 } 677 return 0; 678 } 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 691