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