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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * Routines to prepare request and fetch reply
   27  */ 
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/errno.h>
   35 #include <sys/kernel.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/poll.h>
   39 #include <sys/proc.h>
   40 #include <sys/socket.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/uio.h>
   43 
   44 #include <netncp/ncp.h>
   45 #include <netncp/ncp_conn.h>
   46 #include <netncp/ncp_rq.h>
   47 #include <netncp/ncp_subr.h>
   48 #include <netncp/ncp_ncp.h>
   49 #include <netncp/ncp_sock.h>
   50 #include <netncp/ncp_nls.h>
   51 
   52 static MALLOC_DEFINE(M_NCPRQ, "NCPRQ", "NCP request");
   53 
   54 static int ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
   55 
   56 int
   57 ncp_rq_alloc_any(u_int32_t ptype, u_int8_t fn, struct ncp_conn *ncp,
   58         struct thread *td, struct ucred *cred,
   59         struct ncp_rq **rqpp)
   60 {
   61         struct ncp_rq *rqp;
   62         int error;
   63 
   64         rqp = malloc(sizeof(*rqp), M_NCPRQ, M_WAITOK);
   65         error = ncp_rq_init_any(rqp, ptype, fn, ncp, td, cred);
   66         rqp->nr_flags |= NCPR_ALLOCED;
   67         if (error) {
   68                 ncp_rq_done(rqp);
   69                 return error;
   70         }
   71         *rqpp = rqp;
   72         return 0;
   73 }
   74 
   75 int
   76 ncp_rq_alloc(u_int8_t fn, struct ncp_conn *ncp,
   77         struct thread *td, struct ucred *cred, struct ncp_rq **rqpp)
   78 {
   79         return ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, td, cred, rqpp);
   80 }
   81 
   82 int
   83 ncp_rq_alloc_subfn(u_int8_t fn, u_int8_t subfn, struct ncp_conn *ncp,
   84         struct thread *td, struct ucred *cred, struct ncp_rq **rqpp)
   85 {
   86         struct ncp_rq *rqp;
   87         int error;
   88 
   89         error = ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, td, cred, &rqp);
   90         if (error)
   91                 return error;
   92         mb_reserve(&rqp->rq, 2);
   93         mb_put_uint8(&rqp->rq, subfn);
   94         *rqpp = rqp;
   95         return 0;
   96 }
   97 
   98 int
   99 ncp_rq_init_any(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,
  100         struct ncp_conn *ncp,
  101         struct thread *td, struct ucred *cred)
  102 {
  103         struct ncp_rqhdr *rq;
  104         struct ncp_bursthdr *brq;
  105         struct mbchain *mbp;
  106         int error;
  107 
  108         bzero(rqp, sizeof(*rqp));
  109         error = ncp_conn_access(ncp, cred, NCPM_EXECUTE);
  110         if (error)
  111                 return error;
  112         rqp->nr_td = td;
  113         rqp->nr_cred = cred;
  114         rqp->nr_conn = ncp;
  115         mbp = &rqp->rq;
  116         if (mb_init(mbp) != 0)
  117                 return ENOBUFS;
  118         switch(ptype) {
  119             case NCP_PACKET_BURST:
  120                 brq = (struct ncp_bursthdr*)mb_reserve(mbp, sizeof(*brq));
  121                 brq->bh_type = ptype;
  122                 brq->bh_streamtype = 0x2;
  123                 break;
  124             default:
  125                 rq = (struct ncp_rqhdr*)mb_reserve(mbp, sizeof(*rq));
  126                 rq->type = ptype;
  127                 rq->seq = 0;    /* filled later */
  128                 rq->fn = fn;
  129                 break;
  130         }
  131         rqp->nr_minrplen = -1;
  132         return 0;
  133 }
  134 
  135 void
  136 ncp_rq_done(struct ncp_rq *rqp)
  137 {
  138         mb_done(&rqp->rq);
  139         md_done(&rqp->rp);
  140         if (rqp->nr_flags & NCPR_ALLOCED)
  141                 free(rqp, M_NCPRQ);
  142         return;
  143 }
  144 
  145 /*
  146  * Routines to fill the request
  147  */
  148 
  149 static int
  150 ncp_rq_pathstrhelp(struct mbchain *mbp, c_caddr_t src, caddr_t dst,
  151     size_t *srclen, size_t *dstlen)
  152 {
  153         int len;
  154 
  155         if (*srclen < *dstlen) {
  156                 *dstlen = *srclen;
  157                 len = (int)*srclen;
  158         } else {
  159                 *srclen = *dstlen;
  160                 len = (int)*dstlen;
  161         }
  162         ncp_pathcopy(src, dst, len, mbp->mb_udata);
  163         return 0;
  164 }
  165 
  166 int
  167 ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name,
  168         struct ncp_nlstables *nt)
  169 {
  170         struct mbchain *mbp = &rqp->rq;
  171 
  172         mb_put_uint8(mbp, size);
  173         mbp->mb_copy = ncp_rq_pathstrhelp;
  174         mbp->mb_udata = nt;
  175         return mb_put_mem(mbp, (c_caddr_t)name, size, MB_MCUSTOM);
  176 }
  177 
  178 int 
  179 ncp_rq_pstring(struct ncp_rq *rqp, const char *s)
  180 {
  181         u_int len = strlen(s);
  182         int error;
  183 
  184         if (len > 255)
  185                 return EINVAL;
  186         error = mb_put_uint8(&rqp->rq, len);
  187         if (error)
  188                 return error;
  189         return mb_put_mem(&rqp->rq, s, len, MB_MSYSTEM);
  190 }
  191 
  192 int 
  193 ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
  194                     int namelen, u_char *path, struct ncp_nlstables *nt)
  195 {
  196         struct mbchain *mbp = &rqp->rq;
  197         int complen;
  198 
  199         mb_put_uint8(mbp, vol_num);
  200         mb_put_mem(mbp, (c_caddr_t)&dir_base, sizeof(dir_base), MB_MSYSTEM);
  201         mb_put_uint8(mbp, 1);   /* with dirbase */
  202         if (path != NULL && path[0]) {
  203                 if (namelen < 0) {
  204                         namelen = *path++;
  205                         mb_put_uint8(mbp, namelen);
  206                         for(; namelen; namelen--) {
  207                                 complen = *path++;
  208                                 mb_put_uint8(mbp, complen);
  209                                 mb_put_mem(mbp, path, complen, MB_MSYSTEM);
  210                                 path += complen;
  211                         }
  212                 } else {
  213                         mb_put_uint8(mbp, 1);   /* 1 component */
  214                         ncp_rq_pathstring(rqp, namelen, path, nt);
  215                 }
  216         } else {
  217                 mb_put_uint8(mbp, 0);
  218                 mb_put_uint8(mbp, 0);
  219         }
  220         return 0;
  221 }
  222 
  223 /* 
  224  * Make a signature for the current packet and add it at the end of the
  225  * packet.
  226  */
  227 static int
  228 ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size)
  229 {
  230         u_char data[64];
  231         int error;
  232 
  233         bzero(data, sizeof(data));
  234         bcopy(conn->sign_root, data, 8);
  235         setdle(data, 8, *size);
  236         m_copydata(rqp->rq.mb_top, sizeof(struct ncp_rqhdr) - 1,
  237                 min((*size) - sizeof(struct ncp_rqhdr)+1, 52), data + 12);
  238         ncp_sign(conn->sign_state, data, conn->sign_state);
  239         error = mb_put_mem(&rqp->rq, (caddr_t)conn->sign_state, 8, MB_MSYSTEM);
  240         if (error)
  241                 return error;
  242         (*size) += 8;
  243         return 0;
  244 }
  245 
  246 /*
  247  * Low level send rpc, here we do not attempt to restore any connection,
  248  * Connection expected to be locked
  249  */
  250 int
  251 ncp_request_int(struct ncp_rq *rqp)
  252 {
  253         struct ncp_conn *conn = rqp->nr_conn;
  254         struct thread *td = conn->td;
  255         struct socket *so = conn->ncp_so;
  256         struct ncp_rqhdr *rq;
  257         struct ncp_rphdr *rp=NULL;
  258         struct timeval tv;
  259         struct mbuf *m, *mreply = NULL;
  260         struct mbchain *mbp;
  261         int error, len, dosend, plen = 0, gotpacket;
  262 
  263         if (so == NULL) {
  264                 printf("%s: ncp_so is NULL !\n",__func__);
  265                 ncp_conn_invalidate(conn);
  266                 return ENOTCONN;
  267         }
  268         if (td == NULL)
  269                 td = curthread; /* XXX maybe procpage ? */
  270         /*
  271          * Flush out replies on previous reqs
  272          */
  273         tv.tv_sec = 0;
  274         tv.tv_usec = 0;
  275         while (selsocket(so, POLLIN, &tv, td) == 0) {
  276                 if (ncp_sock_recv(so, &m, &len) != 0)
  277                         break;
  278                 m_freem(m);
  279         }
  280         mbp = &rqp->rq;
  281         len = mb_fixhdr(mbp);
  282         rq = mtod(mbp->mb_top, struct ncp_rqhdr *);
  283         rq->seq = conn->seq;
  284         m = rqp->rq.mb_top;
  285 
  286         switch (rq->fn) {
  287             case 0x15: case 0x16: case 0x17: case 0x23:
  288                 *(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq));
  289                 break;
  290         }
  291         if (conn->flags & NCPFL_SIGNACTIVE) {
  292                 error = ncp_sign_packet(conn, rqp, &len);
  293                 if (error)
  294                         return error;
  295                 mbp->mb_top->m_pkthdr.len = len;
  296         }
  297         rq->conn_low = conn->connid & 0xff;
  298         /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
  299         /* XXX: this is temporary fix till I find a better solution */
  300         rq->task = rq->conn_low;
  301         rq->conn_high = conn->connid >> 8;
  302         rqp->rexmit = conn->li.retry_count;
  303         error = 0;
  304         for(dosend = 1;;) {
  305                 if (rqp->rexmit-- == 0) {
  306                         error = ETIMEDOUT;
  307                         break;
  308                 }
  309                 error = 0;
  310                 if (dosend) {
  311                         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,
  312                                 mbp->mb_top->m_pkthdr.len, rq->seq, rq->task
  313                         );
  314                         error = ncp_sock_send(so, mbp->mb_top, rqp);
  315                         if (error)
  316                                 break;
  317                 }
  318                 tv.tv_sec = conn->li.timeout;
  319                 tv.tv_usec = 0;
  320                 error = selsocket(so, POLLIN, &tv, td);
  321                 if (error == EWOULDBLOCK )      /* timeout expired */
  322                         continue;
  323                 error = ncp_chkintr(conn, td);
  324                 if (error)
  325                         break;
  326                 /*
  327                  * At this point it is possible to get more than one
  328                  * reply from server. In general, last reply should be for
  329                  * current request, but not always. So, we loop through
  330                  * all replies to find the right answer and flush others.
  331                  */
  332                 gotpacket = 0;  /* nothing good found */
  333                 dosend = 1;     /* resend rq if error */
  334                 for (;;) {
  335                         error = 0;
  336                         tv.tv_sec = 0;
  337                         tv.tv_usec = 0;
  338                         if (selsocket(so, POLLIN, &tv, td) != 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: 426700d076278f72f34cda7fd83fbbcb


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