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

Cache object: 2eaaa80fcc05ab3912308d6139fc58ba


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