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

Cache object: 2d21cd9e14e52ccaa7ac11f39a2b77af


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