1139823Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp */ 26116189Sobrien 27116189Sobrien#include <sys/cdefs.h> 28116189Sobrien__FBSDID("$FreeBSD$"); 29116189Sobrien 3075374Sbp#include <sys/param.h> 3195759Stanimura#include <sys/condvar.h> 3275374Sbp#include <sys/kernel.h> 3395759Stanimura#include <sys/lock.h> 3475374Sbp#include <sys/malloc.h> 3575374Sbp#include <sys/mbuf.h> 3695759Stanimura#include <sys/poll.h> 3775374Sbp#include <sys/proc.h> 3875374Sbp#include <sys/protosw.h> 3995759Stanimura#include <sys/signalvar.h> 4075374Sbp#include <sys/socket.h> 4175374Sbp#include <sys/socketvar.h> 4295759Stanimura#include <sys/sx.h> 4395759Stanimura#include <sys/sysctl.h> 4495759Stanimura#include <sys/systm.h> 4575374Sbp#include <sys/uio.h> 4675374Sbp 4775374Sbp#include <net/if.h> 4875374Sbp#include <net/route.h> 49264425Sdteske#include <net/vnet.h> 5075374Sbp 5175374Sbp#include <netinet/in.h> 5275374Sbp#include <netinet/tcp.h> 5375374Sbp 5475374Sbp#include <sys/mchain.h> 5575374Sbp 5675374Sbp#include <netsmb/netbios.h> 5775374Sbp 5875374Sbp#include <netsmb/smb.h> 5975374Sbp#include <netsmb/smb_conn.h> 6075374Sbp#include <netsmb/smb_tran.h> 6175374Sbp#include <netsmb/smb_trantcp.h> 6275374Sbp#include <netsmb/smb_subr.h> 6375374Sbp 6475374Sbp#define M_NBDATA M_PCB 6575374Sbp 66103528Sbpstatic int smb_tcpsndbuf = NB_SNDQ - 1; 67103528Sbpstatic int smb_tcprcvbuf = NB_RCVQ - 1; 6875374Sbp 6975374SbpSYSCTL_DECL(_net_smb); 7075374SbpSYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, ""); 7175374SbpSYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, ""); 7275374Sbp 73160619Srwatson#define nb_sosend(so,m,flags,td) sosend(so, NULL, 0, m, 0, flags, td) 7475374Sbp 7575374Sbpstatic int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 7687192Sbp u_int8_t *rpcodep, struct thread *td); 7787192Sbpstatic int smb_nbst_disconnect(struct smb_vc *vcp, struct thread *td); 7875374Sbp 7975374Sbpstatic int 8075374Sbpnb_setsockopt_int(struct socket *so, int level, int name, int val) 8175374Sbp{ 8275374Sbp struct sockopt sopt; 83264425Sdteske int error; 8475374Sbp 8575374Sbp bzero(&sopt, sizeof(sopt)); 8675374Sbp sopt.sopt_level = level; 8775374Sbp sopt.sopt_name = name; 8875374Sbp sopt.sopt_val = &val; 8975374Sbp sopt.sopt_valsize = sizeof(val); 90264425Sdteske CURVNET_SET(so->so_vnet); 91264425Sdteske error = sosetopt(so, &sopt); 92264425Sdteske CURVNET_RESTORE(); 93264425Sdteske return error; 9475374Sbp} 9575374Sbp 9675374Sbpstatic int 9775374Sbpnb_intr(struct nbpcb *nbp, struct proc *p) 9875374Sbp{ 9975374Sbp return 0; 10075374Sbp} 10175374Sbp 102193272Sjhbstatic int 10375374Sbpnb_upcall(struct socket *so, void *arg, int waitflag) 10475374Sbp{ 10575374Sbp struct nbpcb *nbp = arg; 10675374Sbp 10775374Sbp if (arg == NULL || nbp->nbp_selectid == NULL) 108193272Sjhb return (SU_OK); 10975374Sbp wakeup(nbp->nbp_selectid); 110193272Sjhb return (SU_OK); 11175374Sbp} 11275374Sbp 11375374Sbpstatic int 11475374Sbpnb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len) 11575374Sbp{ 11675374Sbp u_int32_t *p = mtod(m, u_int32_t *); 11775374Sbp 11875374Sbp *p = htonl((len & 0x1FFFF) | (type << 24)); 11975374Sbp return 0; 12075374Sbp} 12175374Sbp 12275374Sbpstatic int 12375374Sbpnb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) 12475374Sbp{ 12575374Sbp int error; 12675374Sbp u_char seglen, *cp; 12775374Sbp 12875374Sbp cp = snb->snb_name; 12975374Sbp if (*cp == 0) 13075374Sbp return EINVAL; 13175374Sbp NBDEBUG("[%s]\n", cp); 13275374Sbp for (;;) { 13375374Sbp seglen = (*cp) + 1; 13475374Sbp error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM); 13575374Sbp if (error) 13675374Sbp return error; 13775374Sbp if (seglen == 1) 13875374Sbp break; 13975374Sbp cp += seglen; 14075374Sbp } 14175374Sbp return 0; 14275374Sbp} 14375374Sbp 14475374Sbpstatic int 14587192Sbpnb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct thread *td) 14675374Sbp{ 14775374Sbp struct socket *so; 14875374Sbp int error, s; 14975374Sbp 15088739Srwatson error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, 15191406Sjhb td->td_ucred, td); 15275374Sbp if (error) 15375374Sbp return error; 15475374Sbp nbp->nbp_tso = so; 155130653Srwatson SOCKBUF_LOCK(&so->so_rcv); 156193272Sjhb soupcall_set(so, SO_RCV, nb_upcall, nbp); 157130653Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 15875374Sbp so->so_rcv.sb_timeo = (5 * hz); 15975374Sbp so->so_snd.sb_timeo = (5 * hz); 16075374Sbp error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf); 16175374Sbp if (error) 16275374Sbp goto bad; 16375374Sbp nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1); 16475374Sbp nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1); 165130653Srwatson SOCKBUF_LOCK(&so->so_rcv); 16675374Sbp so->so_rcv.sb_flags &= ~SB_NOINTR; 167130653Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 168130653Srwatson SOCKBUF_LOCK(&so->so_snd); 16975374Sbp so->so_snd.sb_flags &= ~SB_NOINTR; 170130653Srwatson SOCKBUF_UNLOCK(&so->so_snd); 17187192Sbp error = soconnect(so, (struct sockaddr*)to, td); 17275374Sbp if (error) 17375374Sbp goto bad; 17475374Sbp s = splnet(); 17575374Sbp while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 17697658Stanimura tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz); 17775374Sbp if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && 17887192Sbp (error = nb_intr(nbp, td->td_proc)) != 0) { 17975374Sbp so->so_state &= ~SS_ISCONNECTING; 18075374Sbp splx(s); 18175374Sbp goto bad; 18275374Sbp } 18375374Sbp } 18475374Sbp if (so->so_error) { 18575374Sbp error = so->so_error; 18675374Sbp so->so_error = 0; 18775374Sbp splx(s); 18875374Sbp goto bad; 18975374Sbp } 19075374Sbp splx(s); 19175374Sbp return 0; 19275374Sbpbad: 19387192Sbp smb_nbst_disconnect(nbp->nbp_vc, td); 19475374Sbp return error; 19575374Sbp} 19675374Sbp 19775374Sbpstatic int 19887192Sbpnbssn_rq_request(struct nbpcb *nbp, struct thread *td) 19975374Sbp{ 20075374Sbp struct mbchain mb, *mbp = &mb; 20175374Sbp struct mdchain md, *mdp = &md; 20275374Sbp struct mbuf *m0; 20375374Sbp struct timeval tv; 20475374Sbp struct sockaddr_in sin; 20575374Sbp u_short port; 20675374Sbp u_int8_t rpcode; 20775374Sbp int error, rplen; 20875374Sbp 20975374Sbp error = mb_init(mbp); 21075374Sbp if (error) 21175374Sbp return error; 21275374Sbp mb_put_uint32le(mbp, 0); 21375374Sbp nb_put_name(mbp, nbp->nbp_paddr); 21475374Sbp nb_put_name(mbp, nbp->nbp_laddr); 21575374Sbp nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); 21687192Sbp error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, td); 21775374Sbp if (!error) { 21875374Sbp nbp->nbp_state = NBST_RQSENT; 21975374Sbp } 22075374Sbp mb_detach(mbp); 22175374Sbp mb_done(mbp); 22275374Sbp if (error) 22375374Sbp return error; 22475374Sbp TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo); 225174647Sjeff error = selsocket(nbp->nbp_tso, POLLIN, &tv, td); 22675374Sbp if (error == EWOULDBLOCK) { /* Timeout */ 22775374Sbp NBDEBUG("initial request timeout\n"); 22875374Sbp return ETIMEDOUT; 22975374Sbp } 23075374Sbp if (error) /* restart or interrupt */ 23175374Sbp return error; 23287192Sbp error = nbssn_recv(nbp, &m0, &rplen, &rpcode, td); 23375374Sbp if (error) { 23475374Sbp NBDEBUG("recv() error %d\n", error); 23575374Sbp return error; 23675374Sbp } 23775374Sbp /* 23875374Sbp * Process NETBIOS reply 23975374Sbp */ 24075374Sbp if (m0) 24175374Sbp md_initm(mdp, m0); 24275374Sbp error = 0; 24375374Sbp do { 24475374Sbp if (rpcode == NB_SSN_POSRESP) { 24575374Sbp nbp->nbp_state = NBST_SESSION; 24675374Sbp nbp->nbp_flags |= NBF_CONNECTED; 24775374Sbp break; 24875374Sbp } 24975374Sbp if (rpcode != NB_SSN_RTGRESP) { 25075374Sbp error = ECONNABORTED; 25175374Sbp break; 25275374Sbp } 25375374Sbp if (rplen != 6) { 25475374Sbp error = ECONNABORTED; 25575374Sbp break; 25675374Sbp } 25775374Sbp md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); 25875374Sbp md_get_uint16(mdp, &port); 25975374Sbp sin.sin_port = port; 26075374Sbp nbp->nbp_state = NBST_RETARGET; 26187192Sbp smb_nbst_disconnect(nbp->nbp_vc, td); 26287192Sbp error = nb_connect_in(nbp, &sin, td); 26375374Sbp if (!error) 26487192Sbp error = nbssn_rq_request(nbp, td); 26575374Sbp if (error) { 26687192Sbp smb_nbst_disconnect(nbp->nbp_vc, td); 26775374Sbp break; 26875374Sbp } 26975374Sbp } while(0); 27075374Sbp if (m0) 27175374Sbp md_done(mdp); 27275374Sbp return error; 27375374Sbp} 27475374Sbp 27575374Sbpstatic int 27675374Sbpnbssn_recvhdr(struct nbpcb *nbp, int *lenp, 27787192Sbp u_int8_t *rpcodep, int flags, struct thread *td) 27875374Sbp{ 27975374Sbp struct socket *so = nbp->nbp_tso; 28075374Sbp struct uio auio; 28175374Sbp struct iovec aio; 28275374Sbp u_int32_t len; 28375374Sbp int error; 28475374Sbp 28575374Sbp aio.iov_base = (caddr_t)&len; 28675374Sbp aio.iov_len = sizeof(len); 28775374Sbp auio.uio_iov = &aio; 28875374Sbp auio.uio_iovcnt = 1; 28975374Sbp auio.uio_segflg = UIO_SYSSPACE; 29075374Sbp auio.uio_rw = UIO_READ; 29175374Sbp auio.uio_offset = 0; 29275374Sbp auio.uio_resid = sizeof(len); 29387192Sbp auio.uio_td = td; 294264425Sdteske CURVNET_SET(so->so_vnet); 295160619Srwatson error = soreceive(so, (struct sockaddr **)NULL, &auio, 29675374Sbp (struct mbuf **)NULL, (struct mbuf **)NULL, &flags); 297264425Sdteske CURVNET_RESTORE(); 29875374Sbp if (error) 29975374Sbp return error; 30075374Sbp if (auio.uio_resid > 0) { 30175374Sbp SMBSDEBUG("short reply\n"); 30275374Sbp return EPIPE; 30375374Sbp } 30475374Sbp len = ntohl(len); 30575374Sbp *rpcodep = (len >> 24) & 0xFF; 30675374Sbp len &= 0x1ffff; 30775374Sbp if (len > SMB_MAXPKTLEN) { 30875374Sbp SMBERROR("packet too long (%d)\n", len); 30975374Sbp return EFBIG; 31075374Sbp } 31175374Sbp *lenp = len; 31275374Sbp return 0; 31375374Sbp} 31475374Sbp 31575374Sbpstatic int 31675374Sbpnbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, 31787192Sbp u_int8_t *rpcodep, struct thread *td) 31875374Sbp{ 31975374Sbp struct socket *so = nbp->nbp_tso; 32075374Sbp struct uio auio; 321103528Sbp struct mbuf *m, *tm, *im; 32275374Sbp u_int8_t rpcode; 323103528Sbp int len, resid; 32475374Sbp int error, rcvflg; 32575374Sbp 32675374Sbp if (so == NULL) 32775374Sbp return ENOTCONN; 32875374Sbp 32975374Sbp if (mpp) 33075374Sbp *mpp = NULL; 331103528Sbp m = NULL; 33275374Sbp for(;;) { 333103528Sbp /* 334103528Sbp * Poll for a response header. 335103528Sbp * If we don't have one waiting, return. 336103528Sbp */ 337170804Smjacob len = 0; 338170804Smjacob rpcode = 0; 33987192Sbp error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, td); 340130480Srwatson if ((so->so_state & (SS_ISDISCONNECTING | SS_ISDISCONNECTED)) || 341130480Srwatson (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { 34275374Sbp nbp->nbp_state = NBST_CLOSED; 34375374Sbp NBDEBUG("session closed by peer\n"); 34475374Sbp return ECONNRESET; 34575374Sbp } 34675374Sbp if (error) 34775374Sbp return error; 34875374Sbp if (len == 0 && nbp->nbp_state != NBST_SESSION) 34975374Sbp break; 350103528Sbp /* no data, try again */ 35175374Sbp if (rpcode == NB_SSN_KEEPALIVE) 35275374Sbp continue; 353103528Sbp 354103528Sbp /* 355103528Sbp * Loop, blocking, for data following the response header. 356103528Sbp * 357103528Sbp * Note that we can't simply block here with MSG_WAITALL for the 358103528Sbp * entire response size, as it may be larger than the TCP 359103528Sbp * slow-start window that the sender employs. This will result 360103528Sbp * in the sender stalling until the delayed ACK is sent, then 361103528Sbp * resuming slow-start, resulting in very poor performance. 362103528Sbp * 363103528Sbp * Instead, we never request more than NB_SORECEIVE_CHUNK 364103528Sbp * bytes at a time, resulting in an ack being pushed by 365103528Sbp * the TCP code at the completion of each call. 366103528Sbp */ 367103528Sbp resid = len; 368103528Sbp while (resid > 0) { 369103528Sbp tm = NULL; 37075374Sbp rcvflg = MSG_WAITALL; 371103528Sbp bzero(&auio, sizeof(auio)); 372103528Sbp auio.uio_resid = min(resid, NB_SORECEIVE_CHUNK); 373103528Sbp auio.uio_td = td; 374103528Sbp resid -= auio.uio_resid; 375103528Sbp /* 376103528Sbp * Spin until we have collected everything in 377103528Sbp * this chunk. 378103528Sbp */ 379103528Sbp do { 380103528Sbp rcvflg = MSG_WAITALL; 381264425Sdteske CURVNET_SET(so->so_vnet); 382160619Srwatson error = soreceive(so, (struct sockaddr **)NULL, 383107293Stjr &auio, &tm, (struct mbuf **)NULL, &rcvflg); 384264425Sdteske CURVNET_RESTORE(); 385103528Sbp } while (error == EWOULDBLOCK || error == EINTR || 38675374Sbp error == ERESTART); 387103528Sbp if (error) 388103528Sbp goto out; 389103528Sbp /* short return guarantees unhappiness */ 390103528Sbp if (auio.uio_resid > 0) { 391103528Sbp SMBERROR("packet is shorter than expected\n"); 392103528Sbp error = EPIPE; 393103528Sbp goto out; 394103528Sbp } 395103528Sbp /* append received chunk to previous chunk(s) */ 396103528Sbp if (m == NULL) { 397103528Sbp m = tm; 398103528Sbp } else { 399103528Sbp /* 400103528Sbp * Just glue the new chain on the end. 401103528Sbp * Consumer will pullup as required. 402103528Sbp */ 403103528Sbp for (im = m; im->m_next != NULL; im = im->m_next) 404103528Sbp ; 405103528Sbp im->m_next = tm; 406103528Sbp } 40775374Sbp } 408103528Sbp /* got a session/message packet? */ 40975374Sbp if (nbp->nbp_state == NBST_SESSION && 41075374Sbp rpcode == NB_SSN_MESSAGE) 41175374Sbp break; 412103528Sbp /* drop packet and try for another */ 41375374Sbp NBDEBUG("non-session packet %x\n", rpcode); 414103528Sbp if (m) { 41575374Sbp m_freem(m); 416103528Sbp m = NULL; 417103528Sbp } 41875374Sbp } 419103528Sbp 420103528Sbpout: 42175374Sbp if (error) { 42275374Sbp if (m) 42375374Sbp m_freem(m); 42475374Sbp return error; 42575374Sbp } 42675374Sbp if (mpp) 42775374Sbp *mpp = m; 42875374Sbp else 42975374Sbp m_freem(m); 43075374Sbp *lenp = len; 43175374Sbp *rpcodep = rpcode; 43275374Sbp return 0; 43375374Sbp} 43475374Sbp 43575374Sbp/* 43675374Sbp * SMB transport interface 43775374Sbp */ 43875374Sbpstatic int 43987192Sbpsmb_nbst_create(struct smb_vc *vcp, struct thread *td) 44075374Sbp{ 44175374Sbp struct nbpcb *nbp; 44275374Sbp 443184205Sdes nbp = malloc(sizeof *nbp, M_NBDATA, M_WAITOK); 44475374Sbp bzero(nbp, sizeof *nbp); 44575374Sbp nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */ 44675374Sbp nbp->nbp_state = NBST_CLOSED; 44775374Sbp nbp->nbp_vc = vcp; 44875374Sbp nbp->nbp_sndbuf = smb_tcpsndbuf; 44975374Sbp nbp->nbp_rcvbuf = smb_tcprcvbuf; 45075374Sbp vcp->vc_tdata = nbp; 45175374Sbp return 0; 45275374Sbp} 45375374Sbp 45475374Sbpstatic int 45587192Sbpsmb_nbst_done(struct smb_vc *vcp, struct thread *td) 45675374Sbp{ 45775374Sbp struct nbpcb *nbp = vcp->vc_tdata; 45875374Sbp 45975374Sbp if (nbp == NULL) 46075374Sbp return ENOTCONN; 46187192Sbp smb_nbst_disconnect(vcp, td); 46275374Sbp if (nbp->nbp_laddr) 46375374Sbp free(nbp->nbp_laddr, M_SONAME); 46475374Sbp if (nbp->nbp_paddr) 46575374Sbp free(nbp->nbp_paddr, M_SONAME); 46675374Sbp free(nbp, M_NBDATA); 46775374Sbp return 0; 46875374Sbp} 46975374Sbp 47075374Sbpstatic int 47187192Sbpsmb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) 47275374Sbp{ 47375374Sbp struct nbpcb *nbp = vcp->vc_tdata; 47475374Sbp struct sockaddr_nb *snb; 47575374Sbp int error, slen; 47675374Sbp 47775374Sbp NBDEBUG("\n"); 47875374Sbp error = EINVAL; 47975374Sbp do { 48075374Sbp if (nbp->nbp_flags & NBF_LOCADDR) 48175374Sbp break; 48275374Sbp /* 48375374Sbp * It is possible to create NETBIOS name in the kernel, 48475374Sbp * but nothing prevents us to do it in the user space. 48575374Sbp */ 48675374Sbp if (sap == NULL) 48775374Sbp break; 48875374Sbp slen = sap->sa_len; 48975374Sbp if (slen < NB_MINSALEN) 49075374Sbp break; 491126425Srwatson snb = (struct sockaddr_nb*)sodupsockaddr(sap, M_WAITOK); 49275374Sbp if (snb == NULL) { 49375374Sbp error = ENOMEM; 49475374Sbp break; 49575374Sbp } 49675374Sbp nbp->nbp_laddr = snb; 49775374Sbp nbp->nbp_flags |= NBF_LOCADDR; 49875374Sbp error = 0; 49975374Sbp } while(0); 50075374Sbp return error; 50175374Sbp} 50275374Sbp 50375374Sbpstatic int 50487192Sbpsmb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct thread *td) 50575374Sbp{ 50675374Sbp struct nbpcb *nbp = vcp->vc_tdata; 50775374Sbp struct sockaddr_in sin; 50875374Sbp struct sockaddr_nb *snb; 50975374Sbp struct timespec ts1, ts2; 51075374Sbp int error, slen; 51175374Sbp 51275374Sbp NBDEBUG("\n"); 51375374Sbp if (nbp->nbp_tso != NULL) 51475374Sbp return EISCONN; 51575374Sbp if (nbp->nbp_laddr == NULL) 51675374Sbp return EINVAL; 51775374Sbp slen = sap->sa_len; 51875374Sbp if (slen < NB_MINSALEN) 51975374Sbp return EINVAL; 52075374Sbp if (nbp->nbp_paddr) { 52175374Sbp free(nbp->nbp_paddr, M_SONAME); 52275374Sbp nbp->nbp_paddr = NULL; 52375374Sbp } 524126425Srwatson snb = (struct sockaddr_nb*)sodupsockaddr(sap, M_WAITOK); 52575374Sbp if (snb == NULL) 52675374Sbp return ENOMEM; 52775374Sbp nbp->nbp_paddr = snb; 52875374Sbp sin = snb->snb_addrin; 52975374Sbp getnanotime(&ts1); 53087192Sbp error = nb_connect_in(nbp, &sin, td); 53175374Sbp if (error) 53275374Sbp return error; 53375374Sbp getnanotime(&ts2); 53475374Sbp timespecsub(&ts2, &ts1); 53575374Sbp if (ts2.tv_sec == 0 && ts2.tv_sec == 0) 53675374Sbp ts2.tv_sec = 1; 53775374Sbp nbp->nbp_timo = ts2; 53875374Sbp timespecadd(&nbp->nbp_timo, &ts2); 53975374Sbp timespecadd(&nbp->nbp_timo, &ts2); 54075374Sbp timespecadd(&nbp->nbp_timo, &ts2); /* * 4 */ 54187192Sbp error = nbssn_rq_request(nbp, td); 54275374Sbp if (error) 54387192Sbp smb_nbst_disconnect(vcp, td); 54475374Sbp return error; 54575374Sbp} 54675374Sbp 54775374Sbpstatic int 54887192Sbpsmb_nbst_disconnect(struct smb_vc *vcp, struct thread *td) 54975374Sbp{ 55075374Sbp struct nbpcb *nbp = vcp->vc_tdata; 55175374Sbp struct socket *so; 55275374Sbp 55375374Sbp if (nbp == NULL || nbp->nbp_tso == NULL) 55475374Sbp return ENOTCONN; 55575374Sbp if ((so = nbp->nbp_tso) != NULL) { 55675374Sbp nbp->nbp_flags &= ~NBF_CONNECTED; 55775374Sbp nbp->nbp_tso = (struct socket *)NULL; 55875374Sbp soshutdown(so, 2); 55975374Sbp soclose(so); 56075374Sbp } 56175374Sbp if (nbp->nbp_state != NBST_RETARGET) { 56275374Sbp nbp->nbp_state = NBST_CLOSED; 56375374Sbp } 56475374Sbp return 0; 56575374Sbp} 56675374Sbp 56775374Sbpstatic int 56887192Sbpsmb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct thread *td) 56975374Sbp{ 57075374Sbp struct nbpcb *nbp = vcp->vc_tdata; 57175374Sbp int error; 57275374Sbp 57375374Sbp if (nbp->nbp_state != NBST_SESSION) { 57475374Sbp error = ENOTCONN; 57575374Sbp goto abort; 57675374Sbp } 577177599Sru M_PREPEND(m0, 4, M_WAIT); 57875374Sbp nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4); 57987192Sbp error = nb_sosend(nbp->nbp_tso, m0, 0, td); 58075374Sbp return error; 58175374Sbpabort: 58275374Sbp if (m0) 58375374Sbp m_freem(m0); 58475374Sbp return error; 58575374Sbp} 58675374Sbp 58775374Sbp 58875374Sbpstatic int 58987192Sbpsmb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct thread *td) 59075374Sbp{ 59175374Sbp struct nbpcb *nbp = vcp->vc_tdata; 59275374Sbp u_int8_t rpcode; 59375374Sbp int error, rplen; 59475374Sbp 59575374Sbp nbp->nbp_flags |= NBF_RECVLOCK; 59687192Sbp error = nbssn_recv(nbp, mpp, &rplen, &rpcode, td); 59775374Sbp nbp->nbp_flags &= ~NBF_RECVLOCK; 59875374Sbp return error; 59975374Sbp} 60075374Sbp 60175374Sbpstatic void 60275374Sbpsmb_nbst_timo(struct smb_vc *vcp) 60375374Sbp{ 60475374Sbp return; 60575374Sbp} 60675374Sbp 60775374Sbpstatic void 60875374Sbpsmb_nbst_intr(struct smb_vc *vcp) 60975374Sbp{ 61075374Sbp struct nbpcb *nbp = vcp->vc_tdata; 61175374Sbp 61275374Sbp if (nbp == NULL || nbp->nbp_tso == NULL) 61375374Sbp return; 61475374Sbp sorwakeup(nbp->nbp_tso); 61575374Sbp sowwakeup(nbp->nbp_tso); 61675374Sbp} 61775374Sbp 61875374Sbpstatic int 61975374Sbpsmb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 62075374Sbp{ 62175374Sbp struct nbpcb *nbp = vcp->vc_tdata; 62275374Sbp 62375374Sbp switch (param) { 62475374Sbp case SMBTP_SNDSZ: 62575374Sbp *(int*)data = nbp->nbp_sndbuf; 62675374Sbp break; 62775374Sbp case SMBTP_RCVSZ: 62875374Sbp *(int*)data = nbp->nbp_rcvbuf; 62975374Sbp break; 63075374Sbp case SMBTP_TIMEOUT: 63175374Sbp *(struct timespec*)data = nbp->nbp_timo; 63275374Sbp break; 63375374Sbp default: 63475374Sbp return EINVAL; 63575374Sbp } 63675374Sbp return 0; 63775374Sbp} 63875374Sbp 63975374Sbpstatic int 64075374Sbpsmb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 64175374Sbp{ 64275374Sbp struct nbpcb *nbp = vcp->vc_tdata; 64375374Sbp 64475374Sbp switch (param) { 64575374Sbp case SMBTP_SELECTID: 64675374Sbp nbp->nbp_selectid = data; 64775374Sbp break; 64875374Sbp default: 64975374Sbp return EINVAL; 65075374Sbp } 65175374Sbp return 0; 65275374Sbp} 65375374Sbp 65475374Sbp/* 65575374Sbp * Check for fatal errors 65675374Sbp */ 65775374Sbpstatic int 65875374Sbpsmb_nbst_fatal(struct smb_vc *vcp, int error) 65975374Sbp{ 66075374Sbp switch (error) { 66175374Sbp case ENOTCONN: 66275374Sbp case ENETRESET: 66375374Sbp case ECONNABORTED: 66475374Sbp return 1; 66575374Sbp } 66675374Sbp return 0; 66775374Sbp} 66875374Sbp 66975374Sbp 67075374Sbpstruct smb_tran_desc smb_tran_nbtcp_desc = { 67175374Sbp SMBT_NBTCP, 67275374Sbp smb_nbst_create, smb_nbst_done, 67375374Sbp smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect, 67475374Sbp smb_nbst_send, smb_nbst_recv, 67575374Sbp smb_nbst_timo, smb_nbst_intr, 67675374Sbp smb_nbst_getparam, smb_nbst_setparam, 67775374Sbp smb_nbst_fatal 67875374Sbp}; 67975374Sbp 680