The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netsmb/smb_rq.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000-2001, Boris Popov
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *    This product includes software developed by Boris Popov.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/endian.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/module.h>
   42 #include <sys/proc.h>
   43 #include <sys/lock.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/socket.h>
   46 #include <sys/socketvar.h>
   47 #include <sys/mbuf.h>
   48 
   49 #include <netsmb/smb.h>
   50 #include <netsmb/smb_conn.h>
   51 #include <netsmb/smb_rq.h>
   52 #include <netsmb/smb_subr.h>
   53 #include <netsmb/smb_tran.h>
   54 
   55 MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
   56 
   57 MODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
   58 
   59 static int  smb_rq_reply(struct smb_rq *rqp);
   60 static int  smb_rq_enqueue(struct smb_rq *rqp);
   61 static int  smb_rq_getenv(struct smb_connobj *layer,
   62                 struct smb_vc **vcpp, struct smb_share **sspp);
   63 static int  smb_rq_new(struct smb_rq *rqp, u_char cmd);
   64 static int  smb_t2_reply(struct smb_t2rq *t2p);
   65 
   66 int
   67 smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
   68         struct smb_rq **rqpp)
   69 {
   70         struct smb_rq *rqp;
   71         int error;
   72 
   73         MALLOC(rqp, struct smb_rq *, sizeof(*rqp), M_SMBRQ, M_WAITOK);
   74         if (rqp == NULL)
   75                 return ENOMEM;
   76         error = smb_rq_init(rqp, layer, cmd, scred);
   77         rqp->sr_flags |= SMBR_ALLOCED;
   78         if (error) {
   79                 smb_rq_done(rqp);
   80                 return error;
   81         }
   82         *rqpp = rqp;
   83         return 0;
   84 }
   85 
   86 static char tzero[12];
   87 
   88 int
   89 smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
   90         struct smb_cred *scred)
   91 {
   92         int error;
   93 
   94         bzero(rqp, sizeof(*rqp));
   95         smb_sl_init(&rqp->sr_slock, "srslock");
   96         error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
   97         if (error)
   98                 return error;
   99         error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
  100         if (error)
  101                 return error;
  102         if (rqp->sr_share) {
  103                 error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
  104                 if (error)
  105                         return error;
  106         }
  107         rqp->sr_cred = scred;
  108         rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
  109         return smb_rq_new(rqp, cmd);
  110 }
  111 
  112 static int
  113 smb_rq_new(struct smb_rq *rqp, u_char cmd)
  114 {
  115         struct smb_vc *vcp = rqp->sr_vc;
  116         struct mbchain *mbp = &rqp->sr_rq;
  117         int error;
  118         u_int16_t flags2;
  119 
  120         rqp->sr_sendcnt = 0;
  121         mb_done(mbp);
  122         md_done(&rqp->sr_rp);
  123         error = mb_init(mbp);
  124         if (error)
  125                 return error;
  126         mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
  127         mb_put_uint8(mbp, cmd);
  128         mb_put_uint32le(mbp, 0);                /* DosError */
  129         mb_put_uint8(mbp, vcp->vc_hflags);
  130         flags2 = vcp->vc_hflags2;
  131         if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY)
  132                 flags2 &= ~SMB_FLAGS2_UNICODE;
  133         if (cmd == SMB_COM_NEGOTIATE)
  134                 flags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
  135         mb_put_uint16le(mbp, flags2);
  136         if ((flags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
  137                 mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
  138                 rqp->sr_rqsig = NULL;
  139         } else {
  140                 mb_put_uint16le(mbp, 0 /*scred->sc_p->p_pid >> 16*/);
  141                 rqp->sr_rqsig = (u_int8_t *)mb_reserve(mbp, 8);
  142                 mb_put_uint16le(mbp, 0);
  143         }
  144         rqp->sr_rqtid = mb_reserve(mbp, sizeof(u_int16_t));
  145         mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
  146         rqp->sr_rquid = mb_reserve(mbp, sizeof(u_int16_t));
  147         mb_put_uint16le(mbp, rqp->sr_mid);
  148         return 0;
  149 }
  150 
  151 void
  152 smb_rq_done(struct smb_rq *rqp)
  153 {
  154         mb_done(&rqp->sr_rq);
  155         md_done(&rqp->sr_rp);
  156         smb_sl_destroy(&rqp->sr_slock);
  157         if (rqp->sr_flags & SMBR_ALLOCED)
  158                 free(rqp, M_SMBRQ);
  159 }
  160 
  161 /*
  162  * Simple request-reply exchange
  163  */
  164 int
  165 smb_rq_simple(struct smb_rq *rqp)
  166 {
  167         struct smb_vc *vcp = rqp->sr_vc;
  168         int error = EINVAL, i;
  169 
  170         for (i = 0; i < SMB_MAXRCN; i++) {
  171                 rqp->sr_flags &= ~SMBR_RESTART;
  172                 rqp->sr_timo = vcp->vc_timo;
  173                 rqp->sr_state = SMBRQ_NOTSENT;
  174                 error = smb_rq_enqueue(rqp);
  175                 if (error)
  176                         return error;
  177                 error = smb_rq_reply(rqp);
  178                 if (error == 0)
  179                         break;
  180                 if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
  181                         break;
  182         }
  183         return error;
  184 }
  185 
  186 static int
  187 smb_rq_enqueue(struct smb_rq *rqp)
  188 {
  189         struct smb_share *ssp = rqp->sr_share;
  190         int error;
  191 
  192         if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
  193                 return smb_iod_addrq(rqp);
  194         }
  195         for (;;) {
  196                 SMBS_ST_LOCK(ssp);
  197                 if (ssp->ss_flags & SMBS_RECONNECTING) {
  198                         msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp),
  199                             PWAIT | PDROP, "90trcn", hz);
  200                         if (smb_td_intr(rqp->sr_cred->scr_td))
  201                                 return EINTR;
  202                         continue;
  203                 }
  204                 if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
  205                         SMBS_ST_UNLOCK(ssp);
  206                 } else {
  207                         SMBS_ST_UNLOCK(ssp);
  208                         error = smb_iod_request(rqp->sr_vc->vc_iod,
  209                             SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
  210                         if (error)
  211                                 return error;
  212                 }
  213                 error = smb_iod_addrq(rqp);
  214                 if (error != EXDEV)
  215                         break;
  216         }
  217         return error;
  218 }
  219 
  220 void
  221 smb_rq_wstart(struct smb_rq *rqp)
  222 {
  223         rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
  224         rqp->sr_rq.mb_count = 0;
  225 }
  226 
  227 void
  228 smb_rq_wend(struct smb_rq *rqp)
  229 {
  230         if (rqp->sr_wcount == NULL) {
  231                 SMBERROR("no wcount\n");        /* actually panic */
  232                 return;
  233         }
  234         if (rqp->sr_rq.mb_count & 1)
  235                 SMBERROR("odd word count\n");
  236         *rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
  237 }
  238 
  239 void
  240 smb_rq_bstart(struct smb_rq *rqp)
  241 {
  242         rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof(u_short));
  243         rqp->sr_rq.mb_count = 0;
  244 }
  245 
  246 void
  247 smb_rq_bend(struct smb_rq *rqp)
  248 {
  249         int bcnt;
  250 
  251         if (rqp->sr_bcount == NULL) {
  252                 SMBERROR("no bcount\n");        /* actually panic */
  253                 return;
  254         }
  255         bcnt = rqp->sr_rq.mb_count;
  256         if (bcnt > 0xffff)
  257                 SMBERROR("byte count too large (%d)\n", bcnt);
  258         le16enc(rqp->sr_bcount, bcnt);
  259 }
  260 
  261 int
  262 smb_rq_intr(struct smb_rq *rqp)
  263 {
  264         if (rqp->sr_flags & SMBR_INTR)
  265                 return EINTR;
  266         return smb_td_intr(rqp->sr_cred->scr_td);
  267 }
  268 
  269 int
  270 smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
  271 {
  272         *mbpp = &rqp->sr_rq;
  273         return 0;
  274 }
  275 
  276 int
  277 smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
  278 {
  279         *mbpp = &rqp->sr_rp;
  280         return 0;
  281 }
  282 
  283 static int
  284 smb_rq_getenv(struct smb_connobj *layer,
  285         struct smb_vc **vcpp, struct smb_share **sspp)
  286 {
  287         struct smb_vc *vcp = NULL;
  288         struct smb_share *ssp = NULL;
  289         struct smb_connobj *cp;
  290         int error = 0;
  291 
  292         switch (layer->co_level) {
  293             case SMBL_VC:
  294                 vcp = CPTOVC(layer);
  295                 if (layer->co_parent == NULL) {
  296                         SMBERROR("zombie VC %s\n", vcp->vc_srvname);
  297                         error = EINVAL;
  298                         break;
  299                 }
  300                 break;
  301             case SMBL_SHARE:
  302                 ssp = CPTOSS(layer);
  303                 cp = layer->co_parent;
  304                 if (cp == NULL) {
  305                         SMBERROR("zombie share %s\n", ssp->ss_name);
  306                         error = EINVAL;
  307                         break;
  308                 }
  309                 error = smb_rq_getenv(cp, &vcp, NULL);
  310                 if (error)
  311                         break;
  312                 break;
  313             default:
  314                 SMBERROR("invalid layer %d passed\n", layer->co_level);
  315                 error = EINVAL;
  316         }
  317         if (vcpp)
  318                 *vcpp = vcp;
  319         if (sspp)
  320                 *sspp = ssp;
  321         return error;
  322 }
  323 
  324 /*
  325  * Wait for reply on the request
  326  */
  327 static int
  328 smb_rq_reply(struct smb_rq *rqp)
  329 {
  330         struct mdchain *mdp = &rqp->sr_rp;
  331         u_int32_t tdw;
  332         u_int8_t tb;
  333         int error, rperror = 0;
  334 
  335         error = smb_iod_waitrq(rqp);
  336         if (error)
  337                 return error;
  338         error = md_get_uint32(mdp, &tdw);
  339         if (error)
  340                 return error;
  341         error = md_get_uint8(mdp, &tb);
  342         if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
  343                 error = md_get_uint32le(mdp, &rqp->sr_error);
  344         } else {
  345                 error = md_get_uint8(mdp, &rqp->sr_errclass);
  346                 error = md_get_uint8(mdp, &tb);
  347                 error = md_get_uint16le(mdp, &rqp->sr_serror);
  348                 if (!error)
  349                         rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
  350         }
  351         error = md_get_uint8(mdp, &rqp->sr_rpflags);
  352         error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
  353 
  354         error = md_get_uint32(mdp, &tdw);
  355         error = md_get_uint32(mdp, &tdw);
  356         error = md_get_uint32(mdp, &tdw);
  357 
  358         error = md_get_uint16le(mdp, &rqp->sr_rptid);
  359         error = md_get_uint16le(mdp, &rqp->sr_rppid);
  360         error = md_get_uint16le(mdp, &rqp->sr_rpuid);
  361         error = md_get_uint16le(mdp, &rqp->sr_rpmid);
  362 
  363         if (error == 0 &&
  364             (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE))
  365                 error = smb_rq_verify(rqp);
  366 
  367         SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
  368             rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
  369             rqp->sr_errclass, rqp->sr_serror);
  370         return error ? error : rperror;
  371 }
  372 
  373 
  374 #define ALIGN4(a)       (((a) + 3) & ~3)
  375 
  376 /*
  377  * TRANS2 request implementation
  378  */
  379 int
  380 smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
  381         struct smb_t2rq **t2pp)
  382 {
  383         struct smb_t2rq *t2p;
  384         int error;
  385 
  386         MALLOC(t2p, struct smb_t2rq *, sizeof(*t2p), M_SMBRQ, M_WAITOK);
  387         if (t2p == NULL)
  388                 return ENOMEM;
  389         error = smb_t2_init(t2p, layer, setup, scred);
  390         t2p->t2_flags |= SMBT2_ALLOCED;
  391         if (error) {
  392                 smb_t2_done(t2p);
  393                 return error;
  394         }
  395         *t2pp = t2p;
  396         return 0;
  397 }
  398 
  399 int
  400 smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
  401         struct smb_cred *scred)
  402 {
  403         int error;
  404 
  405         bzero(t2p, sizeof(*t2p));
  406         t2p->t2_source = source;
  407         t2p->t2_setupcount = 1;
  408         t2p->t2_setupdata = t2p->t2_setup;
  409         t2p->t2_setup[0] = setup;
  410         t2p->t2_fid = 0xffff;
  411         t2p->t2_cred = scred;
  412         error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
  413         if (error)
  414                 return error;
  415         return 0;
  416 }
  417 
  418 void
  419 smb_t2_done(struct smb_t2rq *t2p)
  420 {
  421         mb_done(&t2p->t2_tparam);
  422         mb_done(&t2p->t2_tdata);
  423         md_done(&t2p->t2_rparam);
  424         md_done(&t2p->t2_rdata);
  425         if (t2p->t2_flags & SMBT2_ALLOCED)
  426                 free(t2p, M_SMBRQ);
  427 }
  428 
  429 static int
  430 smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
  431         struct mdchain *mdp)
  432 {
  433         struct mbuf *m, *m0;
  434         int len;
  435 
  436         m0 = m_split(mtop, offset, M_TRYWAIT);
  437         if (m0 == NULL)
  438                 return EBADRPC;
  439         len = m_length(m0, &m);
  440         m->m_len -= len - count;
  441         if (mdp->md_top == NULL) {
  442                 md_initm(mdp, m0);
  443         } else
  444                 m_cat(mdp->md_top, m0);
  445         return 0;
  446 }
  447 
  448 static int
  449 smb_t2_reply(struct smb_t2rq *t2p)
  450 {
  451         struct mdchain *mdp;
  452         struct smb_rq *rqp = t2p->t2_rq;
  453         int error, totpgot, totdgot;
  454         u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
  455         u_int16_t tmp, bc, dcount;
  456         u_int8_t wc;
  457 
  458         error = smb_rq_reply(rqp);
  459         if (error)
  460                 return error;
  461         if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
  462                 /* 
  463                  * this is an interim response, ignore it.
  464                  */
  465                 SMBRQ_SLOCK(rqp);
  466                 md_next_record(&rqp->sr_rp);
  467                 SMBRQ_SUNLOCK(rqp);
  468                 return 0;
  469         }
  470         /*
  471          * Now we have to get all subsequent responses. The CIFS specification
  472          * says that they can be disordered which is weird.
  473          * TODO: timo
  474          */
  475         totpgot = totdgot = 0;
  476         totpcount = totdcount = 0xffff;
  477         mdp = &rqp->sr_rp;
  478         for (;;) {
  479                 m_dumpm(mdp->md_top);
  480                 if ((error = md_get_uint8(mdp, &wc)) != 0)
  481                         break;
  482                 if (wc < 10) {
  483                         error = ENOENT;
  484                         break;
  485                 }
  486                 if ((error = md_get_uint16le(mdp, &tmp)) != 0)
  487                         break;
  488                 if (totpcount > tmp)
  489                         totpcount = tmp;
  490                 md_get_uint16le(mdp, &tmp);
  491                 if (totdcount > tmp)
  492                         totdcount = tmp;
  493                 if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
  494                     (error = md_get_uint16le(mdp, &pcount)) != 0 ||
  495                     (error = md_get_uint16le(mdp, &poff)) != 0 ||
  496                     (error = md_get_uint16le(mdp, &pdisp)) != 0)
  497                         break;
  498                 if (pcount != 0 && pdisp != totpgot) {
  499                         SMBERROR("Can't handle disordered parameters %d:%d\n",
  500                             pdisp, totpgot);
  501                         error = EINVAL;
  502                         break;
  503                 }
  504                 if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
  505                     (error = md_get_uint16le(mdp, &doff)) != 0 ||
  506                     (error = md_get_uint16le(mdp, &ddisp)) != 0)
  507                         break;
  508                 if (dcount != 0 && ddisp != totdgot) {
  509                         SMBERROR("Can't handle disordered data\n");
  510                         error = EINVAL;
  511                         break;
  512                 }
  513                 md_get_uint8(mdp, &wc);
  514                 md_get_uint8(mdp, NULL);
  515                 tmp = wc;
  516                 while (tmp--)
  517                         md_get_uint16(mdp, NULL);
  518                 if ((error = md_get_uint16le(mdp, &bc)) != 0)
  519                         break;
  520 /*              tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
  521                 if (dcount) {
  522                         error = smb_t2_placedata(mdp->md_top, doff, dcount,
  523                             &t2p->t2_rdata);
  524                         if (error)
  525                                 break;
  526                 }
  527                 if (pcount) {
  528                         error = smb_t2_placedata(mdp->md_top, poff, pcount,
  529                             &t2p->t2_rparam);
  530                         if (error)
  531                                 break;
  532                 }
  533                 totpgot += pcount;
  534                 totdgot += dcount;
  535                 if (totpgot >= totpcount && totdgot >= totdcount) {
  536                         error = 0;
  537                         t2p->t2_flags |= SMBT2_ALLRECV;
  538                         break;
  539                 }
  540                 /*
  541                  * We're done with this reply, look for the next one.
  542                  */
  543                 SMBRQ_SLOCK(rqp);
  544                 md_next_record(&rqp->sr_rp);
  545                 SMBRQ_SUNLOCK(rqp);
  546                 error = smb_rq_reply(rqp);
  547                 if (error)
  548                         break;
  549         }
  550         return error;
  551 }
  552 
  553 /*
  554  * Perform a full round of TRANS2 request
  555  */
  556 static int
  557 smb_t2_request_int(struct smb_t2rq *t2p)
  558 {
  559         struct smb_vc *vcp = t2p->t2_vc;
  560         struct smb_cred *scred = t2p->t2_cred;
  561         struct mbchain *mbp;
  562         struct mdchain *mdp, mbparam, mbdata;
  563         struct mbuf *m;
  564         struct smb_rq *rqp;
  565         int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
  566         int error, doff, poff, txdcount, txpcount, nmlen;
  567 
  568         m = t2p->t2_tparam.mb_top;
  569         if (m) {
  570                 md_initm(&mbparam, m);  /* do not free it! */
  571                 totpcount = m_fixhdr(m);
  572                 if (totpcount > 0xffff)         /* maxvalue for u_short */
  573                         return EINVAL;
  574         } else
  575                 totpcount = 0;
  576         m = t2p->t2_tdata.mb_top;
  577         if (m) {
  578                 md_initm(&mbdata, m);   /* do not free it! */
  579                 totdcount =  m_fixhdr(m);
  580                 if (totdcount > 0xffff)
  581                         return EINVAL;
  582         } else
  583                 totdcount = 0;
  584         leftdcount = totdcount;
  585         leftpcount = totpcount;
  586         txmax = vcp->vc_txmax;
  587         error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
  588             SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
  589         if (error)
  590                 return error;
  591         rqp->sr_flags |= SMBR_MULTIPACKET;
  592         t2p->t2_rq = rqp;
  593         rqp->sr_t2 = t2p;
  594         mbp = &rqp->sr_rq;
  595         smb_rq_wstart(rqp);
  596         mb_put_uint16le(mbp, totpcount);
  597         mb_put_uint16le(mbp, totdcount);
  598         mb_put_uint16le(mbp, t2p->t2_maxpcount);
  599         mb_put_uint16le(mbp, t2p->t2_maxdcount);
  600         mb_put_uint8(mbp, t2p->t2_maxscount);
  601         mb_put_uint8(mbp, 0);                   /* reserved */
  602         mb_put_uint16le(mbp, 0);                        /* flags */
  603         mb_put_uint32le(mbp, 0);                        /* Timeout */
  604         mb_put_uint16le(mbp, 0);                        /* reserved 2 */
  605         len = mb_fixhdr(mbp);
  606         /*
  607          * now we have known packet size as
  608          * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
  609          * and need to decide which parts should go into the first request
  610          */
  611         nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
  612         len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
  613         if (len + leftpcount > txmax) {
  614                 txpcount = min(leftpcount, txmax - len);
  615                 poff = len;
  616                 txdcount = 0;
  617                 doff = 0;
  618         } else {
  619                 txpcount = leftpcount;
  620                 poff = txpcount ? len : 0;
  621                 len = ALIGN4(len + txpcount);
  622                 txdcount = min(leftdcount, txmax - len);
  623                 doff = txdcount ? len : 0;
  624         }
  625         leftpcount -= txpcount;
  626         leftdcount -= txdcount;
  627         mb_put_uint16le(mbp, txpcount);
  628         mb_put_uint16le(mbp, poff);
  629         mb_put_uint16le(mbp, txdcount);
  630         mb_put_uint16le(mbp, doff);
  631         mb_put_uint8(mbp, t2p->t2_setupcount);
  632         mb_put_uint8(mbp, 0);
  633         for (i = 0; i < t2p->t2_setupcount; i++)
  634                 mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
  635         smb_rq_wend(rqp);
  636         smb_rq_bstart(rqp);
  637         /* TDUNICODE */
  638         if (t2p->t_name)
  639                 mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
  640         mb_put_uint8(mbp, 0);   /* terminating zero */
  641         len = mb_fixhdr(mbp);
  642         if (txpcount) {
  643                 mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
  644                 error = md_get_mbuf(&mbparam, txpcount, &m);
  645                 SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
  646                 if (error)
  647                         goto freerq;
  648                 mb_put_mbuf(mbp, m);
  649         }
  650         len = mb_fixhdr(mbp);
  651         if (txdcount) {
  652                 mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
  653                 error = md_get_mbuf(&mbdata, txdcount, &m);
  654                 if (error)
  655                         goto freerq;
  656                 mb_put_mbuf(mbp, m);
  657         }
  658         smb_rq_bend(rqp);       /* incredible, but thats it... */
  659         error = smb_rq_enqueue(rqp);
  660         if (error)
  661                 goto freerq;
  662         if (leftpcount == 0 && leftdcount == 0)
  663                 t2p->t2_flags |= SMBT2_ALLSENT;
  664         error = smb_t2_reply(t2p);
  665         if (error)
  666                 goto bad;
  667         while (leftpcount || leftdcount) {
  668                 t2p->t2_flags |= SMBT2_SECONDARY;
  669                 error = smb_rq_new(rqp, t2p->t_name ? 
  670                     SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
  671                 if (error)
  672                         goto bad;
  673                 mbp = &rqp->sr_rq;
  674                 smb_rq_wstart(rqp);
  675                 mb_put_uint16le(mbp, totpcount);
  676                 mb_put_uint16le(mbp, totdcount);
  677                 len = mb_fixhdr(mbp);
  678                 /*
  679                  * now we have known packet size as
  680                  * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
  681                  * and need to decide which parts should go into request
  682                  */
  683                 len = ALIGN4(len + 6 * 2 + 2);
  684                 if (t2p->t_name == NULL)
  685                         len += 2;
  686                 if (len + leftpcount > txmax) {
  687                         txpcount = min(leftpcount, txmax - len);
  688                         poff = len;
  689                         txdcount = 0;
  690                         doff = 0;
  691                 } else {
  692                         txpcount = leftpcount;
  693                         poff = txpcount ? len : 0;
  694                         len = ALIGN4(len + txpcount);
  695                         txdcount = min(leftdcount, txmax - len);
  696                         doff = txdcount ? len : 0;
  697                 }
  698                 mb_put_uint16le(mbp, txpcount);
  699                 mb_put_uint16le(mbp, poff);
  700                 mb_put_uint16le(mbp, totpcount - leftpcount);
  701                 mb_put_uint16le(mbp, txdcount);
  702                 mb_put_uint16le(mbp, doff);
  703                 mb_put_uint16le(mbp, totdcount - leftdcount);
  704                 leftpcount -= txpcount;
  705                 leftdcount -= txdcount;
  706                 if (t2p->t_name == NULL)
  707                         mb_put_uint16le(mbp, t2p->t2_fid);
  708                 smb_rq_wend(rqp);
  709                 smb_rq_bstart(rqp);
  710                 mb_put_uint8(mbp, 0);   /* name */
  711                 len = mb_fixhdr(mbp);
  712                 if (txpcount) {
  713                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
  714                         error = md_get_mbuf(&mbparam, txpcount, &m);
  715                         if (error)
  716                                 goto bad;
  717                         mb_put_mbuf(mbp, m);
  718                 }
  719                 len = mb_fixhdr(mbp);
  720                 if (txdcount) {
  721                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
  722                         error = md_get_mbuf(&mbdata, txdcount, &m);
  723                         if (error)
  724                                 goto bad;
  725                         mb_put_mbuf(mbp, m);
  726                 }
  727                 smb_rq_bend(rqp);
  728                 rqp->sr_state = SMBRQ_NOTSENT;
  729                 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
  730                 if (error)
  731                         goto bad;
  732         }       /* while left params or data */
  733         t2p->t2_flags |= SMBT2_ALLSENT;
  734         mdp = &t2p->t2_rdata;
  735         if (mdp->md_top) {
  736                 m_fixhdr(mdp->md_top);
  737                 md_initm(mdp, mdp->md_top);
  738         }
  739         mdp = &t2p->t2_rparam;
  740         if (mdp->md_top) {
  741                 m_fixhdr(mdp->md_top);
  742                 md_initm(mdp, mdp->md_top);
  743         }
  744 bad:
  745         smb_iod_removerq(rqp);
  746 freerq:
  747         smb_rq_done(rqp);
  748         if (error) {
  749                 if (rqp->sr_flags & SMBR_RESTART)
  750                         t2p->t2_flags |= SMBT2_RESTART;
  751                 md_done(&t2p->t2_rparam);
  752                 md_done(&t2p->t2_rdata);
  753         }
  754         return error;
  755 }
  756 
  757 int
  758 smb_t2_request(struct smb_t2rq *t2p)
  759 {
  760         int error = EINVAL, i;
  761 
  762         for (i = 0; i < SMB_MAXRCN; i++) {
  763                 t2p->t2_flags &= ~SMBR_RESTART;
  764                 error = smb_t2_request_int(t2p);
  765                 if (error == 0)
  766                         break;
  767                 if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
  768                         break;
  769         }
  770         return error;
  771 }

Cache object: 08e73473059f0eca564b80fe5f89767f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.