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/netncp/ncp_rq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1999-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  * Routines to prepare request and fetch reply
   33  *
   34  * $FreeBSD: releng/5.0/sys/netncp/ncp_rq.c 106667 2002-11-08 21:26:32Z jhb $
   35  */ 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/errno.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/poll.h>
   43 #include <sys/proc.h>
   44 #include <sys/uio.h>
   45 
   46 #include <netncp/ncp.h>
   47 #include <netncp/ncp_conn.h>
   48 #include <netncp/ncp_rq.h>
   49 #include <netncp/ncp_subr.h>
   50 #include <netncp/ncp_ncp.h>
   51 #include <netncp/ncp_sock.h>
   52 #include <netncp/ncp_nls.h>
   53 
   54 static MALLOC_DEFINE(M_NCPRQ, "NCPRQ", "NCP request");
   55 
   56 static int ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
   57 
   58 int
   59 ncp_rq_alloc_any(u_int32_t ptype, u_int8_t fn, struct ncp_conn *ncp,
   60         struct proc *p, struct ucred *cred,
   61         struct ncp_rq **rqpp)
   62 {
   63         struct ncp_rq *rqp;
   64         int error;
   65 
   66         MALLOC(rqp, struct ncp_rq *, sizeof(*rqp), M_NCPRQ, M_WAITOK);
   67         error = ncp_rq_init_any(rqp, ptype, fn, ncp, p, cred);
   68         rqp->nr_flags |= NCPR_ALLOCED;
   69         if (error) {
   70                 ncp_rq_done(rqp);
   71                 return error;
   72         }
   73         *rqpp = rqp;
   74         return 0;
   75 }
   76 
   77 int
   78 ncp_rq_alloc(u_int8_t fn, struct ncp_conn *ncp,
   79         struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
   80 {
   81         return ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, rqpp);
   82 }
   83 
   84 int
   85 ncp_rq_alloc_subfn(u_int8_t fn, u_int8_t subfn, struct ncp_conn *ncp,
   86         struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
   87 {
   88         struct ncp_rq *rqp;
   89         int error;
   90 
   91         error = ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, &rqp);
   92         if (error)
   93                 return error;
   94         mb_reserve(&rqp->rq, 2);
   95         mb_put_uint8(&rqp->rq, subfn);
   96         *rqpp = rqp;
   97         return 0;
   98 }
   99 
  100 int
  101 ncp_rq_init_any(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,
  102         struct ncp_conn *ncp,
  103         struct proc *p, struct ucred *cred)
  104 {
  105         struct ncp_rqhdr *rq;
  106         struct ncp_bursthdr *brq;
  107         struct mbchain *mbp;
  108         int error;
  109 
  110         bzero(rqp, sizeof(*rqp));
  111         error = ncp_conn_access(ncp, cred, NCPM_EXECUTE);
  112         if (error)
  113                 return error;
  114         rqp->nr_p = p;
  115         rqp->nr_cred = cred;
  116         rqp->nr_conn = ncp;
  117         mbp = &rqp->rq;
  118         if (mb_init(mbp) != 0)
  119                 return ENOBUFS;
  120         switch(ptype) {
  121             case NCP_PACKET_BURST:
  122                 brq = (struct ncp_bursthdr*)mb_reserve(mbp, sizeof(*brq));
  123                 brq->bh_type = ptype;
  124                 brq->bh_streamtype = 0x2;
  125                 break;
  126             default:
  127                 rq = (struct ncp_rqhdr*)mb_reserve(mbp, sizeof(*rq));
  128                 rq->type = ptype;
  129                 rq->seq = 0;    /* filled later */
  130                 rq->fn = fn;
  131                 break;
  132         }
  133         rqp->nr_minrplen = -1;
  134         return 0;
  135 }
  136 
  137 void
  138 ncp_rq_done(struct ncp_rq *rqp)
  139 {
  140         mb_done(&rqp->rq);
  141         md_done(&rqp->rp);
  142         if (rqp->nr_flags & NCPR_ALLOCED)
  143                 free(rqp, M_NCPRQ);
  144         return;
  145 }
  146 
  147 /*
  148  * Routines to fill the request
  149  */
  150 
  151 static int
  152 ncp_rq_pathstrhelp(struct mbchain *mbp, c_caddr_t src, caddr_t dst, size_t len)
  153 {
  154         ncp_pathcopy(src, dst, len, mbp->mb_udata);
  155         return 0;
  156 }
  157 
  158 int
  159 ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name,
  160         struct ncp_nlstables *nt)
  161 {
  162         struct mbchain *mbp = &rqp->rq;
  163 
  164         mb_put_uint8(mbp, size);
  165         mbp->mb_copy = ncp_rq_pathstrhelp;
  166         mbp->mb_udata = nt;
  167         return mb_put_mem(mbp, (c_caddr_t)name, size, MB_MCUSTOM);
  168 }
  169 
  170 int 
  171 ncp_rq_pstring(struct ncp_rq *rqp, const char *s)
  172 {
  173         u_int len = strlen(s);
  174         int error;
  175 
  176         if (len > 255)
  177                 return EINVAL;
  178         error = mb_put_uint8(&rqp->rq, len);
  179         if (error)
  180                 return error;
  181         return mb_put_mem(&rqp->rq, s, len, MB_MSYSTEM);
  182 }
  183 
  184 int 
  185 ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
  186                     int namelen, u_char *path, struct ncp_nlstables *nt)
  187 {
  188         struct mbchain *mbp = &rqp->rq;
  189         int complen;
  190 
  191         mb_put_uint8(mbp, vol_num);
  192         mb_put_mem(mbp, (c_caddr_t)&dir_base, sizeof(dir_base), MB_MSYSTEM);
  193         mb_put_uint8(mbp, 1);   /* with dirbase */
  194         if (path != NULL && path[0]) {
  195                 if (namelen < 0) {
  196                         namelen = *path++;
  197                         mb_put_uint8(mbp, namelen);
  198                         for(; namelen; namelen--) {
  199                                 complen = *path++;
  200                                 mb_put_uint8(mbp, complen);
  201                                 mb_put_mem(mbp, path, complen, MB_MSYSTEM);
  202                                 path += complen;
  203                         }
  204                 } else {
  205                         mb_put_uint8(mbp, 1);   /* 1 component */
  206                         ncp_rq_pathstring(rqp, namelen, path, nt);
  207                 }
  208         } else {
  209                 mb_put_uint8(mbp, 0);
  210                 mb_put_uint8(mbp, 0);
  211         }
  212         return 0;
  213 }
  214 
  215 /* 
  216  * Make a signature for the current packet and add it at the end of the
  217  * packet.
  218  */
  219 static int
  220 ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size)
  221 {
  222         u_char data[64];
  223         int error;
  224 
  225         bzero(data, sizeof(data));
  226         bcopy(conn->sign_root, data, 8);
  227         setdle(data, 8, *size);
  228         m_copydata(rqp->rq.mb_top, sizeof(struct ncp_rqhdr) - 1,
  229                 min((*size) - sizeof(struct ncp_rqhdr)+1, 52), data + 12);
  230         ncp_sign(conn->sign_state, data, conn->sign_state);
  231         error = mb_put_mem(&rqp->rq, (caddr_t)conn->sign_state, 8, MB_MSYSTEM);
  232         if (error)
  233                 return error;
  234         (*size) += 8;
  235         return 0;
  236 }
  237 
  238 /*
  239  * Low level send rpc, here we do not attempt to restore any connection,
  240  * Connection expected to be locked
  241  */
  242 int 
  243 ncp_request_int(struct ncp_rq *rqp)
  244 {
  245         struct ncp_conn *conn = rqp->nr_conn;
  246         struct proc *p = conn->procp;
  247         struct socket *so = conn->ncp_so;
  248         struct ncp_rqhdr *rq;
  249         struct ncp_rphdr *rp=NULL;
  250         struct timeval tv;
  251         struct mbuf *m, *mreply = NULL;
  252         struct mbchain *mbp;
  253         int error, len, dosend, plen = 0, gotpacket;
  254 
  255         if (so == NULL) {
  256                 printf("%s: ncp_so is NULL !\n",__func__);
  257                 ncp_conn_invalidate(conn);
  258                 return ENOTCONN;
  259         }
  260         if (p == NULL)
  261                 p = curproc;    /* XXX maybe procpage ? */
  262         /*
  263          * Flush out replies on previous reqs
  264          */
  265         while (ncp_poll(so, POLLIN) != 0) {
  266                 if (ncp_sock_recv(so, &m, &len) != 0)
  267                         break;
  268                 m_freem(m);
  269         }
  270         mbp = &rqp->rq;
  271         len = mb_fixhdr(mbp);
  272         rq = mtod(mbp->mb_top, struct ncp_rqhdr *);
  273         rq->seq = conn->seq;
  274         m = rqp->rq.mb_top;
  275 
  276         switch (rq->fn) {
  277             case 0x15: case 0x16: case 0x17: case 0x23:
  278                 *(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq));
  279                 break;
  280         }
  281         if (conn->flags & NCPFL_SIGNACTIVE) {
  282                 error = ncp_sign_packet(conn, rqp, &len);
  283                 if (error)
  284                         return error;
  285                 mbp->mb_top->m_pkthdr.len = len;
  286         }
  287         rq->conn_low = conn->connid & 0xff;
  288         /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
  289         /* XXX: this is temporary fix till I find a better solution */
  290         rq->task = rq->conn_low;
  291         rq->conn_high = conn->connid >> 8;
  292         rqp->rexmit = conn->li.retry_count;
  293         error = 0;
  294         for(dosend = 1;;) {
  295                 if (rqp->rexmit-- == 0) {
  296                         error = ETIMEDOUT;
  297                         break;
  298                 }
  299                 error = 0;
  300                 if (dosend) {
  301                         NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low,
  302                                 mbp->mb_top->m_pkthdr.len, rq->seq, rq->task
  303                         );
  304                         error = ncp_sock_send(so, mbp->mb_top, rqp);
  305                         if (error)
  306                                 break;
  307                 }
  308                 tv.tv_sec = conn->li.timeout;
  309                 tv.tv_usec = 0;
  310                 error = ncp_sock_rselect(so, p, &tv, POLLIN);
  311                 if (error == EWOULDBLOCK )      /* timeout expired */
  312                         continue;
  313                 error = ncp_chkintr(conn, p);
  314                 if (error)
  315                         break;
  316                 /*
  317                  * At this point it is possible to get more than one
  318                  * reply from server. In general, last reply should be for
  319                  * current request, but not always. So, we loop through
  320                  * all replies to find the right answer and flush others.
  321                  */
  322                 gotpacket = 0;  /* nothing good found */
  323                 dosend = 1;     /* resend rq if error */
  324                 for (;;) {
  325                         error = 0;
  326                         if (ncp_poll(so, POLLIN) == 0)
  327                                 break;
  328 /*                      if (so->so_rcv.sb_cc == 0) {
  329                                 break;
  330                         }*/
  331                         error = ncp_sock_recv(so, &m, &len);
  332                         if (error)
  333                                 break;          /* must be more checks !!! */
  334                         if (m->m_len < sizeof(*rp)) {
  335                                 m = m_pullup(m, sizeof(*rp));
  336                                 if (m == NULL) {
  337                                         printf("%s: reply too short\n",__func__);
  338                                         continue;
  339                                 }
  340                         }
  341                         rp = mtod(m, struct ncp_rphdr*);
  342                         if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) {
  343                                 NCPSDEBUG("got positive acknowledge\n");
  344                                 m_freem(m);
  345                                 rqp->rexmit = conn->li.retry_count;
  346                                 dosend = 0;     /* server just busy and will reply ASAP */
  347                                 continue;
  348                         }
  349                         NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type,
  350                             (rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task,
  351                              rp->completion_code, rp->connection_state);
  352                         NCPDDEBUG(m);
  353                         if ( (rp->type == NCP_REPLY) && 
  354                             ((rq->type == NCP_ALLOC_SLOT) || 
  355                             ((rp->conn_low == rq->conn_low) &&
  356                              (rp->conn_high == rq->conn_high)
  357                             ))) {
  358                                 if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) {
  359                                         dosend = 1;
  360                                 }
  361                                 if (rp->seq == rq->seq) {
  362                                         if (gotpacket) {
  363                                                 m_freem(m);
  364                                         } else {
  365                                                 gotpacket = 1;
  366                                                 mreply = m;
  367                                                 plen = len;
  368                                         }
  369                                         continue;       /* look up other for other packets */
  370                                 }
  371                         }
  372                         m_freem(m);
  373                         NCPSDEBUG("reply mismatch\n");
  374                 } /* for receive */
  375                 if (error || gotpacket)
  376                         break;
  377                 /* try to resend, or just wait */
  378         }
  379         conn->seq++;
  380         if (error) {
  381                 NCPSDEBUG("error=%d\n", error);
  382                 /*
  383                  * Any error except interruped call means that we have
  384                  * to reconnect. So, eliminate future timeouts by invalidating
  385                  * connection now.
  386                  */
  387                 if (error != EINTR)
  388                         ncp_conn_invalidate(conn);
  389                 return (error);
  390         }
  391         if (conn->flags & NCPFL_SIGNACTIVE) {
  392                 /* XXX: check reply signature */
  393                 m_adj(mreply, -8);
  394                 plen -= 8;
  395         }
  396         rp = mtod(mreply, struct ncp_rphdr*);
  397         md_initm(&rqp->rp, mreply);
  398         rqp->nr_rpsize = plen - sizeof(*rp);
  399         rqp->nr_cc = error = rp->completion_code;
  400         if (error)
  401                 error |= 0x8900;        /* server error */
  402         rqp->nr_cs = rp->connection_state;
  403         if (rqp->nr_cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
  404                 NCPSDEBUG("server drop us\n");
  405                 ncp_conn_invalidate(conn);
  406                 error = ECONNRESET;
  407         }
  408         md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM);
  409         return error;
  410 }
  411 
  412 /*
  413  * Here we will try to restore any loggedin & dropped connection,
  414  * connection should be locked on entry
  415  */
  416 static __inline int
  417 ncp_restore_login(struct ncp_conn *conn)
  418 {
  419         int error;
  420 
  421         printf("ncprq: Restoring connection, flags = %x\n", conn->flags);
  422         conn->flags |= NCPFL_RESTORING;
  423         error = ncp_conn_reconnect(conn);
  424         if (!error && (conn->flags & NCPFL_WASLOGGED))
  425                 error = ncp_conn_login(conn, conn->procp, conn->ucred);
  426         if (error)
  427                 ncp_ncp_disconnect(conn);
  428         conn->flags &= ~NCPFL_RESTORING;
  429         return error;
  430 }
  431 
  432 int
  433 ncp_request(struct ncp_rq *rqp)
  434 {
  435         struct ncp_conn *ncp = rqp->nr_conn;
  436         int error, rcnt;
  437 
  438         error = ncp_conn_lock(ncp, rqp->nr_p, rqp->nr_cred, NCPM_EXECUTE);
  439         if (error)
  440                 goto out;
  441         rcnt = NCP_RESTORE_COUNT;
  442         for(;;) {
  443                 if (ncp->flags & NCPFL_ATTACHED) {
  444                         error = ncp_request_int(rqp);
  445                         if (ncp->flags & NCPFL_ATTACHED)
  446                                 break;
  447                 }
  448                 if (rcnt-- == 0) {
  449                         error = ECONNRESET;
  450                         break;
  451                 }
  452                 /*
  453                  * Do not attempt to restore connection recursively
  454                  */
  455                 if (ncp->flags & NCPFL_RESTORING) {
  456                         error = ENOTCONN;
  457                         break;
  458                 }
  459                 error = ncp_restore_login(ncp);
  460                 if (error)
  461                         continue;
  462         }
  463         ncp_conn_unlock(ncp, rqp->nr_p);
  464 out:
  465         if (error && (rqp->nr_flags & NCPR_DONTFREEONERR) == 0)
  466                 ncp_rq_done(rqp);
  467         return error;
  468 }

Cache object: 02b0fbcf8fe402901cc3006bcd68db4b


[ 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.