1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
33 */
34 /*
35 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
36 * Use is subject to license terms.
37 *
38 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/autoconf.h>
44 #include <sys/sysmacros.h>
45 #include <sys/sunddi.h>
46 #include <sys/kmem.h>
47 #include <sys/proc.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/poll.h>
51 #include <sys/stream.h>
52 #include <sys/strsubr.h>
53 #include <sys/strsun.h>
54 #include <sys/stropts.h>
55 #include <sys/cmn_err.h>
56 #include <sys/tihdr.h>
57 #include <sys/tiuser.h>
58 #include <sys/t_kuser.h>
59 #include <sys/priv.h>
60
61 #include <net/if.h>
62 #include <net/route.h>
63
64 #include <netinet/in.h>
65 #include <netinet/tcp.h>
66
67 #include <netsmb/smb_osdep.h>
68 #include <netsmb/mchain.h>
69 #include <netsmb/netbios.h>
70
71 #include <netsmb/smb.h>
72 #include <netsmb/smb_conn.h>
73 #include <netsmb/smb_subr.h>
74 #include <netsmb/smb_tran.h>
75 #include <netsmb/smb_trantcp.h>
76
77 static int nb_disconnect(struct nbpcb *nbp);
78
79
80 /*
81 * Get mblks into *mpp until the data length is at least mlen.
82 * Note that *mpp may already contain a fragment.
83 *
84 * If we ever have to wait more than 15 sec. to read a message,
85 * return ETIME. (Caller will declare the VD dead.)
86 */
87 static int
nb_getmsg_mlen(struct nbpcb * nbp,mblk_t ** mpp,size_t mlen)88 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
89 {
90 mblk_t *im, *tm;
91 union T_primitives *pptr;
92 size_t dlen;
93 int events, fmode, timo, waitflg;
94 int error = 0;
95
96 /* We should be the only reader. */
97 ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
98 /* nbp->nbp_tiptr checked by caller */
99
100 /*
101 * Get the first message (fragment) if
102 * we don't already have a left-over.
103 */
104 dlen = msgdsize(*mpp); /* *mpp==null is OK */
105 while (dlen < mlen) {
106
107 /*
108 * I think we still want this to return ETIME
109 * if nothing arrives for SMB_NBTIMO (15) sec.
110 * so we can report "server not responding".
111 * We _could_ just block here now that our
112 * IOD is just a reader.
113 */
114 #if 1
115 /* Wait with timeout... */
116 events = 0;
117 waitflg = READWAIT;
118 timo = SEC_TO_TICK(SMB_NBTIMO);
119 error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
120 if (!error && !events)
121 error = ETIME;
122 if (error)
123 break;
124 /* file mode for recv is: */
125 fmode = FNDELAY; /* non-blocking */
126 #else
127 fmode = 0; /* normal (blocking) */
128 #endif
129
130 /* Get some more... */
131 tm = NULL;
132 error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
133 if (error == EAGAIN)
134 continue;
135 if (error)
136 break;
137
138 /*
139 * Normally get M_DATA messages here,
140 * but have to check for other types.
141 */
142 switch (tm->b_datap->db_type) {
143 case M_DATA:
144 break;
145 case M_PROTO:
146 case M_PCPROTO:
147 /*LINTED*/
148 pptr = (union T_primitives *)tm->b_rptr;
149 switch (pptr->type) {
150 case T_DATA_IND:
151 /* remove 1st mblk, keep the rest. */
152 im = tm->b_cont;
153 tm->b_cont = NULL;
154 freeb(tm);
155 tm = im;
156 break;
157 case T_DISCON_IND:
158 /* Peer disconnected. */
159 NBDEBUG("T_DISCON_IND: reason=%d",
160 (int)pptr->discon_ind.DISCON_reason);
161 goto discon;
162 case T_ORDREL_IND:
163 /* Peer disconnecting. */
164 NBDEBUG("T_ORDREL_IND");
165 goto discon;
166 case T_OK_ACK:
167 switch (pptr->ok_ack.CORRECT_prim) {
168 case T_DISCON_REQ:
169 NBDEBUG("T_OK_ACK/T_DISCON_REQ");
170 goto discon;
171 default:
172 NBDEBUG("T_OK_ACK/prim=%d",
173 (int)pptr->ok_ack.CORRECT_prim);
174 goto discon;
175 }
176 default:
177 NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
178 goto discon;
179 }
180 break; /* M_PROTO, M_PCPROTO */
181
182 default:
183 NBDEBUG("unexpected msg type=%d",
184 tm->b_datap->db_type);
185 /*FALLTHROUGH*/
186 discon:
187 /*
188 * The connection is no longer usable.
189 * Drop this message and disconnect.
190 *
191 * Note: nb_disconnect only does t_snddis
192 * on the first call, but does important
193 * cleanup and state change on any call.
194 */
195 freemsg(tm);
196 (void) nb_disconnect(nbp);
197 return (ENOTCONN);
198 }
199
200 /*
201 * If we have a data message, append it to
202 * the previous chunk(s) and update dlen
203 */
204 if (!tm)
205 continue;
206 if (*mpp == NULL) {
207 *mpp = tm;
208 } else {
209 /* Append */
210 for (im = *mpp; im->b_cont; im = im->b_cont)
211 ;
212 im->b_cont = tm;
213 }
214 dlen += msgdsize(tm);
215 }
216
217 return (error);
218 }
219
220 /*
221 * Send a T_DISCON_REQ (disconnect)
222 */
223 static int
nb_snddis(struct nbpcb * nbp)224 nb_snddis(struct nbpcb *nbp)
225 {
226 TIUSER *tiptr = nbp->nbp_tiptr;
227 cred_t *cr = nbp->nbp_cred;
228 mblk_t *mp;
229 struct T_discon_req *dreq;
230 int error, mlen;
231
232 ASSERT(MUTEX_HELD(&nbp->nbp_lock));
233
234 if (tiptr == NULL)
235 return (EBADF);
236
237 mlen = sizeof (struct T_discon_req);
238 if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
239 return (error);
240
241 mp->b_datap->db_type = M_PROTO;
242 /*LINTED*/
243 dreq = (struct T_discon_req *)mp->b_wptr;
244 dreq->PRIM_type = T_DISCON_REQ;
245 dreq->SEQ_number = -1;
246 mp->b_wptr += sizeof (struct T_discon_req);
247
248 error = tli_send(tiptr, mp, tiptr->fp->f_flag);
249 /*
250 * There is an OK/ACK response expected, which is
251 * either handled by our receiver thread, or just
252 * discarded if we're closing this endpoint.
253 */
254
255 return (error);
256 }
257
258 /*
259 * Stuff the NetBIOS header into space already prepended.
260 */
261 static void
nb_sethdr(mblk_t * m,uint8_t type,uint32_t len)262 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
263 {
264 uint32_t *p;
265
266 len &= 0x1FFFF;
267 len |= (type << 24);
268
269 /*LINTED*/
270 p = (uint32_t *)m->b_rptr;
271 *p = htonl(len);
272 }
273
274 /*
275 * Wait for up to 15 sec. for the next packet.
276 * Often return ETIME and do nothing else.
277 * When a packet header is available, check
278 * the header and get the length, but don't
279 * consume it. No side effects here except
280 * for the pullupmsg call.
281 */
282 static int
nbssn_peekhdr(struct nbpcb * nbp,size_t * lenp,uint8_t * rpcodep)283 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep)
284 {
285 uint32_t len, *hdr;
286 int error;
287
288 /*
289 * Get the first message (fragment) if
290 * we don't already have a left-over.
291 */
292 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
293 if (error)
294 return (error);
295
296 if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
297 return (ENOSR);
298
299 /*
300 * Check the NetBIOS header.
301 * (NOT consumed here)
302 */
303 /*LINTED*/
304 hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
305
306 len = ntohl(*hdr);
307 if ((len >> 16) & 0xFE) {
308 NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
309 return (EPIPE);
310 }
311 *rpcodep = (len >> 24) & 0xFF;
312 switch (*rpcodep) {
313 case NB_SSN_MESSAGE:
314 case NB_SSN_REQUEST:
315 case NB_SSN_POSRESP:
316 case NB_SSN_NEGRESP:
317 case NB_SSN_RTGRESP:
318 case NB_SSN_KEEPALIVE:
319 break;
320 default:
321 NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
322 return (EPIPE);
323 }
324 len &= 0x1ffff;
325 if (len > NB_MAXPKTLEN) {
326 NBDEBUG("packet too long (%d)\n", len);
327 return (EFBIG);
328 }
329 *lenp = len;
330 return (0);
331 }
332
333 /*
334 * Receive a NetBIOS message. This may block to wait for the entire
335 * message to arrive. The caller knows there is (or should be) a
336 * message to be read. When we receive and drop a keepalive or
337 * zero-length message, return EAGAIN so the caller knows that
338 * something was received. This avoids false triggering of the
339 * "server not responding" state machine.
340 *
341 * Calls to this are serialized at a higher level.
342 */
343 static int
nbssn_recv(struct nbpcb * nbp,mblk_t ** mpp,int * lenp,uint8_t * rpcodep)344 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
345 uint8_t *rpcodep)
346 {
347 mblk_t *m0;
348 uint8_t rpcode;
349 int error;
350 size_t rlen, len;
351
352 /* We should be the only reader. */
353 ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
354
355 if (nbp->nbp_tiptr == NULL)
356 return (EBADF);
357 if (mpp) {
358 if (*mpp) {
359 NBDEBUG("*mpp not 0 - leak?");
360 }
361 *mpp = NULL;
362 }
363 m0 = NULL;
364
365 /*
366 * Get the NetBIOS header (not consumed yet)
367 */
368 error = nbssn_peekhdr(nbp, &len, &rpcode);
369 if (error) {
370 if (error != ETIME)
371 NBDEBUG("peekhdr, error=%d\n", error);
372 return (error);
373 }
374 NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
375 (int)rpcode, (int)len);
376
377 /*
378 * Block here waiting for the whole packet to arrive.
379 * If we get a timeout, return without side effects.
380 * The data length we wait for here includes both the
381 * NetBIOS header and the payload.
382 */
383 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
384 if (error) {
385 NBDEBUG("getmsg(body), error=%d\n", error);
386 return (error);
387 }
388
389 /*
390 * We now have an entire NetBIOS message.
391 * Trim off the NetBIOS header and consume it.
392 * Note: _peekhdr has done pullupmsg for us,
393 * so we know it's safe to advance b_rptr.
394 */
395 m0 = nbp->nbp_frag;
396 m0->b_rptr += 4;
397
398 /*
399 * There may be more data after the message
400 * we're about to return, in which case we
401 * split it and leave the remainder.
402 */
403 rlen = msgdsize(m0);
404 ASSERT(rlen >= len);
405 nbp->nbp_frag = NULL;
406 if (rlen > len)
407 nbp->nbp_frag = m_split(m0, len, 1);
408
409 if (nbp->nbp_state != NBST_SESSION) {
410 /*
411 * No session is established.
412 * Return whatever packet we got.
413 */
414 goto out;
415 }
416
417 /*
418 * A session is established; the only packets
419 * we should see are session message and
420 * keep-alive packets. Drop anything else.
421 */
422 switch (rpcode) {
423
424 case NB_SSN_KEEPALIVE:
425 /*
426 * It's a keepalive. Discard any data in it
427 * (there's not supposed to be any, but that
428 * doesn't mean some server won't send some)
429 */
430 if (len)
431 NBDEBUG("Keepalive with data %d\n", (int)len);
432 error = EAGAIN;
433 break;
434
435 case NB_SSN_MESSAGE:
436 /*
437 * Session message. Does it have any data?
438 */
439 if (len == 0) {
440 /*
441 * No data - treat as keepalive (drop).
442 */
443 error = EAGAIN;
444 break;
445 }
446 /*
447 * Yes, has data. Return it.
448 */
449 error = 0;
450 break;
451
452 default:
453 /*
454 * Drop anything else.
455 */
456 NBDEBUG("non-session packet %x\n", rpcode);
457 error = EAGAIN;
458 break;
459 }
460
461 out:
462 if (error) {
463 if (m0)
464 m_freem(m0);
465 return (error);
466 }
467 if (mpp)
468 *mpp = m0;
469 else
470 m_freem(m0);
471 *lenp = (int)len;
472 *rpcodep = rpcode;
473 return (0);
474 }
475
476 /*
477 * SMB transport interface
478 *
479 * This is called only by the thread creating this endpoint,
480 * so we're single-threaded here.
481 */
482 static int
smb_nbst_create(struct smb_vc * vcp,cred_t * cr)483 smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
484 {
485 TIUSER *tiptr = NULL;
486 struct nbpcb *nbp = NULL;
487 dev_t dev;
488 int rc;
489 ushort_t fmode;
490
491 switch (vcp->vc_srvaddr.sa.sa_family) {
492 case AF_INET:
493 dev = nsmb_dev_tcp;
494 break;
495 case AF_INET6:
496 dev = nsmb_dev_tcp6;
497 break;
498 default:
499 return (EAFNOSUPPORT);
500 }
501
502 fmode = FREAD|FWRITE;
503 rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
504 if (rc != 0) {
505 cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
506 return (rc);
507 }
508 ASSERT(tiptr != NULL);
509
510 nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
511
512 nbp->nbp_timo.tv_sec = SMB_NBTIMO;
513 nbp->nbp_state = NBST_IDLE;
514 nbp->nbp_vc = vcp;
515 nbp->nbp_tiptr = tiptr;
516 nbp->nbp_fmode = fmode;
517 nbp->nbp_cred = cr;
518 crhold(cr);
519 mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
520
521 vcp->vc_tdata = nbp;
522
523 return (0);
524 }
525
526 /*
527 * destroy a transport endpoint
528 *
529 * This is called only by the thread with the last reference
530 * to this endpoint, so we're single-threaded here.
531 */
532 static int
smb_nbst_done(struct smb_vc * vcp)533 smb_nbst_done(struct smb_vc *vcp)
534 {
535 struct nbpcb *nbp = vcp->vc_tdata;
536
537 if (nbp == NULL)
538 return (ENOTCONN);
539 vcp->vc_tdata = NULL;
540
541 /*
542 * Don't really need to disconnect here,
543 * because the close following will do it.
544 * But it's harmless.
545 */
546 if (nbp->nbp_flags & NBF_CONNECTED)
547 (void) nb_disconnect(nbp);
548 if (nbp->nbp_tiptr)
549 (void) t_kclose(nbp->nbp_tiptr, 0);
550 if (nbp->nbp_laddr)
551 smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
552 if (nbp->nbp_paddr)
553 smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
554 if (nbp->nbp_cred)
555 crfree(nbp->nbp_cred);
556 mutex_destroy(&nbp->nbp_lock);
557 kmem_free(nbp, sizeof (*nbp));
558 return (0);
559 }
560
561 static int
smb_nbst_bind(struct smb_vc * vcp,struct sockaddr * sap)562 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
563 {
564 struct nbpcb *nbp = vcp->vc_tdata;
565 TIUSER *tiptr = nbp->nbp_tiptr;
566 int err;
567
568 /* Only default bind supported. */
569 if (sap != NULL)
570 return (ENOTSUP);
571
572 err = t_kbind(tiptr, NULL, NULL);
573
574 return (err);
575 }
576
577 static int
smb_nbst_unbind(struct smb_vc * vcp)578 smb_nbst_unbind(struct smb_vc *vcp)
579 {
580 struct nbpcb *nbp = vcp->vc_tdata;
581 TIUSER *tiptr = nbp->nbp_tiptr;
582 int err;
583
584 err = t_kunbind(tiptr);
585
586 return (err);
587 }
588
589 static int
smb_nbst_connect(struct smb_vc * vcp,struct sockaddr * sap)590 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
591 {
592 struct t_call call;
593 struct nbpcb *nbp = vcp->vc_tdata;
594 TIUSER *tiptr = nbp->nbp_tiptr;
595 int alen, err;
596
597 /* Need the address length */
598 switch (sap->sa_family) {
599 case AF_INET:
600 alen = sizeof (struct sockaddr_in);
601 break;
602 case AF_INET6:
603 alen = sizeof (struct sockaddr_in6);
604 break;
605 default:
606 return (EAFNOSUPPORT);
607 }
608
609 /* sockaddr goes in the "addr" netbuf */
610 bzero(&call, sizeof (call));
611 call.addr.buf = (char *)sap;
612 call.addr.len = alen;
613 call.addr.maxlen = alen;
614
615 err = t_kconnect(tiptr, &call, NULL);
616 if (err != 0)
617 return (err);
618
619 mutex_enter(&nbp->nbp_lock);
620
621 nbp->nbp_flags |= NBF_CONNECTED;
622 nbp->nbp_state = NBST_SESSION;
623
624 mutex_exit(&nbp->nbp_lock);
625
626 return (0);
627 }
628
629 static int
smb_nbst_disconnect(struct smb_vc * vcp)630 smb_nbst_disconnect(struct smb_vc *vcp)
631 {
632 struct nbpcb *nbp = vcp->vc_tdata;
633
634 if (nbp == NULL)
635 return (ENOTCONN);
636
637 return (nb_disconnect(nbp));
638 }
639
640 static int
nb_disconnect(struct nbpcb * nbp)641 nb_disconnect(struct nbpcb *nbp)
642 {
643 int err = 0;
644
645 mutex_enter(&nbp->nbp_lock);
646
647 if ((nbp->nbp_flags & NBF_CONNECTED) != 0) {
648 nbp->nbp_flags &= ~NBF_CONNECTED;
649 err = nb_snddis(nbp);
650 }
651
652 mutex_exit(&nbp->nbp_lock);
653 return (err);
654 }
655
656 /*
657 * Add the NetBIOS session header and send.
658 *
659 * Calls to this are serialized at a higher level.
660 */
661 static int
nbssn_send(struct nbpcb * nbp,mblk_t * m)662 nbssn_send(struct nbpcb *nbp, mblk_t *m)
663 {
664 ptrdiff_t diff;
665 uint32_t mlen;
666 int error;
667
668 /* We should be the only sender. */
669 ASSERT(nbp->nbp_flags & NBF_SENDLOCK);
670
671 if (nbp->nbp_tiptr == NULL) {
672 error = EBADF;
673 goto errout;
674 }
675
676 /*
677 * Get the message length, which
678 * does NOT include the NetBIOS header
679 */
680 mlen = msgdsize(m);
681
682 /*
683 * Normally, mb_init() will have left space
684 * for us to prepend the NetBIOS header in
685 * the data block of the first mblk.
686 * However, we have to check in case other
687 * code did not leave this space, or if the
688 * message is from dupmsg (db_ref > 1)
689 *
690 * If don't find room in the first data block,
691 * we have to allocb a new message and link it
692 * on the front of the chain. We try not to
693 * do this becuase it's less efficient. Also,
694 * some network drivers will apparently send
695 * each mblk in the chain as separate frames.
696 * (That's arguably a driver bug.)
697 *
698 * Not bothering with allocb_cred_wait below
699 * because the message we're prepending to
700 * should already have a db_credp.
701 */
702
703 diff = MBLKHEAD(m);
704 if (diff == 4 && DB_REF(m) == 1) {
705 /* We can use the first dblk. */
706 m->b_rptr -= 4;
707 } else {
708 /* Link a new mblk on the head. */
709 mblk_t *m0;
710
711 /* M_PREPEND */
712 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
713 if (m0 == NULL)
714 goto errout;
715
716 m0->b_wptr += 4;
717 m0->b_cont = m;
718 m = m0;
719 }
720
721 nb_sethdr(m, NB_SSN_MESSAGE, mlen);
722 error = tli_send(nbp->nbp_tiptr, m, 0);
723 return (error);
724
725 errout:
726 if (m != NULL)
727 m_freem(m);
728 return (error);
729 }
730
731 /*
732 * Always consume the message.
733 * (On error too!)
734 */
735 static int
smb_nbst_send(struct smb_vc * vcp,mblk_t * m)736 smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
737 {
738 struct nbpcb *nbp = vcp->vc_tdata;
739 int err;
740
741 mutex_enter(&nbp->nbp_lock);
742 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
743 err = ENOTCONN;
744 goto out;
745 }
746 if (nbp->nbp_flags & NBF_SENDLOCK) {
747 NBDEBUG("multiple smb_nbst_send!\n");
748 err = EWOULDBLOCK;
749 goto out;
750 }
751 nbp->nbp_flags |= NBF_SENDLOCK;
752 mutex_exit(&nbp->nbp_lock);
753
754 err = nbssn_send(nbp, m);
755 m = NULL; /* nbssn_send always consumes this */
756
757 mutex_enter(&nbp->nbp_lock);
758 nbp->nbp_flags &= ~NBF_SENDLOCK;
759 if (nbp->nbp_flags & NBF_LOCKWAIT) {
760 nbp->nbp_flags &= ~NBF_LOCKWAIT;
761 cv_broadcast(&nbp->nbp_cv);
762 }
763 out:
764 mutex_exit(&nbp->nbp_lock);
765 if (m != NULL)
766 m_freem(m);
767 return (err);
768 }
769
770 static int
smb_nbst_recv(struct smb_vc * vcp,mblk_t ** mpp)771 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
772 {
773 struct nbpcb *nbp = vcp->vc_tdata;
774 uint8_t rpcode;
775 int err, rplen;
776
777 mutex_enter(&nbp->nbp_lock);
778 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) {
779 err = ENOTCONN;
780 goto out;
781 }
782 if (nbp->nbp_flags & NBF_RECVLOCK) {
783 NBDEBUG("multiple smb_nbst_recv!\n");
784 err = EWOULDBLOCK;
785 goto out;
786 }
787 nbp->nbp_flags |= NBF_RECVLOCK;
788 mutex_exit(&nbp->nbp_lock);
789
790 err = nbssn_recv(nbp, mpp, &rplen, &rpcode);
791
792 mutex_enter(&nbp->nbp_lock);
793 nbp->nbp_flags &= ~NBF_RECVLOCK;
794 if (nbp->nbp_flags & NBF_LOCKWAIT) {
795 nbp->nbp_flags &= ~NBF_LOCKWAIT;
796 cv_broadcast(&nbp->nbp_cv);
797 }
798 out:
799 mutex_exit(&nbp->nbp_lock);
800 return (err);
801 }
802
803 /*
804 * Wait for up to "ticks" clock ticks for input on vcp.
805 * Returns zero if input is available, otherwise ETIME
806 * indicating time expired, or other error codes.
807 */
808 /*ARGSUSED*/
809 static int
smb_nbst_poll(struct smb_vc * vcp,int ticks)810 smb_nbst_poll(struct smb_vc *vcp, int ticks)
811 {
812 return (ENOTSUP);
813 }
814
815 /*ARGSUSED*/
816 static int
smb_nbst_getparam(struct smb_vc * vcp,int param,void * data)817 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
818 {
819 return (EINVAL);
820 }
821
822 static int
smb_nbst_setparam(struct smb_vc * vcp,int param,void * data)823 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
824 {
825 struct t_optmgmt oreq, ores;
826 struct {
827 struct T_opthdr oh;
828 int ival;
829 } opts;
830 struct nbpcb *nbp = vcp->vc_tdata;
831 int level, name, err;
832
833 switch (param) {
834 case SMBTP_TCP_NODELAY:
835 level = IPPROTO_TCP;
836 name = TCP_NODELAY;
837 break;
838
839 case SMBTP_TCP_CON_TMO: /* int mSec */
840 level = IPPROTO_TCP;
841 name = TCP_CONN_ABORT_THRESHOLD;
842 break;
843
844 case SMBTP_KEEPALIVE: // SO_KEEPALIVE
845 case SMBTP_SNDBUF: // SO_SNDBUF
846 case SMBTP_RCVBUF: // SO_RCVBUF
847 case SMBTP_RCVTIMEO: // SO_RCVTIMEO
848 level = SOL_SOCKET;
849 name = param;
850 break;
851
852 default:
853 return (EINVAL);
854 }
855
856 /* opt header */
857 opts.oh.len = sizeof (opts);
858 opts.oh.level = level;
859 opts.oh.name = name;
860 opts.oh.status = 0;
861 opts.ival = *(int *)data;
862
863 oreq.flags = T_NEGOTIATE;
864 oreq.opt.buf = (void *)&opts;
865 oreq.opt.len = sizeof (opts);
866 oreq.opt.maxlen = oreq.opt.len;
867
868 ores.flags = 0;
869 ores.opt.buf = NULL;
870 ores.opt.len = 0;
871 ores.opt.maxlen = 0;
872
873 err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
874 if (err != 0) {
875 cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
876 return (EPROTO);
877 }
878
879 if ((ores.flags & T_SUCCESS) == 0) {
880 cmn_err(CE_NOTE, "smb_nbst_setparam: "
881 "flags 0x%x, status 0x%x",
882 (int)ores.flags, (int)opts.oh.status);
883 return (EPROTO);
884 }
885
886 return (0);
887 }
888
889 /*
890 * Check for fatal errors
891 */
892 /*ARGSUSED*/
893 static int
smb_nbst_fatal(struct smb_vc * vcp,int error)894 smb_nbst_fatal(struct smb_vc *vcp, int error)
895 {
896 switch (error) {
897 case ENOTCONN:
898 case ENETRESET:
899 case ECONNABORTED:
900 case EPIPE:
901 return (1);
902 }
903 return (0);
904 }
905
906
907 struct smb_tran_desc smb_tran_nbtcp_desc = {
908 SMBT_NBTCP,
909 smb_nbst_create,
910 smb_nbst_done,
911 smb_nbst_bind,
912 smb_nbst_unbind,
913 smb_nbst_connect,
914 smb_nbst_disconnect,
915 smb_nbst_send,
916 smb_nbst_recv,
917 smb_nbst_poll,
918 smb_nbst_getparam,
919 smb_nbst_setparam,
920 smb_nbst_fatal,
921 {NULL, NULL}
922 };
923