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