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/nfs/krpc_subr.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 /*      $OpenBSD: krpc_subr.c,v 1.37 2022/06/06 14:45:41 claudio Exp $  */
    2 /*      $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1995 Gordon Ross, Adam Glass
    6  * Copyright (c) 1992 Regents of the University of California.
    7  * All rights reserved.
    8  *
    9  * This software was developed by the Computer Systems Engineering group
   10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   11  * contributed to Berkeley.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. All advertising materials mentioning features or use of this software
   22  *    must display the following acknowledgement:
   23  *      This product includes software developed by the University of
   24  *      California, Lawrence Berkeley Laboratory and its contributors.
   25  * 4. Neither the name of the University nor the names of its contributors
   26  *    may be used to endorse or promote products derived from this software
   27  *    without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   39  * SUCH DAMAGE.
   40  *
   41  * partially based on:
   42  *      libnetboot/rpc.c
   43  *               @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/conf.h>
   49 #include <sys/ioctl.h>
   50 #include <sys/proc.h>
   51 #include <sys/mount.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/reboot.h>
   54 #include <sys/socket.h>
   55 #include <sys/socketvar.h>
   56 
   57 #include <netinet/in.h>
   58 
   59 #include <nfs/rpcv2.h>
   60 #include <nfs/krpc.h>
   61 #include <nfs/xdr_subs.h>
   62 #include <crypto/idgen.h>
   63 
   64 /*
   65  * Kernel support for Sun RPC
   66  *
   67  * Used currently for bootstrapping in nfs diskless configurations.
   68  */
   69 
   70 /*
   71  * Generic RPC headers
   72  */
   73 
   74 struct auth_info {
   75         u_int32_t       authtype;       /* auth type */
   76         u_int32_t       authlen;        /* auth length */
   77 };
   78 
   79 struct auth_unix {
   80         int32_t   ua_time;
   81         int32_t   ua_hostname;  /* null */
   82         int32_t   ua_uid;
   83         int32_t   ua_gid;
   84         int32_t   ua_gidlist;   /* null */
   85 };
   86 
   87 struct rpc_call {
   88         u_int32_t       rp_xid;         /* request transaction id */
   89         int32_t         rp_direction;   /* call direction (0) */
   90         u_int32_t       rp_rpcvers;     /* rpc version (2) */
   91         u_int32_t       rp_prog;        /* program */
   92         u_int32_t       rp_vers;        /* version */
   93         u_int32_t       rp_proc;        /* procedure */
   94         struct  auth_info rpc_auth;
   95         struct  auth_unix rpc_unix;
   96         struct  auth_info rpc_verf;
   97 };
   98 
   99 struct rpc_reply {
  100         u_int32_t rp_xid;               /* request transaction id */
  101         int32_t   rp_direction;         /* call direction (1) */
  102         int32_t   rp_astatus;           /* accept status (0: accepted) */
  103         union {
  104                 u_int32_t rpu_errno;
  105                 struct {
  106                         struct auth_info rok_auth;
  107                         u_int32_t       rok_status;
  108                 } rpu_rok;
  109         } rp_u;
  110 };
  111 #define rp_errno  rp_u.rpu_errno
  112 #define rp_auth   rp_u.rpu_rok.rok_auth
  113 #define rp_status rp_u.rpu_rok.rok_status
  114 
  115 #define MIN_REPLY_HDR 16        /* xid, dir, astat, errno */
  116 
  117 u_int32_t krpc_get_xid(void);
  118 
  119 /*
  120  * Return an unpredictable XID.
  121  */
  122 u_int32_t
  123 krpc_get_xid(void)
  124 {
  125         static struct idgen32_ctx krpc_xid_ctx;
  126         static int called = 0;
  127 
  128         if (!called) {
  129                 called = 1;
  130                 idgen32_init(&krpc_xid_ctx);
  131         }
  132         return idgen32(&krpc_xid_ctx);
  133 }
  134 
  135 /*
  136  * What is the longest we will wait before re-sending a request?
  137  * Note this is also the frequency of "RPC timeout" messages.
  138  * The re-send loop count sup linearly to this maximum, so the
  139  * first complaint will happen after (1+2+3+4+5)=15 seconds.
  140  */
  141 #define MAX_RESEND_DELAY 5      /* seconds */
  142 
  143 /*
  144  * Call portmap to lookup a port number for a particular rpc program
  145  * Returns non-zero error on failure.
  146  */
  147 int
  148 krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp)
  149 {
  150         struct sdata {
  151                 u_int32_t prog;         /* call program */
  152                 u_int32_t vers;         /* call version */
  153                 u_int32_t proto;        /* call protocol */
  154                 u_int32_t port;         /* call port (unused) */
  155         } *sdata;
  156         struct rdata {
  157                 u_int16_t pad;
  158                 u_int16_t port;
  159         } *rdata;
  160         struct mbuf *m;
  161         int error;
  162 
  163         /* The portmapper port is fixed. */
  164         if (prog == PMAPPROG) {
  165                 *portp = htons(PMAPPORT);
  166                 return 0;
  167         }
  168 
  169         m = m_get(M_WAIT, MT_DATA);
  170         sdata = mtod(m, struct sdata *);
  171         m->m_len = sizeof(*sdata);
  172 
  173         /* Do the RPC to get it. */
  174         sdata->prog = txdr_unsigned(prog);
  175         sdata->vers = txdr_unsigned(vers);
  176         sdata->proto = txdr_unsigned(IPPROTO_UDP);
  177         sdata->port = 0;
  178 
  179         sin->sin_port = htons(PMAPPORT);
  180         error = krpc_call(sin, PMAPPROG, PMAPVERS,
  181             PMAPPROC_GETPORT, &m, NULL, -1);
  182         if (error) 
  183                 return error;
  184 
  185         if (m->m_len < sizeof(*rdata)) {
  186                 m = m_pullup(m, sizeof(*rdata));
  187                 if (m == NULL)
  188                         return ENOBUFS;
  189         }
  190         rdata = mtod(m, struct rdata *);
  191         *portp = rdata->port;
  192 
  193         m_freem(m);
  194         return 0;
  195 }
  196 
  197 /*
  198  * Do a remote procedure call (RPC) and wait for its reply.
  199  * If from_p is non-null, then we are doing broadcast, and
  200  * the address from whence the response came is saved there.
  201  * data:        input/output
  202  * from_p:      output
  203  */
  204 int
  205 krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func,
  206     struct mbuf **data, struct mbuf **from_p, int retries)
  207 {
  208         struct socket *so;
  209         struct sockaddr_in *sin;
  210         struct mbuf *m, *nam, *mhead, *from, *mopt;
  211         struct rpc_call *call;
  212         struct rpc_reply *reply;
  213         struct uio auio;
  214         int error, rcvflg, timo, secs, len, authlen;
  215         static u_int32_t xid = 0;
  216         char addr[INET_ADDRSTRLEN];
  217         int *ip;
  218         struct timeval tv;
  219 
  220         /*
  221          * Validate address family.
  222          * Sorry, this is INET specific...
  223          */
  224         if (sa->sin_family != AF_INET)
  225                 return (EAFNOSUPPORT);
  226 
  227         /* Free at end if not null. */
  228         nam = mhead = NULL;
  229         from = NULL;
  230 
  231         /*
  232          * Create socket and set its receive timeout.
  233          */
  234         if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
  235                 goto out;
  236 
  237         m = m_get(M_WAIT, MT_SOOPTS);
  238         tv.tv_sec = 1;
  239         tv.tv_usec = 0;
  240         memcpy(mtod(m, struct timeval *), &tv, sizeof tv);
  241         m->m_len = sizeof(tv);
  242         solock(so);
  243         error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m);
  244         sounlock(so);
  245         m_freem(m);
  246         if (error)
  247                 goto out;
  248 
  249         /*
  250          * Enable broadcast if necessary.
  251          */
  252         if (from_p) {
  253                 int32_t *on;
  254                 m = m_get(M_WAIT, MT_SOOPTS);
  255                 on = mtod(m, int32_t *);
  256                 m->m_len = sizeof(*on);
  257                 *on = 1;
  258                 solock(so);
  259                 error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m);
  260                 sounlock(so);
  261                 m_freem(m);
  262                 if (error)
  263                         goto out;
  264         }
  265 
  266         /*
  267          * Bind the local endpoint to a reserved port,
  268          * because some NFS servers refuse requests from
  269          * non-reserved (non-privileged) ports.
  270          */
  271         MGET(mopt, M_WAIT, MT_SOOPTS);
  272         mopt->m_len = sizeof(int);
  273         ip = mtod(mopt, int *);
  274         *ip = IP_PORTRANGE_LOW;
  275         solock(so);
  276         error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
  277         sounlock(so);
  278         m_freem(mopt);
  279         if (error)
  280                 goto out;
  281 
  282         MGET(m, M_WAIT, MT_SONAME);
  283         sin = mtod(m, struct sockaddr_in *);
  284         memset(sin, 0, sizeof(*sin));
  285         sin->sin_len = m->m_len = sizeof(struct sockaddr_in);
  286         sin->sin_family = AF_INET;
  287         sin->sin_addr.s_addr = INADDR_ANY;
  288         sin->sin_port = htons(0);
  289         solock(so);
  290         error = sobind(so, m, &proc0);
  291         sounlock(so);
  292         m_freem(m);
  293         if (error) {
  294                 printf("bind failed\n");
  295                 goto out;
  296         }
  297 
  298         MGET(mopt, M_WAIT, MT_SOOPTS);
  299         mopt->m_len = sizeof(int);
  300         ip = mtod(mopt, int *);
  301         *ip = IP_PORTRANGE_DEFAULT;
  302         solock(so);
  303         error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
  304         sounlock(so);
  305         m_freem(mopt);
  306         if (error)
  307                 goto out;
  308 
  309         /*
  310          * Setup socket address for the server.
  311          */
  312         nam = m_get(M_WAIT, MT_SONAME);
  313         sin = mtod(nam, struct sockaddr_in *);
  314         bcopy(sa, sin, (nam->m_len = sa->sin_len));
  315 
  316         /*
  317          * Prepend RPC message header.
  318          */
  319         mhead = m_gethdr(M_WAIT, MT_DATA);
  320         mhead->m_next = *data;
  321         call = mtod(mhead, struct rpc_call *);
  322         mhead->m_len = sizeof(*call);
  323         memset(call, 0, sizeof(*call));
  324         /* rpc_call part */
  325         xid = krpc_get_xid();
  326         call->rp_xid = txdr_unsigned(xid);
  327         /* call->rp_direction = 0; */
  328         call->rp_rpcvers = txdr_unsigned(2);
  329         call->rp_prog = txdr_unsigned(prog);
  330         call->rp_vers = txdr_unsigned(vers);
  331         call->rp_proc = txdr_unsigned(func);
  332         /* rpc_auth part (auth_unix as root) */
  333         call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX);
  334         call->rpc_auth.authlen  = txdr_unsigned(sizeof(struct auth_unix));
  335         /* rpc_verf part (auth_null) */
  336         call->rpc_verf.authtype = 0;
  337         call->rpc_verf.authlen  = 0;
  338 
  339         /*
  340          * Setup packet header
  341          */
  342         m_calchdrlen(mhead);
  343         mhead->m_pkthdr.ph_ifidx = 0;
  344 
  345         /*
  346          * Send it, repeatedly, until a reply is received,
  347          * but delay each re-send by an increasing amount.
  348          * If the delay hits the maximum, start complaining.
  349          */
  350         for (timo = 0; retries; retries--) {
  351                 /* Send RPC request (or re-send). */
  352                 m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
  353                 if (m == NULL) {
  354                         error = ENOBUFS;
  355                         goto out;
  356                 }
  357                 error = sosend(so, nam, NULL, m, NULL, 0);
  358                 if (error) {
  359                         printf("krpc_call: sosend: %d\n", error);
  360                         goto out;
  361                 }
  362                 m = NULL;
  363 
  364                 /* Determine new timeout. */
  365                 if (timo < MAX_RESEND_DELAY)
  366                         timo++;
  367                 else
  368                         printf("RPC timeout for server %s (0x%x) prog %u\n",
  369                             inet_ntop(AF_INET, &sin->sin_addr,
  370                                 addr, sizeof(addr)),
  371                             ntohl(sin->sin_addr.s_addr), prog);
  372 
  373                 /*
  374                  * Wait for up to timo seconds for a reply.
  375                  * The socket receive timeout was set to 1 second.
  376                  */
  377                 secs = timo;
  378                 while (secs > 0) {
  379                         m_freem(from);
  380                         from = NULL;
  381 
  382                         m_freem(m);
  383                         m = NULL;
  384 
  385                         auio.uio_resid = len = 1<<16;
  386                         auio.uio_procp = NULL;
  387                         rcvflg = 0;
  388                         error = soreceive(so, &from, &auio, &m, NULL, &rcvflg,
  389                             0);
  390                         if (error == EWOULDBLOCK) {
  391                                 secs--;
  392                                 continue;
  393                         }
  394                         if (error)
  395                                 goto out;
  396                         len -= auio.uio_resid;
  397 
  398                         /* Does the reply contain at least a header? */
  399                         if (len < MIN_REPLY_HDR)
  400                                 continue;
  401                         if (m->m_len < MIN_REPLY_HDR)
  402                                 continue;
  403                         reply = mtod(m, struct rpc_reply *);
  404 
  405                         /* Is it the right reply? */
  406                         if (reply->rp_direction != txdr_unsigned(RPC_REPLY))
  407                                 continue;
  408 
  409                         if (reply->rp_xid != txdr_unsigned(xid))
  410                                 continue;
  411 
  412                         /* Was RPC accepted? (authorization OK) */
  413                         if (reply->rp_astatus != 0) {
  414                                 error = fxdr_unsigned(u_int32_t, reply->rp_errno);
  415                                 printf("rpc denied, error=%d\n", error);
  416                                 continue;
  417                         }
  418 
  419                         /* Did the call succeed? */
  420                         if (reply->rp_status != 0) {
  421                                 error = fxdr_unsigned(u_int32_t, reply->rp_status);
  422                                 printf("rpc denied, status=%d\n", error);
  423                                 continue;
  424                         }
  425 
  426                         goto gotreply;  /* break two levels */
  427 
  428                 } /* while secs */
  429         } /* forever send/receive */
  430 
  431         error = ETIMEDOUT;
  432         goto out;
  433 
  434  gotreply:
  435 
  436         /*
  437          * Get RPC reply header into first mbuf,
  438          * get its length, then strip it off.
  439          */
  440         len = sizeof(*reply);
  441         KASSERT(m->m_flags & M_PKTHDR);
  442         if (m->m_pkthdr.len < len) {
  443                 error = EBADRPC;
  444                 goto out;
  445         }
  446         if (m->m_len < len) {
  447                 m = m_pullup(m, len);
  448                 if (m == NULL) {
  449                         error = ENOBUFS;
  450                         goto out;
  451                 }
  452         }
  453         reply = mtod(m, struct rpc_reply *);
  454         if (reply->rp_auth.authtype != 0) {
  455                 authlen = fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
  456                 if (authlen < 0 || authlen > RPCAUTH_MAXSIZ) {
  457                         error = EBADRPC;
  458                         goto out;
  459                 }
  460                 len += (authlen + 3) & ~3; /* XXX? */
  461         }
  462         if (len < 0 || m->m_pkthdr.len < len) {
  463                 error = EBADRPC;
  464                 goto out;
  465         }
  466         m_adj(m, len);
  467 
  468         /* result */
  469         *data = m;
  470         if (from_p && error == 0) {
  471                 *from_p = from;
  472                 from = NULL;
  473         }
  474 
  475  out:
  476         m_freem(nam);
  477         m_freem(mhead);
  478         m_freem(from);
  479         soclose(so, 0);
  480         return error;
  481 }
  482 
  483 /*
  484  * eXternal Data Representation routines.
  485  * (but with non-standard args...)
  486  */
  487 
  488 /*
  489  * String representation for RPC.
  490  */
  491 struct xdr_string {
  492         u_int32_t len;          /* length without null or padding */
  493         char data[4];   /* data (longer, of course) */
  494     /* data is padded to a long-word boundary */
  495 };
  496 
  497 struct mbuf *
  498 xdr_string_encode(char *str, int len)
  499 {
  500         struct mbuf *m;
  501         struct xdr_string *xs;
  502         int dlen;       /* padded string length */
  503         int mlen;       /* message length */
  504 
  505         dlen = (len + 3) & ~3;
  506         mlen = dlen + 4;
  507 
  508         if (mlen > MCLBYTES)            /* If too big, we just can't do it. */
  509                 return (NULL);
  510 
  511         m = m_get(M_WAIT, MT_DATA);
  512         if (mlen > MLEN) {
  513                 MCLGET(m, M_WAIT);
  514                 if ((m->m_flags & M_EXT) == 0) {
  515                         (void) m_free(m);       /* There can be only one. */
  516                         return (NULL);
  517                 }
  518         }
  519         xs = mtod(m, struct xdr_string *);
  520         m->m_len = mlen;
  521         xs->len = txdr_unsigned(len);
  522         bcopy(str, xs->data, len);
  523         return (m);
  524 }
  525 
  526 struct mbuf *
  527 xdr_string_decode(struct mbuf *m, char *str, int *len_p)
  528 {
  529         struct xdr_string *xs;
  530         int mlen;       /* message length */
  531         int slen;       /* string length */
  532 
  533         mlen = sizeof(u_int32_t);
  534         KASSERT(m->m_flags & M_PKTHDR);
  535         if (m->m_pkthdr.len < mlen) {
  536                 m_freem(m);
  537                 return (NULL);
  538         }
  539         if (m->m_len < mlen) {
  540                 m = m_pullup(m, mlen);
  541                 if (m == NULL)
  542                         return (NULL);
  543         }
  544         xs = mtod(m, struct xdr_string *);
  545         slen = fxdr_unsigned(u_int32_t, xs->len);
  546         if (slen < 0 || slen > INT_MAX - 3 - mlen) {
  547                 m_freem(m);
  548                 return (NULL);
  549         }
  550         mlen += (slen + 3) & ~3;
  551 
  552         if (slen > *len_p)
  553                 slen = *len_p;
  554         if (m->m_pkthdr.len < mlen) {
  555                 m_freem(m);
  556                 return (NULL);
  557         }
  558         m_copydata(m, 4, slen, str);
  559         m_adj(m, mlen);
  560 
  561         str[slen] = '\0';
  562         *len_p = slen;
  563 
  564         return (m);
  565 }
  566 
  567 
  568 /*
  569  * Inet address in RPC messages
  570  * (Note, really four ints, NOT chars.  Blech.)
  571  */
  572 struct xdr_inaddr {
  573         u_int32_t atype;
  574         u_int32_t addr[4];
  575 };
  576 
  577 struct mbuf *
  578 xdr_inaddr_encode(struct in_addr *ia)
  579 {
  580         struct mbuf *m;
  581         struct xdr_inaddr *xi;
  582         u_int8_t *cp;
  583         u_int32_t *ip;
  584 
  585         m = m_get(M_WAIT, MT_DATA);
  586         xi = mtod(m, struct xdr_inaddr *);
  587         m->m_len = sizeof(*xi);
  588         xi->atype = txdr_unsigned(1);
  589         ip = xi->addr;
  590         cp = (u_int8_t *)&ia->s_addr;
  591         *ip++ = txdr_unsigned(*cp++);
  592         *ip++ = txdr_unsigned(*cp++);
  593         *ip++ = txdr_unsigned(*cp++);
  594         *ip++ = txdr_unsigned(*cp++);
  595 
  596         return (m);
  597 }
  598 
  599 struct mbuf *
  600 xdr_inaddr_decode(struct mbuf *m, struct in_addr *ia)
  601 {
  602         struct xdr_inaddr *xi;
  603         u_int8_t *cp;
  604         u_int32_t *ip;
  605 
  606         if (m->m_len < sizeof(*xi)) {
  607                 m = m_pullup(m, sizeof(*xi));
  608                 if (m == NULL)
  609                         return (NULL);
  610         }
  611         xi = mtod(m, struct xdr_inaddr *);
  612         if (xi->atype != txdr_unsigned(1)) {
  613                 ia->s_addr = INADDR_ANY;
  614                 goto out;
  615         }
  616         ip = xi->addr;
  617         cp = (u_int8_t *)&ia->s_addr;
  618         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  619         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  620         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  621         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  622 
  623 out:
  624         m_adj(m, sizeof(*xi));
  625         return (m);
  626 }

Cache object: d6b3ed64637317fb2f7b5dbf48d42cd2


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