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