Annotation of src/sys/netsmb/smb_rq.c, Revision 1.1
1.1 ! deberg 1: /* $NetBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2000, Boris Popov
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Boris Popov.
! 18: * 4. Neither the name of the author nor the names of any co-contributors
! 19: * may be used to endorse or promote products derived from this software
! 20: * without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 32: * SUCH DAMAGE.
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/malloc.h>
! 39: #include <sys/proc.h>
! 40: #include <sys/lock.h>
! 41: #include <uvm/uvm_extern.h>
! 42: #include <sys/sysctl.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/socketvar.h>
! 45: #include <sys/mbuf.h>
! 46:
! 47: #include <sys/subr_mbuf.h>
! 48: #include <sys/tree.h>
! 49:
! 50: #include <netsmb/smb.h>
! 51: #include <netsmb/smb_conn.h>
! 52: #include <netsmb/smb_rq.h>
! 53: #include <netsmb/smb_subr.h>
! 54: #include <netsmb/smb_tran.h>
! 55:
! 56: #ifndef NetBSD
! 57: MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
! 58: #endif
! 59:
! 60: static int smb_rq_recv(struct smb_rq *arqp);
! 61: static int smb_rq_send(struct smb_rq *rqp);
! 62: static int smb_rq_reply(struct smb_rq *rqp);
! 63: static int smb_rq_add(struct smb_rq *rqp);
! 64: static void smb_rq_remove(struct smb_rq *rqp);
! 65: static int smb_rq_rcvlock(struct smb_rq *rqp);
! 66: static int smb_rq_rcvunlock(struct smb_rq *rqp);
! 67:
! 68: static int smb_rq_getenv(struct tnode *layer, struct smb_conn **scpp,
! 69: struct smb_vc **vcpp, struct smb_share **sspp);
! 70: static int smb_rq_new(struct smb_rq *rqp, u_char cmd);
! 71: static int smb_t2_reply(struct smb_t2rq *t2p);
! 72:
! 73: int
! 74: smb_rq_alloc(struct tnode *layer, u_char cmd, struct smb_cred *scred,
! 75: struct smb_rq **rqpp)
! 76: {
! 77: struct smb_rq *rqp;
! 78: int error;
! 79:
! 80: MALLOC(rqp, struct smb_rq *, sizeof(*rqp), M_SMBRQ, M_WAITOK);
! 81: if (rqp == NULL)
! 82: return ENOMEM;
! 83: error = smb_rq_init(rqp, layer, cmd, scred);
! 84: rqp->sr_flags |= SMBR_ALLOCED;
! 85: if (error) {
! 86: smb_rq_done(rqp);
! 87: return error;
! 88: }
! 89: *rqpp = rqp;
! 90: return 0;
! 91: }
! 92:
! 93: static char tzero[12];
! 94:
! 95: int
! 96: smb_rq_init(struct smb_rq *rqp, struct tnode *layer, u_char cmd,
! 97: struct smb_cred *scred)
! 98: {
! 99: int error;
! 100:
! 101: bzero(rqp, sizeof(*rqp));
! 102: simple_lock_init(&rqp->sr_slock);
! 103: error = smb_rq_getenv(layer, &rqp->sr_conn, &rqp->sr_vc, &rqp->sr_share);
! 104: if (error)
! 105: return error;
! 106: error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
! 107: if (error)
! 108: return error;
! 109: if (rqp->sr_share) {
! 110: error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
! 111: if (error)
! 112: return error;
! 113: }
! 114: rqp->sr_cred = scred;
! 115: rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
! 116: return smb_rq_new(rqp, cmd);
! 117: }
! 118:
! 119: static int
! 120: smb_rq_new(struct smb_rq *rqp, u_char cmd)
! 121: {
! 122: struct smb_vc *vcp = rqp->sr_vc;
! 123: struct mbdata *mbp = &rqp->sr_rq;
! 124: int error;
! 125:
! 126: mb_done(mbp);
! 127: mb_done(&rqp->sr_rp);
! 128: error = mb_init(mbp);
! 129: if (error)
! 130: return error;
! 131: mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
! 132: mb_put_byte(mbp, cmd);
! 133: mb_put_dwordle(mbp, 0); /* DosError */
! 134: mb_put_byte(mbp, vcp->vc_hflags);
! 135: mb_put_wordle(mbp, vcp->vc_hflags2);
! 136: mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
! 137: rqp->sr_rqtid = (u_int16_t*)mb_fit(mbp, sizeof(u_int16_t));
! 138: mb_put_wordle(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
! 139: rqp->sr_rquid = (u_int16_t*)mb_fit(mbp, sizeof(u_int16_t));
! 140: mb_put_wordle(mbp, rqp->sr_mid);
! 141: return 0;
! 142: }
! 143:
! 144: void
! 145: smb_rq_done(struct smb_rq *rqp)
! 146: {
! 147: mb_done(&rqp->sr_rq);
! 148: mb_done(&rqp->sr_rp);
! 149: if (rqp->sr_flags & SMBR_ALLOCED)
! 150: free(rqp, M_SMBRQ);
! 151: }
! 152:
! 153: /*
! 154: * Simple request-reply exchange
! 155: */
! 156: int
! 157: smb_rq_simple(struct smb_rq *rqp)
! 158: {
! 159: struct smb_conn *scp = rqp->sr_conn;
! 160: int error = EINVAL, i;
! 161:
! 162: for (i = 0; i < SMB_MAXRCN; i++) {
! 163: rqp->sr_flags &= ~SMBR_RESTART;
! 164: rqp->sr_timo = scp->sc_timo;
! 165: error = smb_rq_add(rqp);
! 166: if (error)
! 167: return error;
! 168: error = smb_rq_send(rqp);
! 169: if (!error)
! 170: error = smb_rq_reply(rqp);
! 171: smb_rq_remove(rqp);
! 172: if (error == 0)
! 173: break;
! 174: if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
! 175: break;
! 176: }
! 177: return error;
! 178: }
! 179:
! 180: static int
! 181: smb_rq_add(struct smb_rq *rqp)
! 182: {
! 183: struct smb_vc *vcp = rqp->sr_vc;
! 184: struct proc *p = rqp->sr_cred->scr_p;
! 185: int error;
! 186:
! 187: SMBSDEBUG("M:%d\n", rqp->sr_mid);
! 188: for (;;) {
! 189: error = smb_vc_rqlock(vcp, p);
! 190: if (error)
! 191: return error;
! 192: /*
! 193: * if connection is marked as invalid and we're the only request,
! 194: * try to restore it. Otherwise we have to wait.
! 195: */
! 196: if ((vcp->vc_flags & (SMBV_INVALID | SMBV_RECONNECTING)) == SMBV_INVALID) {
! 197: vcp->vc_flags |= SMBV_RECONNECTING;
! 198: vcp->vc_scred = rqp->sr_cred;
! 199: smb_vc_rqunlock(vcp, p);
! 200: SMBSDEBUG("reconnect\n");
! 201: error = smb_vc_reconnect(vcp);
! 202: vcp->vc_flags &= ~SMBV_RECONNECTING;
! 203: /*
! 204: * If we're still not connected, just bail out
! 205: */
! 206: if (error)
! 207: return error;
! 208: continue;
! 209: }
! 210: if (vcp->vc_flags & SMBV_RECONNECTING) {
! 211: if (vcp->vc_scred == rqp->sr_cred)
! 212: break;
! 213: } else if (vcp->vc_maxmux == 0 ||
! 214: vcp->vc_muxcnt < vcp->vc_maxmux)
! 215: break;
! 216: SMBSDEBUG("sleep\n");
! 217: vcp->vc_muxwant++;
! 218: #ifndef NetBSD
! 219: asleep(&vcp->vc_muxwant, PWAIT, "smbmx", 0);
! 220: smb_vc_rqunlock(vcp, p);
! 221: await(PWAIT, 0);
! 222: #else
! 223: smb_vc_rqunlock(vcp, p);
! 224: tsleep(&vcp->vc_muxwant, PWAIT, "smbmx", 0);
! 225: #endif
! 226: }
! 227: vcp->vc_muxcnt++;
! 228: TAILQ_INSERT_TAIL(&vcp->vc_rqlist, rqp, sr_link);
! 229: smb_vc_rqunlock(vcp, p);
! 230: return 0;
! 231: }
! 232:
! 233: static void
! 234: smb_rq_remove(struct smb_rq *rqp)
! 235: {
! 236: struct smb_vc *vcp = rqp->sr_vc;
! 237: struct proc *p = rqp->sr_cred->scr_p;
! 238:
! 239: SMBSDEBUG("M:%d\n", rqp->sr_mid);
! 240: if (smb_vc_rqlock(vcp, p) != 0) {
! 241: SMBERROR("can't lock connection");
! 242: return;
! 243: }
! 244: TAILQ_REMOVE(&vcp->vc_rqlist, rqp, sr_link);
! 245: vcp->vc_muxcnt--;
! 246: if (vcp->vc_muxwant) {
! 247: vcp->vc_muxwant--;
! 248: wakeup(&vcp->vc_muxwant);
! 249: }
! 250: smb_vc_rqunlock(vcp, p);
! 251: }
! 252:
! 253: void
! 254: smb_rq_wstart(struct smb_rq *rqp)
! 255: {
! 256: rqp->sr_wcount = mb_fit(&rqp->sr_rq, sizeof(u_int8_t));
! 257: rqp->sr_rq.mb_count = 0;
! 258: }
! 259:
! 260: void
! 261: smb_rq_wend(struct smb_rq *rqp)
! 262: {
! 263: if (rqp->sr_wcount == NULL) {
! 264: SMBERROR("no wcount\n"); /* actually panic */
! 265: return;
! 266: }
! 267: if (rqp->sr_rq.mb_count & 1)
! 268: SMBERROR("odd word count\n");
! 269: *rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
! 270: }
! 271:
! 272: void
! 273: smb_rq_bstart(struct smb_rq *rqp)
! 274: {
! 275: rqp->sr_bcount = (u_short*)mb_fit(&rqp->sr_rq, sizeof(u_short));
! 276: rqp->sr_rq.mb_count = 0;
! 277: }
! 278:
! 279: void
! 280: smb_rq_bend(struct smb_rq *rqp)
! 281: {
! 282: int bcnt;
! 283:
! 284: if (rqp->sr_bcount == NULL) {
! 285: SMBERROR("no bcount\n"); /* actually panic */
! 286: return;
! 287: }
! 288: bcnt = rqp->sr_rq.mb_count;
! 289: if (bcnt > 0xffff)
! 290: SMBERROR("byte count too large (%d)\n", bcnt);
! 291: *rqp->sr_bcount = bcnt;
! 292: }
! 293:
! 294: int
! 295: smb_rq_intr(struct smb_rq *rqp)
! 296: {
! 297: struct proc *p = rqp->sr_cred->scr_p;
! 298:
! 299: if (rqp->sr_flags & SMBR_INTR)
! 300: return EINTR;
! 301: return smb_proc_intr(p);
! 302: }
! 303:
! 304: int
! 305: smb_tran_sndlock(struct smb_rq *rqp)
! 306: {
! 307: u_int *statep = &rqp->sr_vc->vc_locks;
! 308: int slpflag = 0, slptimeo = 0;
! 309:
! 310: slpflag = PCATCH;
! 311: if (rqp->sr_flags & SMBR_RESTART)
! 312: return EINTR;
! 313: while (*statep & SMBV_SNDLOCK) {
! 314: if (smb_rq_intr(rqp))
! 315: return EINTR;
! 316: if (rqp->sr_flags & SMBR_RESTART)
! 317: return EINTR;
! 318: *statep |= SMBV_SNDWANT;
! 319: (void)tsleep((caddr_t)statep, slpflag | (PZERO - 1),
! 320: "smbslck", slptimeo);
! 321: if (slpflag == PCATCH) {
! 322: slpflag = 0;
! 323: slptimeo = 2 * hz;
! 324: }
! 325: }
! 326: *statep |= SMBV_SNDLOCK;
! 327: return 0;
! 328: }
! 329:
! 330: int
! 331: smb_tran_sndunlock(struct smb_rq *rqp)
! 332: {
! 333: u_int *statep = &rqp->sr_vc->vc_locks;
! 334:
! 335: if ((*statep & SMBV_SNDLOCK) == 0)
! 336: SMBPANIC("not locked\n");
! 337: *statep &= ~SMBV_SNDLOCK;
! 338: if (*statep & SMBV_SNDWANT) {
! 339: *statep &= ~SMBV_SNDWANT;
! 340: wakeup((caddr_t)statep);
! 341: }
! 342: return 0;
! 343: }
! 344:
! 345: static void
! 346: smb_printrqlist(struct smb_vc *vcp)
! 347: {
! 348: #if 0
! 349: struct smb_rq *rqp;
! 350: TAILQ_FOREACH(rqp, &scp->sc_rqlist, sr_link) {
! 351: printf("RQ: MID=%d, GOTRESPONCE=%s\n", (u_int)rqp->sr_mid,
! 352: rqp->sr_rp.mb_top ? "yes" : "no");
! 353: }
! 354: #endif
! 355: }
! 356:
! 357: static int
! 358: smb_rq_rcvlock(struct smb_rq *rqp)
! 359: {
! 360: u_int *statep = &rqp->sr_vc->vc_locks;
! 361: int slpflag, slptimeo = 0;
! 362:
! 363: if (rqp->sr_rp.mb_top)
! 364: return EALREADY;
! 365: if (rqp->sr_flags & SMBR_RESTART)
! 366: return EINTR;
! 367: slpflag = PCATCH;
! 368: while (*statep & SMBV_RCVLOCK) {
! 369: if (smb_rq_intr(rqp))
! 370: return EINTR;
! 371: *statep |= SMBV_RCVWANT;
! 372: (void)tsleep((caddr_t)statep, slpflag | (PZERO - 1), "smbrlck",
! 373: slptimeo);
! 374:
! 375: if (rqp->sr_rp.mb_top)
! 376: return EALREADY;
! 377: if (rqp->sr_flags & SMBR_RESTART)
! 378: return EINTR;
! 379: if (slpflag == PCATCH) {
! 380: slpflag = 0;
! 381: slptimeo = 2 * hz;
! 382: }
! 383: /*
! 384: printf("sleep: MID=%d, MUX=%d, NEXTMID=%d\n", (u_int)rqp->sr_mid,
! 385: rqp->sr_conn->sc_muxcnt, (u_int)rqp->sr_conn->sc_mid);
! 386: smb_printrqlist(rqp->sr_conn);
! 387: */
! 388: }
! 389: *statep |= SMBV_RCVLOCK;
! 390: return 0;
! 391: }
! 392:
! 393: static int
! 394: smb_rq_rcvunlock(struct smb_rq *rqp)
! 395: {
! 396: u_int *statep = &rqp->sr_vc->vc_locks;
! 397:
! 398: if ((*statep & SMBV_RCVLOCK) == 0)
! 399: SMBPANIC("not locked");
! 400: *statep &= ~SMBV_RCVLOCK;
! 401: if (*statep & SMBV_RCVWANT) {
! 402: *statep &= ~SMBV_RCVWANT;
! 403: wakeup((caddr_t)statep);
! 404: }
! 405: return 0;
! 406: }
! 407:
! 408: int
! 409: smb_rq_getrequest(struct smb_rq *rqp, struct mbdata **mbpp)
! 410: {
! 411: *mbpp = &rqp->sr_rq;
! 412: return 0;
! 413: }
! 414:
! 415: int
! 416: smb_rq_getreply(struct smb_rq *rqp, struct mbdata **mbpp)
! 417: {
! 418: *mbpp = &rqp->sr_rp;
! 419: return 0;
! 420: }
! 421:
! 422: static int
! 423: smb_rq_getenv(struct tnode *layer, struct smb_conn **scpp,
! 424: struct smb_vc **vcpp, struct smb_share **sspp)
! 425: {
! 426: struct smb_conn *scp = NULL;
! 427: struct smb_vc *vcp = NULL;
! 428: struct smb_share *ssp = NULL;
! 429: struct tnode *tp;
! 430: int error = 0;
! 431:
! 432: switch (TTYPE(layer)) {
! 433: case TSMB_CONN:
! 434: scp = TNTOCN(layer);
! 435: break;
! 436: case TSMB_VC:
! 437: vcp = TNTOVC(layer);
! 438: tp = layer->t_parent;
! 439: if (tp == NULL) {
! 440: SMBERROR("zombie VC %s\n", layer->t_name);
! 441: error = EINVAL;
! 442: break;
! 443: }
! 444: scp = TNTOCN(tp);
! 445: break;
! 446: case TSMB_SHARE:
! 447: ssp = TNTOSS(layer);
! 448: tp = layer->t_parent;
! 449: if (tp == NULL) {
! 450: SMBERROR("zombie share %s\n", layer->t_name);
! 451: error = EINVAL;
! 452: break;
! 453: }
! 454: vcp = TNTOVC(tp);
! 455: tp = tp->t_parent;
! 456: if (tp == NULL) {
! 457: SMBERROR("zombie VC %s\n", layer->t_name);
! 458: error = EINVAL;
! 459: break;
! 460: }
! 461: scp = TNTOCN(tp);
! 462: break;
! 463: default:
! 464: SMBERROR("invalid layer %d passed\n", TTYPE(layer));
! 465: error = EINVAL;
! 466: }
! 467: if (scpp)
! 468: *scpp = scp;
! 469: if (vcpp)
! 470: *vcpp = vcp;
! 471: if (sspp)
! 472: *sspp = ssp;
! 473: return error;
! 474: }
! 475:
! 476: /*
! 477: * Wait for reply on the request
! 478: */
! 479: static int
! 480: smb_rq_reply(struct smb_rq *rqp)
! 481: {
! 482: struct mbdata *mbp = &rqp->sr_rp;
! 483: u_int32_t tdw;
! 484: u_int8_t tb;
! 485: int error, rperror = 0;
! 486:
! 487: error = smb_rq_recv(rqp);
! 488: if (error)
! 489: return error;
! 490: error = mb_get_dword(mbp, &tdw);
! 491: error = mb_get_byte(mbp, &tb);
! 492: if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
! 493: error = mb_get_dwordle(mbp, &rqp->sr_error);
! 494: } else {
! 495: error = mb_get_byte(mbp, &rqp->sr_errclass);
! 496: error = mb_get_byte(mbp, &tb);
! 497: error = mb_get_wordle(mbp, &rqp->sr_serror);
! 498: if (!error)
! 499: rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
! 500: }
! 501: error = mb_get_byte(mbp, &rqp->sr_rpflags);
! 502: error = mb_get_wordle(mbp, &rqp->sr_rpflags2);
! 503:
! 504: error = mb_get_dword(mbp, &tdw);
! 505: error = mb_get_dword(mbp, &tdw);
! 506: error = mb_get_dword(mbp, &tdw);
! 507:
! 508: error = mb_get_wordle(mbp, &rqp->sr_rptid);
! 509: error = mb_get_wordle(mbp, &rqp->sr_rppid);
! 510: error = mb_get_wordle(mbp, &rqp->sr_rpuid);
! 511: error = mb_get_wordle(mbp, &rqp->sr_rpmid);
! 512:
! 513: SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
! 514: rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
! 515: rqp->sr_errclass, rqp->sr_serror);
! 516: return error ? error : rperror;
! 517: }
! 518:
! 519: /*
! 520: * Check for fatal errors
! 521: */
! 522: static __inline int
! 523: smb_rq_fatal(int error)
! 524: {
! 525: switch (error) {
! 526: case ENOTCONN:
! 527: case ENETRESET:
! 528: case ECONNABORTED:
! 529: return 1;
! 530: }
! 531: return 0;
! 532: }
! 533:
! 534: static int
! 535: smb_rq_recv(struct smb_rq *arqp)
! 536: {
! 537: struct smb_vc *vcp = arqp->sr_vc;
! 538: struct proc *p = arqp->sr_cred->scr_p;
! 539: struct smb_rq *rqp;
! 540: struct mbdata *mbp, mb;
! 541: struct mbuf *m;
! 542: u_char *hp;
! 543: u_short mid;
! 544: int error;
! 545:
! 546: #define rcverr(err) do { error = err; goto exit; }while(0)
! 547:
! 548: mbp = &mb;
! 549: for (;;) {
! 550: simple_lock(&arqp->sr_slock);
! 551: error = mb_fetch_record(&arqp->sr_rp);
! 552: simple_unlock(&arqp->sr_slock);
! 553: if (!error)
! 554: return 0;
! 555: bzero(mbp, sizeof(struct mbdata));
! 556: error = smb_rq_rcvlock(arqp);
! 557: if (error == EALREADY)
! 558: return 0;
! 559: if (error)
! 560: return error;
! 561: do {
! 562: error = SMB_TRAN_RECV(vcp, &m, p);
! 563: if (error == EWOULDBLOCK && (arqp->sr_flags & SMBR_INTR)) {
! 564: error = EINTR;
! 565: break;
! 566: }
! 567: } while (error == EWOULDBLOCK);
! 568: if (smb_rq_fatal(error)) {
! 569: smb_vc_invalidate(vcp);
! 570: goto unlock;
! 571: }
! 572: if (error)
! 573: goto unlock;
! 574: if (m == NULL) {
! 575: SMBERROR("tran return a NULL without error\n");
! 576: error = EPIPE;
! 577: goto unlock;
! 578: }
! 579: m = m_pullup(m, SMB_HDRLEN);
! 580: if (m == NULL) {
! 581: smb_rq_rcvunlock(arqp);
! 582: continue; /* wait for a good packet */
! 583: }
! 584: mb_initm(mbp, m);
! 585: /*
! 586: * Now we got an entire and possibly invalid SMB packet.
! 587: * Be careful while parsing it.
! 588: */
! 589: m_dumpm(mbp->mb_top);
! 590: hp = mtod(mbp->mb_top, u_char*);
! 591: if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0)
! 592: rcverr(EBADRPC);
! 593: mid = SMB_HDRMID(hp);
! 594: SMBSDEBUG("mid %04x\n", (u_int)mid);
! 595: smb_vc_rqlock(vcp, p);
! 596: TAILQ_FOREACH(rqp, &vcp->vc_rqlist, sr_link) {
! 597: if (rqp->sr_mid != mid)
! 598: continue;
! 599: if (rqp->sr_rp.mb_top == NULL)
! 600: mb_initm(&rqp->sr_rp, m);
! 601: else {
! 602: simple_lock(&rqp->sr_slock);
! 603: mb_append_record(&rqp->sr_rp, m);
! 604: simple_unlock(&rqp->sr_slock);
! 605: }
! 606: if (rqp == arqp) {
! 607: smb_vc_rqunlock(vcp, p);
! 608: goto unlock;
! 609: }
! 610: break;
! 611: }
! 612: smb_vc_rqunlock(vcp, p);
! 613: if (rqp == NULL) {
! 614: SMBSDEBUG("drop resp with mid %d\n", (u_int)mid);
! 615: smb_printrqlist(vcp);
! 616: mb_done(mbp);
! 617: }
! 618: smb_rq_rcvunlock(arqp);
! 619: }
! 620: exit:
! 621: mb_done(mbp);
! 622: unlock:
! 623: smb_rq_rcvunlock(arqp);
! 624: return error;
! 625: }
! 626:
! 627: static int
! 628: smb_rq_send(struct smb_rq *rqp)
! 629: {
! 630: struct proc *p = rqp->sr_cred->scr_p;
! 631: struct smb_vc *vcp = rqp->sr_vc;
! 632: struct smb_share *ssp = rqp->sr_share;
! 633: struct mbuf *m;
! 634: int error, rcnt, rmax;
! 635:
! 636: rmax = 5; /* TODO: configurable */
! 637: *rqp->sr_rqtid = htoles(ssp ? ssp->ss_id : SMB_TID_UNKNOWN);
! 638: *rqp->sr_rquid = htoles(vcp ? vcp->vc_id : 0);
! 639: mb_fixhdr(&rqp->sr_rq);
! 640: rqp->sr_flags &= ~SMBR_SENT;
! 641: error = ENOTCONN;
! 642: for (rcnt = 0; rcnt < rmax; rcnt++) {
! 643: error = smb_tran_sndlock(rqp);
! 644: if (error)
! 645: return error;
! 646: if (vcp->vc_tdata == NULL) {
! 647: smb_tran_sndunlock(rqp);
! 648: return ENOTCONN;
! 649: }
! 650: SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n",
! 651: rqp->sr_mid, 0, 0, 0);
! 652: m_dumpm(rqp->sr_rq.mb_top);
! 653: m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT);
! 654: error = SMB_TRAN_SEND(vcp, m, p);
! 655: smb_tran_sndunlock(rqp);
! 656: if (error == 0) {
! 657: rqp->sr_flags |= SMBR_SENT;
! 658: return 0;
! 659: }
! 660: /*
! 661: * Check for fatal errors
! 662: */
! 663: if (smb_rq_fatal(error)) {
! 664: smb_vc_invalidate(vcp);
! 665: return error;
! 666: }
! 667: /*
! 668: * These errors are not fatal and can be recovered later
! 669: */
! 670: if (error == EINTR || error == ENETDOWN || error == EPIPE)
! 671: return error;
! 672: if (smb_rq_intr(rqp))
! 673: return EINTR;
! 674: rqp->sr_rexmit = 1;
! 675: tsleep(&rqp->sr_rexmit, PWAIT | PCATCH, "smbrxm", 5 * hz);
! 676: if (smb_rq_intr(rqp))
! 677: return EINTR;
! 678: }
! 679: return error;
! 680: }
! 681:
! 682:
! 683: #define ALIGN4(a) (((a) + 3) & ~3)
! 684:
! 685: /*
! 686: * TRANS2 request implementation
! 687: */
! 688: int
! 689: smb_t2_alloc(struct tnode *layer, u_short setup, struct smb_cred *scred,
! 690: struct smb_t2rq **t2pp)
! 691: {
! 692: struct smb_t2rq *t2p;
! 693: int error;
! 694:
! 695: MALLOC(t2p, struct smb_t2rq *, sizeof(*t2p), M_SMBRQ, M_WAITOK);
! 696: if (t2p == NULL)
! 697: return ENOMEM;
! 698: error = smb_t2_init(t2p, layer, setup, scred);
! 699: t2p->t2_flags |= SMBT2_ALLOCED;
! 700: if (error) {
! 701: smb_t2_done(t2p);
! 702: return error;
! 703: }
! 704: *t2pp = t2p;
! 705: return 0;
! 706: }
! 707:
! 708: int
! 709: smb_t2_init(struct smb_t2rq *t2p, struct tnode *source, u_short setup,
! 710: struct smb_cred *scred)
! 711: {
! 712: int error;
! 713:
! 714: bzero(t2p, sizeof(*t2p));
! 715: t2p->t2_source = source;
! 716: t2p->t2_setupcount = 1;
! 717: t2p->t2_setupdata = t2p->t2_setup;
! 718: t2p->t2_setup[0] = setup;
! 719: t2p->t2_fid = 0xffff;
! 720: t2p->t2_cred = scred;
! 721: error = smb_rq_getenv(source, &t2p->t2_conn,&t2p->t2_vc, NULL);
! 722: if (error)
! 723: return error;
! 724: return 0;
! 725: }
! 726:
! 727: void
! 728: smb_t2_done(struct smb_t2rq *t2p)
! 729: {
! 730: mb_done(&t2p->t2_tparam);
! 731: mb_done(&t2p->t2_tdata);
! 732: mb_done(&t2p->t2_rparam);
! 733: mb_done(&t2p->t2_rdata);
! 734: if (t2p->t2_flags & SMBT2_ALLOCED)
! 735: free(t2p, M_SMBRQ);
! 736: }
! 737:
! 738: static int
! 739: smb_t2_reply(struct smb_t2rq *t2p)
! 740: {
! 741: struct mbuf *m, *m0;
! 742: struct mbdata *mbp;
! 743: struct smb_rq *rqp = t2p->t2_rq;
! 744: int error, totpgot, totdgot, len;
! 745: u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
! 746: u_int16_t tmp, bc, dcount;
! 747: u_int8_t wc;
! 748:
! 749: error = smb_rq_reply(rqp);
! 750: if (error)
! 751: return error;
! 752: if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
! 753: /*
! 754: * this is an interim response, ignore it.
! 755: */
! 756: mb_done(&rqp->sr_rp);
! 757: return 0;
! 758: }
! 759: /*
! 760: * Now we have to get all subseqent responses. The CIFS specification
! 761: * says that they can be misordered which is weird.
! 762: * TODO: timo
! 763: */
! 764: totpgot = totdgot = 0;
! 765: totpcount = totdcount = 0xffff;
! 766: if (mb_init(&t2p->t2_rparam) != 0 || mb_init(&t2p->t2_rdata) != 0)
! 767: return ENOBUFS;
! 768: mbp = &rqp->sr_rp;
! 769: for (;;) {
! 770: m_dumpm(mbp->mb_top);
! 771: mb_get_byte(mbp, &wc);
! 772: mb_get_wordle(mbp, &tmp);
! 773: if (totpcount > tmp)
! 774: totpcount = tmp;
! 775: mb_get_wordle(mbp, &tmp);
! 776: if (totdcount > tmp)
! 777: totdcount = tmp;
! 778: mb_get_wordle(mbp, &tmp); /* reserved */
! 779: mb_get_wordle(mbp, &pcount);
! 780: mb_get_wordle(mbp, &poff);
! 781: mb_get_wordle(mbp, &pdisp);
! 782: if (pcount != 0 && pdisp != totpgot) {
! 783: SMBERROR("Can't handle misordered parameters %d:%d\n",
! 784: pdisp, totpgot);
! 785: error = EINVAL;
! 786: break;
! 787: }
! 788: mb_get_wordle(mbp, &dcount);
! 789: mb_get_wordle(mbp, &doff);
! 790: mb_get_wordle(mbp, &ddisp);
! 791: if (dcount != 0 && ddisp != totdgot) {
! 792: SMBERROR("Can't handle misordered data\n");
! 793: error = EINVAL;
! 794: break;
! 795: }
! 796: mb_get_byte(mbp, &wc);
! 797: mb_get_byte(mbp, NULL);
! 798: tmp = wc;
! 799: while (tmp--)
! 800: mb_get_word(mbp, NULL);
! 801: mb_get_wordle(mbp, &bc);
! 802: /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
! 803: error = EBADRPC;
! 804: if (dcount) {
! 805: m0 = m_split(mbp->mb_top, doff, M_WAIT);
! 806: if (m0 == NULL)
! 807: break;
! 808: for(len = 0, m = m0; m->m_next; m = m->m_next)
! 809: len += m->m_len;
! 810: len += m->m_len;
! 811: m->m_len -= len - dcount;
! 812: m_cat(t2p->t2_rdata.mb_top, m0);
! 813: }
! 814: if (pcount) {
! 815: m0 = m_split(mbp->mb_top, poff, M_WAIT);
! 816: if (m0 == NULL)
! 817: break;
! 818: for(len = 0, m = m0; m->m_next; m = m->m_next)
! 819: len += m->m_len;
! 820: len += m->m_len;
! 821: m->m_len -= len - pcount;
! 822: m_cat(t2p->t2_rparam.mb_top, m0);
! 823: }
! 824: totpgot += pcount;
! 825: totdgot += dcount;
! 826: if (totpgot >= totpcount && totdgot >= totdcount) {
! 827: error = 0;
! 828: t2p->t2_flags |= SMBT2_ALLRECV;
! 829: break;
! 830: }
! 831: error = smb_rq_reply(rqp);
! 832: if (error)
! 833: break;
! 834: }
! 835: return error;
! 836: }
! 837:
! 838: /*
! 839: * Perform a full round of TRANS2 request
! 840: */
! 841: static int
! 842: smb_t2_request_int(struct smb_t2rq *t2p)
! 843: {
! 844: struct mbdata *mbp;
! 845: struct mbuf *m;
! 846: struct smb_rq rq, *rqp = &rq;
! 847: struct smb_vc *vcp = t2p->t2_vc;
! 848: struct smb_cred *scred = t2p->t2_cred;
! 849: int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
! 850: int error, doff, poff, txdcount, txpcount, nmlen;
! 851:
! 852: mbp = &t2p->t2_tparam;
! 853: if (mbp->mb_top) {
! 854: mb_initm(mbp, mbp->mb_top);
! 855: totpcount = mb_fixhdr(mbp);
! 856: if (totpcount > 0xffff) /* maxvalue for u_short */
! 857: return EINVAL;
! 858: } else
! 859: totpcount = 0;
! 860: mbp = &t2p->t2_tdata;
! 861: if (mbp->mb_top) {
! 862: mb_initm(mbp, mbp->mb_top);
! 863: totdcount = mb_fixhdr(mbp);
! 864: if (totdcount > 0xffff)
! 865: return EINVAL;
! 866: } else
! 867: totdcount = 0;
! 868: leftdcount = totdcount;
! 869: leftpcount = totpcount;
! 870: txmax = vcp->vc_txmax;
! 871: error = smb_rq_init(rqp, t2p->t2_source, t2p->t_name ?
! 872: SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred);
! 873: if (error)
! 874: return error;
! 875: t2p->t2_rq = rqp;
! 876: mbp = &rqp->sr_rq;
! 877: smb_rq_wstart(rqp);
! 878: mb_put_wordle(mbp, totpcount);
! 879: mb_put_wordle(mbp, totdcount);
! 880: mb_put_wordle(mbp, t2p->t2_maxpcount);
! 881: mb_put_wordle(mbp, t2p->t2_maxdcount);
! 882: mb_put_byte(mbp, t2p->t2_maxscount);
! 883: mb_put_byte(mbp, 0); /* reserved */
! 884: mb_put_wordle(mbp, 0); /* flags */
! 885: mb_put_dwordle(mbp, 0); /* Timeout */
! 886: mb_put_wordle(mbp, 0); /* reserved 2 */
! 887: len = mb_fixhdr(mbp);
! 888: /*
! 889: * now we have known packet size as
! 890: * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
! 891: * and need to decide which parts should go into the first request
! 892: */
! 893: nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
! 894: len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
! 895: if (len + leftpcount > txmax) {
! 896: txpcount = min(leftpcount, txmax - len);
! 897: poff = len;
! 898: txdcount = 0;
! 899: doff = 0;
! 900: } else {
! 901: txpcount = leftpcount;
! 902: poff = txpcount ? len : 0;
! 903: len = ALIGN4(len + txpcount);
! 904: txdcount = min(leftdcount, txmax - len);
! 905: doff = txdcount ? len : 0;
! 906: }
! 907: leftpcount -= txpcount;
! 908: leftdcount -= txdcount;
! 909: mb_put_wordle(mbp, txpcount);
! 910: mb_put_wordle(mbp, poff);
! 911: mb_put_wordle(mbp, txdcount);
! 912: mb_put_wordle(mbp, doff);
! 913: mb_put_byte(mbp, t2p->t2_setupcount);
! 914: mb_put_byte(mbp, 0);
! 915: for (i = 0; i < t2p->t2_setupcount; i++)
! 916: mb_put_wordle(mbp, t2p->t2_setupdata[i]);
! 917: smb_rq_wend(rqp);
! 918: smb_rq_bstart(rqp);
! 919: /* TDUNICODE */
! 920: if (t2p->t_name)
! 921: mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
! 922: mb_put_byte(mbp, 0); /* terminating zero */
! 923: len = mb_fixhdr(mbp);
! 924: if (txpcount) {
! 925: mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
! 926: error = mb_get_mbuf(&t2p->t2_tparam, txpcount, &m);
! 927: SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
! 928: if (error)
! 929: goto freerq;
! 930: mb_put_mbuf(mbp, m);
! 931: }
! 932: len = mb_fixhdr(mbp);
! 933: if (txdcount) {
! 934: mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
! 935: error = mb_get_mbuf(&t2p->t2_tdata, txdcount, &m);
! 936: if (error)
! 937: goto freerq;
! 938: mb_put_mbuf(mbp, m);
! 939: }
! 940: smb_rq_bend(rqp); /* incredible, but thats it... */
! 941: error = smb_rq_add(rqp);
! 942: if (error)
! 943: goto freerq;
! 944: error = smb_rq_send(rqp);
! 945: if (error)
! 946: goto bad;
! 947: if (leftpcount == 0 && leftdcount == 0)
! 948: t2p->t2_flags |= SMBT2_ALLSENT;
! 949: error = smb_t2_reply(t2p);
! 950: if (error)
! 951: goto bad;
! 952: while (leftpcount || leftdcount) {
! 953: error = smb_rq_new(rqp, t2p->t_name ?
! 954: SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
! 955: if (error)
! 956: goto bad;
! 957: mbp = &rqp->sr_rq;
! 958: smb_rq_wstart(rqp);
! 959: mb_put_wordle(mbp, totpcount);
! 960: mb_put_wordle(mbp, totdcount);
! 961: len = mb_fixhdr(mbp);
! 962: /*
! 963: * now we have known packet size as
! 964: * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
! 965: * and need to decide which parts should go into request
! 966: */
! 967: len = ALIGN4(len + 6 * 2 + 2);
! 968: if (t2p->t_name == NULL)
! 969: len += 2;
! 970: if (len + leftpcount > txmax) {
! 971: txpcount = min(leftpcount, txmax - len);
! 972: poff = len;
! 973: txdcount = 0;
! 974: doff = 0;
! 975: } else {
! 976: txpcount = leftpcount;
! 977: poff = txpcount ? len : 0;
! 978: len = ALIGN4(len + txpcount);
! 979: txdcount = min(leftdcount, txmax - len);
! 980: doff = txdcount ? len : 0;
! 981: }
! 982: mb_put_wordle(mbp, txpcount);
! 983: mb_put_wordle(mbp, poff);
! 984: mb_put_wordle(mbp, totpcount - leftpcount);
! 985: mb_put_wordle(mbp, txdcount);
! 986: mb_put_wordle(mbp, doff);
! 987: mb_put_wordle(mbp, totdcount - leftdcount);
! 988: leftpcount -= txpcount;
! 989: leftdcount -= txdcount;
! 990: if (t2p->t_name == NULL)
! 991: mb_put_wordle(mbp, t2p->t2_fid);
! 992: smb_rq_wend(rqp);
! 993: smb_rq_bstart(rqp);
! 994: mb_put_byte(mbp, 0); /* name */
! 995: len = mb_fixhdr(mbp);
! 996: if (txpcount) {
! 997: mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
! 998: error = mb_get_mbuf(&t2p->t2_tparam, txpcount, &m);
! 999: if (error)
! 1000: goto bad;
! 1001: mb_put_mbuf(mbp, m);
! 1002: }
! 1003: len = mb_fixhdr(mbp);
! 1004: if (txdcount) {
! 1005: mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
! 1006: error = mb_get_mbuf(&t2p->t2_tdata, txdcount, &m);
! 1007: if (error)
! 1008: goto bad;
! 1009: mb_put_mbuf(mbp, m);
! 1010: }
! 1011: smb_rq_bend(rqp);
! 1012: error = smb_rq_send(rqp);
! 1013: if (error)
! 1014: goto bad;
! 1015: } /* while left params or data */
! 1016: t2p->t2_flags |= SMBT2_ALLSENT;
! 1017: mbp = &t2p->t2_rdata;
! 1018: if (mbp->mb_top) {
! 1019: m_fixhdr(mbp->mb_top);
! 1020: mb_initm(mbp, mbp->mb_top);
! 1021: }
! 1022: mbp = &t2p->t2_rparam;
! 1023: if (mbp->mb_top) {
! 1024: m_fixhdr(mbp->mb_top);
! 1025: mb_initm(mbp, mbp->mb_top);
! 1026: }
! 1027: bad:
! 1028: smb_rq_remove(rqp);
! 1029: freerq:
! 1030: if (error && (rqp->sr_flags & SMBR_RESTART))
! 1031: t2p->t2_flags |= SMBT2_RESTART;
! 1032: smb_rq_done(rqp);
! 1033: return error;
! 1034: }
! 1035:
! 1036: int
! 1037: smb_t2_request(struct smb_t2rq *t2p)
! 1038: {
! 1039: int error = EINVAL, i;
! 1040:
! 1041: for (i = 0; i < SMB_MAXRCN; i++) {
! 1042: t2p->t2_flags &= ~SMBR_RESTART;
! 1043: error = smb_t2_request_int(t2p);
! 1044: if (error == 0)
! 1045: break;
! 1046: if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
! 1047: break;
! 1048: }
! 1049: return error;
! 1050: }
CVSweb <webmaster@jp.NetBSD.org>