xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_net.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*f82c7503SGordon Ross  * Copyright 2022 RackTop Systems, Inc.
23897907ceSGordon Ross  * Copyright 2011-2021 Tintri by DDN, Inc. All rights reserved.
245cdbe942Sjb150015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25da6c28aaSamw  * Use is subject to license terms.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw #include <sys/types.h>
29da6c28aaSamw #include <sys/param.h>
30da6c28aaSamw #include <sys/ddi.h>
31da6c28aaSamw #include <sys/sunddi.h>
32da6c28aaSamw #include <sys/time.h>
33da6c28aaSamw #include <sys/varargs.h>
34da6c28aaSamw #include <sys/modctl.h>
35da6c28aaSamw #include <sys/pathname.h>
36da6c28aaSamw #include <sys/vnode.h>
37b819cea2SGordon Ross #include <sys/socket.h>
380f1702c5SYu Xiangning #include <sys/ksocket.h>
39*f82c7503SGordon Ross #include <sys/stream.h>
40*f82c7503SGordon Ross #include <sys/strsubr.h>
41da6c28aaSamw 
42da6c28aaSamw #include <smbsrv/smb_vops.h>
43da6c28aaSamw #include <smbsrv/smb.h>
44da6c28aaSamw #include <smbsrv/smb_kproto.h>
4521b7895dSjb150015 #include <smbsrv/smb_kstat.h>
4621b7895dSjb150015 
47da6c28aaSamw /*
48897907ceSGordon Ross  * How many iovec we'll handle as a local array (no allocation)
49897907ceSGordon Ross  * See also IOV_MAX_STACK <sys/limits.h> but we need this to
50897907ceSGordon Ross  * work also with _FAKE_KERNEL
51897907ceSGordon Ross  */
52897907ceSGordon Ross #define	SMB_LOCAL_IOV_MAX	16
53897907ceSGordon Ross 
54897907ceSGordon Ross /*
55da6c28aaSamw  * SMB Network Socket API
56da6c28aaSamw  *
57da6c28aaSamw  * smb_socreate:	Creates an socket based on domain/type.
58da6c28aaSamw  * smb_soshutdown:	Disconnect a socket created with smb_socreate
59da6c28aaSamw  * smb_sodestroy:	Release resources associated with a socket
60da6c28aaSamw  * smb_sosend:		Send the contents of a buffer on a socket
61da6c28aaSamw  * smb_sorecv:		Receive data into a buffer from a socket
62da6c28aaSamw  * smb_iov_sosend:	Send the contents of an iovec on a socket
63da6c28aaSamw  * smb_iov_sorecv:	Receive data into an iovec from a socket
64da6c28aaSamw  */
65da6c28aaSamw 
660f1702c5SYu Xiangning ksocket_t
smb_socreate(int domain,int type,int protocol)67da6c28aaSamw smb_socreate(int domain, int type, int protocol)
68da6c28aaSamw {
690f1702c5SYu Xiangning 	ksocket_t	sock;
70da6c28aaSamw 	int		err = 0;
71da6c28aaSamw 
720f1702c5SYu Xiangning 	err = ksocket_socket(&sock, domain, type, protocol, KSOCKET_SLEEP,
730f1702c5SYu Xiangning 	    CRED());
74da6c28aaSamw 
750f1702c5SYu Xiangning 	if (err != 0)
76da6c28aaSamw 		return (NULL);
770f1702c5SYu Xiangning 	else
780f1702c5SYu Xiangning 		return (sock);
79da6c28aaSamw }
80da6c28aaSamw 
81da6c28aaSamw /*
82da6c28aaSamw  * smb_soshutdown will disconnect the socket and prevent subsequent PDU
83da6c28aaSamw  * reception and transmission.  The sonode still exists but its state
84da6c28aaSamw  * gets modified to indicate it is no longer connected.  Calls to
85da6c28aaSamw  * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
86da6c28aaSamw  * regain control of a thread stuck in smb_sorecv.
87da6c28aaSamw  */
88da6c28aaSamw void
smb_soshutdown(ksocket_t so)890f1702c5SYu Xiangning smb_soshutdown(ksocket_t so)
90da6c28aaSamw {
910f1702c5SYu Xiangning 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
92da6c28aaSamw }
93da6c28aaSamw 
94da6c28aaSamw /*
95da6c28aaSamw  * smb_sodestroy releases all resources associated with a socket previously
96da6c28aaSamw  * created with smb_socreate.  The socket must be shutdown using smb_soshutdown
97da6c28aaSamw  * before the socket is destroyed with smb_sodestroy, otherwise undefined
98da6c28aaSamw  * behavior will result.
99da6c28aaSamw  */
100da6c28aaSamw void
smb_sodestroy(ksocket_t so)1010f1702c5SYu Xiangning smb_sodestroy(ksocket_t so)
102da6c28aaSamw {
1030f1702c5SYu Xiangning 	(void) ksocket_close(so, CRED());
104da6c28aaSamw }
105da6c28aaSamw 
106da6c28aaSamw int
smb_sorecv(ksocket_t so,void * msg,size_t len)1070f1702c5SYu Xiangning smb_sorecv(ksocket_t so, void *msg, size_t len)
108da6c28aaSamw {
1090f1702c5SYu Xiangning 	size_t recvd;
110da6c28aaSamw 	int err;
111da6c28aaSamw 
112da6c28aaSamw 	ASSERT(so != NULL);
113da6c28aaSamw 	ASSERT(len != 0);
114da6c28aaSamw 
1150f1702c5SYu Xiangning 	if ((err = ksocket_recv(so, msg, len, MSG_WAITALL, &recvd,
1160f1702c5SYu Xiangning 	    CRED())) != 0) {
117da6c28aaSamw 		return (err);
118da6c28aaSamw 	}
119da6c28aaSamw 
120da6c28aaSamw 	/* Successful receive */
1210f1702c5SYu Xiangning 	return ((recvd == len) ? 0 : -1);
122da6c28aaSamw }
1235cdbe942Sjb150015 
1245cdbe942Sjb150015 /*
125897907ceSGordon Ross  * Receive a message as an mbuf chain (returned in *mpp)
126897907ceSGordon Ross  * where the length requested is len.
127897907ceSGordon Ross  *
128897907ceSGordon Ross  * Some day hopefully this will be able to receive an actual
129897907ceSGordon Ross  * mblk chain from the network stack (without copying), and
130897907ceSGordon Ross  * either wrap those to create mbufs, or use mblks directly.
131897907ceSGordon Ross  * For now, we allocate buffers here to recv into.
132897907ceSGordon Ross  */
133897907ceSGordon Ross int
smb_net_recv_mbufs(smb_session_t * s,mbuf_t ** mpp,size_t len)134897907ceSGordon Ross smb_net_recv_mbufs(smb_session_t *s, mbuf_t **mpp, size_t len)
135897907ceSGordon Ross {
136897907ceSGordon Ross 	struct nmsghdr	msg;
137897907ceSGordon Ross 	uio_t	uio;
138897907ceSGordon Ross 	iovec_t iov[SMB_LOCAL_IOV_MAX];
139897907ceSGordon Ross 	mbuf_t	*mhead = NULL;
140897907ceSGordon Ross 	size_t	rlen;
141897907ceSGordon Ross 	int	rc;
142897907ceSGordon Ross 
143897907ceSGordon Ross 	bzero(&msg, sizeof (msg));
144897907ceSGordon Ross 	bzero(&uio, sizeof (uio));
145897907ceSGordon Ross 	ASSERT(len > 0);
146897907ceSGordon Ross 
147897907ceSGordon Ross 	mhead = smb_mbuf_alloc_chain(len);
148897907ceSGordon Ross 
149897907ceSGordon Ross 	uio.uio_resid = len;
150897907ceSGordon Ross 	uio.uio_iov = iov;
151897907ceSGordon Ross 	uio.uio_iovcnt = SMB_LOCAL_IOV_MAX;
152897907ceSGordon Ross 
153897907ceSGordon Ross 	rc = smb_mbuf_mkuio(mhead, &uio);
154897907ceSGordon Ross 	if (rc != 0)
155897907ceSGordon Ross 		goto errout;
156897907ceSGordon Ross 
157897907ceSGordon Ross 	msg.msg_iov = uio.uio_iov;
158897907ceSGordon Ross 	msg.msg_iovlen = uio.uio_iovcnt;
159897907ceSGordon Ross 	rlen = len;
160897907ceSGordon Ross 	rc = ksocket_recvmsg(s->sock, &msg, MSG_WAITALL, &rlen, CRED());
161897907ceSGordon Ross 	if (rc != 0)
162897907ceSGordon Ross 		goto errout;
163897907ceSGordon Ross 	if (rlen != len) {
164897907ceSGordon Ross 		rc = SET_ERROR(EIO);
165897907ceSGordon Ross 		goto errout;
166897907ceSGordon Ross 	}
167897907ceSGordon Ross 
168897907ceSGordon Ross 	*mpp = mhead;
169897907ceSGordon Ross 	return (rc);
170897907ceSGordon Ross 
171897907ceSGordon Ross errout:
172897907ceSGordon Ross 	m_freem(mhead);
173897907ceSGordon Ross 	return (rc);
174897907ceSGordon Ross }
175897907ceSGordon Ross 
176897907ceSGordon Ross /*
1775cdbe942Sjb150015  * smb_net_txl_constructor
1785cdbe942Sjb150015  *
1795cdbe942Sjb150015  *	Transmit list constructor
1805cdbe942Sjb150015  */
1815cdbe942Sjb150015 void
smb_net_txl_constructor(smb_txlst_t * txl)1825cdbe942Sjb150015 smb_net_txl_constructor(smb_txlst_t *txl)
1835cdbe942Sjb150015 {
1845cdbe942Sjb150015 	ASSERT(txl->tl_magic != SMB_TXLST_MAGIC);
1855cdbe942Sjb150015 
1865cdbe942Sjb150015 	mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL);
187a90cf9f2SGordon Ross 	cv_init(&txl->tl_wait_cv, NULL, CV_DEFAULT, NULL);
1885cdbe942Sjb150015 	txl->tl_active = B_FALSE;
1895cdbe942Sjb150015 	txl->tl_magic = SMB_TXLST_MAGIC;
1905cdbe942Sjb150015 }
1915cdbe942Sjb150015 
1925cdbe942Sjb150015 /*
1935cdbe942Sjb150015  * smb_net_txl_destructor
1945cdbe942Sjb150015  *
1955cdbe942Sjb150015  *	Transmit list destructor
1965cdbe942Sjb150015  */
1975cdbe942Sjb150015 void
smb_net_txl_destructor(smb_txlst_t * txl)1985cdbe942Sjb150015 smb_net_txl_destructor(smb_txlst_t *txl)
1995cdbe942Sjb150015 {
2005cdbe942Sjb150015 	ASSERT(txl->tl_magic == SMB_TXLST_MAGIC);
2015cdbe942Sjb150015 
2025cdbe942Sjb150015 	txl->tl_magic = 0;
203a90cf9f2SGordon Ross 	cv_destroy(&txl->tl_wait_cv);
2045cdbe942Sjb150015 	mutex_destroy(&txl->tl_mutex);
2055cdbe942Sjb150015 }
2065cdbe942Sjb150015 
207*f82c7503SGordon Ross static void
smb_net_send_free(void * arg)208*f82c7503SGordon Ross smb_net_send_free(void *arg)
209897907ceSGordon Ross {
210*f82c7503SGordon Ross 	mbuf_t *m = arg;
211*f82c7503SGordon Ross 	(void) m_free(m);
212*f82c7503SGordon Ross }
213897907ceSGordon Ross 
214897907ceSGordon Ross /*
215*f82c7503SGordon Ross  * Create an mblk that wraps the passed mbuf
216*f82c7503SGordon Ross  *
217*f82c7503SGordon Ross  * Note we need a place to store a frtn_t for each mbuf.
218*f82c7503SGordon Ross  * For M_EXT packets (most are) we have lots of unused space
219*f82c7503SGordon Ross  * after the headers: M_dat.MH.MH_dat.MH_ext (a.k.a. m_ext)
220*f82c7503SGordon Ross  * If not M_EXT but there's enough trailing space, just use
221*f82c7503SGordon Ross  * the trailing space, otherwise convert to external type
222*f82c7503SGordon Ross  * (which means copying the data, so do only if necessary).
223*f82c7503SGordon Ross  *
224*f82c7503SGordon Ross  * To simplify the code, the frtn_t is always located at the
225*f82c7503SGordon Ross  * end of the mbuf (in space we make sure is unused).
226897907ceSGordon Ross  */
227*f82c7503SGordon Ross static mblk_t *
smb_net_wrap_mbuf(mbuf_t * mbuf)228*f82c7503SGordon Ross smb_net_wrap_mbuf(mbuf_t *mbuf)
229*f82c7503SGordon Ross {
230*f82c7503SGordon Ross 	frtn_t		*frtn;
231*f82c7503SGordon Ross 	mblk_t		*mblk;
232*f82c7503SGordon Ross 
233*f82c7503SGordon Ross 	if ((mbuf->m_flags & M_EXT) == 0 &&
234*f82c7503SGordon Ross 	    M_TRAILINGSPACE(mbuf) < sizeof (*frtn)) {
235*f82c7503SGordon Ross 		/*
236*f82c7503SGordon Ross 		 * Convert to M_EXT type, like MCLGET(),
237*f82c7503SGordon Ross 		 * but copy before updating mbuf->m_ext,
238*f82c7503SGordon Ross 		 * which would otherwise overwrite data.
239*f82c7503SGordon Ross 		 */
240*f82c7503SGordon Ross 		caddr_t buf = smb_mbufcl_alloc();
241*f82c7503SGordon Ross 		ASSERT(mbuf->m_len <= MLEN);
242*f82c7503SGordon Ross 		bcopy(mbuf->m_data, buf, mbuf->m_len);
243*f82c7503SGordon Ross 		mbuf->m_ext.ext_buf = buf;
244*f82c7503SGordon Ross 		mbuf->m_data = buf;
245*f82c7503SGordon Ross 		mbuf->m_flags |= M_EXT;
246*f82c7503SGordon Ross 		mbuf->m_ext.ext_size = MCLBYTES;
247*f82c7503SGordon Ross 		mbuf->m_ext.ext_free = smb_mbufcl_free;
248897907ceSGordon Ross 	}
249897907ceSGordon Ross 
250897907ceSGordon Ross 	/*
251*f82c7503SGordon Ross 	 * Store frtn_t at the end of the mbuf data area.
252*f82c7503SGordon Ross 	 * Note: This is the _internal_ data area (unused)
253*f82c7503SGordon Ross 	 * not the external data pointed to by m_data.
254897907ceSGordon Ross 	 */
255*f82c7503SGordon Ross 	frtn = (void *) &mbuf->m_dat[MLEN - sizeof (*frtn)];
256*f82c7503SGordon Ross 
257*f82c7503SGordon Ross 	frtn->free_func = smb_net_send_free;
258*f82c7503SGordon Ross 	frtn->free_arg = (caddr_t)mbuf;
259*f82c7503SGordon Ross 
260*f82c7503SGordon Ross 	mblk = esballoca_wait((void *)mbuf->m_data, mbuf->m_len,
261*f82c7503SGordon Ross 	    BPRI_MED, frtn);
262*f82c7503SGordon Ross 	if (mblk != NULL) {
263*f82c7503SGordon Ross 		mblk->b_wptr += mbuf->m_len;
264*f82c7503SGordon Ross 		mblk->b_datap->db_type = M_DATA;
265897907ceSGordon Ross 	}
266897907ceSGordon Ross 
267*f82c7503SGordon Ross 	return (mblk);
268*f82c7503SGordon Ross }
269897907ceSGordon Ross 
270*f82c7503SGordon Ross /*
271*f82c7503SGordon Ross  * This routine sends an mbuf chain by encapsulating each segment
272*f82c7503SGordon Ross  * with an mblk_t setup with external storage (zero-copy).
273*f82c7503SGordon Ross  *
274*f82c7503SGordon Ross  * Note: the mbufs passed in are free'd via smb_net_send_free.
275*f82c7503SGordon Ross  */
276*f82c7503SGordon Ross static int
smb_net_send_mblks(smb_session_t * s,mbuf_t * mbuf_head)277*f82c7503SGordon Ross smb_net_send_mblks(smb_session_t *s, mbuf_t *mbuf_head)
278*f82c7503SGordon Ross {
279*f82c7503SGordon Ross 	struct nmsghdr	msg;
280*f82c7503SGordon Ross 	mblk_t	*mblk_head;
281*f82c7503SGordon Ross 	mblk_t	*mblk_prev;
282*f82c7503SGordon Ross 	mblk_t	*mblk;
283*f82c7503SGordon Ross 	mbuf_t	*mbuf_prev;
284*f82c7503SGordon Ross 	mbuf_t	*mbuf;
285*f82c7503SGordon Ross 	smb_txlst_t *txl;
286*f82c7503SGordon Ross 	int	rc = 0;
287*f82c7503SGordon Ross 
288*f82c7503SGordon Ross 	bzero(&msg, sizeof (msg));
289*f82c7503SGordon Ross 
290*f82c7503SGordon Ross 	mblk_prev = NULL;
291*f82c7503SGordon Ross 	mblk_head = NULL;
292*f82c7503SGordon Ross 	mbuf_prev = NULL;
293*f82c7503SGordon Ross 	mbuf = mbuf_head;
294*f82c7503SGordon Ross 	while (mbuf != NULL) {
295*f82c7503SGordon Ross 		mblk = smb_net_wrap_mbuf(mbuf);
296*f82c7503SGordon Ross 		if (mblk == NULL) {
297*f82c7503SGordon Ross 			rc = ENOSR;
298*f82c7503SGordon Ross 			break;
299*f82c7503SGordon Ross 		}
300*f82c7503SGordon Ross 		if (mblk_head == NULL)
301*f82c7503SGordon Ross 			mblk_head = mblk;
302*f82c7503SGordon Ross 		if (mblk_prev != NULL)
303*f82c7503SGordon Ross 			mblk_prev->b_cont = mblk;
304*f82c7503SGordon Ross 
305*f82c7503SGordon Ross 		mblk_prev = mblk;
306*f82c7503SGordon Ross 		mbuf_prev = mbuf;
307*f82c7503SGordon Ross 		mbuf = mbuf->m_next;
308*f82c7503SGordon Ross 	}
309*f82c7503SGordon Ross 	if (rc != 0) {
310*f82c7503SGordon Ross 		/* Bailed with ENOSR. Cleanup */
311*f82c7503SGordon Ross 		if (mbuf != NULL) {
312*f82c7503SGordon Ross 			if (mbuf_prev != NULL)
313*f82c7503SGordon Ross 				mbuf_prev->m_next = NULL;
314*f82c7503SGordon Ross 			m_freem(mbuf);
315*f82c7503SGordon Ross 		}
316*f82c7503SGordon Ross 		if (mblk_head != NULL)
317*f82c7503SGordon Ross 			freemsg(mblk_head);
318*f82c7503SGordon Ross 		return (rc);
319*f82c7503SGordon Ross 	}
320*f82c7503SGordon Ross 
321*f82c7503SGordon Ross 	/*
322*f82c7503SGordon Ross 	 * Wait for our turn to send.
323*f82c7503SGordon Ross 	 */
324*f82c7503SGordon Ross 	DTRACE_PROBE1(send__wait__start, struct smb_session_t *, s);
325*f82c7503SGordon Ross 	txl = &s->s_txlst;
326*f82c7503SGordon Ross 	mutex_enter(&txl->tl_mutex);
327*f82c7503SGordon Ross 	while (txl->tl_active)
328*f82c7503SGordon Ross 		cv_wait(&txl->tl_wait_cv, &txl->tl_mutex);
329*f82c7503SGordon Ross 	txl->tl_active = B_TRUE;
330*f82c7503SGordon Ross 	mutex_exit(&txl->tl_mutex);
331*f82c7503SGordon Ross 	DTRACE_PROBE1(send__wait__done, struct smb_session_t *, s);
332*f82c7503SGordon Ross 
333*f82c7503SGordon Ross 	/*
334*f82c7503SGordon Ross 	 * OK, send it.
335*f82c7503SGordon Ross 	 */
336*f82c7503SGordon Ross 	rc = ksocket_sendmblk(s->sock, &msg, 0, &mblk_head, CRED());
337*f82c7503SGordon Ross 	if (rc != 0) {
338*f82c7503SGordon Ross 		if (mblk_head != NULL) {
339*f82c7503SGordon Ross 			freemsg(mblk_head);
340*f82c7503SGordon Ross 			mblk_head = NULL;
341*f82c7503SGordon Ross 		}
342*f82c7503SGordon Ross 	}
343*f82c7503SGordon Ross 
344*f82c7503SGordon Ross 	mutex_enter(&txl->tl_mutex);
345*f82c7503SGordon Ross 	txl->tl_active = B_FALSE;
346*f82c7503SGordon Ross 	cv_signal(&txl->tl_wait_cv);
347*f82c7503SGordon Ross 	mutex_exit(&txl->tl_mutex);
348897907ceSGordon Ross 
349897907ceSGordon Ross 	return (rc);
350897907ceSGordon Ross }
351897907ceSGordon Ross 
352897907ceSGordon Ross /*
353*f82c7503SGordon Ross  * This routine sends an mbuf chain by copying its segments
354*f82c7503SGordon Ross  * (scatter/gather) via UIO.
3555cdbe942Sjb150015  *
356*f82c7503SGordon Ross  * The mbuf chain is always free'd (error or not)
3575cdbe942Sjb150015  */
358*f82c7503SGordon Ross static int
smb_net_send_uio(smb_session_t * s,mbuf_t * mbuf_head)359*f82c7503SGordon Ross smb_net_send_uio(smb_session_t *s, mbuf_t *mbuf_head)
3605cdbe942Sjb150015 {
361*f82c7503SGordon Ross 	struct nmsghdr	msg;
362*f82c7503SGordon Ross 	uio_t	uio;
363*f82c7503SGordon Ross 	iovec_t iov_local[SMB_LOCAL_IOV_MAX];
364*f82c7503SGordon Ross 	mbuf_t	*mbuf;
365*f82c7503SGordon Ross 	smb_txlst_t *txl;
366*f82c7503SGordon Ross 	smb_vdb_t *vdb = NULL;
367a90cf9f2SGordon Ross 	size_t sent;
368*f82c7503SGordon Ross 	int	len, nseg, rc;
369*f82c7503SGordon Ross 
370*f82c7503SGordon Ross 	bzero(&msg, sizeof (msg));
371*f82c7503SGordon Ross 	bzero(&uio, sizeof (uio));
372*f82c7503SGordon Ross 
373*f82c7503SGordon Ross 	len = nseg = 0;
374*f82c7503SGordon Ross 	for (mbuf = mbuf_head;
375*f82c7503SGordon Ross 	     mbuf != NULL;
376*f82c7503SGordon Ross 	     mbuf = mbuf->m_next) {
377*f82c7503SGordon Ross 		nseg++;
378*f82c7503SGordon Ross 		len += mbuf->m_len;
379*f82c7503SGordon Ross 	}
380*f82c7503SGordon Ross 
381*f82c7503SGordon Ross 	if (nseg <= SMB_LOCAL_IOV_MAX) {
382*f82c7503SGordon Ross 		uio.uio_iov = iov_local;
383*f82c7503SGordon Ross 		uio.uio_iovcnt = SMB_LOCAL_IOV_MAX;
384*f82c7503SGordon Ross 	} else {
385*f82c7503SGordon Ross 		vdb = kmem_alloc(sizeof (*vdb), KM_SLEEP);
386*f82c7503SGordon Ross 		uio.uio_iov = &vdb->vdb_iovec[0];
387*f82c7503SGordon Ross 		uio.uio_iovcnt = MAX_IOVEC;
388*f82c7503SGordon Ross 	}
389*f82c7503SGordon Ross 	uio.uio_resid = len;
390*f82c7503SGordon Ross 
391*f82c7503SGordon Ross 	rc = smb_mbuf_mkuio(mbuf_head, &uio);
392*f82c7503SGordon Ross 	if (rc != 0)
393*f82c7503SGordon Ross 		goto out;
3945cdbe942Sjb150015 
395a90cf9f2SGordon Ross 	DTRACE_PROBE1(send__wait__start, struct smb_session_t *, s);
3965cdbe942Sjb150015 
397a90cf9f2SGordon Ross 	/*
398a90cf9f2SGordon Ross 	 * Wait for our turn to send.
399a90cf9f2SGordon Ross 	 */
400*f82c7503SGordon Ross 	txl = &s->s_txlst;
4015cdbe942Sjb150015 	mutex_enter(&txl->tl_mutex);
402a90cf9f2SGordon Ross 	while (txl->tl_active)
403a90cf9f2SGordon Ross 		cv_wait(&txl->tl_wait_cv, &txl->tl_mutex);
4045cdbe942Sjb150015 	txl->tl_active = B_TRUE;
405a90cf9f2SGordon Ross 	mutex_exit(&txl->tl_mutex);
406a90cf9f2SGordon Ross 
407a90cf9f2SGordon Ross 	DTRACE_PROBE1(send__wait__done, struct smb_session_t *, s);
408a90cf9f2SGordon Ross 
409a90cf9f2SGordon Ross 	/*
410a90cf9f2SGordon Ross 	 * OK, try to send.
411a90cf9f2SGordon Ross 	 *
412a90cf9f2SGordon Ross 	 * This should block until we've sent it all,
413a90cf9f2SGordon Ross 	 * or given up due to errors (socket closed).
414a90cf9f2SGordon Ross 	 */
415*f82c7503SGordon Ross 	msg.msg_iov = uio.uio_iov;
416*f82c7503SGordon Ross 	msg.msg_iovlen = uio.uio_iovcnt;
417*f82c7503SGordon Ross 	while (uio.uio_resid > 0) {
418a90cf9f2SGordon Ross 		rc = ksocket_sendmsg(s->sock, &msg, 0, &sent, CRED());
419a90cf9f2SGordon Ross 		if (rc != 0)
420a90cf9f2SGordon Ross 			break;
421*f82c7503SGordon Ross 		uio.uio_resid -= sent;
422a90cf9f2SGordon Ross 	}
423a90cf9f2SGordon Ross 
4245cdbe942Sjb150015 	mutex_enter(&txl->tl_mutex);
4255cdbe942Sjb150015 	txl->tl_active = B_FALSE;
426a90cf9f2SGordon Ross 	cv_signal(&txl->tl_wait_cv);
4275cdbe942Sjb150015 	mutex_exit(&txl->tl_mutex);
428a90cf9f2SGordon Ross 
429*f82c7503SGordon Ross out:
430*f82c7503SGordon Ross 	if (vdb != NULL)
431*f82c7503SGordon Ross 		kmem_free(vdb, sizeof (*vdb));
432*f82c7503SGordon Ross 	m_freem(mbuf_head);
433*f82c7503SGordon Ross 	return (rc);
434*f82c7503SGordon Ross }
435*f82c7503SGordon Ross 
436*f82c7503SGordon Ross /*
437*f82c7503SGordon Ross  * This has an optional code path calling ksocket_sendmblk,
438*f82c7503SGordon Ross  * which is faster than ksocket_sendmsg (UIO copying) in some
439*f82c7503SGordon Ross  * configurations, but needs work before it's uniformly faster.
440*f82c7503SGordon Ross  * In particular, the ksocket_sendmblk code path probably needs
441*f82c7503SGordon Ross  * to do more like socopyinuio etc, checking the send socket
442*f82c7503SGordon Ross  * SO_SND_BUFINFO, SO_SND_COPYAVOID, etc. to find out what is
443*f82c7503SGordon Ross  * the preferred MSS, header space, copying preference, etc.
444*f82c7503SGordon Ross  *
445*f82c7503SGordon Ross  * As it is, this works well with some NIC drivers, particularly
446*f82c7503SGordon Ross  * with MTU=9000 as is typical in high performance setups, so
447*f82c7503SGordon Ross  * this remains available via this tunable for now.
448*f82c7503SGordon Ross  */
449*f82c7503SGordon Ross int smb_send_mblks = 0;
450*f82c7503SGordon Ross 
451*f82c7503SGordon Ross /*
452*f82c7503SGordon Ross  * smb_net_send_mbufs
453*f82c7503SGordon Ross  *
454*f82c7503SGordon Ross  * Send the buf chain using either mblk encapsulation (zero-copy)
455*f82c7503SGordon Ross  * or via scatter/gather UIO vector, based on the setting.
456*f82c7503SGordon Ross  */
457*f82c7503SGordon Ross int
smb_net_send_mbufs(smb_session_t * s,mbuf_t * mbuf_head)458*f82c7503SGordon Ross smb_net_send_mbufs(smb_session_t *s, mbuf_t *mbuf_head)
459*f82c7503SGordon Ross {
460*f82c7503SGordon Ross 	int rc;
461*f82c7503SGordon Ross 
462*f82c7503SGordon Ross 	if (smb_send_mblks != 0) {
463*f82c7503SGordon Ross 		rc = smb_net_send_mblks(s, mbuf_head);
464*f82c7503SGordon Ross 	} else {
465*f82c7503SGordon Ross 		rc = smb_net_send_uio(s, mbuf_head);
466*f82c7503SGordon Ross 	}
4675cdbe942Sjb150015 	return (rc);
4685cdbe942Sjb150015 }
469