xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 	} else
994 		nbp->nbp_state = NBST_SESSION;
995 
996 out:
997 	mutex_enter(&nbp->nbp_lock);
998 	nbp->nbp_flags &= ~NBF_RECVLOCK;
999 	mutex_exit(&nbp->nbp_lock);
1000 
1001 	return (error);
1002 }
1003 
1004 /*ARGSUSED*/
1005 static int
1006 smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
1007 {
1008 	struct nbpcb *nbp = vcp->vc_tdata;
1009 
1010 	if (nbp == NULL)
1011 		return (ENOTCONN);
1012 
1013 	return (nb_disconnect(nbp));
1014 }
1015 
1016 static int
1017 nb_disconnect(struct nbpcb *nbp)
1018 {
1019 	TIUSER *tiptr;
1020 	int save_flags;
1021 
1022 	tiptr = nbp->nbp_tiptr;
1023 	if (tiptr == NULL)
1024 		return (EBADF);
1025 
1026 	mutex_enter(&nbp->nbp_lock);
1027 	save_flags = nbp->nbp_flags;
1028 	nbp->nbp_flags &= ~NBF_CONNECTED;
1029 	if (nbp->nbp_frag) {
1030 		freemsg(nbp->nbp_frag);
1031 		nbp->nbp_frag = NULL;
1032 	}
1033 	mutex_exit(&nbp->nbp_lock);
1034 
1035 	if (save_flags & NBF_CONNECTED)
1036 		nb_snddis(tiptr);
1037 
1038 	if (nbp->nbp_state != NBST_RETARGET) {
1039 		nbp->nbp_state = NBST_CLOSED; /* really IDLE */
1040 	}
1041 	return (0);
1042 }
1043 
1044 /*
1045  * Always consume the message.
1046  * (On error too!)
1047  */
1048 /*ARGSUSED*/
1049 static int
1050 smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
1051 {
1052 	struct nbpcb *nbp = vcp->vc_tdata;
1053 	ptrdiff_t diff;
1054 	uint32_t mlen;
1055 	int error;
1056 
1057 	if (nbp == NULL || nbp->nbp_tiptr == NULL) {
1058 		error = EBADF;
1059 		goto errout;
1060 	}
1061 
1062 	/*
1063 	 * Get the message length, which
1064 	 * does NOT include the NetBIOS header
1065 	 */
1066 	mlen = msgdsize(m);
1067 
1068 	/*
1069 	 * Normally, mb_init() will have left space
1070 	 * for us to prepend the NetBIOS header in
1071 	 * the data block of the first mblk.
1072 	 * However, we have to check in case other
1073 	 * code did not leave this space, or if the
1074 	 * message is from dupmsg (db_ref > 1)
1075 	 *
1076 	 * If don't find room in the first data block,
1077 	 * we have to allocb a new message and link it
1078 	 * on the front of the chain.  We try not to
1079 	 * do this becuase it's less efficient.  Also,
1080 	 * some network drivers will apparently send
1081 	 * each mblk in the chain as separate frames.
1082 	 * (That's arguably a driver bug.)
1083 	 */
1084 
1085 	diff = MBLKHEAD(m);
1086 	if (diff == 4 && DB_REF(m) == 1) {
1087 		/* We can use the first dblk. */
1088 		m->b_rptr -= 4;
1089 	} else {
1090 		/* Link a new mblk on the head. */
1091 		mblk_t *m0;
1092 
1093 		/* M_PREPEND */
1094 		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
1095 		if (!m0)
1096 			goto errout;
1097 
1098 		m0->b_wptr += 4;
1099 		m0->b_cont = m;
1100 		m = m0;
1101 	}
1102 
1103 	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
1104 	error = tli_send(nbp->nbp_tiptr, m, 0);
1105 	return (error);
1106 
1107 errout:
1108 	if (m)
1109 		m_freem(m);
1110 	return (error);
1111 }
1112 
1113 
1114 static int
1115 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
1116 {
1117 	struct nbpcb *nbp = vcp->vc_tdata;
1118 	uint8_t rpcode;
1119 	int error, rplen;
1120 
1121 	mutex_enter(&nbp->nbp_lock);
1122 	if (nbp->nbp_flags & NBF_RECVLOCK) {
1123 		NBDEBUG("attempt to reenter session layer!\n");
1124 		mutex_exit(&nbp->nbp_lock);
1125 		return (EWOULDBLOCK);
1126 	}
1127 	nbp->nbp_flags |= NBF_RECVLOCK;
1128 	mutex_exit(&nbp->nbp_lock);
1129 	error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
1130 	mutex_enter(&nbp->nbp_lock);
1131 	nbp->nbp_flags &= ~NBF_RECVLOCK;
1132 	mutex_exit(&nbp->nbp_lock);
1133 	return (error);
1134 }
1135 
1136 /*
1137  * Wait for up to "ticks" clock ticks for input on vcp.
1138  * Returns zero if input is available, otherwise ETIME
1139  * indicating time expired, or other error codes.
1140  */
1141 /*ARGSUSED*/
1142 static int
1143 smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p)
1144 {
1145 	int error;
1146 	int events = 0;
1147 	int waitflg = READWAIT;
1148 	struct nbpcb *nbp = vcp->vc_tdata;
1149 
1150 	error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events);
1151 	if (!error && !events)
1152 		error = ETIME;
1153 
1154 	return (error);
1155 }
1156 
1157 static int
1158 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
1159 {
1160 	struct nbpcb *nbp = vcp->vc_tdata;
1161 
1162 	switch (param) {
1163 	case SMBTP_SNDSZ:
1164 		*(int *)data = nbp->nbp_sndbuf;
1165 		break;
1166 	case SMBTP_RCVSZ:
1167 		*(int *)data = nbp->nbp_rcvbuf;
1168 		break;
1169 	case SMBTP_TIMEOUT:
1170 		*(struct timespec *)data = nbp->nbp_timo;
1171 		break;
1172 #ifdef SMBTP_SELECTID
1173 	case SMBTP_SELECTID:
1174 		*(void **)data = nbp->nbp_selectid;
1175 		break;
1176 #endif
1177 #ifdef SMBTP_UPCALL
1178 	case SMBTP_UPCALL:
1179 		*(void **)data = nbp->nbp_upcall;
1180 		break;
1181 #endif
1182 	default:
1183 		return (EINVAL);
1184 	}
1185 	return (0);
1186 }
1187 
1188 /*ARGSUSED*/
1189 static int
1190 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
1191 {
1192 	return (EINVAL);
1193 }
1194 
1195 /*
1196  * Check for fatal errors
1197  */
1198 /*ARGSUSED*/
1199 static int
1200 smb_nbst_fatal(struct smb_vc *vcp, int error)
1201 {
1202 	switch (error) {
1203 	case ENOTCONN:
1204 	case ENETRESET:
1205 	case ECONNABORTED:
1206 	case EPIPE:
1207 		return (1);
1208 	}
1209 	return (0);
1210 }
1211 
1212 
1213 struct smb_tran_desc smb_tran_nbtcp_desc = {
1214 	SMBT_NBTCP,
1215 	smb_nbst_create,
1216 	smb_nbst_done,
1217 	smb_nbst_bind,
1218 	smb_nbst_connect,
1219 	smb_nbst_disconnect,
1220 	smb_nbst_send,
1221 	smb_nbst_recv,
1222 	smb_nbst_poll,
1223 	smb_nbst_getparam,
1224 	smb_nbst_setparam,
1225 	smb_nbst_fatal,
1226 	{NULL, NULL}
1227 };
1228