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 */
3422eb7cb5Sgd78059 /*
35de8c4a14SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3622eb7cb5Sgd78059 * Use is subject to license terms.
378329232eSGordon Ross *
3840c0e231SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
3922eb7cb5Sgd78059 */
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;
2314bff34e3Sthurlow
2323d804dabSGordon Ross ASSERT(MUTEX_HELD(&nbp->nbp_lock));
2333d804dabSGordon Ross
2343d804dabSGordon Ross if (tiptr == NULL)
2353d804dabSGordon Ross return (EBADF);
2363d804dabSGordon Ross
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
5614bff34e3Sthurlow static int
smb_nbst_bind(struct smb_vc * vcp,struct sockaddr * sap)562613a2f6bSGordon Ross smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
563613a2f6bSGordon Ross {
56440c0e231SGordon Ross struct nbpcb *nbp = vcp->vc_tdata;
56540c0e231SGordon Ross TIUSER *tiptr = nbp->nbp_tiptr;
56640c0e231SGordon Ross int err;
56740c0e231SGordon Ross
56840c0e231SGordon Ross /* Only default bind supported. */
56940c0e231SGordon Ross if (sap != NULL)
570613a2f6bSGordon Ross return (ENOTSUP);
57140c0e231SGordon Ross
57240c0e231SGordon Ross err = t_kbind(tiptr, NULL, NULL);
57340c0e231SGordon Ross
57440c0e231SGordon Ross return (err);
575613a2f6bSGordon Ross }
576613a2f6bSGordon Ross
577613a2f6bSGordon Ross static int
smb_nbst_unbind(struct smb_vc * vcp)578*adee6784SGordon Ross smb_nbst_unbind(struct smb_vc *vcp)
579*adee6784SGordon Ross {
580*adee6784SGordon Ross struct nbpcb *nbp = vcp->vc_tdata;
581*adee6784SGordon Ross TIUSER *tiptr = nbp->nbp_tiptr;
582*adee6784SGordon Ross int err;
583*adee6784SGordon Ross
584*adee6784SGordon Ross err = t_kunbind(tiptr);
585*adee6784SGordon Ross
586*adee6784SGordon Ross return (err);
587*adee6784SGordon Ross }
588*adee6784SGordon Ross
589*adee6784SGordon 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);
607613a2f6bSGordon Ross }
608613a2f6bSGordon 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);
62740c0e231SGordon Ross }
62840c0e231SGordon Ross
629613a2f6bSGordon Ross 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);
6463d804dabSGordon Ross
6473d804dabSGordon Ross if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
6484bff34e3Sthurlow 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 {
8194bff34e3Sthurlow return (EINVAL);
8204bff34e3Sthurlow }
8214bff34e3Sthurlow
8224bff34e3Sthurlow static int
smb_nbst_setparam(struct smb_vc * vcp,int param,void * data)8234bff34e3Sthurlow smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
8244bff34e3Sthurlow {
82540c0e231SGordon Ross struct t_optmgmt oreq, ores;
82640c0e231SGordon Ross struct {
82740c0e231SGordon Ross struct T_opthdr oh;
82840c0e231SGordon Ross int ival;
82940c0e231SGordon Ross } opts;
83040c0e231SGordon Ross struct nbpcb *nbp = vcp->vc_tdata;
83140c0e231SGordon Ross int level, name, err;
83240c0e231SGordon Ross
83340c0e231SGordon Ross switch (param) {
83440c0e231SGordon Ross case SMBTP_TCP_NODELAY:
83540c0e231SGordon Ross level = IPPROTO_TCP;
83640c0e231SGordon Ross name = TCP_NODELAY;
83740c0e231SGordon Ross break;
83840c0e231SGordon Ross
83940c0e231SGordon Ross case SMBTP_TCP_CON_TMO: /* int mSec */
84040c0e231SGordon Ross level = IPPROTO_TCP;
84140c0e231SGordon Ross name = TCP_CONN_ABORT_THRESHOLD;
84240c0e231SGordon Ross 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;
85040c0e231SGordon Ross break;
85140c0e231SGordon Ross
85240c0e231SGordon Ross 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);
88740c0e231SGordon Ross }
88840c0e231SGordon Ross
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