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$");
   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,
  155     size_t *srclen, size_t *dstlen)
  156 {
  157         int len;
  158 
  159         if (*srclen < *dstlen) {
  160                 *dstlen = *srclen;
  161                 len = (int)*srclen;
  162         } else {
  163                 *srclen = *dstlen;
  164                 len = (int)*dstlen;
  165         }
  166         ncp_pathcopy(src, dst, len, mbp->mb_udata);
  167         return 0;
  168 }
  169 
  170 int
  171 ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name,
  172         struct ncp_nlstables *nt)
  173 {
  174         struct mbchain *mbp = &rqp->rq;
  175 
  176         mb_put_uint8(mbp, size);
  177         mbp->mb_copy = ncp_rq_pathstrhelp;
  178         mbp->mb_udata = nt;
  179         return mb_put_mem(mbp, (c_caddr_t)name, size, MB_MCUSTOM);
  180 }
  181 
  182 int 
  183 ncp_rq_pstring(struct ncp_rq *rqp, const char *s)
  184 {
  185         u_int len = strlen(s);
  186         int error;
  187 
  188         if (len > 255)
  189                 return EINVAL;
  190         error = mb_put_uint8(&rqp->rq, len);
  191         if (error)
  192                 return error;
  193         return mb_put_mem(&rqp->rq, s, len, MB_MSYSTEM);
  194 }
  195 
  196 int 
  197 ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
  198                     int namelen, u_char *path, struct ncp_nlstables *nt)
  199 {
  200         struct mbchain *mbp = &rqp->rq;
  201         int complen;
  202 
  203         mb_put_uint8(mbp, vol_num);
  204         mb_put_mem(mbp, (c_caddr_t)&dir_base, sizeof(dir_base), MB_MSYSTEM);
  205         mb_put_uint8(mbp, 1);   /* with dirbase */
  206         if (path != NULL && path[0]) {
  207                 if (namelen < 0) {
  208                         namelen = *path++;
  209                         mb_put_uint8(mbp, namelen);
  210                         for(; namelen; namelen--) {
  211                                 complen = *path++;
  212                                 mb_put_uint8(mbp, complen);
  213                                 mb_put_mem(mbp, path, complen, MB_MSYSTEM);
  214                                 path += complen;
  215                         }
  216                 } else {
  217                         mb_put_uint8(mbp, 1);   /* 1 component */
  218                         ncp_rq_pathstring(rqp, namelen, path, nt);
  219                 }
  220         } else {
  221                 mb_put_uint8(mbp, 0);
  222                 mb_put_uint8(mbp, 0);
  223         }
  224         return 0;
  225 }
  226 
  227 /* 
  228  * Make a signature for the current packet and add it at the end of the
  229  * packet.
  230  */
  231 static int
  232 ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size)
  233 {
  234         u_char data[64];
  235         int error;
  236 
  237         bzero(data, sizeof(data));
  238         bcopy(conn->sign_root, data, 8);
  239         setdle(data, 8, *size);
  240         m_copydata(rqp->rq.mb_top, sizeof(struct ncp_rqhdr) - 1,
  241                 min((*size) - sizeof(struct ncp_rqhdr)+1, 52), data + 12);
  242         ncp_sign(conn->sign_state, data, conn->sign_state);
  243         error = mb_put_mem(&rqp->rq, (caddr_t)conn->sign_state, 8, MB_MSYSTEM);
  244         if (error)
  245                 return error;
  246         (*size) += 8;
  247         return 0;
  248 }
  249 
  250 /*
  251  * Low level send rpc, here we do not attempt to restore any connection,
  252  * Connection expected to be locked
  253  */
  254 int
  255 ncp_request_int(struct ncp_rq *rqp)
  256 {
  257         struct ncp_conn *conn = rqp->nr_conn;
  258         struct thread *td = conn->td;
  259         struct socket *so = conn->ncp_so;
  260         struct ncp_rqhdr *rq;
  261         struct ncp_rphdr *rp=NULL;
  262         struct timeval tv;
  263         struct mbuf *m, *mreply = NULL;
  264         struct mbchain *mbp;
  265         int error, len, dosend, plen = 0, gotpacket;
  266 
  267         if (so == NULL) {
  268                 printf("%s: ncp_so is NULL !\n",__func__);
  269                 ncp_conn_invalidate(conn);
  270                 return ENOTCONN;
  271         }
  272         if (td == NULL)
  273                 td = curthread; /* XXX maybe procpage ? */
  274         /*
  275          * Flush out replies on previous reqs
  276          */
  277         while (ncp_poll(so, POLLIN) != 0) {
  278                 if (ncp_sock_recv(so, &m, &len) != 0)
  279                         break;
  280                 m_freem(m);
  281         }
  282         mbp = &rqp->rq;
  283         len = mb_fixhdr(mbp);
  284         rq = mtod(mbp->mb_top, struct ncp_rqhdr *);
  285         rq->seq = conn->seq;
  286         m = rqp->rq.mb_top;
  287 
  288         switch (rq->fn) {
  289             case 0x15: case 0x16: case 0x17: case 0x23:
  290                 *(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq));
  291                 break;
  292         }
  293         if (conn->flags & NCPFL_SIGNACTIVE) {
  294                 error = ncp_sign_packet(conn, rqp, &len);
  295                 if (error)
  296                         return error;
  297                 mbp->mb_top->m_pkthdr.len = len;
  298         }
  299         rq->conn_low = conn->connid & 0xff;
  300         /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
  301         /* XXX: this is temporary fix till I find a better solution */
  302         rq->task = rq->conn_low;
  303         rq->conn_high = conn->connid >> 8;
  304         rqp->rexmit = conn->li.retry_count;
  305         error = 0;
  306         for(dosend = 1;;) {
  307                 if (rqp->rexmit-- == 0) {
  308                         error = ETIMEDOUT;
  309                         break;
  310                 }
  311                 error = 0;
  312                 if (dosend) {
  313                         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,
  314                                 mbp->mb_top->m_pkthdr.len, rq->seq, rq->task
  315                         );
  316                         error = ncp_sock_send(so, mbp->mb_top, rqp);
  317                         if (error)
  318                                 break;
  319                 }
  320                 tv.tv_sec = conn->li.timeout;
  321                 tv.tv_usec = 0;
  322                 error = ncp_sock_rselect(so, td, &tv, POLLIN);
  323                 if (error == EWOULDBLOCK )      /* timeout expired */
  324                         continue;
  325                 error = ncp_chkintr(conn, td);
  326                 if (error)
  327                         break;
  328                 /*
  329                  * At this point it is possible to get more than one
  330                  * reply from server. In general, last reply should be for
  331                  * current request, but not always. So, we loop through
  332                  * all replies to find the right answer and flush others.
  333                  */
  334                 gotpacket = 0;  /* nothing good found */
  335                 dosend = 1;     /* resend rq if error */
  336                 for (;;) {
  337                         error = 0;
  338                         if (ncp_poll(so, POLLIN) == 0)
  339                                 break;
  340 /*                      if (so->so_rcv.sb_cc == 0) {
  341                                 break;
  342                         }*/
  343                         error = ncp_sock_recv(so, &m, &len);
  344                         if (error)
  345                                 break;          /* must be more checks !!! */
  346                         if (m->m_len < sizeof(*rp)) {
  347                                 m = m_pullup(m, sizeof(*rp));
  348                                 if (m == NULL) {
  349                                         printf("%s: reply too short\n",__func__);
  350                                         continue;
  351                                 }
  352                         }
  353                         rp = mtod(m, struct ncp_rphdr*);
  354                         if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) {
  355                                 NCPSDEBUG("got positive acknowledge\n");
  356                                 m_freem(m);
  357                                 rqp->rexmit = conn->li.retry_count;
  358                                 dosend = 0;     /* server just busy and will reply ASAP */
  359                                 continue;
  360                         }
  361                         NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type,
  362                             (rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task,
  363                              rp->completion_code, rp->connection_state);
  364                         NCPDDEBUG(m);
  365                         if ( (rp->type == NCP_REPLY) && 
  366                             ((rq->type == NCP_ALLOC_SLOT) || 
  367                             ((rp->conn_low == rq->conn_low) &&
  368                              (rp->conn_high == rq->conn_high)
  369                             ))) {
  370                                 if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) {
  371                                         dosend = 1;
  372                                 }
  373                                 if (rp->seq == rq->seq) {
  374                                         if (gotpacket) {
  375                                                 m_freem(m);
  376                                         } else {
  377                                                 gotpacket = 1;
  378                                                 mreply = m;
  379                                                 plen = len;
  380                                         }
  381                                         continue;       /* look up other for other packets */
  382                                 }
  383                         }
  384                         m_freem(m);
  385                         NCPSDEBUG("reply mismatch\n");
  386                 } /* for receive */
  387                 if (error || gotpacket)
  388                         break;
  389                 /* try to resend, or just wait */
  390         }
  391         conn->seq++;
  392         if (error) {
  393                 NCPSDEBUG("error=%d\n", error);
  394                 /*
  395                  * Any error except interruped call means that we have
  396                  * to reconnect. So, eliminate future timeouts by invalidating
  397                  * connection now.
  398                  */
  399                 if (error != EINTR)
  400                         ncp_conn_invalidate(conn);
  401                 return (error);
  402         }
  403         if (conn->flags & NCPFL_SIGNACTIVE) {
  404                 /* XXX: check reply signature */
  405                 m_adj(mreply, -8);
  406                 plen -= 8;
  407         }
  408         rp = mtod(mreply, struct ncp_rphdr*);
  409         md_initm(&rqp->rp, mreply);
  410         rqp->nr_rpsize = plen - sizeof(*rp);
  411         rqp->nr_cc = error = rp->completion_code;
  412         if (error)
  413                 error |= 0x8900;        /* server error */
  414         rqp->nr_cs = rp->connection_state;
  415         if (rqp->nr_cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
  416                 NCPSDEBUG("server drop us\n");
  417                 ncp_conn_invalidate(conn);
  418                 error = ECONNRESET;
  419         }
  420         md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM);
  421         return error;
  422 }
  423 
  424 /*
  425  * Here we will try to restore any loggedin & dropped connection,
  426  * connection should be locked on entry
  427  */
  428 static __inline int
  429 ncp_restore_login(struct ncp_conn *conn)
  430 {
  431         int error;
  432 
  433         printf("ncprq: Restoring connection, flags = %x\n", conn->flags);
  434         conn->flags |= NCPFL_RESTORING;
  435         error = ncp_conn_reconnect(conn);
  436         if (!error && (conn->flags & NCPFL_WASLOGGED))
  437                 error = ncp_conn_login(conn, conn->td, conn->ucred);
  438         if (error)
  439                 ncp_ncp_disconnect(conn);
  440         conn->flags &= ~NCPFL_RESTORING;
  441         return error;
  442 }
  443 
  444 int
  445 ncp_request(struct ncp_rq *rqp)
  446 {
  447         struct ncp_conn *ncp = rqp->nr_conn;
  448         int error, rcnt;
  449 
  450         error = ncp_conn_lock(ncp, rqp->nr_td, rqp->nr_cred, NCPM_EXECUTE);
  451         if (error)
  452                 goto out;
  453         rcnt = NCP_RESTORE_COUNT;
  454         for(;;) {
  455                 if (ncp->flags & NCPFL_ATTACHED) {
  456                         error = ncp_request_int(rqp);
  457                         if (ncp->flags & NCPFL_ATTACHED)
  458                                 break;
  459                 }
  460                 if (rcnt-- == 0) {
  461                         error = ECONNRESET;
  462                         break;
  463                 }
  464                 /*
  465                  * Do not attempt to restore connection recursively
  466                  */
  467                 if (ncp->flags & NCPFL_RESTORING) {
  468                         error = ENOTCONN;
  469                         break;
  470                 }
  471                 error = ncp_restore_login(ncp);
  472                 if (error)
  473                         continue;
  474         }
  475         ncp_conn_unlock(ncp, rqp->nr_td);
  476 out:
  477         if (error && (rqp->nr_flags & NCPR_DONTFREEONERR) == 0)
  478                 ncp_rq_done(rqp);
  479         return error;
  480 }

Cache object: 44189708e6fc1ca1e289ddeb60540233


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