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