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