1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40#include <sys/kpi_mbuf.h>
41#include <sys/proc.h>
42#include <sys/socket.h>
43#include <sys/uio.h>
44#include <sys/sysctl.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/tcp.h>
51
52#include <sys/smb_apple.h>
53
54#include <sys/mchain.h>
55
56#include <netsmb/netbios.h>
57
58#include <netsmb/smb.h>
59#include <netsmb/smb_2.h>
60#include <netsmb/smb_conn.h>
61#include <netsmb/smb_rq.h>
62#include <netsmb/smb_tran.h>
63#include <netsmb/smb_trantcp.h>
64#include <netsmb/smb_subr.h>
65
66#include <netsmb/smb_sleephandler.h>
67
68#define M_NBDATA	M_PCB
69
70static uint32_t smb_tcpsndbuf = 4 * 1024 * 1024; /* SMBX srvr starts at 4 MB */
71static uint32_t smb_tcprcvbuf = 4 * 1024 * 1024;
72
73SYSCTL_DECL(_net_smb_fs);
74SYSCTL_INT(_net_smb_fs, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, "");
75SYSCTL_INT(_net_smb_fs, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, "");
76
77static int nbssn_recv(struct nbpcb *nbp, mbuf_t *mpp, int *lenp, uint8_t *rpcodep,
78					  struct timespec *wait_time);
79static int  smb_nbst_disconnect(struct smb_vc *vcp);
80
81static int
82nb_setsockopt_int(socket_t so, int level, int name, int val)
83{
84	return (sock_setsockopt(so, level, name, &val, (int)sizeof(val)));
85}
86
87static void
88nb_upcall(socket_t so, void *arg, int waitflag)
89{
90#pragma unused(so, waitflag)
91	struct nbpcb *nbp = (struct nbpcb *)arg;
92
93	/* sanity check make sure everything seems ok */
94	if ((so == NULL) || (nbp == NULL) || (nbp->nbp_tso == NULL) || (nbp->nbp_tso != so)) {
95#ifdef SMB_DEBUG
96		/* Don't log if nbp_tso is null we could be getting called after a disconnect */
97		if (nbp && nbp->nbp_tso) {
98			SMBDEBUG("UPCALLED: so = %p nbp = %p nbp->nbp_tso = %p\n", so, nbp, (nbp) ? nbp->nbp_tso : NULL);
99		}
100#endif // SMB_DEBUG
101		return;
102	}
103
104	lck_mtx_lock(&nbp->nbp_lock);
105
106	nbp->nbp_flags |= NBF_UPCALLED;
107	/*
108	 * If there's an upcall, pass it the selectid,
109	 * otherwise wakeup on the selectid
110	 */
111	if (nbp->nbp_upcall) {
112		nbp->nbp_upcall(nbp->nbp_selectid);
113	} else if (nbp->nbp_selectid)
114		wakeup(nbp->nbp_selectid);
115	lck_mtx_unlock(&nbp->nbp_lock);
116	return;
117}
118
119static int
120nb_sethdr(struct nbpcb *nbp, mbuf_t m, uint8_t type, uint32_t len)
121{
122	uint32_t *p = mbuf_data(m);
123
124	if (nbp->nbp_flags & NBF_NETBIOS) {
125		/* NetBIOS connection the length field is 17 bits */
126		*p = htonl((len & SMB_MAXPKTLEN) | (type << 24));
127	} else {
128		/* NetBIOS-less connection the length field is 24 bits */
129		*p = htonl((len & SMB_LARGE_MAXPKTLEN) | (type << 24));
130	}
131
132	return (0);
133}
134
135static int
136nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
137{
138	int error;
139	u_char seglen, *cp;
140
141	cp = snb->snb_name;
142	if (*cp == 0)
143		return (EINVAL);
144	NBDEBUG("[%s]\n", cp);
145	for (;;) {
146		seglen = (*cp) + 1;
147		error = mb_put_mem(mbp, (const char *)cp, seglen, MB_MSYSTEM);
148		if (error)
149			return (error);
150		if (seglen == 1)
151			break;
152		cp += seglen;
153	}
154	return (0);
155}
156
157static int tcp_connect(struct nbpcb *nbp, struct sockaddr *to)
158{
159	socket_t so;
160	int error;
161	struct timeval  tv;
162	int optlen;
163	uint32_t bufsize, default_size;
164
165	error = sock_socket(to->sa_family, SOCK_STREAM, IPPROTO_TCP, nb_upcall, nbp, &so);
166	if (error)
167		return (error);
168
169	nbp->nbp_tso = so;
170	tv.tv_sec = SMBSBTIMO;
171	tv.tv_usec = 0;
172	error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, (int)sizeof(tv));
173	if (error)
174		goto bad;
175
176	error = sock_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &tv, (int)sizeof(tv));
177	if (error)
178		goto bad;
179
180	sock_getsockopt(so, SOL_SOCKET, SO_RCVBUF, &nbp->nbp_rcvchunk, &optlen);
181	if (error) {
182		goto bad;
183	}
184		/* Max size we want to read off the buffer at a time, always half the socket size */
185	nbp->nbp_rcvchunk /= 2;
186		/* Never let it go below 8K */
187	if (nbp->nbp_rcvchunk < NB_SORECEIVE_CHUNK) {
188		nbp->nbp_rcvchunk = NB_SORECEIVE_CHUNK;
189	}
190
191	/*
192	 * The default socket buffer size can vary depending on system pressure.
193     * Set SO_SNDBUF as large as we can get.
194	 */
195	bufsize = nbp->nbp_sndbuf;
196	optlen = sizeof(bufsize);
197	error = sock_getsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, &optlen);
198	if (error) {
199		/* Not sure what else we can do here, should never happen */
200        SMBERROR("sock_getsockopt failed %d\n", error);
201		goto bad;
202	}
203    default_size = bufsize;
204
205	if (bufsize < nbp->nbp_sndbuf) {
206        do {
207            /* Not big enough, try to make it bigger */
208            bufsize = nbp->nbp_sndbuf;
209            optlen = sizeof(bufsize);
210            error = sock_setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, optlen);
211            if ((error == 0) && (bufsize > 0x100000)) {
212				/* Currently, 1 MB seems to work fine */
213				break;
214			} else {
215				/* Reduce by 64K and try again */
216				nbp->nbp_sndbuf -= 0x10000;
217			}
218        } while (nbp->nbp_sndbuf >= 0x100000);
219	}
220    if (error) {
221        nbp->nbp_sndbuf = default_size;
222    }
223    else {
224        nbp->nbp_sndbuf = bufsize;
225    }
226
227	if (nbp->nbp_sndbuf < smb_tcpsndbuf) {
228		SMBWARNING("nbp_rcvbuf = %d nbp_sndbuf = %d\n", nbp->nbp_rcvbuf, nbp->nbp_sndbuf);
229	}
230
231	error = nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1);
232	if (error)
233		goto bad;
234
235	error = nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1);
236	if (error)
237		goto bad;
238
239	/* set SO_NOADDRERR to detect network changes ASAP */
240	error = nb_setsockopt_int(so, SOL_SOCKET, SO_NOADDRERR, 1);
241	if (error)	/* Should we error out if this fails? */
242		goto bad;
243
244	/* just playin' it safe */
245	nb_setsockopt_int(so, SOL_SOCKET, SO_UPCALLCLOSEWAIT, 1);
246
247	error = sock_nointerrupt(so, 0);
248	if (error)
249		goto bad;
250
251	error = sock_connect(so, (struct sockaddr*)to, MSG_DONTWAIT);
252	if (error && error != EINPROGRESS)
253		goto bad;
254
255	tv.tv_sec = 2;
256	tv.tv_usec = 0;
257	while ((error = sock_connectwait(so, &tv)) == EINPROGRESS) {
258		if ((error = smb_iod_nb_intr(nbp->nbp_vc)))
259			break;
260	}
261	if (!error)
262		return (0);
263
264bad:
265	smb_nbst_disconnect(nbp->nbp_vc);
266	return (error);
267}
268
269static int
270nbssn_rq_request(struct nbpcb *nbp)
271{
272	struct mbchain mb, *mbp = &mb;
273	struct mdchain md, *mdp = &md;
274	mbuf_t m0;
275	struct sockaddr_in sin;
276	u_short port;
277	uint8_t rpcode;
278	int error, rplen;
279
280	error = mb_init(mbp);
281	if (error)
282		return (error);
283	mb_put_uint32le(mbp, 0);
284	nb_put_name(mbp, nbp->nbp_paddr);
285	nb_put_name(mbp, nbp->nbp_laddr);
286	nb_sethdr(nbp, mbp->mb_top, NB_SSN_REQUEST, (uint32_t)(mb_fixhdr(mbp) - 4));
287	error = sock_sendmbuf(nbp->nbp_tso, NULL, (mbuf_t)mbp->mb_top, 0, NULL);
288	if (!error)
289		nbp->nbp_state = NBST_RQSENT;
290	mb_detach(mbp);
291	mb_done(mbp);
292	if (error)
293		return (error);
294	error = nbssn_recv(nbp, &m0, &rplen, &rpcode, &nbp->nbp_timo);
295	if (error == EWOULDBLOCK) {	/* Timeout */
296		NBDEBUG("initial request timeout\n");
297		return (ETIMEDOUT);
298	}
299	if (error) {
300		NBDEBUG("recv() error %d\n", error);
301		return (error);
302	}
303	/*
304	 * Process NETBIOS reply
305	 */
306	if (m0)
307		md_initm(mdp, m0);
308	error = 0;
309	do {
310		if (rpcode == NB_SSN_POSRESP) {
311			lck_mtx_lock(&nbp->nbp_lock);
312			nbp->nbp_state = NBST_SESSION;
313			nbp->nbp_flags |= NBF_CONNECTED;
314			lck_mtx_unlock(&nbp->nbp_lock);
315			break;
316		}
317		if (rpcode != NB_SSN_RTGRESP) {
318			error = ECONNABORTED;
319			break;
320		}
321		if (rplen != 6) {
322			error = ECONNABORTED;
323			break;
324		}
325		md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
326		md_get_uint16(mdp, &port);
327		sin.sin_port = port;
328		nbp->nbp_state = NBST_RETARGET;
329		smb_nbst_disconnect(nbp->nbp_vc);
330		error = tcp_connect(nbp, (struct sockaddr *)&sin);
331		if (!error)
332			error = nbssn_rq_request(nbp);
333		if (error) {
334			smb_nbst_disconnect(nbp->nbp_vc);
335			break;
336		}
337	} while(0);
338	if (m0)
339		md_done(mdp);
340	return (error);
341}
342
343static int nbssn_recvhdr(struct nbpcb *nbp, uint32_t *lenp, uint8_t *rpcodep,
344						 struct timespec *wait_time)
345{
346	struct iovec aio;
347	uint32_t len;
348	uint8_t *bytep;
349	int error;
350	size_t resid, recvdlen;
351	struct msghdr msg;
352	struct smbiod *iod = nbp->nbp_vc->vc_iod;
353	int flags = MSG_DONTWAIT;
354
355	resid = sizeof(len);
356	bytep = (uint8_t *)&len;
357	while (resid != 0) {
358		aio.iov_base = bytep;
359		aio.iov_len = resid;
360		bzero(&msg, sizeof(msg));
361		msg.msg_iov = &aio;
362		msg.msg_iovlen = 1;
363
364		/*
365		 * We are trying to read the nbt header which is 4 bytes long. The first
366		 * time though the loop we set the flag to be MSG_DONTWAIT. Once we receive
367		 * at least one byte then we will reset the flag to MSG_WAITALL. This means
368		 * once we get part of the header we will only wait 5 seconds before giving
369		 * up.
370		 */
371		error = sock_receive(nbp->nbp_tso, &msg, flags, &recvdlen);
372		/*
373		 * If we have wait_time then we want to wait here for some amount of time
374		 * that is determined by wait_time.
375		 */
376		if ((error == EWOULDBLOCK) && wait_time) {
377			lck_mtx_lock(&nbp->nbp_lock);
378			if (!(nbp->nbp_flags & NBF_UPCALLED))
379				msleep(&iod->iod_flags, &nbp->nbp_lock, PWAIT, "nbssn", wait_time);
380			lck_mtx_unlock(&nbp->nbp_lock);
381			wait_time = 0;	/* We are suppose to have some data waiting by now */
382			flags = MSG_WAITALL; /* Wait for all four bytes */
383			continue;
384		}
385
386		/*
387		 * If we didn't get an error and recvdlen is zero then we have reached
388		 * EOF. So the socket has the SS_CANTRCVMORE flag set. This means the other
389		 * side has closed their side of the connection.
390		 */
391		if ((error == 0) && (recvdlen == 0) && resid) {
392			SMBWARNING("Server closed their side of the connection.\n");
393			nbp->nbp_state = NBST_CLOSED;
394			error = EPIPE;
395		}
396		/* This should never happen, someday should we make it just a debug assert. */
397		if ((error == 0) && (recvdlen > resid)) {
398			SMBERROR("Got more data than we asked for!\n");
399			error = EPIPE;
400		}
401		/* The connect got closed */
402		if (!sock_isconnected(nbp->nbp_tso)) {
403			nbp->nbp_state = NBST_CLOSED;
404			NBDEBUG("session closed by peer\n");
405			error = EPIPE;
406		}
407		if (error) {
408			if ((error == EWOULDBLOCK) && resid && (resid < sizeof(len)))
409				SMBERROR("Timed out reading the nbt header: missing %ld bytes\n", resid);
410			return error;
411		}
412
413		/*
414		 * At this point we have received some data, reset the flag to wait. We got
415		 * part of the 4 byte length field only wait 5 seconds to get the rest.
416		 */
417		flags = MSG_WAITALL;
418		resid -= recvdlen;
419		bytep += recvdlen;
420	}
421	/*
422	 * From http://support.microsoft.com/kb/204279
423	 *
424	 * Direct hosted "NetBIOS-less" SMB traffic uses port 445 (TCP and UDP). In
425	 * this situation, a four-byte header precedes the SMB traffic. The first
426	 * byte of this header is always 0x00, and the next three bytes are the
427	 * length of the remaining data.
428	 */
429	len = ntohl(len);
430	*rpcodep = (len >> 24) & 0xFF; /* For port 445 this should be zero, NB_SSN_MESSAGE */
431	if (nbp->nbp_flags & NBF_NETBIOS) {
432		/* Port 139, we can only use the first 17 bits for the length */
433		if ((len >> 16) & 0xFE) {
434			SMBERROR("bad nb header received 0x%x (MBZ flag set)\n", len);
435			return (EPIPE);
436		}
437		len &= SMB_MAXPKTLEN;
438	} else {
439		/* "NetBIOS-less", we can only use the frist 24 bits for the length */
440		len &= SMB_LARGE_MAXPKTLEN;
441	}
442	switch (*rpcodep) {
443	    case NB_SSN_MESSAGE:
444	    case NB_SSN_KEEPALIVE:	/* Can "NetBIOS-less" have a keep alive, does hurt anything */
445			break;
446	    case NB_SSN_REQUEST:
447	    case NB_SSN_POSRESP:
448	    case NB_SSN_NEGRESP:
449	    case NB_SSN_RTGRESP:
450			if (nbp->nbp_flags & NBF_NETBIOS) {
451				break;
452			}
453	    default:
454		SMBERROR("bad nb header received 0x%x (bogus type)\n", len);
455		return (EPIPE);
456	}
457	*lenp = len;
458	return (0);
459}
460
461static int nbssn_recv(struct nbpcb *nbp, mbuf_t *mpp, int *lenp, uint8_t *rpcodep,
462					  struct timespec *wait_time)
463{
464	socket_t so = nbp->nbp_tso;
465	mbuf_t m;
466	mbuf_t tm;
467	uint8_t rpcode;
468	uint32_t len;
469	int32_t error;
470	size_t recvdlen, resid;
471
472	if (so == NULL)
473		return (ENOTCONN);
474	if (mpp)
475		*mpp = NULL;
476	m = NULL;
477	for(;;) {
478		/*
479		 * Read the response header.
480		 */
481		lck_mtx_lock(&nbp->nbp_lock);
482		nbp->nbp_flags &= ~NBF_UPCALLED;
483		lck_mtx_unlock(&nbp->nbp_lock);
484		error = nbssn_recvhdr(nbp, &len, &rpcode, wait_time);
485		if (error)
486			return (error);
487
488		/*
489		 * Loop, blocking, for data following the response header, if any.
490		 *
491		 * Note that we can't simply block here with MSG_WAITALL for the
492		 * entire response size, as it may be larger than the TCP
493		 * slow-start window that the sender employs.  This will result
494		 * in the sender stalling until the delayed ACK is sent, then
495		 * resuming slow-start, resulting in very poor performance.
496		 *
497		 * Instead, we never request more than NB_SORECEIVE_CHUNK
498		 * bytes at a time, resulting in an ack being pushed by
499		 * the TCP code at the completion of each call.
500		 */
501		resid = len;
502		while (resid != 0) {
503			struct timespec tstart, tend;
504			tm = NULL;
505			/*
506			 * We use to spin until we got a hard error, we no longer wait forever.
507			 * We now limit how long we will block receiving any message. This timer only
508			 * starts after we have read the 4 byte header length field. We then try to read
509			 * the data in 8K chunks, if any read takes longer that 15 seconds we break the
510			 * connection and give up. If we went to sleep then we reset our start timer to when we
511			 * woke up. Now for the reason behind the fix. We have the message length, but looks
512			 * like only part of the message has made it in. We went to sleep and the server
513			 * broke the connect while we were still a sleep. Looks like we got the first
514			 * ethernet packet but not the rest. We are in a loop waiting for the rest of the
515			 * message. Since we can't send in this state there is no way for us to know that
516			 * the connect is really down.
517			 */
518			nanouptime(&tstart);
519			do {
520				recvdlen = MIN(resid, nbp->nbp_rcvchunk);
521				error = sock_receivembuf(so, NULL, &tm, MSG_WAITALL, &recvdlen);
522				if (error == EAGAIN) {
523					nanouptime(&tend);
524					/* We fell asleep reset our timer to the wake up timer */
525					if (tstart.tv_sec < gWakeTime.tv_sec)
526						tstart.tv_sec = gWakeTime.tv_sec;
527						/* Ok we have tried hard enough just break the connection and give up. */
528					if (tend.tv_sec > (tstart.tv_sec + SMB_SB_RCVTIMEO)) {
529						error = EPIPE;
530						SMBERROR("Breaking connection, sock_receivembuf blocked for %d\n", (int)(tend.tv_sec - tstart.tv_sec));
531					}
532				}
533			} while ((error == EAGAIN) || (error == EINTR) || (error == ERESTART));
534			/*
535			 * If we didn't get an error and recvdlen is zero then we have reached
536			 * EOF. So the socket has the SS_CANTRCVMORE flag set. This means the other
537			 * side has closed their side of the connection.
538			 */
539			if ((error == 0) && (recvdlen == 0) && resid) {
540				SMBWARNING("Server closed their side of the connection.\n");
541				error = EPIPE;
542			}
543			/*
544			 * This should never happen, someday should we make it just
545			 * a debug assert.
546			 */
547			if ((error == 0) && (recvdlen > resid)) {
548				SMBERROR("Got more data than we asked for!\n");
549				if (tm)
550					mbuf_freem(tm);
551				error = EPIPE;
552			}
553			if (error)
554				goto out;
555
556			resid -= recvdlen;
557			/*
558			 * Append received chunk to previous chunk. Just glue
559			 * the new chain on the end. Consumer will pullup as required.
560			 */
561			if (!m) {
562				m = (mbuf_t )tm;
563                m_fixhdr(m); /* Work around <15114764> */
564			} else if (tm) {
565				mbuf_cat_internal(m, (mbuf_t )tm);
566                m_fixhdr(m); /* Work around <15114764> */
567			}
568		}
569
570		/*
571		 * If it's a keepalive, discard any data in it
572		 * (there's not supposed to be any, but that
573		 * doesn't mean some server won't send some)
574		 * and get the next packet.
575		 */
576		if (rpcode == NB_SSN_KEEPALIVE) {
577			if (m) {
578				mbuf_freem(m);
579				m = NULL;
580			}
581			continue;
582		}
583
584		if (nbp->nbp_state != NBST_SESSION) {
585			/*
586			 * No session is established.
587			 * Return whatever packet we got.
588			 */
589			break;
590		}
591
592		/*
593		 * A session is established; the only packets
594		 * we should see are session message and
595		 * keep-alive packets.
596		 */
597		if (rpcode == NB_SSN_MESSAGE) {
598			/*
599			 * Session message.  Does it have any data?
600			 */
601			if (!m) {
602				/*
603				 * No - complain and continue.
604				 */
605				SMBERROR("empty session packet\n");
606				continue;
607			}
608
609			/*
610			 * Yes - return it to our caller.
611			 */
612			break;
613		}
614
615		/*
616		 * Ignore other types of packets - drop packet
617		 * and try for another.
618		 */
619		SMBERROR("non-session packet %x\n", rpcode);
620		if (m) {
621			mbuf_freem(m);
622			m = NULL;
623		}
624	}
625out:
626	if (error) {
627		if (m)
628			mbuf_freem(m);
629		return (error);
630	}
631	if (mpp)
632		*mpp = m;
633	else
634		mbuf_freem(m);
635	*lenp = len;
636	*rpcodep = rpcode;
637	return (0);
638}
639
640/*
641 * SMB transport interface
642 */
643static int
644smb_nbst_create(struct smb_vc *vcp)
645{
646	struct nbpcb *nbp;
647
648	SMB_MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK);
649	bzero(nbp, sizeof *nbp);
650	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
651	nbp->nbp_state = NBST_CLOSED;
652	nbp->nbp_vc = vcp;
653	nbp->nbp_sndbuf = smb_tcpsndbuf;
654	nbp->nbp_rcvbuf = smb_tcprcvbuf;
655	lck_mtx_init(&nbp->nbp_lock, nbp_lck_group, nbp_lck_attr);
656	vcp->vc_tdata = nbp;
657	return (0);
658}
659
660static int
661smb_nbst_done(struct smb_vc *vcp)
662{
663	struct nbpcb *nbp = vcp->vc_tdata;
664
665	if (nbp == NULL)
666		return (ENOTCONN);
667	smb_nbst_disconnect(vcp);
668	if (nbp->nbp_laddr)
669		SMB_FREE(nbp->nbp_laddr, M_SONAME);
670	if (nbp->nbp_paddr)
671		SMB_FREE(nbp->nbp_paddr, M_SONAME);
672	/* The vc_tdata is no longer valid */
673	vcp->vc_tdata = NULL;
674	lck_mtx_destroy(&nbp->nbp_lock, nbp_lck_group);
675	SMB_FREE(nbp, M_NBDATA);
676	return (0);
677}
678
679static int
680smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
681{
682	struct nbpcb *nbp = vcp->vc_tdata;
683	struct sockaddr_nb *snb;
684	int error, slen;
685
686	DBG_ASSERT(vcp->vc_tdata != NULL);
687	NBDEBUG("\n");
688	error = EINVAL;
689	do {
690		if (nbp->nbp_flags & NBF_LOCADDR)
691			break;
692		/*
693		 * It is possible to create NETBIOS name in the kernel,
694		 * but nothing prevents us to do it in the user space.
695		 */
696		if (sap == NULL)
697			break;
698		slen = sap->sa_len;
699		if (slen < (int)NB_MINSALEN)
700			break;
701		snb = (struct sockaddr_nb*)smb_dup_sockaddr(sap, 1);
702		if (snb == NULL) {
703			error = ENOMEM;
704			break;
705		}
706		lck_mtx_lock(&nbp->nbp_lock);
707		nbp->nbp_laddr = snb;
708		nbp->nbp_flags |= NBF_LOCADDR;
709		lck_mtx_unlock(&nbp->nbp_lock);
710		error = 0;
711	} while(0);
712	return (error);
713}
714
715static int
716smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
717{
718	struct nbpcb *nbp = vcp->vc_tdata;
719	struct sockaddr *so;
720	struct timespec ts1, ts2;
721	int error, slen;
722
723	NBDEBUG("\n");
724	if (nbp == NULL)
725		return (EINVAL);
726	if (nbp->nbp_tso != NULL)
727		return (EISCONN);
728	if (sap->sa_family == AF_NETBIOS) {
729		if (nbp->nbp_laddr == NULL)
730			return (EINVAL);
731		slen = sap->sa_len;
732		if (slen < (int)NB_MINSALEN)
733			return (EINVAL);
734		if (nbp->nbp_paddr) {
735			SMB_FREE(nbp->nbp_paddr, M_SONAME);
736			nbp->nbp_paddr = NULL;
737		}
738		nbp->nbp_paddr = (struct sockaddr_nb*)smb_dup_sockaddr(sap, 1);
739		if (nbp->nbp_paddr == NULL)
740			return (ENOMEM);
741		so = (struct sockaddr*)&(nbp->nbp_paddr)->snb_addrin;
742	} else {
743		so = sap;
744	}
745	/*
746	 * For our general timeout we use the greater of
747	 * the default (15 sec) and 4 times the time it
748	 * took for the first round trip.  We used to use
749	 * just the latter, but sometimes if the first
750	 * round trip is very fast the subsequent 4 sec
751	 * timeouts are simply too short.
752	 */
753	nanouptime(&ts1);
754	error = tcp_connect(nbp, so);
755	if (error)
756		return (error);
757	nanouptime(&ts2);
758	timespecsub(&ts2, &ts1);
759	timespecadd(&ts2, &ts2);
760	timespecadd(&ts2, &ts2);	/*  * 4 */
761	if (timespeccmp(&ts2, &nbp->nbp_timo, >))
762		nbp->nbp_timo = ts2;
763	/* If its not a NetBIOS connection, then we don't need to do a NetBIOS session connect */
764	if (sap->sa_family != AF_NETBIOS)
765		nbp->nbp_state = NBST_SESSION;
766	else {
767		nbp->nbp_flags |= NBF_NETBIOS;
768		error = nbssn_rq_request(nbp);
769		if (error)
770			smb_nbst_disconnect(vcp);
771	}
772	return (error);
773}
774
775static int
776smb_nbst_disconnect(struct smb_vc *vcp)
777{
778	struct nbpcb *nbp = vcp->vc_tdata;
779	socket_t so;
780
781	if (nbp == NULL || nbp->nbp_tso == NULL)
782		return (ENOTCONN);
783	if ((so = nbp->nbp_tso) != NULL) {
784		lck_mtx_lock(&nbp->nbp_lock);
785		nbp->nbp_flags &= ~NBF_CONNECTED;
786		nbp->nbp_tso = (socket_t) NULL;
787		lck_mtx_unlock(&nbp->nbp_lock);
788		sock_shutdown(so, 2);
789		sock_close(so);
790	}
791	if (nbp->nbp_state != NBST_RETARGET) {
792		nbp->nbp_state = NBST_CLOSED;
793	}
794	return (0);
795}
796
797static int
798smb_nbst_send(struct smb_vc *vcp, mbuf_t m0)
799{
800	struct nbpcb *nbp = vcp->vc_tdata;
801	int error;
802
803	/* Should never happen, but just in case */
804	DBG_ASSERT(nbp);
805	if ((nbp == NULL) || (nbp->nbp_state != NBST_SESSION)) {
806		error = ENOTCONN;
807		goto abort;
808	}
809
810    /* Add in the NetBIOS 4 byte header */
811	if (mbuf_prepend(&m0, 4, MBUF_WAITOK))
812		return (ENOBUFS);
813	nb_sethdr(nbp, m0, NB_SSN_MESSAGE, (uint32_t)(m_fixhdr(m0) - 4));
814	error = sock_sendmbuf(nbp->nbp_tso, NULL, (mbuf_t)m0, 0, NULL);
815	return (error);
816abort:
817	if (m0)
818		mbuf_freem(m0);
819	return (error);
820}
821
822
823static int
824smb_nbst_recv(struct smb_vc *vcp, mbuf_t *mpp)
825{
826	struct nbpcb *nbp = vcp->vc_tdata;
827	uint8_t rpcode, *hp;
828	int error, rplen;
829
830	/* Should never happen, but just in case */
831	DBG_ASSERT(nbp);
832	if (nbp == NULL)
833		return (ENOTCONN);
834
835	lck_mtx_lock(&nbp->nbp_lock);
836	if (nbp->nbp_flags & NBF_RECVLOCK) {
837		SMBERROR("attempt to reenter session layer!\n");
838		lck_mtx_unlock(&nbp->nbp_lock);
839		return (EWOULDBLOCK);
840	}
841	nbp->nbp_flags |= NBF_RECVLOCK;
842	lck_mtx_unlock(&nbp->nbp_lock);
843
844	error = nbssn_recv(nbp, mpp, &rplen, &rpcode, NULL);
845
846    if (!error) {
847        /* Handle case when first mbuf is zero-length */
848        error = mbuf_pullup(mpp, 1);
849    }
850
851    // Check for a transform header (encrypted msg)
852    if (!error) {
853        hp = mbuf_data(*mpp);
854        if (*hp == 0xfd) {
855            error = smb3_msg_decrypt(vcp, mpp);
856        }
857    }
858
859    if (error) {
860        *mpp = NULL;
861    }
862
863	lck_mtx_lock(&nbp->nbp_lock);
864	nbp->nbp_flags &= ~NBF_RECVLOCK;
865	lck_mtx_unlock(&nbp->nbp_lock);
866	return (error);
867}
868
869static void
870smb_nbst_timo(struct smb_vc *vcp)
871{
872	#pragma unused(vcp)
873	return;
874}
875
876static int
877smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
878{
879	struct nbpcb *nbp = vcp->vc_tdata;
880
881	/* Should never happen, but just in case */
882	DBG_ASSERT(nbp);
883	if (nbp == NULL)
884		return (EINVAL);
885	switch (param) {
886	    case SMBTP_SNDSZ:
887		*(uint32_t*)data = nbp->nbp_sndbuf;
888		break;
889	    case SMBTP_RCVSZ:
890		*(uint32_t*)data = nbp->nbp_rcvbuf;
891		break;
892	    case SMBTP_TIMEOUT:
893		*(struct timespec*)data = nbp->nbp_timo;
894		break;
895	    case SMBTP_SELECTID:
896		*(void **)data = nbp->nbp_selectid;
897		break;
898	    case SMBTP_UPCALL:
899		*(void **)data = nbp->nbp_upcall;
900		break;
901	    default:
902		return (EINVAL);
903	}
904	return (0);
905}
906
907static int
908smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
909{
910	struct nbpcb *nbp = vcp->vc_tdata;
911
912	/* Should never happen, but just in case */
913	DBG_ASSERT(nbp);
914	if (nbp == NULL)
915		return (EINVAL);
916	switch (param) {
917	    case SMBTP_SELECTID:
918		nbp->nbp_selectid = data;
919		break;
920	    case SMBTP_UPCALL:
921		nbp->nbp_upcall = data;
922		break;
923	    default:
924		return (EINVAL);
925	}
926	return (0);
927}
928
929/*
930 * Check for fatal errors
931 */
932static int
933smb_nbst_fatal(struct smb_vc *vcp, int error)
934{
935	struct nbpcb *nbp;
936
937	switch (error) {
938	    case EHOSTDOWN:
939	    case ENETUNREACH:
940	    case ENOTCONN:
941	    case ENETRESET:
942	    case ECONNABORTED:
943	    case EPIPE:
944		case EADDRNOTAVAIL:
945		return 1;
946	}
947	DBG_ASSERT(vcp);
948	nbp = vcp->vc_tdata;
949	if ((nbp == NULL) || (nbp->nbp_tso == NULL) || (! sock_isconnected(nbp->nbp_tso)))
950			return 1;
951
952	return (0);
953}
954
955struct smb_tran_desc smb_tran_nbtcp_desc = {
956	SMBT_NBTCP,
957	smb_nbst_create, smb_nbst_done,
958	smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect,
959	smb_nbst_send, smb_nbst_recv,
960	smb_nbst_timo,
961	smb_nbst_getparam, smb_nbst_setparam,
962	smb_nbst_fatal,
963	{NULL, NULL}
964};
965