xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c (revision 97ab9a43fe40d6c2336c9f23fdc4b2e576266e03)
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 2008 Sun Microsystems, Inc.  All rights reserved.
36  * Use is subject to license terms.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/autoconf.h>
42 #include <sys/sysmacros.h>
43 #include <sys/sunddi.h>
44 #include <sys/kmem.h>
45 #include <sys/proc.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/poll.h>
49 #include <sys/stream.h>
50 #include <sys/strsubr.h>
51 #include <sys/strsun.h>
52 #include <sys/stropts.h>
53 #include <sys/cmn_err.h>
54 #include <sys/tihdr.h>
55 #include <sys/tiuser.h>
56 #include <sys/t_kuser.h>
57 #include <sys/priv.h>
58 
59 #include <net/if.h>
60 #include <net/route.h>
61 
62 #include <netinet/in.h>
63 #include <netinet/tcp.h>
64 
65 #ifdef APPLE
66 #include <sys/smb_apple.h>
67 #else
68 #include <netsmb/smb_osdep.h>
69 #endif
70 
71 #include <netsmb/mchain.h>
72 #include <netsmb/netbios.h>
73 
74 #include <netsmb/smb.h>
75 #include <netsmb/smb_conn.h>
76 #include <netsmb/smb_subr.h>
77 #include <netsmb/smb_tran.h>
78 #include <netsmb/smb_trantcp.h>
79 
80 /*
81  * SMB messages are up to 64K.
82  * Let's leave room for two.
83  */
84 static int smb_tcpsndbuf = 0x20000;
85 static int smb_tcprcvbuf = 0x20000;
86 
87 static dev_t smb_tcp_dev;
88 
89 static int  nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
90 	uint8_t *rpcodep, struct proc *p);
91 static int  nb_disconnect(struct nbpcb *nbp);
92 
93 
94 /*
95  * Internal set sockopt for int-sized options.
96  * Is there a common Solaris function for this?
97  * Code from uts/common/rpc/clnt_cots.c
98  */
99 static int
100 nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val)
101 {
102 	int fmode;
103 	mblk_t *mp;
104 	struct opthdr *opt;
105 	struct T_optmgmt_req *tor;
106 	struct T_optmgmt_ack *toa;
107 	int *valp;
108 	int error, mlen;
109 
110 	mlen = (sizeof (struct T_optmgmt_req) +
111 	    sizeof (struct opthdr) + sizeof (int));
112 	if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error)))
113 		return (error);
114 
115 	mp->b_datap->db_type = M_PROTO;
116 	/*LINTED*/
117 	tor = (struct T_optmgmt_req *)mp->b_wptr;
118 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
119 	tor->MGMT_flags = T_NEGOTIATE;
120 	tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
121 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
122 	mp->b_wptr += sizeof (struct T_optmgmt_req);
123 
124 	/*LINTED*/
125 	opt = (struct opthdr *)mp->b_wptr;
126 	opt->level = level;
127 	opt->name = name;
128 	opt->len = sizeof (int);
129 	mp->b_wptr += sizeof (struct opthdr);
130 
131 	/* LINTED */
132 	valp = (int *)mp->b_wptr;
133 	*valp = val;
134 	mp->b_wptr += sizeof (int);
135 
136 	fmode = tiptr->fp->f_flag;
137 	if ((error = tli_send(tiptr, mp, fmode)) != 0)
138 		return (error);
139 
140 	/*
141 	 * Wait for T_OPTMGMT_ACK
142 	 */
143 	mp = NULL;
144 	fmode = 0; /* need to block */
145 	if ((error = tli_recv(tiptr, &mp, fmode)) != 0)
146 		return (error);
147 	/*LINTED*/
148 	toa = (struct T_optmgmt_ack *)mp->b_rptr;
149 	if (toa->PRIM_type != T_OPTMGMT_ACK)
150 		error = EPROTO;
151 	freemsg(mp);
152 
153 	return (error);
154 }
155 
156 static void
157 nb_setopts(struct nbpcb *nbp)
158 {
159 	int error;
160 	TIUSER *tiptr = NULL;
161 
162 	tiptr = nbp->nbp_tiptr;
163 	if (tiptr == NULL) {
164 		NBDEBUG("no tiptr!\n");
165 		return;
166 	}
167 
168 	/*
169 	 * Set various socket/TCP options.
170 	 * Failures here are not fatal -
171 	 * just log a complaint.
172 	 *
173 	 * We don't need these two:
174 	 *   SO_RCVTIMEO, SO_SNDTIMEO
175 	 */
176 
177 	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF,
178 	    nbp->nbp_sndbuf);
179 	if (error)
180 		NBDEBUG("can't set SO_SNDBUF");
181 
182 	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
183 	    nbp->nbp_rcvbuf);
184 	if (error)
185 		NBDEBUG("can't set SO_RCVBUF");
186 
187 	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
188 	if (error)
189 		NBDEBUG("can't set SO_KEEPALIVE");
190 
191 	error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
192 	if (error)
193 		NBDEBUG("can't set TCP_NODELAY");
194 
195 	/* Set the connect timeout (in milliseconds). */
196 	error = nb_setsockopt_int(tiptr, IPPROTO_TCP,
197 	    TCP_CONN_ABORT_THRESHOLD,
198 	    nbp->nbp_timo.tv_sec * 1000);
199 	if (error)
200 		NBDEBUG("can't set connect timeout");
201 }
202 
203 /*
204  * Get mblks into *mpp until the data length is at least mlen.
205  * Note that *mpp may already contain a fragment.
206  *
207  * If we ever have to wait more than 15 sec. to read a message,
208  * return ETIME.  (Caller will declare the VD dead.)
209  */
210 static int
211 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
212 {
213 	mblk_t *im, *tm;
214 	union T_primitives	*pptr;
215 	size_t dlen;
216 	int events, fmode, timo, waitflg;
217 	int error = 0;
218 
219 	/*
220 	 * Get the first message (fragment) if
221 	 * we don't already have a left-over.
222 	 */
223 	dlen = msgdsize(*mpp); /* *mpp==null is OK */
224 	while (dlen < mlen) {
225 
226 		/*
227 		 * I think we still want this to return ETIME
228 		 * if nothing arrives for SMB_NBTIMO (15) sec.
229 		 * so we can report "server not responding".
230 		 * We _could_ just block here now that our
231 		 * IOD is just a reader.
232 		 */
233 #if 1
234 		/* Wait with timeout... */
235 		events = 0;
236 		waitflg = READWAIT;
237 		timo = SEC_TO_TICK(SMB_NBTIMO);
238 		error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
239 		if (!error && !events)
240 			error = ETIME;
241 		if (error)
242 			break;
243 		/* file mode for recv is: */
244 		fmode = FNDELAY; /* non-blocking */
245 #else
246 		fmode = 0; /* normal (blocking) */
247 #endif
248 
249 		/* Get some more... */
250 		tm = NULL;
251 		error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
252 		if (error == EAGAIN)
253 			continue;
254 		if (error)
255 			break;
256 
257 		/*
258 		 * Normally get M_DATA messages here,
259 		 * but have to check for other types.
260 		 */
261 		switch (tm->b_datap->db_type) {
262 		case M_DATA:
263 			break;
264 		case M_PROTO:
265 		case M_PCPROTO:
266 			/*LINTED*/
267 			pptr = (union T_primitives *)tm->b_rptr;
268 			switch (pptr->type) {
269 			case T_DATA_IND:
270 				/* remove 1st mblk, keep the rest. */
271 				im = tm->b_cont;
272 				tm->b_cont = NULL;
273 				freeb(tm);
274 				tm = im;
275 				break;
276 			case T_DISCON_IND:
277 				/* Peer disconnected. */
278 				NBDEBUG("T_DISCON_IND: reason=%d",
279 				    pptr->discon_ind.DISCON_reason);
280 				goto discon;
281 			case T_ORDREL_IND:
282 				/* Peer disconnecting. */
283 				NBDEBUG("T_ORDREL_IND");
284 				goto discon;
285 			case T_OK_ACK:
286 				switch (pptr->ok_ack.CORRECT_prim) {
287 				case T_DISCON_REQ:
288 					NBDEBUG("T_OK_ACK/T_DISCON_REQ");
289 					goto discon;
290 				default:
291 					NBDEBUG("T_OK_ACK/prim=%d",
292 					    pptr->ok_ack.CORRECT_prim);
293 					goto discon;
294 				}
295 			default:
296 				NBDEBUG("M_PROTO/type=%d", pptr->type);
297 				goto discon;
298 			}
299 			break; /* M_PROTO, M_PCPROTO */
300 
301 		default:
302 			NBDEBUG("unexpected msg type=%d",
303 			    tm->b_datap->db_type);
304 			/*FALLTHROUGH*/
305 discon:
306 			/*
307 			 * The connection is no longer usable.
308 			 * Drop this message and disconnect.
309 			 *
310 			 * Note: nb_disconnect only does t_snddis
311 			 * on the first call, but does important
312 			 * cleanup and state change on any call.
313 			 */
314 			freemsg(tm);
315 			nb_disconnect(nbp);
316 			return (ENOTCONN);
317 		}
318 
319 		/*
320 		 * If we have a data message, append it to
321 		 * the previous chunk(s) and update dlen
322 		 */
323 		if (!tm)
324 			continue;
325 		if (*mpp == NULL) {
326 			*mpp = tm;
327 		} else {
328 			/* Append */
329 			for (im = *mpp; im->b_cont; im = im->b_cont)
330 				;
331 			im->b_cont = tm;
332 		}
333 		dlen += msgdsize(tm);
334 	}
335 
336 	return (error);
337 }
338 
339 /*
340  * Send a T_DISCON_REQ (disconnect)
341  */
342 static int
343 nb_snddis(TIUSER *tiptr)
344 {
345 	mblk_t *mp;
346 	struct T_discon_req *dreq;
347 	int error, fmode, mlen;
348 
349 	mlen = sizeof (struct T_discon_req);
350 	if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error)))
351 		return (error);
352 
353 	mp->b_datap->db_type = M_PROTO;
354 	/*LINTED*/
355 	dreq = (struct T_discon_req *)mp->b_wptr;
356 	dreq->PRIM_type = T_DISCON_REQ;
357 	dreq->SEQ_number = -1;
358 	mp->b_wptr += sizeof (struct T_discon_req);
359 
360 	fmode = tiptr->fp->f_flag;
361 	if ((error = tli_send(tiptr, mp, fmode)) != 0)
362 		return (error);
363 
364 	fmode = 0; /* need to block */
365 	error = get_ok_ack(tiptr, T_DISCON_REQ, fmode);
366 
367 	return (error);
368 }
369 
370 #ifdef APPLE
371 static int
372 nb_intr(struct nbpcb *nbp, struct proc *p)
373 {
374 	return (0);
375 }
376 #endif
377 
378 /*
379  * Stuff the NetBIOS header into space already prepended.
380  */
381 static int
382 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
383 {
384 	uint32_t *p;
385 
386 	len &= 0x1FFFF;
387 	len |= (type << 24);
388 
389 	/*LINTED*/
390 	p = (uint32_t *)m->b_rptr;
391 	*p = htonl(len);
392 	return (0);
393 }
394 
395 /*
396  * Note: Moved name encoding into here.
397  */
398 static int
399 nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
400 {
401 	int i, len;
402 	uchar_t ch, *p;
403 
404 	/*
405 	 * Do the NetBIOS "first-level encoding" here.
406 	 * (RFC1002 explains this wierdness...)
407 	 * See similar code in smbfs library:
408 	 *   lib/libsmbfs/smb/nb_name.c
409 	 *
410 	 * Here is what we marshall:
411 	 *   uint8_t NAME_LENGTH (always 32)
412 	 *   uint8_t ENCODED_NAME[32]
413 	 *   uint8_t SCOPE_LENGTH
414 	 *   XXX Scope should follow here, then another null,
415 	 *   if and when we support NetBIOS scopes.
416 	 */
417 	len = 1 + (2 * NB_NAMELEN) + 1;
418 
419 	p = mb_reserve(mbp, len);
420 	if (!p)
421 		return (ENOSR);
422 
423 	/* NAME_LENGTH */
424 	*p++ = (2 * NB_NAMELEN);
425 
426 	/* ENCODED_NAME */
427 	for (i = 0; i < NB_NAMELEN; i++) {
428 		ch = (uchar_t)snb->snb_name[i];
429 		*p++ = 'A' + ((ch >> 4) & 0xF);
430 		*p++ = 'A' + ((ch) & 0xF);
431 	}
432 
433 	/* SCOPE_LENGTH */
434 	*p++ = 0;
435 
436 	return (0);
437 }
438 
439 static int
440 nb_tcpopen(struct nbpcb *nbp, struct proc *p)
441 {
442 	TIUSER *tiptr;
443 	int err, oflags = FREAD|FWRITE;
444 	cred_t *cr = p->p_cred;
445 
446 	if (!smb_tcp_dev) {
447 		smb_tcp_dev = makedevice(
448 		    clone_major, ddi_name_to_major("tcp"));
449 	}
450 
451 	/*
452 	 * This magic arranges for our network endpoint
453 	 * to have the right "label" for operation in a
454 	 * "trusted extensions" environment.
455 	 */
456 	if (is_system_labeled()) {
457 		cr = crdup(cr);
458 		(void) setpflags(NET_MAC_AWARE, 1, cr);
459 	} else {
460 		crhold(cr);
461 	}
462 	err = t_kopen(NULL, smb_tcp_dev, oflags, &tiptr, cr);
463 	crfree(cr);
464 	if (err)
465 		return (err);
466 
467 	/* Note: I_PUSH "timod" is done by t_kopen */
468 
469 	/* Save the TPI handle we use everywhere. */
470 	nbp->nbp_tiptr = tiptr;
471 
472 	/*
473 	 * Internal ktli calls need the "fmode" flags
474 	 * from the t_kopen call.  XXX: Not sure if the
475 	 * flags have the right bits set, or if we
476 	 * always want the same block/non-block flags.
477 	 * XXX: Look into this...
478 	 */
479 	nbp->nbp_fmode = tiptr->fp->f_flag;
480 	return (0);
481 }
482 
483 /*ARGSUSED*/
484 static int
485 nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
486 {
487 	int error;
488 	TIUSER *tiptr = NULL;
489 	struct t_call call;
490 
491 	tiptr = nbp->nbp_tiptr;
492 	if (tiptr == NULL)
493 		return (EBADF);
494 	if (nbp->nbp_flags & NBF_CONNECTED)
495 		return (EISCONN);
496 
497 	/*
498 	 * Setup (snd)call address (connect to).
499 	 * Just pass NULL for the (rcv)call.
500 	 */
501 	bzero(&call, sizeof (call));
502 	call.addr.len = sizeof (*to);
503 	call.addr.buf = (char *)to;
504 	/* call.opt - none */
505 	/* call.udata -- XXX: Should put NB session req here! */
506 
507 	/* Send the connect, wait... */
508 	error = t_kconnect(tiptr, &call, NULL);
509 	if (error) {
510 		NBDEBUG("nb_connect_in: connect %d error", error);
511 	} else {
512 		mutex_enter(&nbp->nbp_lock);
513 		nbp->nbp_flags |= NBF_CONNECTED;
514 		mutex_exit(&nbp->nbp_lock);
515 	}
516 
517 	return (error);
518 }
519 
520 static int
521 nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
522 {
523 	struct mbchain mb, *mbp = &mb;
524 	struct mdchain md, *mdp = &md;
525 	mblk_t *m0;
526 	struct sockaddr_in sin;
527 	ushort_t port;
528 	uint8_t rpcode;
529 	int error, rplen;
530 
531 	error = mb_init(mbp);
532 	if (error)
533 		return (error);
534 
535 	/*
536 	 * Put a zero for the 4-byte NetBIOS header,
537 	 * then let nb_sethdr() overwrite it.
538 	 */
539 	mb_put_uint32le(mbp, 0);
540 	nb_put_name(mbp, nbp->nbp_paddr);
541 	nb_put_name(mbp, nbp->nbp_laddr);
542 	nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
543 
544 	m0 = mb_detach(mbp);
545 	error = tli_send(nbp->nbp_tiptr, m0, nbp->nbp_fmode);
546 	m0 = NULL; /* Note: _always_ consumed by tli_send */
547 	mb_done(mbp);
548 	if (error)
549 		return (error);
550 
551 	nbp->nbp_state = NBST_RQSENT;
552 	error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
553 	if (error == EWOULDBLOCK) {	/* Timeout */
554 		NBDEBUG("initial request timeout\n");
555 		return (ETIMEDOUT);
556 	}
557 	if (error) {
558 		NBDEBUG("recv() error %d\n", error);
559 		return (error);
560 	}
561 	/*
562 	 * Process NETBIOS reply
563 	 */
564 	if (m0)
565 		md_initm(mdp, m0);
566 
567 	error = 0;
568 	if (rpcode == NB_SSN_POSRESP) {
569 		mutex_enter(&nbp->nbp_lock);
570 		nbp->nbp_state = NBST_SESSION;
571 		mutex_exit(&nbp->nbp_lock);
572 		goto out;
573 	}
574 	if (rpcode != NB_SSN_RTGRESP) {
575 		error = ECONNABORTED;
576 		goto out;
577 	}
578 	if (rplen != 6) {
579 		error = ECONNABORTED;
580 		goto out;
581 	}
582 	md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
583 	md_get_uint16(mdp, &port);
584 	sin.sin_port = port;
585 	nbp->nbp_state = NBST_RETARGET;
586 	nb_disconnect(nbp);
587 	error = nb_connect_in(nbp, &sin, p);
588 	if (!error)
589 		error = nbssn_rq_request(nbp, p);
590 	if (error) {
591 		nb_disconnect(nbp);
592 	}
593 
594 out:
595 	if (m0)
596 		md_done(mdp);
597 	return (error);
598 }
599 
600 /*
601  * Wait for up to 15 sec. for the next packet.
602  * Often return ETIME and do nothing else.
603  * When a packet header is available, check
604  * the header and get the length, but don't
605  * consume it.  No side effects here except
606  * for the pullupmsg call.
607  */
608 static int
609 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,	uint8_t *rpcodep)
610 {
611 	uint32_t len, *hdr;
612 	int error;
613 
614 	/*
615 	 * Get the first message (fragment) if
616 	 * we don't already have a left-over.
617 	 */
618 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
619 	if (error)
620 		return (error);
621 
622 	if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
623 		return (ENOSR);
624 
625 	/*
626 	 * Check the NetBIOS header.
627 	 * (NOT consumed here)
628 	 */
629 	/*LINTED*/
630 	hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
631 
632 	len = ntohl(*hdr);
633 	if ((len >> 16) & 0xFE) {
634 		NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
635 		return (EPIPE);
636 	}
637 	*rpcodep = (len >> 24) & 0xFF;
638 	switch (*rpcodep) {
639 	case NB_SSN_MESSAGE:
640 	case NB_SSN_REQUEST:
641 	case NB_SSN_POSRESP:
642 	case NB_SSN_NEGRESP:
643 	case NB_SSN_RTGRESP:
644 	case NB_SSN_KEEPALIVE:
645 		break;
646 	default:
647 		NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
648 		return (EPIPE);
649 	}
650 	len &= 0x1ffff;
651 	if (len > SMB_MAXPKTLEN) {
652 		NBDEBUG("packet too long (%d)\n", len);
653 		return (EFBIG);
654 	}
655 	*lenp = len;
656 	return (0);
657 }
658 
659 /*
660  * Receive a NetBIOS message.  This may block to wait for the entire
661  * message to arrive.  The caller knows there is (or should be) a
662  * message to be read.  When we receive and drop a keepalive or
663  * zero-length message, return EAGAIN so the caller knows that
664  * something was received.  This avoids false triggering of the
665  * "server not responding" state machine.
666  */
667 /*ARGSUSED*/
668 static int
669 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
670     uint8_t *rpcodep, struct proc *p)
671 {
672 	TIUSER *tiptr = nbp->nbp_tiptr;
673 	mblk_t *m0;
674 	uint8_t rpcode;
675 	int error;
676 	size_t rlen, len;
677 
678 	/* We should be the only reader. */
679 	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
680 	if ((nbp->nbp_flags & NBF_CONNECTED) == 0)
681 		return (ENOTCONN);
682 
683 	if (tiptr == NULL)
684 		return (EBADF);
685 	if (mpp) {
686 		if (*mpp) {
687 			NBDEBUG("*mpp not 0 - leak?");
688 		}
689 		*mpp = NULL;
690 	}
691 	m0 = NULL;
692 
693 	/*
694 	 * Get the NetBIOS header (not consumed yet)
695 	 */
696 	error = nbssn_peekhdr(nbp, &len, &rpcode);
697 	if (error) {
698 		if (error != ETIME)
699 			NBDEBUG("peekhdr, error=%d\n", error);
700 		return (error);
701 	}
702 	NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
703 	    (int)rpcode, (int)len);
704 
705 	/*
706 	 * Block here waiting for the whole packet to arrive.
707 	 * If we get a timeout, return without side effects.
708 	 * The data length we wait for here includes both the
709 	 * NetBIOS header and the payload.
710 	 */
711 	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
712 	if (error) {
713 		NBDEBUG("getmsg(body), error=%d\n", error);
714 		return (error);
715 	}
716 
717 	/*
718 	 * We now have an entire NetBIOS message.
719 	 * Trim off the NetBIOS header and consume it.
720 	 * Note: _peekhdr has done pullupmsg for us,
721 	 * so we know it's safe to advance b_rptr.
722 	 */
723 	m0 = nbp->nbp_frag;
724 	m0->b_rptr += 4;
725 
726 	/*
727 	 * There may be more data after the message
728 	 * we're about to return, in which case we
729 	 * split it and leave the remainder.
730 	 */
731 	rlen = msgdsize(m0);
732 	ASSERT(rlen >= len);
733 	nbp->nbp_frag = NULL;
734 	if (rlen > len)
735 		nbp->nbp_frag = m_split(m0, len, 1);
736 
737 	if (nbp->nbp_state != NBST_SESSION) {
738 		/*
739 		 * No session is established.
740 		 * Return whatever packet we got.
741 		 */
742 		goto out;
743 	}
744 
745 	/*
746 	 * A session is established; the only packets
747 	 * we should see are session message and
748 	 * keep-alive packets.  Drop anything else.
749 	 */
750 	switch (rpcode) {
751 
752 	case NB_SSN_KEEPALIVE:
753 		/*
754 		 * It's a keepalive.  Discard any data in it
755 		 * (there's not supposed to be any, but that
756 		 * doesn't mean some server won't send some)
757 		 */
758 		if (len)
759 			NBDEBUG("Keepalive with data %d\n", (int)len);
760 		error = EAGAIN;
761 		break;
762 
763 	case NB_SSN_MESSAGE:
764 		/*
765 		 * Session message.  Does it have any data?
766 		 */
767 		if (len == 0) {
768 			/*
769 			 * No data - treat as keepalive (drop).
770 			 */
771 			error = EAGAIN;
772 			break;
773 		}
774 		/*
775 		 * Yes, has data.  Return it.
776 		 */
777 		error = 0;
778 		break;
779 
780 	default:
781 		/*
782 		 * Drop anything else.
783 		 */
784 		NBDEBUG("non-session packet %x\n", rpcode);
785 		error = EAGAIN;
786 		break;
787 	}
788 
789 out:
790 	if (error) {
791 		if (m0)
792 			m_freem(m0);
793 		return (error);
794 	}
795 	if (mpp)
796 		*mpp = m0;
797 	else
798 		m_freem(m0);
799 	*lenp = (int)len;
800 	*rpcodep = rpcode;
801 	return (0);
802 }
803 
804 /*
805  * SMB transport interface
806  */
807 static int
808 smb_nbst_create(struct smb_vc *vcp, struct proc *p)
809 {
810 	struct nbpcb *nbp;
811 	int error;
812 
813 	nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
814 
815 	/*
816 	 * We don't keep reference counts or otherwise
817 	 * prevent nbp->nbp_tiptr from going away, so
818 	 * do the TLI open here and keep it until the
819 	 * last ref calls smb_nbst_done.
820 	 * This does t_kopen (open endpoint)
821 	 */
822 	error = nb_tcpopen(nbp, p);
823 	if (error) {
824 		kmem_free(nbp, sizeof (*nbp));
825 		return (error);
826 	}
827 
828 	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
829 	nbp->nbp_state = NBST_CLOSED; /* really IDLE */
830 	nbp->nbp_vc = vcp;
831 	nbp->nbp_sndbuf = smb_tcpsndbuf;
832 	nbp->nbp_rcvbuf = smb_tcprcvbuf;
833 	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
834 	vcp->vc_tdata = nbp;
835 
836 	nb_setopts(nbp);
837 
838 	return (0);
839 }
840 
841 /*ARGSUSED*/
842 static int
843 smb_nbst_done(struct smb_vc *vcp, struct proc *p)
844 {
845 	struct nbpcb *nbp = vcp->vc_tdata;
846 
847 	if (nbp == NULL)
848 		return (ENOTCONN);
849 	vcp->vc_tdata = NULL;
850 
851 	/*
852 	 * Don't really need to disconnect here,
853 	 * because the close following will do it.
854 	 * But it's harmless.
855 	 */
856 	if (nbp->nbp_flags & NBF_CONNECTED)
857 		nb_disconnect(nbp);
858 	if (nbp->nbp_tiptr)
859 		t_kclose(nbp->nbp_tiptr, 1);
860 	if (nbp->nbp_laddr)
861 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
862 	if (nbp->nbp_paddr)
863 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
864 	mutex_destroy(&nbp->nbp_lock);
865 	kmem_free(nbp, sizeof (*nbp));
866 	return (0);
867 }
868 
869 /*ARGSUSED*/
870 static int
871 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
872 {
873 	struct nbpcb *nbp = vcp->vc_tdata;
874 	struct sockaddr_nb *snb;
875 	int error = 0;
876 
877 	if (nbp->nbp_tiptr == NULL)
878 		return (EBADF);
879 
880 	/*
881 	 * Allow repeated bind calls on one endpoint.
882 	 * This happens with reconnect.
883 	 */
884 
885 	/*
886 	 * Null name is an "anonymous" (NULL) bind request.
887 	 * (Let the transport pick a local name.)
888 	 * This transport does not support NULL bind,
889 	 * because we require a local NetBIOS name.
890 	 */
891 	if (sap == NULL)
892 		return (EINVAL);
893 
894 	/*LINTED*/
895 	snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
896 	if (snb == NULL)
897 		return (ENOMEM);
898 
899 	mutex_enter(&nbp->nbp_lock);
900 	if (nbp->nbp_laddr)
901 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
902 	nbp->nbp_laddr = snb;
903 
904 	/*
905 	 * Do local TCP bind with NULL (any address),
906 	 * but just once (for multiple connect attempts)
907 	 * or extra bind calls would cause errors.
908 	 */
909 	if ((nbp->nbp_flags & NBF_LOCADDR) == 0) {
910 		error = t_kbind(nbp->nbp_tiptr, NULL, NULL);
911 		if (error) {
912 			NBDEBUG("t_kbind failed");
913 		} else {
914 			nbp->nbp_flags |= NBF_LOCADDR;
915 		}
916 	}
917 	mutex_exit(&nbp->nbp_lock);
918 
919 	return (error);
920 }
921 
922 static int
923 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
924 {
925 	struct nbpcb *nbp = vcp->vc_tdata;
926 	struct sockaddr_in sin;
927 	struct sockaddr_nb *snb;
928 	int error;
929 
930 	if (nbp->nbp_tiptr == NULL)
931 		return (EBADF);
932 	if (nbp->nbp_laddr == NULL)
933 		return (EINVAL);
934 
935 	/*
936 	 * Note: nbssn_rq_request() will call nbssn_recv(),
937 	 * so set the RECVLOCK flag here.  Otherwise we'll
938 	 * hit an ASSERT for this flag in nbssn_recv().
939 	 */
940 	mutex_enter(&nbp->nbp_lock);
941 	if (nbp->nbp_flags & NBF_RECVLOCK) {
942 		NBDEBUG("attempt to reenter session layer!\n");
943 		mutex_exit(&nbp->nbp_lock);
944 		return (EWOULDBLOCK);
945 	}
946 	nbp->nbp_flags |= NBF_RECVLOCK;
947 	mutex_exit(&nbp->nbp_lock);
948 
949 	/*LINTED*/
950 	snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
951 	if (snb == NULL) {
952 		error = ENOMEM;
953 		goto out;
954 	}
955 	if (nbp->nbp_paddr)
956 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
957 	nbp->nbp_paddr = snb;
958 
959 	/*
960 	 * Setup the remote IP address.
961 	 * Try plain TCP first (port 445).
962 	 */
963 	bzero(&sin, sizeof (sin));
964 	sin.sin_family = AF_INET;
965 	sin.sin_port = htons(IPPORT_SMB); /* port 445 */
966 	sin.sin_addr.s_addr = snb->snb_ipaddr;
967 
968 again:
969 	NBDEBUG("trying port %d\n", ntohs(sin.sin_port));
970 	error = nb_connect_in(nbp, &sin, p);
971 	switch (error) {
972 	case 0:
973 		break;
974 	case ECONNREFUSED:
975 		if (sin.sin_port != htons(IPPORT_NETBIOS_SSN)) {
976 			/* Try again w/ NetBIOS (port 139) */
977 			sin.sin_port = htons(IPPORT_NETBIOS_SSN);
978 			goto again;
979 		}
980 		/* FALLTHROUGH */
981 	default:
982 		goto out;
983 	}
984 
985 	/*
986 	 * If we connected via NetBIOS (port 139),
987 	 * need to do a session request.
988 	 */
989 	if (sin.sin_port == htons(IPPORT_NETBIOS_SSN)) {
990 		error = nbssn_rq_request(nbp, p);
991 		if (error)
992 			nb_disconnect(nbp);
993 	}
994 
995 out:
996 	mutex_enter(&nbp->nbp_lock);
997 	nbp->nbp_flags &= ~NBF_RECVLOCK;
998 	mutex_exit(&nbp->nbp_lock);
999 
1000 	return (error);
1001 }
1002 
1003 /*ARGSUSED*/
1004 static int
1005 smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
1006 {
1007 	struct nbpcb *nbp = vcp->vc_tdata;
1008 
1009 	if (nbp == NULL)
1010 		return (ENOTCONN);
1011 
1012 	return (nb_disconnect(nbp));
1013 }
1014 
1015 static int
1016 nb_disconnect(struct nbpcb *nbp)
1017 {
1018 	TIUSER *tiptr;
1019 	int save_flags;
1020 
1021 	tiptr = nbp->nbp_tiptr;
1022 	if (tiptr == NULL)
1023 		return (EBADF);
1024 
1025 	mutex_enter(&nbp->nbp_lock);
1026 	save_flags = nbp->nbp_flags;
1027 	nbp->nbp_flags &= ~NBF_CONNECTED;
1028 	if (nbp->nbp_frag) {
1029 		freemsg(nbp->nbp_frag);
1030 		nbp->nbp_frag = NULL;
1031 	}
1032 	mutex_exit(&nbp->nbp_lock);
1033 
1034 	if (save_flags & NBF_CONNECTED)
1035 		nb_snddis(tiptr);
1036 
1037 	if (nbp->nbp_state != NBST_RETARGET) {
1038 		nbp->nbp_state = NBST_CLOSED; /* really IDLE */
1039 	}
1040 	return (0);
1041 }
1042 
1043 /*
1044  * Always consume the message.
1045  * (On error too!)
1046  */
1047 /*ARGSUSED*/
1048 static int
1049 smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
1050 {
1051 	struct nbpcb *nbp = vcp->vc_tdata;
1052 	ptrdiff_t diff;
1053 	uint32_t mlen;
1054 	int error;
1055 
1056 	if (nbp == NULL || nbp->nbp_tiptr == NULL) {
1057 		error = EBADF;
1058 		goto errout;
1059 	}
1060 
1061 	/*
1062 	 * Get the message length, which
1063 	 * does NOT include the NetBIOS header
1064 	 */
1065 	mlen = msgdsize(m);
1066 
1067 	/*
1068 	 * Normally, mb_init() will have left space
1069 	 * for us to prepend the NetBIOS header in
1070 	 * the data block of the first mblk.
1071 	 * However, we have to check in case other
1072 	 * code did not leave this space, or if the
1073 	 * message is from dupmsg (db_ref > 1)
1074 	 *
1075 	 * If don't find room in the first data block,
1076 	 * we have to allocb a new message and link it
1077 	 * on the front of the chain.  We try not to
1078 	 * do this becuase it's less efficient.  Also,
1079 	 * some network drivers will apparently send
1080 	 * each mblk in the chain as separate frames.
1081 	 * (That's arguably a driver bug.)
1082 	 */
1083 
1084 	diff = MBLKHEAD(m);
1085 	if (diff == 4 && DB_REF(m) == 1) {
1086 		/* We can use the first dblk. */
1087 		m->b_rptr -= 4;
1088 	} else {
1089 		/* Link a new mblk on the head. */
1090 		mblk_t *m0;
1091 
1092 		/* M_PREPEND */
1093 		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
1094 		if (!m0)
1095 			goto errout;
1096 
1097 		m0->b_wptr += 4;
1098 		m0->b_cont = m;
1099 		m = m0;
1100 	}
1101 
1102 	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
1103 	error = tli_send(nbp->nbp_tiptr, m, 0);
1104 	return (error);
1105 
1106 errout:
1107 	if (m)
1108 		m_freem(m);
1109 	return (error);
1110 }
1111 
1112 
1113 static int
1114 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
1115 {
1116 	struct nbpcb *nbp = vcp->vc_tdata;
1117 	uint8_t rpcode;
1118 	int error, rplen;
1119 
1120 	mutex_enter(&nbp->nbp_lock);
1121 	if (nbp->nbp_flags & NBF_RECVLOCK) {
1122 		NBDEBUG("attempt to reenter session layer!\n");
1123 		mutex_exit(&nbp->nbp_lock);
1124 		return (EWOULDBLOCK);
1125 	}
1126 	nbp->nbp_flags |= NBF_RECVLOCK;
1127 	mutex_exit(&nbp->nbp_lock);
1128 	error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
1129 	mutex_enter(&nbp->nbp_lock);
1130 	nbp->nbp_flags &= ~NBF_RECVLOCK;
1131 	mutex_exit(&nbp->nbp_lock);
1132 	return (error);
1133 }
1134 
1135 /*
1136  * Wait for up to "ticks" clock ticks for input on vcp.
1137  * Returns zero if input is available, otherwise ETIME
1138  * indicating time expired, or other error codes.
1139  */
1140 /*ARGSUSED*/
1141 static int
1142 smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p)
1143 {
1144 	int error;
1145 	int events = 0;
1146 	int waitflg = READWAIT;
1147 	struct nbpcb *nbp = vcp->vc_tdata;
1148 
1149 	error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events);
1150 	if (!error && !events)
1151 		error = ETIME;
1152 
1153 	return (error);
1154 }
1155 
1156 static int
1157 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
1158 {
1159 	struct nbpcb *nbp = vcp->vc_tdata;
1160 
1161 	switch (param) {
1162 	case SMBTP_SNDSZ:
1163 		*(int *)data = nbp->nbp_sndbuf;
1164 		break;
1165 	case SMBTP_RCVSZ:
1166 		*(int *)data = nbp->nbp_rcvbuf;
1167 		break;
1168 	case SMBTP_TIMEOUT:
1169 		*(struct timespec *)data = nbp->nbp_timo;
1170 		break;
1171 #ifdef SMBTP_SELECTID
1172 	case SMBTP_SELECTID:
1173 		*(void **)data = nbp->nbp_selectid;
1174 		break;
1175 #endif
1176 #ifdef SMBTP_UPCALL
1177 	case SMBTP_UPCALL:
1178 		*(void **)data = nbp->nbp_upcall;
1179 		break;
1180 #endif
1181 	default:
1182 		return (EINVAL);
1183 	}
1184 	return (0);
1185 }
1186 
1187 /*ARGSUSED*/
1188 static int
1189 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
1190 {
1191 	return (EINVAL);
1192 }
1193 
1194 /*
1195  * Check for fatal errors
1196  */
1197 /*ARGSUSED*/
1198 static int
1199 smb_nbst_fatal(struct smb_vc *vcp, int error)
1200 {
1201 	switch (error) {
1202 	case ENOTCONN:
1203 	case ENETRESET:
1204 	case ECONNABORTED:
1205 	case EPIPE:
1206 		return (1);
1207 	}
1208 	return (0);
1209 }
1210 
1211 
1212 struct smb_tran_desc smb_tran_nbtcp_desc = {
1213 	SMBT_NBTCP,
1214 	smb_nbst_create,
1215 	smb_nbst_done,
1216 	smb_nbst_bind,
1217 	smb_nbst_connect,
1218 	smb_nbst_disconnect,
1219 	smb_nbst_send,
1220 	smb_nbst_recv,
1221 	smb_nbst_poll,
1222 	smb_nbst_getparam,
1223 	smb_nbst_setparam,
1224 	smb_nbst_fatal,
1225 	{NULL, NULL}
1226 };
1227