14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
334bff34e3Sthurlow  */
3422eb7cb5Sgd /*
35de8c4a14SErik Nordmark  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3622eb7cb5Sgd  * Use is subject to license terms.
378329232eSGordon Ross  *
3840c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
3922eb7cb5Sgd  */
404bff34e3Sthurlow 
414bff34e3Sthurlow #include <sys/param.h>
424bff34e3Sthurlow #include <sys/systm.h>
434bff34e3Sthurlow #include <sys/autoconf.h>
444bff34e3Sthurlow #include <sys/sysmacros.h>
454bff34e3Sthurlow #include <sys/sunddi.h>
464bff34e3Sthurlow #include <sys/kmem.h>
474bff34e3Sthurlow #include <sys/proc.h>
484bff34e3Sthurlow #include <sys/protosw.h>
494bff34e3Sthurlow #include <sys/socket.h>
504bff34e3Sthurlow #include <sys/poll.h>
514bff34e3Sthurlow #include <sys/stream.h>
524bff34e3Sthurlow #include <sys/strsubr.h>
534bff34e3Sthurlow #include <sys/strsun.h>
544bff34e3Sthurlow #include <sys/stropts.h>
554bff34e3Sthurlow #include <sys/cmn_err.h>
564bff34e3Sthurlow #include <sys/tihdr.h>
574bff34e3Sthurlow #include <sys/tiuser.h>
584bff34e3Sthurlow #include <sys/t_kuser.h>
594bff34e3Sthurlow #include <sys/priv.h>
604bff34e3Sthurlow 
614bff34e3Sthurlow #include <net/if.h>
624bff34e3Sthurlow #include <net/route.h>
634bff34e3Sthurlow 
644bff34e3Sthurlow #include <netinet/in.h>
654bff34e3Sthurlow #include <netinet/tcp.h>
664bff34e3Sthurlow 
674bff34e3Sthurlow #include <netsmb/smb_osdep.h>
684bff34e3Sthurlow #include <netsmb/mchain.h>
694bff34e3Sthurlow #include <netsmb/netbios.h>
704bff34e3Sthurlow 
714bff34e3Sthurlow #include <netsmb/smb.h>
724bff34e3Sthurlow #include <netsmb/smb_conn.h>
734bff34e3Sthurlow #include <netsmb/smb_subr.h>
744bff34e3Sthurlow #include <netsmb/smb_tran.h>
754bff34e3Sthurlow #include <netsmb/smb_trantcp.h>
764bff34e3Sthurlow 
774bff34e3Sthurlow static int  nb_disconnect(struct nbpcb *nbp);
784bff34e3Sthurlow 
794bff34e3Sthurlow 
804bff34e3Sthurlow /*
814bff34e3Sthurlow  * Get mblks into *mpp until the data length is at least mlen.
824bff34e3Sthurlow  * Note that *mpp may already contain a fragment.
834bff34e3Sthurlow  *
844bff34e3Sthurlow  * If we ever have to wait more than 15 sec. to read a message,
854bff34e3Sthurlow  * return ETIME.  (Caller will declare the VD dead.)
864bff34e3Sthurlow  */
874bff34e3Sthurlow static int
nb_getmsg_mlen(struct nbpcb * nbp,mblk_t ** mpp,size_t mlen)884bff34e3Sthurlow nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
894bff34e3Sthurlow {
904bff34e3Sthurlow 	mblk_t *im, *tm;
914bff34e3Sthurlow 	union T_primitives	*pptr;
924bff34e3Sthurlow 	size_t dlen;
934bff34e3Sthurlow 	int events, fmode, timo, waitflg;
944bff34e3Sthurlow 	int error = 0;
954bff34e3Sthurlow 
963d804dabSGordon Ross 	/* We should be the only reader. */
973d804dabSGordon Ross 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
983d804dabSGordon Ross 	/* nbp->nbp_tiptr checked by caller */
993d804dabSGordon Ross 
1004bff34e3Sthurlow 	/*
1014bff34e3Sthurlow 	 * Get the first message (fragment) if
1024bff34e3Sthurlow 	 * we don't already have a left-over.
1034bff34e3Sthurlow 	 */
1044bff34e3Sthurlow 	dlen = msgdsize(*mpp); /* *mpp==null is OK */
1054bff34e3Sthurlow 	while (dlen < mlen) {
1064bff34e3Sthurlow 
1074bff34e3Sthurlow 		/*
1084bff34e3Sthurlow 		 * I think we still want this to return ETIME
1094bff34e3Sthurlow 		 * if nothing arrives for SMB_NBTIMO (15) sec.
1104bff34e3Sthurlow 		 * so we can report "server not responding".
1114bff34e3Sthurlow 		 * We _could_ just block here now that our
1124bff34e3Sthurlow 		 * IOD is just a reader.
1134bff34e3Sthurlow 		 */
1144bff34e3Sthurlow #if 1
1154bff34e3Sthurlow 		/* Wait with timeout... */
1164bff34e3Sthurlow 		events = 0;
1174bff34e3Sthurlow 		waitflg = READWAIT;
1184bff34e3Sthurlow 		timo = SEC_TO_TICK(SMB_NBTIMO);
1194bff34e3Sthurlow 		error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
1204bff34e3Sthurlow 		if (!error && !events)
1214bff34e3Sthurlow 			error = ETIME;
1224bff34e3Sthurlow 		if (error)
1234bff34e3Sthurlow 			break;
1244bff34e3Sthurlow 		/* file mode for recv is: */
1254bff34e3Sthurlow 		fmode = FNDELAY; /* non-blocking */
1264bff34e3Sthurlow #else
1274bff34e3Sthurlow 		fmode = 0; /* normal (blocking) */
1284bff34e3Sthurlow #endif
1294bff34e3Sthurlow 
1304bff34e3Sthurlow 		/* Get some more... */
1314bff34e3Sthurlow 		tm = NULL;
1324bff34e3Sthurlow 		error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
1334bff34e3Sthurlow 		if (error == EAGAIN)
1344bff34e3Sthurlow 			continue;
1354bff34e3Sthurlow 		if (error)
1364bff34e3Sthurlow 			break;
1374bff34e3Sthurlow 
1384bff34e3Sthurlow 		/*
1394bff34e3Sthurlow 		 * Normally get M_DATA messages here,
1404bff34e3Sthurlow 		 * but have to check for other types.
1414bff34e3Sthurlow 		 */
1424bff34e3Sthurlow 		switch (tm->b_datap->db_type) {
1434bff34e3Sthurlow 		case M_DATA:
1444bff34e3Sthurlow 			break;
1454bff34e3Sthurlow 		case M_PROTO:
1464bff34e3Sthurlow 		case M_PCPROTO:
1474bff34e3Sthurlow 			/*LINTED*/
1484bff34e3Sthurlow 			pptr = (union T_primitives *)tm->b_rptr;
1494bff34e3Sthurlow 			switch (pptr->type) {
1504bff34e3Sthurlow 			case T_DATA_IND:
1514bff34e3Sthurlow 				/* remove 1st mblk, keep the rest. */
1524bff34e3Sthurlow 				im = tm->b_cont;
1534bff34e3Sthurlow 				tm->b_cont = NULL;
1544bff34e3Sthurlow 				freeb(tm);
1554bff34e3Sthurlow 				tm = im;
1564bff34e3Sthurlow 				break;
1574bff34e3Sthurlow 			case T_DISCON_IND:
1584bff34e3Sthurlow 				/* Peer disconnected. */
1594bff34e3Sthurlow 				NBDEBUG("T_DISCON_IND: reason=%d",
1608329232eSGordon Ross 				    (int)pptr->discon_ind.DISCON_reason);
1614bff34e3Sthurlow 				goto discon;
1624bff34e3Sthurlow 			case T_ORDREL_IND:
1634bff34e3Sthurlow 				/* Peer disconnecting. */
1644bff34e3Sthurlow 				NBDEBUG("T_ORDREL_IND");
1654bff34e3Sthurlow 				goto discon;
1664bff34e3Sthurlow 			case T_OK_ACK:
1674bff34e3Sthurlow 				switch (pptr->ok_ack.CORRECT_prim) {
1684bff34e3Sthurlow 				case T_DISCON_REQ:
1694bff34e3Sthurlow 					NBDEBUG("T_OK_ACK/T_DISCON_REQ");
1704bff34e3Sthurlow 					goto discon;
1714bff34e3Sthurlow 				default:
1724bff34e3Sthurlow 					NBDEBUG("T_OK_ACK/prim=%d",
1738329232eSGordon Ross 					    (int)pptr->ok_ack.CORRECT_prim);
1744bff34e3Sthurlow 					goto discon;
1754bff34e3Sthurlow 				}
1764bff34e3Sthurlow 			default:
1778329232eSGordon Ross 				NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
1784bff34e3Sthurlow 				goto discon;
1794bff34e3Sthurlow 			}
1804bff34e3Sthurlow 			break; /* M_PROTO, M_PCPROTO */
1814bff34e3Sthurlow 
1824bff34e3Sthurlow 		default:
1834bff34e3Sthurlow 			NBDEBUG("unexpected msg type=%d",
1844bff34e3Sthurlow 			    tm->b_datap->db_type);
1854bff34e3Sthurlow 			/*FALLTHROUGH*/
1864bff34e3Sthurlow discon:
1874bff34e3Sthurlow 			/*
1884bff34e3Sthurlow 			 * The connection is no longer usable.
1894bff34e3Sthurlow 			 * Drop this message and disconnect.
1904bff34e3Sthurlow 			 *
1914bff34e3Sthurlow 			 * Note: nb_disconnect only does t_snddis
1924bff34e3Sthurlow 			 * on the first call, but does important
1934bff34e3Sthurlow 			 * cleanup and state change on any call.
1944bff34e3Sthurlow 			 */
1954bff34e3Sthurlow 			freemsg(tm);
19602d09e03SGordon Ross 			(void) nb_disconnect(nbp);
1974bff34e3Sthurlow 			return (ENOTCONN);
1984bff34e3Sthurlow 		}
1994bff34e3Sthurlow 
2004bff34e3Sthurlow 		/*
2014bff34e3Sthurlow 		 * If we have a data message, append it to
2024bff34e3Sthurlow 		 * the previous chunk(s) and update dlen
2034bff34e3Sthurlow 		 */
2044bff34e3Sthurlow 		if (!tm)
2054bff34e3Sthurlow 			continue;
2064bff34e3Sthurlow 		if (*mpp == NULL) {
2074bff34e3Sthurlow 			*mpp = tm;
2084bff34e3Sthurlow 		} else {
2094bff34e3Sthurlow 			/* Append */
2104bff34e3Sthurlow 			for (im = *mpp; im->b_cont; im = im->b_cont)
2114bff34e3Sthurlow 				;
2124bff34e3Sthurlow 			im->b_cont = tm;
2134bff34e3Sthurlow 		}
2144bff34e3Sthurlow 		dlen += msgdsize(tm);
2154bff34e3Sthurlow 	}
2164bff34e3Sthurlow 
2174bff34e3Sthurlow 	return (error);
2184bff34e3Sthurlow }
2194bff34e3Sthurlow 
2204bff34e3Sthurlow /*
2214bff34e3Sthurlow  * Send a T_DISCON_REQ (disconnect)
2224bff34e3Sthurlow  */
2234bff34e3Sthurlow static int
nb_snddis(struct nbpcb * nbp)2243d804dabSGordon Ross nb_snddis(struct nbpcb *nbp)
2254bff34e3Sthurlow {
2263d804dabSGordon Ross 	TIUSER *tiptr = nbp->nbp_tiptr;
2273d804dabSGordon Ross 	cred_t *cr = nbp->nbp_cred;
2284bff34e3Sthurlow 	mblk_t *mp;
2294bff34e3Sthurlow 	struct T_discon_req *dreq;
2303d804dabSGordon Ross 	int error, mlen;
2313d804dabSGordon Ross 
2323d804dabSGordon Ross 	ASSERT(MUTEX_HELD(&nbp->nbp_lock));
2333d804dabSGordon Ross 
2343d804dabSGordon Ross 	if (tiptr == NULL)
2353d804dabSGordon Ross 		return (EBADF);
2364bff34e3Sthurlow 
2374bff34e3Sthurlow 	mlen = sizeof (struct T_discon_req);
238613a2f6bSGordon Ross 	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
2394bff34e3Sthurlow 		return (error);
2404bff34e3Sthurlow 
2414bff34e3Sthurlow 	mp->b_datap->db_type = M_PROTO;
2424bff34e3Sthurlow 	/*LINTED*/
2434bff34e3Sthurlow 	dreq = (struct T_discon_req *)mp->b_wptr;
2444bff34e3Sthurlow 	dreq->PRIM_type = T_DISCON_REQ;
2454bff34e3Sthurlow 	dreq->SEQ_number = -1;
2464bff34e3Sthurlow 	mp->b_wptr += sizeof (struct T_discon_req);
2474bff34e3Sthurlow 
2483d804dabSGordon Ross 	error = tli_send(tiptr, mp, tiptr->fp->f_flag);
2493d804dabSGordon Ross 	/*
2503d804dabSGordon Ross 	 * There is an OK/ACK response expected, which is
2513d804dabSGordon Ross 	 * either handled by our receiver thread, or just
2523d804dabSGordon Ross 	 * discarded if we're closing this endpoint.
2533d804dabSGordon Ross 	 */
2546723e17fSGordon Ross 
2554bff34e3Sthurlow 	return (error);
2564bff34e3Sthurlow }
2574bff34e3Sthurlow 
2584bff34e3Sthurlow /*
2594bff34e3Sthurlow  * Stuff the NetBIOS header into space already prepended.
2604bff34e3Sthurlow  */
26102d09e03SGordon Ross static void
nb_sethdr(mblk_t * m,uint8_t type,uint32_t len)2624bff34e3Sthurlow nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
2634bff34e3Sthurlow {
2644bff34e3Sthurlow 	uint32_t *p;
2654bff34e3Sthurlow 
2664bff34e3Sthurlow 	len &= 0x1FFFF;
2674bff34e3Sthurlow 	len |= (type << 24);
2684bff34e3Sthurlow 
2694bff34e3Sthurlow 	/*LINTED*/
2704bff34e3Sthurlow 	p = (uint32_t *)m->b_rptr;
2714bff34e3Sthurlow 	*p = htonl(len);
2724bff34e3Sthurlow }
2734bff34e3Sthurlow 
2744bff34e3Sthurlow /*
2754bff34e3Sthurlow  * Wait for up to 15 sec. for the next packet.
2764bff34e3Sthurlow  * Often return ETIME and do nothing else.
2774bff34e3Sthurlow  * When a packet header is available, check
2784bff34e3Sthurlow  * the header and get the length, but don't
2794bff34e3Sthurlow  * consume it.  No side effects here except
2804bff34e3Sthurlow  * for the pullupmsg call.
2814bff34e3Sthurlow  */
2824bff34e3Sthurlow static int
nbssn_peekhdr(struct nbpcb * nbp,size_t * lenp,uint8_t * rpcodep)2834bff34e3Sthurlow nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,	uint8_t *rpcodep)
2844bff34e3Sthurlow {
2854bff34e3Sthurlow 	uint32_t len, *hdr;
2864bff34e3Sthurlow 	int error;
2874bff34e3Sthurlow 
2884bff34e3Sthurlow 	/*
2894bff34e3Sthurlow 	 * Get the first message (fragment) if
2904bff34e3Sthurlow 	 * we don't already have a left-over.
2914bff34e3Sthurlow 	 */
2924bff34e3Sthurlow 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
2934bff34e3Sthurlow 	if (error)
2944bff34e3Sthurlow 		return (error);
2954bff34e3Sthurlow 
2964bff34e3Sthurlow 	if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
2974bff34e3Sthurlow 		return (ENOSR);
2984bff34e3Sthurlow 
2994bff34e3Sthurlow 	/*
3004bff34e3Sthurlow 	 * Check the NetBIOS header.
3014bff34e3Sthurlow 	 * (NOT consumed here)
3024bff34e3Sthurlow 	 */
3034bff34e3Sthurlow 	/*LINTED*/
3044bff34e3Sthurlow 	hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
3054bff34e3Sthurlow 
3064bff34e3Sthurlow 	len = ntohl(*hdr);
3074bff34e3Sthurlow 	if ((len >> 16) & 0xFE) {
3084bff34e3Sthurlow 		NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
3094bff34e3Sthurlow 		return (EPIPE);
3104bff34e3Sthurlow 	}
3114bff34e3Sthurlow 	*rpcodep = (len >> 24) & 0xFF;
3124bff34e3Sthurlow 	switch (*rpcodep) {
3134bff34e3Sthurlow 	case NB_SSN_MESSAGE:
3144bff34e3Sthurlow 	case NB_SSN_REQUEST:
3154bff34e3Sthurlow 	case NB_SSN_POSRESP:
3164bff34e3Sthurlow 	case NB_SSN_NEGRESP:
3174bff34e3Sthurlow 	case NB_SSN_RTGRESP:
3184bff34e3Sthurlow 	case NB_SSN_KEEPALIVE:
3194bff34e3Sthurlow 		break;
3204bff34e3Sthurlow 	default:
3214bff34e3Sthurlow 		NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
3224bff34e3Sthurlow 		return (EPIPE);
3234bff34e3Sthurlow 	}
3244bff34e3Sthurlow 	len &= 0x1ffff;
325613a2f6bSGordon Ross 	if (len > NB_MAXPKTLEN) {
3264bff34e3Sthurlow 		NBDEBUG("packet too long (%d)\n", len);
3274bff34e3Sthurlow 		return (EFBIG);
3284bff34e3Sthurlow 	}
3294bff34e3Sthurlow 	*lenp = len;
3304bff34e3Sthurlow 	return (0);
3314bff34e3Sthurlow }
3324bff34e3Sthurlow 
3334bff34e3Sthurlow /*
3344bff34e3Sthurlow  * Receive a NetBIOS message.  This may block to wait for the entire
3354bff34e3Sthurlow  * message to arrive.  The caller knows there is (or should be) a
3364bff34e3Sthurlow  * message to be read.  When we receive and drop a keepalive or
3374bff34e3Sthurlow  * zero-length message, return EAGAIN so the caller knows that
3384bff34e3Sthurlow  * something was received.  This avoids false triggering of the
3394bff34e3Sthurlow  * "server not responding" state machine.
3403d804dabSGordon Ross  *
3413d804dabSGordon Ross  * Calls to this are serialized at a higher level.
3424bff34e3Sthurlow  */
3434bff34e3Sthurlow static int
nbssn_recv(struct nbpcb * nbp,mblk_t ** mpp,int * lenp,uint8_t * rpcodep)3444bff34e3Sthurlow nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
345613a2f6bSGordon Ross     uint8_t *rpcodep)
3464bff34e3Sthurlow {
3474bff34e3Sthurlow 	mblk_t *m0;
3484bff34e3Sthurlow 	uint8_t rpcode;
3494bff34e3Sthurlow 	int error;
3504bff34e3Sthurlow 	size_t rlen, len;
3514bff34e3Sthurlow 
3524bff34e3Sthurlow 	/* We should be the only reader. */
3534bff34e3Sthurlow 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
3544bff34e3Sthurlow 
3553d804dabSGordon Ross 	if (nbp->nbp_tiptr == NULL)
3564bff34e3Sthurlow 		return (EBADF);
3574bff34e3Sthurlow 	if (mpp) {
3584bff34e3Sthurlow 		if (*mpp) {
3594bff34e3Sthurlow 			NBDEBUG("*mpp not 0 - leak?");
3604bff34e3Sthurlow 		}
3614bff34e3Sthurlow 		*mpp = NULL;
3624bff34e3Sthurlow 	}
3634bff34e3Sthurlow 	m0 = NULL;
3644bff34e3Sthurlow 
3654bff34e3Sthurlow 	/*
3664bff34e3Sthurlow 	 * Get the NetBIOS header (not consumed yet)
3674bff34e3Sthurlow 	 */
3684bff34e3Sthurlow 	error = nbssn_peekhdr(nbp, &len, &rpcode);
3694bff34e3Sthurlow 	if (error) {
3704bff34e3Sthurlow 		if (error != ETIME)
3714bff34e3Sthurlow 			NBDEBUG("peekhdr, error=%d\n", error);
3724bff34e3Sthurlow 		return (error);
3734bff34e3Sthurlow 	}
3744bff34e3Sthurlow 	NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
3754bff34e3Sthurlow 	    (int)rpcode, (int)len);
3764bff34e3Sthurlow 
3774bff34e3Sthurlow 	/*
3784bff34e3Sthurlow 	 * Block here waiting for the whole packet to arrive.
3794bff34e3Sthurlow 	 * If we get a timeout, return without side effects.
3804bff34e3Sthurlow 	 * The data length we wait for here includes both the
3814bff34e3Sthurlow 	 * NetBIOS header and the payload.
3824bff34e3Sthurlow 	 */
3834bff34e3Sthurlow 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
3844bff34e3Sthurlow 	if (error) {
3854bff34e3Sthurlow 		NBDEBUG("getmsg(body), error=%d\n", error);
3864bff34e3Sthurlow 		return (error);
3874bff34e3Sthurlow 	}
3884bff34e3Sthurlow 
3894bff34e3Sthurlow 	/*
3904bff34e3Sthurlow 	 * We now have an entire NetBIOS message.
3914bff34e3Sthurlow 	 * Trim off the NetBIOS header and consume it.
3924bff34e3Sthurlow 	 * Note: _peekhdr has done pullupmsg for us,
3934bff34e3Sthurlow 	 * so we know it's safe to advance b_rptr.
3944bff34e3Sthurlow 	 */
3954bff34e3Sthurlow 	m0 = nbp->nbp_frag;
3964bff34e3Sthurlow 	m0->b_rptr += 4;
3974bff34e3Sthurlow 
3984bff34e3Sthurlow 	/*
3994bff34e3Sthurlow 	 * There may be more data after the message
4004bff34e3Sthurlow 	 * we're about to return, in which case we
4014bff34e3Sthurlow 	 * split it and leave the remainder.
4024bff34e3Sthurlow 	 */
4034bff34e3Sthurlow 	rlen = msgdsize(m0);
4044bff34e3Sthurlow 	ASSERT(rlen >= len);
4054bff34e3Sthurlow 	nbp->nbp_frag = NULL;
4064bff34e3Sthurlow 	if (rlen > len)
4074bff34e3Sthurlow 		nbp->nbp_frag = m_split(m0, len, 1);
4084bff34e3Sthurlow 
4094bff34e3Sthurlow 	if (nbp->nbp_state != NBST_SESSION) {
4104bff34e3Sthurlow 		/*
4114bff34e3Sthurlow 		 * No session is established.
4124bff34e3Sthurlow 		 * Return whatever packet we got.
4134bff34e3Sthurlow 		 */
4144bff34e3Sthurlow 		goto out;
4154bff34e3Sthurlow 	}
4164bff34e3Sthurlow 
4174bff34e3Sthurlow 	/*
4184bff34e3Sthurlow 	 * A session is established; the only packets
4194bff34e3Sthurlow 	 * we should see are session message and
4204bff34e3Sthurlow 	 * keep-alive packets.  Drop anything else.
4214bff34e3Sthurlow 	 */
4224bff34e3Sthurlow 	switch (rpcode) {
4234bff34e3Sthurlow 
4244bff34e3Sthurlow 	case NB_SSN_KEEPALIVE:
4254bff34e3Sthurlow 		/*
4264bff34e3Sthurlow 		 * It's a keepalive.  Discard any data in it
4274bff34e3Sthurlow 		 * (there's not supposed to be any, but that
4284bff34e3Sthurlow 		 * doesn't mean some server won't send some)
4294bff34e3Sthurlow 		 */
4304bff34e3Sthurlow 		if (len)
4314bff34e3Sthurlow 			NBDEBUG("Keepalive with data %d\n", (int)len);
4324bff34e3Sthurlow 		error = EAGAIN;
4334bff34e3Sthurlow 		break;
4344bff34e3Sthurlow 
4354bff34e3Sthurlow 	case NB_SSN_MESSAGE:
4364bff34e3Sthurlow 		/*
4374bff34e3Sthurlow 		 * Session message.  Does it have any data?
4384bff34e3Sthurlow 		 */
4394bff34e3Sthurlow 		if (len == 0) {
4404bff34e3Sthurlow 			/*
4414bff34e3Sthurlow 			 * No data - treat as keepalive (drop).
4424bff34e3Sthurlow 			 */
4434bff34e3Sthurlow 			error = EAGAIN;
4444bff34e3Sthurlow 			break;
4454bff34e3Sthurlow 		}
4464bff34e3Sthurlow 		/*
4474bff34e3Sthurlow 		 * Yes, has data.  Return it.
4484bff34e3Sthurlow 		 */
4494bff34e3Sthurlow 		error = 0;
4504bff34e3Sthurlow 		break;
4514bff34e3Sthurlow 
4524bff34e3Sthurlow 	default:
4534bff34e3Sthurlow 		/*
4544bff34e3Sthurlow 		 * Drop anything else.
4554bff34e3Sthurlow 		 */
4564bff34e3Sthurlow 		NBDEBUG("non-session packet %x\n", rpcode);
4574bff34e3Sthurlow 		error = EAGAIN;
4584bff34e3Sthurlow 		break;
4594bff34e3Sthurlow 	}
4604bff34e3Sthurlow 
4614bff34e3Sthurlow out:
4624bff34e3Sthurlow 	if (error) {
4634bff34e3Sthurlow 		if (m0)
4644bff34e3Sthurlow 			m_freem(m0);
4654bff34e3Sthurlow 		return (error);
4664bff34e3Sthurlow 	}
4674bff34e3Sthurlow 	if (mpp)
4684bff34e3Sthurlow 		*mpp = m0;
4694bff34e3Sthurlow 	else
4704bff34e3Sthurlow 		m_freem(m0);
4714bff34e3Sthurlow 	*lenp = (int)len;
4724bff34e3Sthurlow 	*rpcodep = rpcode;
4734bff34e3Sthurlow 	return (0);
4744bff34e3Sthurlow }
4754bff34e3Sthurlow 
4764bff34e3Sthurlow /*
4774bff34e3Sthurlow  * SMB transport interface
4783d804dabSGordon Ross  *
4793d804dabSGordon Ross  * This is called only by the thread creating this endpoint,
4803d804dabSGordon Ross  * so we're single-threaded here.
4814bff34e3Sthurlow  */
4824bff34e3Sthurlow static int
smb_nbst_create(struct smb_vc * vcp,cred_t * cr)483613a2f6bSGordon Ross smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
4844bff34e3Sthurlow {
48540c0e231SGordon Ross 	TIUSER *tiptr = NULL;
48640c0e231SGordon Ross 	struct nbpcb *nbp = NULL;
48740c0e231SGordon Ross 	dev_t dev;
48840c0e231SGordon Ross 	int rc;
48940c0e231SGordon Ross 	ushort_t fmode;
49040c0e231SGordon Ross 
49140c0e231SGordon Ross 	switch (vcp->vc_srvaddr.sa.sa_family) {
49240c0e231SGordon Ross 	case AF_INET:
49340c0e231SGordon Ross 		dev = nsmb_dev_tcp;
49440c0e231SGordon Ross 		break;
49540c0e231SGordon Ross 	case AF_INET6:
49640c0e231SGordon Ross 		dev = nsmb_dev_tcp6;
49740c0e231SGordon Ross 		break;
49840c0e231SGordon Ross 	default:
49940c0e231SGordon Ross 		return (EAFNOSUPPORT);
50040c0e231SGordon Ross 	}
50140c0e231SGordon Ross 
50240c0e231SGordon Ross 	fmode = FREAD|FWRITE;
50340c0e231SGordon Ross 	rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
50440c0e231SGordon Ross 	if (rc != 0) {
50540c0e231SGordon Ross 		cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
50640c0e231SGordon Ross 		return (rc);
50740c0e231SGordon Ross 	}
50840c0e231SGordon Ross 	ASSERT(tiptr != NULL);
5094bff34e3Sthurlow 
5104bff34e3Sthurlow 	nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
5114bff34e3Sthurlow 
5124bff34e3Sthurlow 	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
51340c0e231SGordon Ross 	nbp->nbp_state = NBST_IDLE;
5144bff34e3Sthurlow 	nbp->nbp_vc = vcp;
51540c0e231SGordon Ross 	nbp->nbp_tiptr = tiptr;
51640c0e231SGordon Ross 	nbp->nbp_fmode = fmode;
5173d804dabSGordon Ross 	nbp->nbp_cred = cr;
5183d804dabSGordon Ross 	crhold(cr);
5194bff34e3Sthurlow 	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
52040c0e231SGordon Ross 
5214bff34e3Sthurlow 	vcp->vc_tdata = nbp;
5226723e17fSGordon Ross 
5234bff34e3Sthurlow 	return (0);
5244bff34e3Sthurlow }
5254bff34e3Sthurlow 
5263d804dabSGordon Ross /*
5273d804dabSGordon Ross  * destroy a transport endpoint
5283d804dabSGordon Ross  *
5293d804dabSGordon Ross  * This is called only by the thread with the last reference
5303d804dabSGordon Ross  * to this endpoint, so we're single-threaded here.
5313d804dabSGordon Ross  */
5324bff34e3Sthurlow static int
smb_nbst_done(struct smb_vc * vcp)533613a2f6bSGordon Ross smb_nbst_done(struct smb_vc *vcp)
5344bff34e3Sthurlow {
5354bff34e3Sthurlow 	struct nbpcb *nbp = vcp->vc_tdata;
5364bff34e3Sthurlow 
5374bff34e3Sthurlow 	if (nbp == NULL)
5384bff34e3Sthurlow 		return (ENOTCONN);
5394bff34e3Sthurlow 	vcp->vc_tdata = NULL;
5404bff34e3Sthurlow 
5414bff34e3Sthurlow 	/*
5424bff34e3Sthurlow 	 * Don't really need to disconnect here,
5434bff34e3Sthurlow 	 * because the close following will do it.
5444bff34e3Sthurlow 	 * But it's harmless.
5454bff34e3Sthurlow 	 */
5464bff34e3Sthurlow 	if (nbp->nbp_flags & NBF_CONNECTED)
54702d09e03SGordon Ross 		(void) nb_disconnect(nbp);
5484bff34e3Sthurlow 	if (nbp->nbp_tiptr)
54902d09e03SGordon Ross 		(void) t_kclose(nbp->nbp_tiptr, 0);
5504bff34e3Sthurlow 	if (nbp->nbp_laddr)
5514bff34e3Sthurlow 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
5524bff34e3Sthurlow 	if (nbp->nbp_paddr)
5534bff34e3Sthurlow 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
5543d804dabSGordon Ross 	if (nbp->nbp_cred)
5553d804dabSGordon Ross 		crfree(nbp->nbp_cred);
5564bff34e3Sthurlow 	mutex_destroy(&nbp->nbp_lock);
5574bff34e3Sthurlow 	kmem_free(nbp, sizeof (*nbp));
5584bff34e3Sthurlow 	return (0);
5594bff34e3Sthurlow }
5604bff34e3Sthurlow 
5613d804dabSGordon Ross static int
smb_nbst_bind(struct smb_vc * vcp,struct sockaddr * sap)562*adee6784SGordon Ross smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
5633d804dabSGordon Ross {
5643d804dabSGordon Ross 	struct nbpcb *nbp = vcp->vc_tdata;
565*adee6784SGordon Ross 	TIUSER *tiptr = nbp->nbp_tiptr;
566*adee6784SGordon Ross 	int err;
5673d804dabSGordon Ross 
568*adee6784SGordon Ross 	/* Only default bind supported. */
569*adee6784SGordon Ross 	if (sap != NULL)
570*adee6784SGordon Ross 		return (ENOTSUP);
5717962806fSGordon Ross 
572*adee6784SGordon Ross 	err = t_kbind(tiptr, NULL, NULL);
573613a2f6bSGordon Ross 
574*adee6784SGordon Ross 	return (err);
5754bff34e3Sthurlow }
5764bff34e3Sthurlow 
5774bff34e3Sthurlow static int
smb_nbst_unbind(struct smb_vc * vcp)578*adee6784SGordon Ross smb_nbst_unbind(struct smb_vc *vcp)
5794bff34e3Sthurlow {
58040c0e231SGordon Ross 	struct nbpcb *nbp = vcp->vc_tdata;
58140c0e231SGordon Ross 	TIUSER *tiptr = nbp->nbp_tiptr;
58240c0e231SGordon Ross 	int err;
58340c0e231SGordon Ross 
584*adee6784SGordon Ross 	err = t_kunbind(tiptr);
58540c0e231SGordon Ross 
58640c0e231SGordon Ross 	return (err);
587613a2f6bSGordon Ross }
5884bff34e3Sthurlow 
589613a2f6bSGordon Ross static int
smb_nbst_connect(struct smb_vc * vcp,struct sockaddr * sap)590613a2f6bSGordon Ross smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
591613a2f6bSGordon Ross {
59240c0e231SGordon Ross 	struct t_call	call;
59340c0e231SGordon Ross 	struct nbpcb	*nbp = vcp->vc_tdata;
59440c0e231SGordon Ross 	TIUSER		*tiptr = nbp->nbp_tiptr;
59540c0e231SGordon Ross 	int alen, err;
59640c0e231SGordon Ross 
59740c0e231SGordon Ross 	/* Need the address length */
59840c0e231SGordon Ross 	switch (sap->sa_family) {
59940c0e231SGordon Ross 	case AF_INET:
60040c0e231SGordon Ross 		alen = sizeof (struct sockaddr_in);
60140c0e231SGordon Ross 		break;
60240c0e231SGordon Ross 	case AF_INET6:
60340c0e231SGordon Ross 		alen = sizeof (struct sockaddr_in6);
60440c0e231SGordon Ross 		break;
60540c0e231SGordon Ross 	default:
60640c0e231SGordon Ross 		return (EAFNOSUPPORT);
60740c0e231SGordon Ross 	}
60840c0e231SGordon Ross 
60940c0e231SGordon Ross 	/* sockaddr goes in the "addr" netbuf */
61040c0e231SGordon Ross 	bzero(&call, sizeof (call));
61140c0e231SGordon Ross 	call.addr.buf = (char *)sap;
61240c0e231SGordon Ross 	call.addr.len = alen;
61340c0e231SGordon Ross 	call.addr.maxlen = alen;
61440c0e231SGordon Ross 
61540c0e231SGordon Ross 	err = t_kconnect(tiptr, &call, NULL);
61640c0e231SGordon Ross 	if (err != 0)
61740c0e231SGordon Ross 		return (err);
61840c0e231SGordon Ross 
61940c0e231SGordon Ross 	mutex_enter(&nbp->nbp_lock);
62040c0e231SGordon Ross 
62140c0e231SGordon Ross 	nbp->nbp_flags |= NBF_CONNECTED;
62240c0e231SGordon Ross 	nbp->nbp_state = NBST_SESSION;
62340c0e231SGordon Ross 
62440c0e231SGordon Ross 	mutex_exit(&nbp->nbp_lock);
62540c0e231SGordon Ross 
62640c0e231SGordon Ross 	return (0);
6274bff34e3Sthurlow }
6284bff34e3Sthurlow 
6294bff34e3Sthurlow static int
smb_nbst_disconnect(struct smb_vc * vcp)630613a2f6bSGordon Ross smb_nbst_disconnect(struct smb_vc *vcp)
6314bff34e3Sthurlow {
6324bff34e3Sthurlow 	struct nbpcb *nbp = vcp->vc_tdata;
6334bff34e3Sthurlow 
6344bff34e3Sthurlow 	if (nbp == NULL)
6354bff34e3Sthurlow 		return (ENOTCONN);
6364bff34e3Sthurlow 
6374bff34e3Sthurlow 	return (nb_disconnect(nbp));
6384bff34e3Sthurlow }
6394bff34e3Sthurlow 
6404bff34e3Sthurlow static int
nb_disconnect(struct nbpcb * nbp)6414bff34e3Sthurlow nb_disconnect(struct nbpcb *nbp)
6424bff34e3Sthurlow {
64302d09e03SGordon Ross 	int err = 0;
6444bff34e3Sthurlow 
6454bff34e3Sthurlow 	mutex_enter(&nbp->nbp_lock);
6464bff34e3Sthurlow 
6473d804dabSGordon Ross 	if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
6483d804dabSGordon Ross 		nbp->nbp_flags &= ~NBF_CONNECTED;
6493d804dabSGordon Ross 		err = nb_snddis(nbp);
6504bff34e3Sthurlow 	}
65102d09e03SGordon Ross 
6523d804dabSGordon Ross 	mutex_exit(&nbp->nbp_lock);
65302d09e03SGordon Ross 	return (err);
6544bff34e3Sthurlow }
6554bff34e3Sthurlow 
6564bff34e3Sthurlow /*
6573d804dabSGordon Ross  * Add the NetBIOS session header and send.
6583d804dabSGordon Ross  *
6593d804dabSGordon Ross  * Calls to this are serialized at a higher level.
6604bff34e3Sthurlow  */
6614bff34e3Sthurlow static int
nbssn_send(struct nbpcb * nbp,mblk_t * m)6623d804dabSGordon Ross nbssn_send(struct nbpcb *nbp, mblk_t *m)
6634bff34e3Sthurlow {
6644bff34e3Sthurlow 	ptrdiff_t diff;
6654bff34e3Sthurlow 	uint32_t mlen;
6664bff34e3Sthurlow 	int error;
6674bff34e3Sthurlow 
6683d804dabSGordon Ross 	/* We should be the only sender. */
6693d804dabSGordon Ross 	ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
6703d804dabSGordon Ross 
6713d804dabSGordon Ross 	if (nbp->nbp_tiptr == NULL) {
6724bff34e3Sthurlow 		error = EBADF;
6734bff34e3Sthurlow 		goto errout;
6744bff34e3Sthurlow 	}
6754bff34e3Sthurlow 
6764bff34e3Sthurlow 	/*
6774bff34e3Sthurlow 	 * Get the message length, which
6784bff34e3Sthurlow 	 * does NOT include the NetBIOS header
6794bff34e3Sthurlow 	 */
6804bff34e3Sthurlow 	mlen = msgdsize(m);
6814bff34e3Sthurlow 
6824bff34e3Sthurlow 	/*
6834bff34e3Sthurlow 	 * Normally, mb_init() will have left space
6844bff34e3Sthurlow 	 * for us to prepend the NetBIOS header in
6854bff34e3Sthurlow 	 * the data block of the first mblk.
6864bff34e3Sthurlow 	 * However, we have to check in case other
6874bff34e3Sthurlow 	 * code did not leave this space, or if the
6884bff34e3Sthurlow 	 * message is from dupmsg (db_ref > 1)
6894bff34e3Sthurlow 	 *
6904bff34e3Sthurlow 	 * If don't find room in the first data block,
6914bff34e3Sthurlow 	 * we have to allocb a new message and link it
6924bff34e3Sthurlow 	 * on the front of the chain.  We try not to
6934bff34e3Sthurlow 	 * do this becuase it's less efficient.  Also,
6944bff34e3Sthurlow 	 * some network drivers will apparently send
6954bff34e3Sthurlow 	 * each mblk in the chain as separate frames.
6964bff34e3Sthurlow 	 * (That's arguably a driver bug.)
697613a2f6bSGordon Ross 	 *
698613a2f6bSGordon Ross 	 * Not bothering with allocb_cred_wait below
699613a2f6bSGordon Ross 	 * because the message we're prepending to
700613a2f6bSGordon Ross 	 * should already have a db_credp.
7014bff34e3Sthurlow 	 */
7024bff34e3Sthurlow 
7034bff34e3Sthurlow 	diff = MBLKHEAD(m);
7044bff34e3Sthurlow 	if (diff == 4 && DB_REF(m) == 1) {
7054bff34e3Sthurlow 		/* We can use the first dblk. */
7064bff34e3Sthurlow 		m->b_rptr -= 4;
7074bff34e3Sthurlow 	} else {
7084bff34e3Sthurlow 		/* Link a new mblk on the head. */
7094bff34e3Sthurlow 		mblk_t *m0;
7104bff34e3Sthurlow 
7114bff34e3Sthurlow 		/* M_PREPEND */
7124bff34e3Sthurlow 		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
7133d804dabSGordon Ross 		if (m0 == NULL)
7144bff34e3Sthurlow 			goto errout;
7154bff34e3Sthurlow 
7164bff34e3Sthurlow 		m0->b_wptr += 4;
7174bff34e3Sthurlow 		m0->b_cont = m;
7184bff34e3Sthurlow 		m = m0;
7194bff34e3Sthurlow 	}
7204bff34e3Sthurlow 
7214bff34e3Sthurlow 	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
7224bff34e3Sthurlow 	error = tli_send(nbp->nbp_tiptr, m, 0);
7234bff34e3Sthurlow 	return (error);
7244bff34e3Sthurlow 
7254bff34e3Sthurlow errout:
7263d804dabSGordon Ross 	if (m != NULL)
7274bff34e3Sthurlow 		m_freem(m);
7284bff34e3Sthurlow 	return (error);
7294bff34e3Sthurlow }
7304bff34e3Sthurlow 
7313d804dabSGordon Ross /*
7323d804dabSGordon Ross  * Always consume the message.
7333d804dabSGordon Ross  * (On error too!)
7343d804dabSGordon Ross  */
7353d804dabSGordon Ross static int
smb_nbst_send(struct smb_vc * vcp,mblk_t * m)7363d804dabSGordon Ross smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
7373d804dabSGordon Ross {
7383d804dabSGordon Ross 	struct nbpcb *nbp = vcp->vc_tdata;
7393d804dabSGordon Ross 	int err;
7403d804dabSGordon Ross 
7413d804dabSGordon Ross 	mutex_enter(&nbp->nbp_lock);
7423d804dabSGordon Ross 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
7433d804dabSGordon Ross 		err = ENOTCONN;
7443d804dabSGordon Ross 		goto out;
7453d804dabSGordon Ross 	}
7463d804dabSGordon Ross 	if (nbp->nbp_flags & NBF_SENDLOCK) {
7473d804dabSGordon Ross 		NBDEBUG("multiple smb_nbst_send!\n");
7483d804dabSGordon Ross 		err = EWOULDBLOCK;
7493d804dabSGordon Ross 		goto out;
7503d804dabSGordon Ross 	}
7513d804dabSGordon Ross 	nbp->nbp_flags |= NBF_SENDLOCK;
7523d804dabSGordon Ross 	mutex_exit(&nbp->nbp_lock);
7533d804dabSGordon Ross 
7543d804dabSGordon Ross 	err = nbssn_send(nbp, m);
7553d804dabSGordon Ross 	m = NULL; /* nbssn_send always consumes this */
7563d804dabSGordon Ross 
7573d804dabSGordon Ross 	mutex_enter(&nbp->nbp_lock);
7583d804dabSGordon Ross 	nbp->nbp_flags &= ~NBF_SENDLOCK;
7593d804dabSGordon Ross 	if (nbp->nbp_flags & NBF_LOCKWAIT) {
7603d804dabSGordon Ross 		nbp->nbp_flags &= ~NBF_LOCKWAIT;
7613d804dabSGordon Ross 		cv_broadcast(&nbp->nbp_cv);
7623d804dabSGordon Ross 	}
7633d804dabSGordon Ross out:
7643d804dabSGordon Ross 	mutex_exit(&nbp->nbp_lock);
7653d804dabSGordon Ross 	if (m != NULL)
7663d804dabSGordon Ross 		m_freem(m);
7673d804dabSGordon Ross 	return (err);
7683d804dabSGordon Ross }
7693d804dabSGordon Ross 
7704bff34e3Sthurlow static int
smb_nbst_recv(struct smb_vc * vcp,mblk_t ** mpp)771613a2f6bSGordon Ross smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
7724bff34e3Sthurlow {
7734bff34e3Sthurlow 	struct nbpcb *nbp = vcp->vc_tdata;
7744bff34e3Sthurlow 	uint8_t rpcode;
7753d804dabSGordon Ross 	int err, rplen;
7764bff34e3Sthurlow 
7774bff34e3Sthurlow 	mutex_enter(&nbp->nbp_lock);
7783d804dabSGordon Ross 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
7793d804dabSGordon Ross 		err = ENOTCONN;
7803d804dabSGordon Ross 		goto out;
7813d804dabSGordon Ross 	}
7824bff34e3Sthurlow 	if (nbp->nbp_flags & NBF_RECVLOCK) {
7833d804dabSGordon Ross 		NBDEBUG("multiple smb_nbst_recv!\n");
7843d804dabSGordon Ross 		err = EWOULDBLOCK;
7853d804dabSGordon Ross 		goto out;
7864bff34e3Sthurlow 	}
7874bff34e3Sthurlow 	nbp->nbp_flags |= NBF_RECVLOCK;
7884bff34e3Sthurlow 	mutex_exit(&nbp->nbp_lock);
7893d804dabSGordon Ross 
7903d804dabSGordon Ross 	err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
7913d804dabSGordon Ross 
7924bff34e3Sthurlow 	mutex_enter(&nbp->nbp_lock);
7934bff34e3Sthurlow 	nbp->nbp_flags &= ~NBF_RECVLOCK;
7943d804dabSGordon Ross 	if (nbp->nbp_flags & NBF_LOCKWAIT) {
7953d804dabSGordon Ross 		nbp->nbp_flags &= ~NBF_LOCKWAIT;
7963d804dabSGordon Ross 		cv_broadcast(&nbp->nbp_cv);
7973d804dabSGordon Ross 	}
7983d804dabSGordon Ross out:
7994bff34e3Sthurlow 	mutex_exit(&nbp->nbp_lock);
8003d804dabSGordon Ross 	return (err);
8014bff34e3Sthurlow }
8024bff34e3Sthurlow 
8034bff34e3Sthurlow /*
8044bff34e3Sthurlow  * Wait for up to "ticks" clock ticks for input on vcp.
8054bff34e3Sthurlow  * Returns zero if input is available, otherwise ETIME
8064bff34e3Sthurlow  * indicating time expired, or other error codes.
8074bff34e3Sthurlow  */
8084bff34e3Sthurlow /*ARGSUSED*/
8094bff34e3Sthurlow static int
smb_nbst_poll(struct smb_vc * vcp,int ticks)810613a2f6bSGordon Ross smb_nbst_poll(struct smb_vc *vcp, int ticks)
8114bff34e3Sthurlow {
8123d804dabSGordon Ross 	return (ENOTSUP);
8134bff34e3Sthurlow }
8144bff34e3Sthurlow 
81540c0e231SGordon Ross /*ARGSUSED*/
8164bff34e3Sthurlow static int
smb_nbst_getparam(struct smb_vc * vcp,int param,void * data)8174bff34e3Sthurlow smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
8184bff34e3Sthurlow {
81940c0e231SGordon Ross 	return (EINVAL);
82040c0e231SGordon Ross }
82140c0e231SGordon Ross 
82240c0e231SGordon Ross static int
smb_nbst_setparam(struct smb_vc * vcp,int param,void * data)82340c0e231SGordon Ross smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
82440c0e231SGordon Ross {
82540c0e231SGordon Ross 	struct t_optmgmt oreq, ores;
82640c0e231SGordon Ross 	struct {
82740c0e231SGordon Ross 		struct T_opthdr oh;
82840c0e231SGordon Ross 		int ival;
82940c0e231SGordon Ross 	} opts;
8304bff34e3Sthurlow 	struct nbpcb *nbp = vcp->vc_tdata;
83140c0e231SGordon Ross 	int level, name, err;
8324bff34e3Sthurlow 
8334bff34e3Sthurlow 	switch (param) {
83440c0e231SGordon Ross 	case SMBTP_TCP_NODELAY:
83540c0e231SGordon Ross 		level = IPPROTO_TCP;
83640c0e231SGordon Ross 		name = TCP_NODELAY;
8374bff34e3Sthurlow 		break;
83840c0e231SGordon Ross 
83940c0e231SGordon Ross 	case SMBTP_TCP_CON_TMO:	/* int mSec */
84040c0e231SGordon Ross 		level = IPPROTO_TCP;
84140c0e231SGordon Ross 		name = TCP_CONN_ABORT_THRESHOLD;
8424bff34e3Sthurlow 		break;
84340c0e231SGordon Ross 
84440c0e231SGordon Ross 	case SMBTP_KEEPALIVE:	// SO_KEEPALIVE
84540c0e231SGordon Ross 	case SMBTP_SNDBUF:	// SO_SNDBUF
84640c0e231SGordon Ross 	case SMBTP_RCVBUF:	// SO_RCVBUF
84740c0e231SGordon Ross 	case SMBTP_RCVTIMEO:	// SO_RCVTIMEO
84840c0e231SGordon Ross 		level = SOL_SOCKET;
84940c0e231SGordon Ross 		name = param;
8504bff34e3Sthurlow 		break;
85140c0e231SGordon Ross 
8524bff34e3Sthurlow 	default:
8534bff34e3Sthurlow 		return (EINVAL);
8544bff34e3Sthurlow 	}
8554bff34e3Sthurlow 
85640c0e231SGordon Ross 	/* opt header */
85740c0e231SGordon Ross 	opts.oh.len = sizeof (opts);
85840c0e231SGordon Ross 	opts.oh.level = level;
85940c0e231SGordon Ross 	opts.oh.name = name;
86040c0e231SGordon Ross 	opts.oh.status = 0;
86140c0e231SGordon Ross 	opts.ival = *(int *)data;
86240c0e231SGordon Ross 
86340c0e231SGordon Ross 	oreq.flags = T_NEGOTIATE;
86440c0e231SGordon Ross 	oreq.opt.buf = (void *)&opts;
86540c0e231SGordon Ross 	oreq.opt.len = sizeof (opts);
86640c0e231SGordon Ross 	oreq.opt.maxlen = oreq.opt.len;
86740c0e231SGordon Ross 
86840c0e231SGordon Ross 	ores.flags = 0;
86940c0e231SGordon Ross 	ores.opt.buf = NULL;
87040c0e231SGordon Ross 	ores.opt.len = 0;
87140c0e231SGordon Ross 	ores.opt.maxlen = 0;
87240c0e231SGordon Ross 
87340c0e231SGordon Ross 	err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
87440c0e231SGordon Ross 	if (err != 0) {
87540c0e231SGordon Ross 		cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
87640c0e231SGordon Ross 		return (EPROTO);
87740c0e231SGordon Ross 	}
87840c0e231SGordon Ross 
879*adee6784SGordon Ross 	if ((ores.flags & T_SUCCESS) == 0) {
88040c0e231SGordon Ross 		cmn_err(CE_NOTE, "smb_nbst_setparam: "
88140c0e231SGordon Ross 		    "flags 0x%x, status 0x%x",
88240c0e231SGordon Ross 		    (int)ores.flags, (int)opts.oh.status);
88340c0e231SGordon Ross 		return (EPROTO);
88440c0e231SGordon Ross 	}
88540c0e231SGordon Ross 
88640c0e231SGordon Ross 	return (0);
8874bff34e3Sthurlow }
8884bff34e3Sthurlow 
8894bff34e3Sthurlow /*
8904bff34e3Sthurlow  * Check for fatal errors
8914bff34e3Sthurlow  */
8924bff34e3Sthurlow /*ARGSUSED*/
8934bff34e3Sthurlow static int
smb_nbst_fatal(struct smb_vc * vcp,int error)8944bff34e3Sthurlow smb_nbst_fatal(struct smb_vc *vcp, int error)
8954bff34e3Sthurlow {
8964bff34e3Sthurlow 	switch (error) {
8974bff34e3Sthurlow 	case ENOTCONN:
8984bff34e3Sthurlow 	case ENETRESET:
8994bff34e3Sthurlow 	case ECONNABORTED:
9004bff34e3Sthurlow 	case EPIPE:
9014bff34e3Sthurlow 		return (1);
9024bff34e3Sthurlow 	}
9034bff34e3Sthurlow 	return (0);
9044bff34e3Sthurlow }
9054bff34e3Sthurlow 
9064bff34e3Sthurlow 
9074bff34e3Sthurlow struct smb_tran_desc smb_tran_nbtcp_desc = {
9084bff34e3Sthurlow 	SMBT_NBTCP,
9094bff34e3Sthurlow 	smb_nbst_create,
9104bff34e3Sthurlow 	smb_nbst_done,
9114bff34e3Sthurlow 	smb_nbst_bind,
912*adee6784SGordon Ross 	smb_nbst_unbind,
9134bff34e3Sthurlow 	smb_nbst_connect,
9144bff34e3Sthurlow 	smb_nbst_disconnect,
9154bff34e3Sthurlow 	smb_nbst_send,
9164bff34e3Sthurlow 	smb_nbst_recv,
9174bff34e3Sthurlow 	smb_nbst_poll,
9184bff34e3Sthurlow 	smb_nbst_getparam,
9194bff34e3Sthurlow 	smb_nbst_setparam,
9204bff34e3Sthurlow 	smb_nbst_fatal,
9214bff34e3Sthurlow 	{NULL, NULL}
9224bff34e3Sthurlow };
923