[BACK]Return to smb_rq.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netsmb

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>