[BACK]Return to krpc_subr.c CVS log [TXT][DIR] Up to [local] / sys / nfs

Annotation of sys/nfs/krpc_subr.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: krpc_subr.c,v 1.14 2007/02/27 19:09:56 deraadt 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 <net/if.h>
                     58: #include <netinet/in.h>
                     59:
                     60: #include <nfs/rpcv2.h>
                     61: #include <nfs/krpc.h>
                     62: #include <nfs/xdr_subs.h>
                     63: #include <dev/rndvar.h>
                     64:
                     65: /*
                     66:  * Kernel support for Sun RPC
                     67:  *
                     68:  * Used currently for bootstrapping in nfs diskless configurations.
                     69:  */
                     70:
                     71: /*
                     72:  * Generic RPC headers
                     73:  */
                     74:
                     75: struct auth_info {
                     76:        u_int32_t       authtype;       /* auth type */
                     77:        u_int32_t       authlen;        /* auth length */
                     78: };
                     79:
                     80: struct auth_unix {
                     81:        int32_t   ua_time;
                     82:        int32_t   ua_hostname;  /* null */
                     83:        int32_t   ua_uid;
                     84:        int32_t   ua_gid;
                     85:        int32_t   ua_gidlist;   /* null */
                     86: };
                     87:
                     88: struct rpc_call {
                     89:        u_int32_t       rp_xid;         /* request transaction id */
                     90:        int32_t         rp_direction;   /* call direction (0) */
                     91:        u_int32_t       rp_rpcvers;     /* rpc version (2) */
                     92:        u_int32_t       rp_prog;        /* program */
                     93:        u_int32_t       rp_vers;        /* version */
                     94:        u_int32_t       rp_proc;        /* procedure */
                     95:        struct  auth_info rpc_auth;
                     96:        struct  auth_unix rpc_unix;
                     97:        struct  auth_info rpc_verf;
                     98: };
                     99:
                    100: struct rpc_reply {
                    101:        u_int32_t rp_xid;               /* request transaction id */
                    102:        int32_t   rp_direction;         /* call direction (1) */
                    103:        int32_t   rp_astatus;           /* accept status (0: accepted) */
                    104:        union {
                    105:                u_int32_t rpu_errno;
                    106:                struct {
                    107:                        struct auth_info rok_auth;
                    108:                        u_int32_t       rok_status;
                    109:                } rpu_rok;
                    110:        } rp_u;
                    111: };
                    112: #define rp_errno  rp_u.rpu_errno
                    113: #define rp_auth   rp_u.rpu_rok.rok_auth
                    114: #define rp_status rp_u.rpu_rok.rok_status
                    115:
                    116: #define MIN_REPLY_HDR 16       /* xid, dir, astat, errno */
                    117:
                    118: /*
                    119:  * What is the longest we will wait before re-sending a request?
                    120:  * Note this is also the frequency of "RPC timeout" messages.
                    121:  * The re-send loop count sup linearly to this maximum, so the
                    122:  * first complaint will happen after (1+2+3+4+5)=15 seconds.
                    123:  */
                    124: #define        MAX_RESEND_DELAY 5      /* seconds */
                    125:
                    126: /*
                    127:  * Call portmap to lookup a port number for a particular rpc program
                    128:  * Returns non-zero error on failure.
                    129:  */
                    130: int
                    131: krpc_portmap(sin,  prog, vers, portp)
                    132:        struct sockaddr_in *sin;                /* server address */
                    133:        u_int prog, vers;       /* host order */
                    134:        u_int16_t *portp;       /* network order */
                    135: {
                    136:        struct sdata {
                    137:                u_int32_t prog;         /* call program */
                    138:                u_int32_t vers;         /* call version */
                    139:                u_int32_t proto;        /* call protocol */
                    140:                u_int32_t port;         /* call port (unused) */
                    141:        } *sdata;
                    142:        struct rdata {
                    143:                u_int16_t pad;
                    144:                u_int16_t port;
                    145:        } *rdata;
                    146:        struct mbuf *m;
                    147:        int error;
                    148:
                    149:        /* The portmapper port is fixed. */
                    150:        if (prog == PMAPPROG) {
                    151:                *portp = htons(PMAPPORT);
                    152:                return 0;
                    153:        }
                    154:
                    155:        m = m_get(M_WAIT, MT_DATA);
                    156:        sdata = mtod(m, struct sdata *);
                    157:        m->m_len = sizeof(*sdata);
                    158:
                    159:        /* Do the RPC to get it. */
                    160:        sdata->prog = txdr_unsigned(prog);
                    161:        sdata->vers = txdr_unsigned(vers);
                    162:        sdata->proto = txdr_unsigned(IPPROTO_UDP);
                    163:        sdata->port = 0;
                    164:
                    165:        sin->sin_port = htons(PMAPPORT);
                    166:        error = krpc_call(sin, PMAPPROG, PMAPVERS,
                    167:            PMAPPROC_GETPORT, &m, NULL, -1);
                    168:        if (error)
                    169:                return error;
                    170:
                    171:        if (m->m_len < sizeof(*rdata)) {
                    172:                m = m_pullup(m, sizeof(*rdata));
                    173:                if (m == NULL)
                    174:                        return ENOBUFS;
                    175:        }
                    176:        rdata = mtod(m, struct rdata *);
                    177:        *portp = rdata->port;
                    178:
                    179:        m_freem(m);
                    180:        return 0;
                    181: }
                    182:
                    183: /*
                    184:  * Do a remote procedure call (RPC) and wait for its reply.
                    185:  * If from_p is non-null, then we are doing broadcast, and
                    186:  * the address from whence the response came is saved there.
                    187:  */
                    188: int
                    189: krpc_call(sa, prog, vers, func, data, from_p, retries)
                    190:        struct sockaddr_in *sa;
                    191:        u_int prog, vers, func;
                    192:        struct mbuf **data;     /* input/output */
                    193:        struct mbuf **from_p;   /* output */
                    194:        int retries;
                    195: {
                    196:        struct socket *so;
                    197:        struct sockaddr_in *sin;
                    198:        struct mbuf *m, *nam, *mhead, *from, *mopt;
                    199:        struct rpc_call *call;
                    200:        struct rpc_reply *reply;
                    201:        struct uio auio;
                    202:        int error, rcvflg, timo, secs, len;
                    203:        static u_int32_t xid = 0;
                    204:        u_int32_t newxid;
                    205:        int *ip;
                    206:        struct timeval *tv;
                    207:
                    208:        /*
                    209:         * Validate address family.
                    210:         * Sorry, this is INET specific...
                    211:         */
                    212:        if (sa->sin_family != AF_INET)
                    213:                return (EAFNOSUPPORT);
                    214:
                    215:        /* Free at end if not null. */
                    216:        nam = mhead = NULL;
                    217:        from = NULL;
                    218:
                    219:        /*
                    220:         * Create socket and set its receive timeout.
                    221:         */
                    222:        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
                    223:                goto out;
                    224:
                    225:        m = m_get(M_WAIT, MT_SOOPTS);
                    226:        tv = mtod(m, struct timeval *);
                    227:        m->m_len = sizeof(*tv);
                    228:        tv->tv_sec = 1;
                    229:        tv->tv_usec = 0;
                    230:        if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
                    231:                goto out;
                    232:
                    233:        /*
                    234:         * Enable broadcast if necessary.
                    235:         */
                    236:        if (from_p) {
                    237:                int32_t *on;
                    238:                m = m_get(M_WAIT, MT_SOOPTS);
                    239:                on = mtod(m, int32_t *);
                    240:                m->m_len = sizeof(*on);
                    241:                *on = 1;
                    242:                if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
                    243:                        goto out;
                    244:        }
                    245:
                    246:        /*
                    247:         * Bind the local endpoint to a reserved port,
                    248:         * because some NFS servers refuse requests from
                    249:         * non-reserved (non-privileged) ports.
                    250:         */
                    251:        m = m_getclr(M_WAIT, MT_SONAME);
                    252:        sin = mtod(m, struct sockaddr_in *);
                    253:        sin->sin_len = m->m_len = sizeof(*sin);
                    254:        sin->sin_family = AF_INET;
                    255:        sin->sin_addr.s_addr = INADDR_ANY;
                    256:
                    257:        MGET(mopt, M_WAIT, MT_SOOPTS);
                    258:        mopt->m_len = sizeof(int);
                    259:        ip = mtod(mopt, int *);
                    260:        *ip = IP_PORTRANGE_LOW;
                    261:        error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
                    262:        if (error)
                    263:                goto out;
                    264:
                    265:        MGET(m, M_WAIT, MT_SONAME);
                    266:        sin = mtod(m, struct sockaddr_in *);
                    267:        sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
                    268:        sin->sin_family = AF_INET;
                    269:        sin->sin_addr.s_addr = INADDR_ANY;
                    270:        sin->sin_port = htons(0);
                    271:        error = sobind(so, m);
                    272:        m_freem(m);
                    273:        if (error) {
                    274:                printf("bind failed\n");
                    275:                goto out;
                    276:        }
                    277:
                    278:        MGET(mopt, M_WAIT, MT_SOOPTS);
                    279:        mopt->m_len = sizeof(int);
                    280:        ip = mtod(mopt, int *);
                    281:        *ip = IP_PORTRANGE_DEFAULT;
                    282:        error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
                    283:        if (error)
                    284:                goto out;
                    285:
                    286:        /*
                    287:         * Setup socket address for the server.
                    288:         */
                    289:        nam = m_get(M_WAIT, MT_SONAME);
                    290:        sin = mtod(nam, struct sockaddr_in *);
                    291:        bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len));
                    292:
                    293:        /*
                    294:         * Prepend RPC message header.
                    295:         */
                    296:        mhead = m_gethdr(M_WAIT, MT_DATA);
                    297:        mhead->m_next = *data;
                    298:        call = mtod(mhead, struct rpc_call *);
                    299:        mhead->m_len = sizeof(*call);
                    300:        bzero((caddr_t)call, sizeof(*call));
                    301:        /* rpc_call part */
                    302:        while ((newxid = arc4random()) == xid);
                    303:        xid = newxid;
                    304:        call->rp_xid = txdr_unsigned(xid);
                    305:        /* call->rp_direction = 0; */
                    306:        call->rp_rpcvers = txdr_unsigned(2);
                    307:        call->rp_prog = txdr_unsigned(prog);
                    308:        call->rp_vers = txdr_unsigned(vers);
                    309:        call->rp_proc = txdr_unsigned(func);
                    310:        /* rpc_auth part (auth_unix as root) */
                    311:        call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX);
                    312:        call->rpc_auth.authlen  = txdr_unsigned(sizeof(struct auth_unix));
                    313:        /* rpc_verf part (auth_null) */
                    314:        call->rpc_verf.authtype = 0;
                    315:        call->rpc_verf.authlen  = 0;
                    316:
                    317:        /*
                    318:         * Setup packet header
                    319:         */
                    320:        len = 0;
                    321:        m = mhead;
                    322:        while (m) {
                    323:                len += m->m_len;
                    324:                m = m->m_next;
                    325:        }
                    326:        mhead->m_pkthdr.len = len;
                    327:        mhead->m_pkthdr.rcvif = NULL;
                    328:
                    329:        /*
                    330:         * Send it, repeatedly, until a reply is received,
                    331:         * but delay each re-send by an increasing amount.
                    332:         * If the delay hits the maximum, start complaining.
                    333:         */
                    334:        for (timo = 0; retries; retries--) {
                    335:                /* Send RPC request (or re-send). */
                    336:                m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
                    337:                if (m == NULL) {
                    338:                        error = ENOBUFS;
                    339:                        goto out;
                    340:                }
                    341:                error = sosend(so, nam, NULL, m, NULL, 0);
                    342:                if (error) {
                    343:                        printf("krpc_call: sosend: %d\n", error);
                    344:                        goto out;
                    345:                }
                    346:                m = NULL;
                    347:
                    348:                /* Determine new timeout. */
                    349:                if (timo < MAX_RESEND_DELAY)
                    350:                        timo++;
                    351:                else
                    352:                        printf("RPC timeout for server %s (0x%x) prog %u\n",
                    353:                            inet_ntoa(sin->sin_addr),
                    354:                            ntohl(sin->sin_addr.s_addr), prog);
                    355:
                    356:                /*
                    357:                 * Wait for up to timo seconds for a reply.
                    358:                 * The socket receive timeout was set to 1 second.
                    359:                 */
                    360:                secs = timo;
                    361:                while (secs > 0) {
                    362:                        if (from) {
                    363:                                m_freem(from);
                    364:                                from = NULL;
                    365:                        }
                    366:                        if (m) {
                    367:                                m_freem(m);
                    368:                                m = NULL;
                    369:                        }
                    370:                        auio.uio_resid = len = 1<<16;
                    371:                        auio.uio_procp = NULL;
                    372:                        rcvflg = 0;
                    373:                        error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
                    374:                        if (error == EWOULDBLOCK) {
                    375:                                secs--;
                    376:                                continue;
                    377:                        }
                    378:                        if (error)
                    379:                                goto out;
                    380:                        len -= auio.uio_resid;
                    381:
                    382:                        /* Does the reply contain at least a header? */
                    383:                        if (len < MIN_REPLY_HDR)
                    384:                                continue;
                    385:                        if (m->m_len < MIN_REPLY_HDR)
                    386:                                continue;
                    387:                        reply = mtod(m, struct rpc_reply *);
                    388:
                    389:                        /* Is it the right reply? */
                    390:                        if (reply->rp_direction != txdr_unsigned(RPC_REPLY))
                    391:                                continue;
                    392:
                    393:                        if (reply->rp_xid != txdr_unsigned(xid))
                    394:                                continue;
                    395:
                    396:                        /* Was RPC accepted? (authorization OK) */
                    397:                        if (reply->rp_astatus != 0) {
                    398:                                error = fxdr_unsigned(u_int32_t, reply->rp_errno);
                    399:                                printf("rpc denied, error=%d\n", error);
                    400:                                continue;
                    401:                        }
                    402:
                    403:                        /* Did the call succeed? */
                    404:                        if (reply->rp_status != 0) {
                    405:                                error = fxdr_unsigned(u_int32_t, reply->rp_status);
                    406:                                printf("rpc denied, status=%d\n", error);
                    407:                                continue;
                    408:                        }
                    409:
                    410:                        goto gotreply;  /* break two levels */
                    411:
                    412:                } /* while secs */
                    413:        } /* forever send/receive */
                    414:
                    415:        error = ETIMEDOUT;
                    416:        goto out;
                    417:
                    418:  gotreply:
                    419:
                    420:        /*
                    421:         * Get RPC reply header into first mbuf,
                    422:         * get its length, then strip it off.
                    423:         */
                    424:        len = sizeof(*reply);
                    425:        if (m->m_len < len) {
                    426:                m = m_pullup(m, len);
                    427:                if (m == NULL) {
                    428:                        error = ENOBUFS;
                    429:                        goto out;
                    430:                }
                    431:        }
                    432:        reply = mtod(m, struct rpc_reply *);
                    433:        if (reply->rp_auth.authtype != 0) {
                    434:                len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
                    435:                len = (len + 3) & ~3; /* XXX? */
                    436:        }
                    437:        m_adj(m, len);
                    438:
                    439:        /* result */
                    440:        *data = m;
                    441:        if (from_p) {
                    442:                *from_p = from;
                    443:                from = NULL;
                    444:        }
                    445:
                    446:  out:
                    447:        if (nam) m_freem(nam);
                    448:        if (mhead) m_freem(mhead);
                    449:        if (from) m_freem(from);
                    450:        soclose(so);
                    451:        return error;
                    452: }
                    453:
                    454: /*
                    455:  * eXternal Data Representation routines.
                    456:  * (but with non-standard args...)
                    457:  */
                    458:
                    459: /*
                    460:  * String representation for RPC.
                    461:  */
                    462: struct xdr_string {
                    463:        u_int32_t len;          /* length without null or padding */
                    464:        char data[4];   /* data (longer, of course) */
                    465:     /* data is padded to a long-word boundary */
                    466: };
                    467:
                    468: struct mbuf *
                    469: xdr_string_encode(str, len)
                    470:        char *str;
                    471:        int len;
                    472: {
                    473:        struct mbuf *m;
                    474:        struct xdr_string *xs;
                    475:        int dlen;       /* padded string length */
                    476:        int mlen;       /* message length */
                    477:
                    478:        dlen = (len + 3) & ~3;
                    479:        mlen = dlen + 4;
                    480:
                    481:        if (mlen > MCLBYTES)            /* If too big, we just can't do it. */
                    482:                return (NULL);
                    483:
                    484:        m = m_get(M_WAIT, MT_DATA);
                    485:        if (mlen > MLEN) {
                    486:                MCLGET(m, M_WAIT);
                    487:                if ((m->m_flags & M_EXT) == 0) {
                    488:                        (void) m_free(m);       /* There can be only one. */
                    489:                        return (NULL);
                    490:                }
                    491:        }
                    492:        xs = mtod(m, struct xdr_string *);
                    493:        m->m_len = mlen;
                    494:        xs->len = txdr_unsigned(len);
                    495:        bcopy(str, xs->data, len);
                    496:        return (m);
                    497: }
                    498:
                    499: struct mbuf *
                    500: xdr_string_decode(m, str, len_p)
                    501:        struct mbuf *m;
                    502:        char *str;
                    503:        int *len_p;             /* bufsize - 1 */
                    504: {
                    505:        struct xdr_string *xs;
                    506:        int mlen;       /* message length */
                    507:        int slen;       /* string length */
                    508:
                    509:        if (m->m_len < 4) {
                    510:                m = m_pullup(m, 4);
                    511:                if (m == NULL)
                    512:                        return (NULL);
                    513:        }
                    514:        xs = mtod(m, struct xdr_string *);
                    515:        slen = fxdr_unsigned(u_int32_t, xs->len);
                    516:        mlen = 4 + ((slen + 3) & ~3);
                    517:
                    518:        if (slen > *len_p)
                    519:                slen = *len_p;
                    520:        if (slen > m->m_pkthdr.len) {
                    521:                m_freem(m);
                    522:                return (NULL);
                    523:        }
                    524:        m_copydata(m, 4, slen, str);
                    525:        m_adj(m, mlen);
                    526:
                    527:        str[slen] = '\0';
                    528:        *len_p = slen;
                    529:
                    530:        return (m);
                    531: }
                    532:
                    533:
                    534: /*
                    535:  * Inet address in RPC messages
                    536:  * (Note, really four ints, NOT chars.  Blech.)
                    537:  */
                    538: struct xdr_inaddr {
                    539:        u_int32_t atype;
                    540:        u_int32_t addr[4];
                    541: };
                    542:
                    543: struct mbuf *
                    544: xdr_inaddr_encode(ia)
                    545:        struct in_addr *ia;             /* already in network order */
                    546: {
                    547:        struct mbuf *m;
                    548:        struct xdr_inaddr *xi;
                    549:        u_int8_t *cp;
                    550:        u_int32_t *ip;
                    551:
                    552:        m = m_get(M_WAIT, MT_DATA);
                    553:        xi = mtod(m, struct xdr_inaddr *);
                    554:        m->m_len = sizeof(*xi);
                    555:        xi->atype = txdr_unsigned(1);
                    556:        ip = xi->addr;
                    557:        cp = (u_int8_t *)&ia->s_addr;
                    558:        *ip++ = txdr_unsigned(*cp++);
                    559:        *ip++ = txdr_unsigned(*cp++);
                    560:        *ip++ = txdr_unsigned(*cp++);
                    561:        *ip++ = txdr_unsigned(*cp++);
                    562:
                    563:        return (m);
                    564: }
                    565:
                    566: struct mbuf *
                    567: xdr_inaddr_decode(m, ia)
                    568:        struct mbuf *m;
                    569:        struct in_addr *ia;             /* already in network order */
                    570: {
                    571:        struct xdr_inaddr *xi;
                    572:        u_int8_t *cp;
                    573:        u_int32_t *ip;
                    574:
                    575:        if (m->m_len < sizeof(*xi)) {
                    576:                m = m_pullup(m, sizeof(*xi));
                    577:                if (m == NULL)
                    578:                        return (NULL);
                    579:        }
                    580:        xi = mtod(m, struct xdr_inaddr *);
                    581:        if (xi->atype != txdr_unsigned(1)) {
                    582:                ia->s_addr = INADDR_ANY;
                    583:                goto out;
                    584:        }
                    585:        ip = xi->addr;
                    586:        cp = (u_int8_t *)&ia->s_addr;
                    587:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    588:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    589:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    590:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    591:
                    592: out:
                    593:        m_adj(m, sizeof(*xi));
                    594:        return (m);
                    595: }

CVSweb