xref: /titanic_50/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c (revision 3ce9ce383e93f64f4baed13c5a0a28d7a5f1b71e)
1 /*
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
33  */
34 /*
35  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
36  * Use is subject to license terms.
37  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/autoconf.h>
43 #include <sys/sysmacros.h>
44 #include <sys/sunddi.h>
45 #include <sys/kmem.h>
46 #include <sys/proc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/poll.h>
50 #include <sys/stream.h>
51 #include <sys/strsubr.h>
52 #include <sys/strsun.h>
53 #include <sys/stropts.h>
54 #include <sys/cmn_err.h>
55 #include <sys/tihdr.h>
56 #include <sys/tiuser.h>
57 #include <sys/t_kuser.h>
58 #include <sys/priv.h>
59 
60 #include <net/if.h>
61 #include <net/route.h>
62 
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
65 
66 #include <netsmb/smb_osdep.h>
67 #include <netsmb/mchain.h>
68 #include <netsmb/netbios.h>
69 
70 #include <netsmb/smb.h>
71 #include <netsmb/smb_conn.h>
72 #include <netsmb/smb_subr.h>
73 #include <netsmb/smb_tran.h>
74 #include <netsmb/smb_trantcp.h>
75 
76 /*
77  * SMB messages are up to 64K.
78  * Let's leave room for two.
79  */
80 static int smb_tcpsndbuf = 0x20000;
81 static int smb_tcprcvbuf = 0x20000;
82 
83 static int  nb_disconnect(struct nbpcb *nbp);
84 
85 
86 /*
87  * Get mblks into *mpp until the data length is at least mlen.
88  * Note that *mpp may already contain a fragment.
89  *
90  * If we ever have to wait more than 15 sec. to read a message,
91  * return ETIME.  (Caller will declare the VD dead.)
92  */
93 static int
nb_getmsg_mlen(struct nbpcb * nbp,mblk_t ** mpp,size_t mlen)94 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
95 {
96 	mblk_t *im, *tm;
97 	union T_primitives	*pptr;
98 	size_t dlen;
99 	int events, fmode, timo, waitflg;
100 	int error = 0;
101 
102 	/* We should be the only reader. */
103 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
104 	/* nbp->nbp_tiptr checked by caller */
105 
106 	/*
107 	 * Get the first message (fragment) if
108 	 * we don't already have a left-over.
109 	 */
110 	dlen = msgdsize(*mpp); /* *mpp==null is OK */
111 	while (dlen < mlen) {
112 
113 		/*
114 		 * I think we still want this to return ETIME
115 		 * if nothing arrives for SMB_NBTIMO (15) sec.
116 		 * so we can report "server not responding".
117 		 * We _could_ just block here now that our
118 		 * IOD is just a reader.
119 		 */
120 #if 1
121 		/* Wait with timeout... */
122 		events = 0;
123 		waitflg = READWAIT;
124 		timo = SEC_TO_TICK(SMB_NBTIMO);
125 		error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
126 		if (!error && !events)
127 			error = ETIME;
128 		if (error)
129 			break;
130 		/* file mode for recv is: */
131 		fmode = FNDELAY; /* non-blocking */
132 #else
133 		fmode = 0; /* normal (blocking) */
134 #endif
135 
136 		/* Get some more... */
137 		tm = NULL;
138 		error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
139 		if (error == EAGAIN)
140 			continue;
141 		if (error)
142 			break;
143 
144 		/*
145 		 * Normally get M_DATA messages here,
146 		 * but have to check for other types.
147 		 */
148 		switch (tm->b_datap->db_type) {
149 		case M_DATA:
150 			break;
151 		case M_PROTO:
152 		case M_PCPROTO:
153 			/*LINTED*/
154 			pptr = (union T_primitives *)tm->b_rptr;
155 			switch (pptr->type) {
156 			case T_DATA_IND:
157 				/* remove 1st mblk, keep the rest. */
158 				im = tm->b_cont;
159 				tm->b_cont = NULL;
160 				freeb(tm);
161 				tm = im;
162 				break;
163 			case T_DISCON_IND:
164 				/* Peer disconnected. */
165 				NBDEBUG("T_DISCON_IND: reason=%d",
166 				    pptr->discon_ind.DISCON_reason);
167 				goto discon;
168 			case T_ORDREL_IND:
169 				/* Peer disconnecting. */
170 				NBDEBUG("T_ORDREL_IND");
171 				goto discon;
172 			case T_OK_ACK:
173 				switch (pptr->ok_ack.CORRECT_prim) {
174 				case T_DISCON_REQ:
175 					NBDEBUG("T_OK_ACK/T_DISCON_REQ");
176 					goto discon;
177 				default:
178 					NBDEBUG("T_OK_ACK/prim=%d",
179 					    pptr->ok_ack.CORRECT_prim);
180 					goto discon;
181 				}
182 			default:
183 				NBDEBUG("M_PROTO/type=%d", pptr->type);
184 				goto discon;
185 			}
186 			break; /* M_PROTO, M_PCPROTO */
187 
188 		default:
189 			NBDEBUG("unexpected msg type=%d",
190 			    tm->b_datap->db_type);
191 			/*FALLTHROUGH*/
192 discon:
193 			/*
194 			 * The connection is no longer usable.
195 			 * Drop this message and disconnect.
196 			 *
197 			 * Note: nb_disconnect only does t_snddis
198 			 * on the first call, but does important
199 			 * cleanup and state change on any call.
200 			 */
201 			freemsg(tm);
202 			(void) nb_disconnect(nbp);
203 			return (ENOTCONN);
204 		}
205 
206 		/*
207 		 * If we have a data message, append it to
208 		 * the previous chunk(s) and update dlen
209 		 */
210 		if (!tm)
211 			continue;
212 		if (*mpp == NULL) {
213 			*mpp = tm;
214 		} else {
215 			/* Append */
216 			for (im = *mpp; im->b_cont; im = im->b_cont)
217 				;
218 			im->b_cont = tm;
219 		}
220 		dlen += msgdsize(tm);
221 	}
222 
223 	return (error);
224 }
225 
226 /*
227  * Send a T_DISCON_REQ (disconnect)
228  */
229 static int
nb_snddis(struct nbpcb * nbp)230 nb_snddis(struct nbpcb *nbp)
231 {
232 	TIUSER *tiptr = nbp->nbp_tiptr;
233 	cred_t *cr = nbp->nbp_cred;
234 	mblk_t *mp;
235 	struct T_discon_req *dreq;
236 	int error, mlen;
237 
238 	ASSERT(MUTEX_HELD(&nbp->nbp_lock));
239 
240 	if (tiptr == NULL)
241 		return (EBADF);
242 
243 	mlen = sizeof (struct T_discon_req);
244 	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
245 		return (error);
246 
247 	mp->b_datap->db_type = M_PROTO;
248 	/*LINTED*/
249 	dreq = (struct T_discon_req *)mp->b_wptr;
250 	dreq->PRIM_type = T_DISCON_REQ;
251 	dreq->SEQ_number = -1;
252 	mp->b_wptr += sizeof (struct T_discon_req);
253 
254 	error = tli_send(tiptr, mp, tiptr->fp->f_flag);
255 	/*
256 	 * There is an OK/ACK response expected, which is
257 	 * either handled by our receiver thread, or just
258 	 * discarded if we're closing this endpoint.
259 	 */
260 
261 	return (error);
262 }
263 
264 /*
265  * Stuff the NetBIOS header into space already prepended.
266  */
267 static void
nb_sethdr(mblk_t * m,uint8_t type,uint32_t len)268 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
269 {
270 	uint32_t *p;
271 
272 	len &= 0x1FFFF;
273 	len |= (type << 24);
274 
275 	/*LINTED*/
276 	p = (uint32_t *)m->b_rptr;
277 	*p = htonl(len);
278 }
279 
280 /*
281  * Wait for up to 15 sec. for the next packet.
282  * Often return ETIME and do nothing else.
283  * When a packet header is available, check
284  * the header and get the length, but don't
285  * consume it.  No side effects here except
286  * for the pullupmsg call.
287  */
288 static int
nbssn_peekhdr(struct nbpcb * nbp,size_t * lenp,uint8_t * rpcodep)289 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,	uint8_t *rpcodep)
290 {
291 	uint32_t len, *hdr;
292 	int error;
293 
294 	/*
295 	 * Get the first message (fragment) if
296 	 * we don't already have a left-over.
297 	 */
298 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
299 	if (error)
300 		return (error);
301 
302 	if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
303 		return (ENOSR);
304 
305 	/*
306 	 * Check the NetBIOS header.
307 	 * (NOT consumed here)
308 	 */
309 	/*LINTED*/
310 	hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
311 
312 	len = ntohl(*hdr);
313 	if ((len >> 16) & 0xFE) {
314 		NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
315 		return (EPIPE);
316 	}
317 	*rpcodep = (len >> 24) & 0xFF;
318 	switch (*rpcodep) {
319 	case NB_SSN_MESSAGE:
320 	case NB_SSN_REQUEST:
321 	case NB_SSN_POSRESP:
322 	case NB_SSN_NEGRESP:
323 	case NB_SSN_RTGRESP:
324 	case NB_SSN_KEEPALIVE:
325 		break;
326 	default:
327 		NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
328 		return (EPIPE);
329 	}
330 	len &= 0x1ffff;
331 	if (len > NB_MAXPKTLEN) {
332 		NBDEBUG("packet too long (%d)\n", len);
333 		return (EFBIG);
334 	}
335 	*lenp = len;
336 	return (0);
337 }
338 
339 /*
340  * Receive a NetBIOS message.  This may block to wait for the entire
341  * message to arrive.  The caller knows there is (or should be) a
342  * message to be read.  When we receive and drop a keepalive or
343  * zero-length message, return EAGAIN so the caller knows that
344  * something was received.  This avoids false triggering of the
345  * "server not responding" state machine.
346  *
347  * Calls to this are serialized at a higher level.
348  */
349 static int
nbssn_recv(struct nbpcb * nbp,mblk_t ** mpp,int * lenp,uint8_t * rpcodep)350 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
351     uint8_t *rpcodep)
352 {
353 	mblk_t *m0;
354 	uint8_t rpcode;
355 	int error;
356 	size_t rlen, len;
357 
358 	/* We should be the only reader. */
359 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
360 
361 	if (nbp->nbp_tiptr == NULL)
362 		return (EBADF);
363 	if (mpp) {
364 		if (*mpp) {
365 			NBDEBUG("*mpp not 0 - leak?");
366 		}
367 		*mpp = NULL;
368 	}
369 	m0 = NULL;
370 
371 	/*
372 	 * Get the NetBIOS header (not consumed yet)
373 	 */
374 	error = nbssn_peekhdr(nbp, &len, &rpcode);
375 	if (error) {
376 		if (error != ETIME)
377 			NBDEBUG("peekhdr, error=%d\n", error);
378 		return (error);
379 	}
380 	NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
381 	    (int)rpcode, (int)len);
382 
383 	/*
384 	 * Block here waiting for the whole packet to arrive.
385 	 * If we get a timeout, return without side effects.
386 	 * The data length we wait for here includes both the
387 	 * NetBIOS header and the payload.
388 	 */
389 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
390 	if (error) {
391 		NBDEBUG("getmsg(body), error=%d\n", error);
392 		return (error);
393 	}
394 
395 	/*
396 	 * We now have an entire NetBIOS message.
397 	 * Trim off the NetBIOS header and consume it.
398 	 * Note: _peekhdr has done pullupmsg for us,
399 	 * so we know it's safe to advance b_rptr.
400 	 */
401 	m0 = nbp->nbp_frag;
402 	m0->b_rptr += 4;
403 
404 	/*
405 	 * There may be more data after the message
406 	 * we're about to return, in which case we
407 	 * split it and leave the remainder.
408 	 */
409 	rlen = msgdsize(m0);
410 	ASSERT(rlen >= len);
411 	nbp->nbp_frag = NULL;
412 	if (rlen > len)
413 		nbp->nbp_frag = m_split(m0, len, 1);
414 
415 	if (nbp->nbp_state != NBST_SESSION) {
416 		/*
417 		 * No session is established.
418 		 * Return whatever packet we got.
419 		 */
420 		goto out;
421 	}
422 
423 	/*
424 	 * A session is established; the only packets
425 	 * we should see are session message and
426 	 * keep-alive packets.  Drop anything else.
427 	 */
428 	switch (rpcode) {
429 
430 	case NB_SSN_KEEPALIVE:
431 		/*
432 		 * It's a keepalive.  Discard any data in it
433 		 * (there's not supposed to be any, but that
434 		 * doesn't mean some server won't send some)
435 		 */
436 		if (len)
437 			NBDEBUG("Keepalive with data %d\n", (int)len);
438 		error = EAGAIN;
439 		break;
440 
441 	case NB_SSN_MESSAGE:
442 		/*
443 		 * Session message.  Does it have any data?
444 		 */
445 		if (len == 0) {
446 			/*
447 			 * No data - treat as keepalive (drop).
448 			 */
449 			error = EAGAIN;
450 			break;
451 		}
452 		/*
453 		 * Yes, has data.  Return it.
454 		 */
455 		error = 0;
456 		break;
457 
458 	default:
459 		/*
460 		 * Drop anything else.
461 		 */
462 		NBDEBUG("non-session packet %x\n", rpcode);
463 		error = EAGAIN;
464 		break;
465 	}
466 
467 out:
468 	if (error) {
469 		if (m0)
470 			m_freem(m0);
471 		return (error);
472 	}
473 	if (mpp)
474 		*mpp = m0;
475 	else
476 		m_freem(m0);
477 	*lenp = (int)len;
478 	*rpcodep = rpcode;
479 	return (0);
480 }
481 
482 /*
483  * SMB transport interface
484  *
485  * This is called only by the thread creating this endpoint,
486  * so we're single-threaded here.
487  */
488 /*ARGSUSED*/
489 static int
smb_nbst_create(struct smb_vc * vcp,cred_t * cr)490 smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
491 {
492 	struct nbpcb *nbp;
493 
494 	nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
495 
496 	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
497 	nbp->nbp_state = NBST_CLOSED; /* really IDLE */
498 	nbp->nbp_vc = vcp;
499 	nbp->nbp_sndbuf = smb_tcpsndbuf;
500 	nbp->nbp_rcvbuf = smb_tcprcvbuf;
501 	nbp->nbp_cred = cr;
502 	crhold(cr);
503 	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
504 	vcp->vc_tdata = nbp;
505 
506 	return (0);
507 }
508 
509 /*
510  * destroy a transport endpoint
511  *
512  * This is called only by the thread with the last reference
513  * to this endpoint, so we're single-threaded here.
514  */
515 static int
smb_nbst_done(struct smb_vc * vcp)516 smb_nbst_done(struct smb_vc *vcp)
517 {
518 	struct nbpcb *nbp = vcp->vc_tdata;
519 
520 	if (nbp == NULL)
521 		return (ENOTCONN);
522 	vcp->vc_tdata = NULL;
523 
524 	/*
525 	 * Don't really need to disconnect here,
526 	 * because the close following will do it.
527 	 * But it's harmless.
528 	 */
529 	if (nbp->nbp_flags & NBF_CONNECTED)
530 		(void) nb_disconnect(nbp);
531 	if (nbp->nbp_tiptr)
532 		(void) t_kclose(nbp->nbp_tiptr, 0);
533 	if (nbp->nbp_laddr)
534 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
535 	if (nbp->nbp_paddr)
536 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
537 	if (nbp->nbp_cred)
538 		crfree(nbp->nbp_cred);
539 	mutex_destroy(&nbp->nbp_lock);
540 	kmem_free(nbp, sizeof (*nbp));
541 	return (0);
542 }
543 
544 /*
545  * Loan a transport file pointer (from user space) to this
546  * IOD endpoint.  There should be no other thread using this
547  * endpoint when we do this, but lock for consistency.
548  */
549 static int
nb_loan_fp(struct nbpcb * nbp,struct file * fp,cred_t * cr)550 nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
551 {
552 	TIUSER *tiptr;
553 	int err;
554 
555 	err = t_kopen(fp, 0, 0, &tiptr, cr);
556 	if (err != 0)
557 		return (err);
558 
559 	mutex_enter(&nbp->nbp_lock);
560 
561 	nbp->nbp_tiptr = tiptr;
562 	nbp->nbp_fmode = tiptr->fp->f_flag;
563 	nbp->nbp_flags |= NBF_CONNECTED;
564 	nbp->nbp_state = NBST_SESSION;
565 
566 	mutex_exit(&nbp->nbp_lock);
567 
568 	return (0);
569 }
570 
571 /*
572  * Take back the transport file pointer we previously loaned.
573  * It's possible there may be another thread in here, so let
574  * others get out of the way before we pull the rug out.
575  *
576  * Some notes about the locking here:  The higher-level IOD code
577  * serializes activity such that at most one reader and writer
578  * thread can be active in this code (and possibly both).
579  * Keeping nbp_lock held during the activities of these two
580  * threads would lead to the possibility of nbp_lock being
581  * held by a blocked thread, so this instead sets one of the
582  * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a
583  * receiver is active (respectively).  Lastly, tear-down is
584  * the only tricky bit (here) where we must wait for any of
585  * these activities to get out of current calls so they will
586  * notice that we've turned off the NBF_CONNECTED flag.
587  */
588 static void
nb_unloan_fp(struct nbpcb * nbp)589 nb_unloan_fp(struct nbpcb *nbp)
590 {
591 
592 	mutex_enter(&nbp->nbp_lock);
593 
594 	nbp->nbp_flags &= ~NBF_CONNECTED;
595 	while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) {
596 		nbp->nbp_flags |= NBF_LOCKWAIT;
597 		cv_wait(&nbp->nbp_cv, &nbp->nbp_lock);
598 	}
599 	if (nbp->nbp_frag != NULL) {
600 		freemsg(nbp->nbp_frag);
601 		nbp->nbp_frag = NULL;
602 	}
603 	if (nbp->nbp_tiptr != NULL) {
604 		(void) t_kclose(nbp->nbp_tiptr, 0);
605 		nbp->nbp_tiptr = NULL;
606 	}
607 	nbp->nbp_state = NBST_CLOSED;
608 
609 	mutex_exit(&nbp->nbp_lock);
610 }
611 
612 static int
smb_nbst_loan_fp(struct smb_vc * vcp,struct file * fp,cred_t * cr)613 smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
614 {
615 	struct nbpcb *nbp = vcp->vc_tdata;
616 	int error = 0;
617 
618 	/*
619 	 * Un-loan the existing one, if any.
620 	 */
621 	(void) nb_disconnect(nbp);
622 	nb_unloan_fp(nbp);
623 
624 	/*
625 	 * Loan the new one passed in.
626 	 */
627 	if (fp != NULL) {
628 		error = nb_loan_fp(nbp, fp, cr);
629 	}
630 
631 	return (error);
632 }
633 
634 /*ARGSUSED*/
635 static int
smb_nbst_bind(struct smb_vc * vcp,struct sockaddr * sap)636 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
637 {
638 	return (ENOTSUP);
639 }
640 
641 /*ARGSUSED*/
642 static int
smb_nbst_connect(struct smb_vc * vcp,struct sockaddr * sap)643 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
644 {
645 	return (ENOTSUP);
646 }
647 
648 /*ARGSUSED*/
649 static int
smb_nbst_disconnect(struct smb_vc * vcp)650 smb_nbst_disconnect(struct smb_vc *vcp)
651 {
652 	struct nbpcb *nbp = vcp->vc_tdata;
653 
654 	if (nbp == NULL)
655 		return (ENOTCONN);
656 
657 	return (nb_disconnect(nbp));
658 }
659 
660 static int
nb_disconnect(struct nbpcb * nbp)661 nb_disconnect(struct nbpcb *nbp)
662 {
663 	int err = 0;
664 
665 	mutex_enter(&nbp->nbp_lock);
666 
667 	if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
668 		nbp->nbp_flags &= ~NBF_CONNECTED;
669 		err = nb_snddis(nbp);
670 	}
671 
672 	mutex_exit(&nbp->nbp_lock);
673 	return (err);
674 }
675 
676 /*
677  * Add the NetBIOS session header and send.
678  *
679  * Calls to this are serialized at a higher level.
680  */
681 static int
nbssn_send(struct nbpcb * nbp,mblk_t * m)682 nbssn_send(struct nbpcb *nbp, mblk_t *m)
683 {
684 	ptrdiff_t diff;
685 	uint32_t mlen;
686 	int error;
687 
688 	/* We should be the only sender. */
689 	ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
690 
691 	if (nbp->nbp_tiptr == NULL) {
692 		error = EBADF;
693 		goto errout;
694 	}
695 
696 	/*
697 	 * Get the message length, which
698 	 * does NOT include the NetBIOS header
699 	 */
700 	mlen = msgdsize(m);
701 
702 	/*
703 	 * Normally, mb_init() will have left space
704 	 * for us to prepend the NetBIOS header in
705 	 * the data block of the first mblk.
706 	 * However, we have to check in case other
707 	 * code did not leave this space, or if the
708 	 * message is from dupmsg (db_ref > 1)
709 	 *
710 	 * If don't find room in the first data block,
711 	 * we have to allocb a new message and link it
712 	 * on the front of the chain.  We try not to
713 	 * do this becuase it's less efficient.  Also,
714 	 * some network drivers will apparently send
715 	 * each mblk in the chain as separate frames.
716 	 * (That's arguably a driver bug.)
717 	 *
718 	 * Not bothering with allocb_cred_wait below
719 	 * because the message we're prepending to
720 	 * should already have a db_credp.
721 	 */
722 
723 	diff = MBLKHEAD(m);
724 	if (diff == 4 && DB_REF(m) == 1) {
725 		/* We can use the first dblk. */
726 		m->b_rptr -= 4;
727 	} else {
728 		/* Link a new mblk on the head. */
729 		mblk_t *m0;
730 
731 		/* M_PREPEND */
732 		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
733 		if (m0 == NULL)
734 			goto errout;
735 
736 		m0->b_wptr += 4;
737 		m0->b_cont = m;
738 		m = m0;
739 	}
740 
741 	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
742 	error = tli_send(nbp->nbp_tiptr, m, 0);
743 	return (error);
744 
745 errout:
746 	if (m != NULL)
747 		m_freem(m);
748 	return (error);
749 }
750 
751 /*
752  * Always consume the message.
753  * (On error too!)
754  */
755 static int
smb_nbst_send(struct smb_vc * vcp,mblk_t * m)756 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
757 {
758 	struct nbpcb *nbp = vcp->vc_tdata;
759 	int err;
760 
761 	mutex_enter(&nbp->nbp_lock);
762 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
763 		err = ENOTCONN;
764 		goto out;
765 	}
766 	if (nbp->nbp_flags & NBF_SENDLOCK) {
767 		NBDEBUG("multiple smb_nbst_send!\n");
768 		err = EWOULDBLOCK;
769 		goto out;
770 	}
771 	nbp->nbp_flags |= NBF_SENDLOCK;
772 	mutex_exit(&nbp->nbp_lock);
773 
774 	err = nbssn_send(nbp, m);
775 	m = NULL; /* nbssn_send always consumes this */
776 
777 	mutex_enter(&nbp->nbp_lock);
778 	nbp->nbp_flags &= ~NBF_SENDLOCK;
779 	if (nbp->nbp_flags & NBF_LOCKWAIT) {
780 		nbp->nbp_flags &= ~NBF_LOCKWAIT;
781 		cv_broadcast(&nbp->nbp_cv);
782 	}
783 out:
784 	mutex_exit(&nbp->nbp_lock);
785 	if (m != NULL)
786 		m_freem(m);
787 	return (err);
788 }
789 
790 static int
smb_nbst_recv(struct smb_vc * vcp,mblk_t ** mpp)791 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
792 {
793 	struct nbpcb *nbp = vcp->vc_tdata;
794 	uint8_t rpcode;
795 	int err, rplen;
796 
797 	mutex_enter(&nbp->nbp_lock);
798 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
799 		err = ENOTCONN;
800 		goto out;
801 	}
802 	if (nbp->nbp_flags & NBF_RECVLOCK) {
803 		NBDEBUG("multiple smb_nbst_recv!\n");
804 		err = EWOULDBLOCK;
805 		goto out;
806 	}
807 	nbp->nbp_flags |= NBF_RECVLOCK;
808 	mutex_exit(&nbp->nbp_lock);
809 
810 	err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
811 
812 	mutex_enter(&nbp->nbp_lock);
813 	nbp->nbp_flags &= ~NBF_RECVLOCK;
814 	if (nbp->nbp_flags & NBF_LOCKWAIT) {
815 		nbp->nbp_flags &= ~NBF_LOCKWAIT;
816 		cv_broadcast(&nbp->nbp_cv);
817 	}
818 out:
819 	mutex_exit(&nbp->nbp_lock);
820 	return (err);
821 }
822 
823 /*
824  * Wait for up to "ticks" clock ticks for input on vcp.
825  * Returns zero if input is available, otherwise ETIME
826  * indicating time expired, or other error codes.
827  */
828 /*ARGSUSED*/
829 static int
smb_nbst_poll(struct smb_vc * vcp,int ticks)830 smb_nbst_poll(struct smb_vc *vcp, int ticks)
831 {
832 	return (ENOTSUP);
833 }
834 
835 static int
smb_nbst_getparam(struct smb_vc * vcp,int param,void * data)836 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
837 {
838 	struct nbpcb *nbp = vcp->vc_tdata;
839 
840 	switch (param) {
841 	case SMBTP_SNDSZ:
842 		*(int *)data = nbp->nbp_sndbuf;
843 		break;
844 	case SMBTP_RCVSZ:
845 		*(int *)data = nbp->nbp_rcvbuf;
846 		break;
847 	case SMBTP_TIMEOUT:
848 		*(struct timespec *)data = nbp->nbp_timo;
849 		break;
850 #ifdef SMBTP_SELECTID
851 	case SMBTP_SELECTID:
852 		*(void **)data = nbp->nbp_selectid;
853 		break;
854 #endif
855 #ifdef SMBTP_UPCALL
856 	case SMBTP_UPCALL:
857 		*(void **)data = nbp->nbp_upcall;
858 		break;
859 #endif
860 	default:
861 		return (EINVAL);
862 	}
863 	return (0);
864 }
865 
866 /*ARGSUSED*/
867 static int
smb_nbst_setparam(struct smb_vc * vcp,int param,void * data)868 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
869 {
870 	return (EINVAL);
871 }
872 
873 /*
874  * Check for fatal errors
875  */
876 /*ARGSUSED*/
877 static int
smb_nbst_fatal(struct smb_vc * vcp,int error)878 smb_nbst_fatal(struct smb_vc *vcp, int error)
879 {
880 	switch (error) {
881 	case ENOTCONN:
882 	case ENETRESET:
883 	case ECONNABORTED:
884 	case EPIPE:
885 		return (1);
886 	}
887 	return (0);
888 }
889 
890 
891 struct smb_tran_desc smb_tran_nbtcp_desc = {
892 	SMBT_NBTCP,
893 	smb_nbst_create,
894 	smb_nbst_done,
895 	smb_nbst_bind,
896 	smb_nbst_connect,
897 	smb_nbst_disconnect,
898 	smb_nbst_send,
899 	smb_nbst_recv,
900 	smb_nbst_poll,
901 	smb_nbst_loan_fp,
902 	smb_nbst_getparam,
903 	smb_nbst_setparam,
904 	smb_nbst_fatal,
905 	{NULL, NULL}
906 };
907