qemu/slirp/ip_input.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 1982, 1986, 1988, 1993
   3 *      The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
  14 *    may be used to endorse or promote products derived from this software
  15 *    without specific prior written permission.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 *
  29 *      @(#)ip_input.c  8.2 (Berkeley) 1/4/94
  30 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
  31 */
  32
  33/*
  34 * Changes and additions relating to SLiRP are
  35 * Copyright (c) 1995 Danny Gasparovski.
  36 *
  37 * Please read the file COPYRIGHT for the
  38 * terms and conditions of the copyright.
  39 */
  40
  41#include <slirp.h>
  42#include <qemu/osdep.h>
  43#include "ip_icmp.h"
  44
  45static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
  46static void ip_freef(Slirp *slirp, struct ipq *fp);
  47static void ip_enq(register struct ipasfrag *p,
  48                   register struct ipasfrag *prev);
  49static void ip_deq(register struct ipasfrag *p);
  50
  51/*
  52 * IP initialization: fill in IP protocol switch table.
  53 * All protocols not implemented in kernel go to raw IP protocol handler.
  54 */
  55void
  56ip_init(Slirp *slirp)
  57{
  58    slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
  59    udp_init(slirp);
  60    tcp_init(slirp);
  61    icmp_init(slirp);
  62}
  63
  64void ip_cleanup(Slirp *slirp)
  65{
  66    udp_cleanup(slirp);
  67    tcp_cleanup(slirp);
  68    icmp_cleanup(slirp);
  69}
  70
  71/*
  72 * Ip input routine.  Checksum and byte swap header.  If fragmented
  73 * try to reassemble.  Process options.  Pass to next level.
  74 */
  75void
  76ip_input(struct mbuf *m)
  77{
  78        Slirp *slirp = m->slirp;
  79        register struct ip *ip;
  80        int hlen;
  81
  82        DEBUG_CALL("ip_input");
  83        DEBUG_ARG("m = %lx", (long)m);
  84        DEBUG_ARG("m_len = %d", m->m_len);
  85
  86        if (m->m_len < sizeof (struct ip)) {
  87                return;
  88        }
  89
  90        ip = mtod(m, struct ip *);
  91
  92        if (ip->ip_v != IPVERSION) {
  93                goto bad;
  94        }
  95
  96        hlen = ip->ip_hl << 2;
  97        if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
  98          goto bad;                                  /* or packet too short */
  99        }
 100
 101        /* keep ip header intact for ICMP reply
 102         * ip->ip_sum = cksum(m, hlen);
 103         * if (ip->ip_sum) {
 104         */
 105        if(cksum(m,hlen)) {
 106          goto bad;
 107        }
 108
 109        /*
 110         * Convert fields to host representation.
 111         */
 112        NTOHS(ip->ip_len);
 113        if (ip->ip_len < hlen) {
 114                goto bad;
 115        }
 116        NTOHS(ip->ip_id);
 117        NTOHS(ip->ip_off);
 118
 119        /*
 120         * Check that the amount of data in the buffers
 121         * is as at least much as the IP header would have us expect.
 122         * Trim mbufs if longer than we expect.
 123         * Drop packet if shorter than we expect.
 124         */
 125        if (m->m_len < ip->ip_len) {
 126                goto bad;
 127        }
 128
 129        /* Should drop packet if mbuf too long? hmmm... */
 130        if (m->m_len > ip->ip_len)
 131           m_adj(m, ip->ip_len - m->m_len);
 132
 133        /* check ip_ttl for a correct ICMP reply */
 134        if(ip->ip_ttl==0) {
 135          icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
 136          goto bad;
 137        }
 138
 139        /*
 140         * If offset or IP_MF are set, must reassemble.
 141         * Otherwise, nothing need be done.
 142         * (We could look in the reassembly queue to see
 143         * if the packet was previously fragmented,
 144         * but it's not worth the time; just let them time out.)
 145         *
 146         * XXX This should fail, don't fragment yet
 147         */
 148        if (ip->ip_off &~ IP_DF) {
 149          register struct ipq *fp;
 150      struct qlink *l;
 151                /*
 152                 * Look for queue of fragments
 153                 * of this datagram.
 154                 */
 155                for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
 156                     l = l->next) {
 157            fp = container_of(l, struct ipq, ip_link);
 158            if (ip->ip_id == fp->ipq_id &&
 159                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
 160                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
 161                    ip->ip_p == fp->ipq_p)
 162                    goto found;
 163        }
 164        fp = NULL;
 165        found:
 166
 167                /*
 168                 * Adjust ip_len to not reflect header,
 169                 * set ip_mff if more fragments are expected,
 170                 * convert offset of this to bytes.
 171                 */
 172                ip->ip_len -= hlen;
 173                if (ip->ip_off & IP_MF)
 174                  ip->ip_tos |= 1;
 175                else
 176                  ip->ip_tos &= ~1;
 177
 178                ip->ip_off <<= 3;
 179
 180                /*
 181                 * If datagram marked as having more fragments
 182                 * or if this is not the first fragment,
 183                 * attempt reassembly; if it succeeds, proceed.
 184                 */
 185                if (ip->ip_tos & 1 || ip->ip_off) {
 186                        ip = ip_reass(slirp, ip, fp);
 187                        if (ip == NULL)
 188                                return;
 189                        m = dtom(slirp, ip);
 190                } else
 191                        if (fp)
 192                           ip_freef(slirp, fp);
 193
 194        } else
 195                ip->ip_len -= hlen;
 196
 197        /*
 198         * Switch out to protocol's input routine.
 199         */
 200        switch (ip->ip_p) {
 201         case IPPROTO_TCP:
 202                tcp_input(m, hlen, (struct socket *)NULL);
 203                break;
 204         case IPPROTO_UDP:
 205                udp_input(m, hlen);
 206                break;
 207         case IPPROTO_ICMP:
 208                icmp_input(m, hlen);
 209                break;
 210         default:
 211                m_free(m);
 212        }
 213        return;
 214bad:
 215        m_free(m);
 216}
 217
 218#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
 219#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
 220/*
 221 * Take incoming datagram fragment and try to
 222 * reassemble it into whole datagram.  If a chain for
 223 * reassembly of this datagram already exists, then it
 224 * is given as fp; otherwise have to make a chain.
 225 */
 226static struct ip *
 227ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
 228{
 229        register struct mbuf *m = dtom(slirp, ip);
 230        register struct ipasfrag *q;
 231        int hlen = ip->ip_hl << 2;
 232        int i, next;
 233
 234        DEBUG_CALL("ip_reass");
 235        DEBUG_ARG("ip = %lx", (long)ip);
 236        DEBUG_ARG("fp = %lx", (long)fp);
 237        DEBUG_ARG("m = %lx", (long)m);
 238
 239        /*
 240         * Presence of header sizes in mbufs
 241         * would confuse code below.
 242         * Fragment m_data is concatenated.
 243         */
 244        m->m_data += hlen;
 245        m->m_len -= hlen;
 246
 247        /*
 248         * If first fragment to arrive, create a reassembly queue.
 249         */
 250        if (fp == NULL) {
 251          struct mbuf *t = m_get(slirp);
 252
 253          if (t == NULL) {
 254              goto dropfrag;
 255          }
 256          fp = mtod(t, struct ipq *);
 257          insque(&fp->ip_link, &slirp->ipq.ip_link);
 258          fp->ipq_ttl = IPFRAGTTL;
 259          fp->ipq_p = ip->ip_p;
 260          fp->ipq_id = ip->ip_id;
 261          fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
 262          fp->ipq_src = ip->ip_src;
 263          fp->ipq_dst = ip->ip_dst;
 264          q = (struct ipasfrag *)fp;
 265          goto insert;
 266        }
 267
 268        /*
 269         * Find a segment which begins after this one does.
 270         */
 271        for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
 272            q = q->ipf_next)
 273                if (q->ipf_off > ip->ip_off)
 274                        break;
 275
 276        /*
 277         * If there is a preceding segment, it may provide some of
 278         * our data already.  If so, drop the data from the incoming
 279         * segment.  If it provides all of our data, drop us.
 280         */
 281        if (q->ipf_prev != &fp->frag_link) {
 282        struct ipasfrag *pq = q->ipf_prev;
 283                i = pq->ipf_off + pq->ipf_len - ip->ip_off;
 284                if (i > 0) {
 285                        if (i >= ip->ip_len)
 286                                goto dropfrag;
 287                        m_adj(dtom(slirp, ip), i);
 288                        ip->ip_off += i;
 289                        ip->ip_len -= i;
 290                }
 291        }
 292
 293        /*
 294         * While we overlap succeeding segments trim them or,
 295         * if they are completely covered, dequeue them.
 296         */
 297        while (q != (struct ipasfrag*)&fp->frag_link &&
 298            ip->ip_off + ip->ip_len > q->ipf_off) {
 299                i = (ip->ip_off + ip->ip_len) - q->ipf_off;
 300                if (i < q->ipf_len) {
 301                        q->ipf_len -= i;
 302                        q->ipf_off += i;
 303                        m_adj(dtom(slirp, q), i);
 304                        break;
 305                }
 306                q = q->ipf_next;
 307                m_free(dtom(slirp, q->ipf_prev));
 308                ip_deq(q->ipf_prev);
 309        }
 310
 311insert:
 312        /*
 313         * Stick new segment in its place;
 314         * check for complete reassembly.
 315         */
 316        ip_enq(iptofrag(ip), q->ipf_prev);
 317        next = 0;
 318        for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
 319            q = q->ipf_next) {
 320                if (q->ipf_off != next)
 321                        return NULL;
 322                next += q->ipf_len;
 323        }
 324        if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
 325                return NULL;
 326
 327        /*
 328         * Reassembly is complete; concatenate fragments.
 329         */
 330    q = fp->frag_link.next;
 331        m = dtom(slirp, q);
 332
 333        q = (struct ipasfrag *) q->ipf_next;
 334        while (q != (struct ipasfrag*)&fp->frag_link) {
 335          struct mbuf *t = dtom(slirp, q);
 336          q = (struct ipasfrag *) q->ipf_next;
 337          m_cat(m, t);
 338        }
 339
 340        /*
 341         * Create header for new ip packet by
 342         * modifying header of first packet;
 343         * dequeue and discard fragment reassembly header.
 344         * Make header visible.
 345         */
 346        q = fp->frag_link.next;
 347
 348        /*
 349         * If the fragments concatenated to an mbuf that's
 350         * bigger than the total size of the fragment, then and
 351         * m_ext buffer was alloced. But fp->ipq_next points to
 352         * the old buffer (in the mbuf), so we must point ip
 353         * into the new buffer.
 354         */
 355        if (m->m_flags & M_EXT) {
 356          int delta = (char *)q - m->m_dat;
 357          q = (struct ipasfrag *)(m->m_ext + delta);
 358        }
 359
 360    ip = fragtoip(q);
 361        ip->ip_len = next;
 362        ip->ip_tos &= ~1;
 363        ip->ip_src = fp->ipq_src;
 364        ip->ip_dst = fp->ipq_dst;
 365        remque(&fp->ip_link);
 366        (void) m_free(dtom(slirp, fp));
 367        m->m_len += (ip->ip_hl << 2);
 368        m->m_data -= (ip->ip_hl << 2);
 369
 370        return ip;
 371
 372dropfrag:
 373        m_free(m);
 374        return NULL;
 375}
 376
 377/*
 378 * Free a fragment reassembly header and all
 379 * associated datagrams.
 380 */
 381static void
 382ip_freef(Slirp *slirp, struct ipq *fp)
 383{
 384        register struct ipasfrag *q, *p;
 385
 386        for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
 387                p = q->ipf_next;
 388                ip_deq(q);
 389                m_free(dtom(slirp, q));
 390        }
 391        remque(&fp->ip_link);
 392        (void) m_free(dtom(slirp, fp));
 393}
 394
 395/*
 396 * Put an ip fragment on a reassembly chain.
 397 * Like insque, but pointers in middle of structure.
 398 */
 399static void
 400ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
 401{
 402        DEBUG_CALL("ip_enq");
 403        DEBUG_ARG("prev = %lx", (long)prev);
 404        p->ipf_prev =  prev;
 405        p->ipf_next = prev->ipf_next;
 406        ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
 407        prev->ipf_next = p;
 408}
 409
 410/*
 411 * To ip_enq as remque is to insque.
 412 */
 413static void
 414ip_deq(register struct ipasfrag *p)
 415{
 416        ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
 417        ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
 418}
 419
 420/*
 421 * IP timer processing;
 422 * if a timer expires on a reassembly
 423 * queue, discard it.
 424 */
 425void
 426ip_slowtimo(Slirp *slirp)
 427{
 428    struct qlink *l;
 429
 430        DEBUG_CALL("ip_slowtimo");
 431
 432    l = slirp->ipq.ip_link.next;
 433
 434        if (l == NULL)
 435           return;
 436
 437    while (l != &slirp->ipq.ip_link) {
 438        struct ipq *fp = container_of(l, struct ipq, ip_link);
 439        l = l->next;
 440                if (--fp->ipq_ttl == 0) {
 441                        ip_freef(slirp, fp);
 442                }
 443    }
 444}
 445
 446/*
 447 * Do option processing on a datagram,
 448 * possibly discarding it if bad options are encountered,
 449 * or forwarding it if source-routed.
 450 * Returns 1 if packet has been forwarded/freed,
 451 * 0 if the packet should be processed further.
 452 */
 453
 454#ifdef notdef
 455
 456int
 457ip_dooptions(m)
 458        struct mbuf *m;
 459{
 460        register struct ip *ip = mtod(m, struct ip *);
 461        register u_char *cp;
 462        register struct ip_timestamp *ipt;
 463        register struct in_ifaddr *ia;
 464        int opt, optlen, cnt, off, code, type, forward = 0;
 465        struct in_addr *sin, dst;
 466typedef uint32_t n_time;
 467        n_time ntime;
 468
 469        dst = ip->ip_dst;
 470        cp = (u_char *)(ip + 1);
 471        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
 472        for (; cnt > 0; cnt -= optlen, cp += optlen) {
 473                opt = cp[IPOPT_OPTVAL];
 474                if (opt == IPOPT_EOL)
 475                        break;
 476                if (opt == IPOPT_NOP)
 477                        optlen = 1;
 478                else {
 479                        optlen = cp[IPOPT_OLEN];
 480                        if (optlen <= 0 || optlen > cnt) {
 481                                code = &cp[IPOPT_OLEN] - (u_char *)ip;
 482                                goto bad;
 483                        }
 484                }
 485                switch (opt) {
 486
 487                default:
 488                        break;
 489
 490                /*
 491                 * Source routing with record.
 492                 * Find interface with current destination address.
 493                 * If none on this machine then drop if strictly routed,
 494                 * or do nothing if loosely routed.
 495                 * Record interface address and bring up next address
 496                 * component.  If strictly routed make sure next
 497                 * address is on directly accessible net.
 498                 */
 499                case IPOPT_LSRR:
 500                case IPOPT_SSRR:
 501                        if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
 502                                code = &cp[IPOPT_OFFSET] - (u_char *)ip;
 503                                goto bad;
 504                        }
 505                        ipaddr.sin_addr = ip->ip_dst;
 506                        ia = (struct in_ifaddr *)
 507                                ifa_ifwithaddr((struct sockaddr *)&ipaddr);
 508                        if (ia == 0) {
 509                                if (opt == IPOPT_SSRR) {
 510                                        type = ICMP_UNREACH;
 511                                        code = ICMP_UNREACH_SRCFAIL;
 512                                        goto bad;
 513                                }
 514                                /*
 515                                 * Loose routing, and not at next destination
 516                                 * yet; nothing to do except forward.
 517                                 */
 518                                break;
 519                        }
 520                        off--; /* 0 origin */
 521                        if (off > optlen - sizeof(struct in_addr)) {
 522                                /*
 523                                 * End of source route.  Should be for us.
 524                                 */
 525                                save_rte(cp, ip->ip_src);
 526                                break;
 527                        }
 528                        /*
 529                         * locate outgoing interface
 530                         */
 531                        bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
 532                            sizeof(ipaddr.sin_addr));
 533                        if (opt == IPOPT_SSRR) {
 534#define INA     struct in_ifaddr *
 535#define SA      struct sockaddr *
 536                            if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
 537                                ia = (INA)ifa_ifwithnet((SA)&ipaddr);
 538                        } else
 539                                ia = ip_rtaddr(ipaddr.sin_addr);
 540                        if (ia == 0) {
 541                                type = ICMP_UNREACH;
 542                                code = ICMP_UNREACH_SRCFAIL;
 543                                goto bad;
 544                        }
 545                        ip->ip_dst = ipaddr.sin_addr;
 546                        bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
 547                            (caddr_t)(cp + off), sizeof(struct in_addr));
 548                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
 549                        /*
 550                         * Let ip_intr's mcast routing check handle mcast pkts
 551                         */
 552                        forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
 553                        break;
 554
 555                case IPOPT_RR:
 556                        if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
 557                                code = &cp[IPOPT_OFFSET] - (u_char *)ip;
 558                                goto bad;
 559                        }
 560                        /*
 561                         * If no space remains, ignore.
 562                         */
 563                        off--; /* 0 origin */
 564                        if (off > optlen - sizeof(struct in_addr))
 565                                break;
 566                        bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
 567                            sizeof(ipaddr.sin_addr));
 568                        /*
 569                         * locate outgoing interface; if we're the destination,
 570                         * use the incoming interface (should be same).
 571                         */
 572                        if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
 573                            (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
 574                                type = ICMP_UNREACH;
 575                                code = ICMP_UNREACH_HOST;
 576                                goto bad;
 577                        }
 578                        bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
 579                            (caddr_t)(cp + off), sizeof(struct in_addr));
 580                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
 581                        break;
 582
 583                case IPOPT_TS:
 584                        code = cp - (u_char *)ip;
 585                        ipt = (struct ip_timestamp *)cp;
 586                        if (ipt->ipt_len < 5)
 587                                goto bad;
 588                        if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
 589                                if (++ipt->ipt_oflw == 0)
 590                                        goto bad;
 591                                break;
 592                        }
 593                        sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
 594                        switch (ipt->ipt_flg) {
 595
 596                        case IPOPT_TS_TSONLY:
 597                                break;
 598
 599                        case IPOPT_TS_TSANDADDR:
 600                                if (ipt->ipt_ptr + sizeof(n_time) +
 601                                    sizeof(struct in_addr) > ipt->ipt_len)
 602                                        goto bad;
 603                                ipaddr.sin_addr = dst;
 604                                ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
 605                                                            m->m_pkthdr.rcvif);
 606                                if (ia == 0)
 607                                        continue;
 608                                bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
 609                                    (caddr_t)sin, sizeof(struct in_addr));
 610                                ipt->ipt_ptr += sizeof(struct in_addr);
 611                                break;
 612
 613                        case IPOPT_TS_PRESPEC:
 614                                if (ipt->ipt_ptr + sizeof(n_time) +
 615                                    sizeof(struct in_addr) > ipt->ipt_len)
 616                                        goto bad;
 617                                bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
 618                                    sizeof(struct in_addr));
 619                                if (ifa_ifwithaddr((SA)&ipaddr) == 0)
 620                                        continue;
 621                                ipt->ipt_ptr += sizeof(struct in_addr);
 622                                break;
 623
 624                        default:
 625                                goto bad;
 626                        }
 627                        ntime = iptime();
 628                        bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
 629                            sizeof(n_time));
 630                        ipt->ipt_ptr += sizeof(n_time);
 631                }
 632        }
 633        if (forward) {
 634                ip_forward(m, 1);
 635                return (1);
 636        }
 637        return (0);
 638bad:
 639        icmp_error(m, type, code, 0, 0);
 640
 641        return (1);
 642}
 643
 644#endif /* notdef */
 645
 646/*
 647 * Strip out IP options, at higher
 648 * level protocol in the kernel.
 649 * Second argument is buffer to which options
 650 * will be moved, and return value is their length.
 651 * (XXX) should be deleted; last arg currently ignored.
 652 */
 653void
 654ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
 655{
 656        register int i;
 657        struct ip *ip = mtod(m, struct ip *);
 658        register caddr_t opts;
 659        int olen;
 660
 661        olen = (ip->ip_hl<<2) - sizeof (struct ip);
 662        opts = (caddr_t)(ip + 1);
 663        i = m->m_len - (sizeof (struct ip) + olen);
 664        memcpy(opts, opts  + olen, (unsigned)i);
 665        m->m_len -= olen;
 666
 667        ip->ip_hl = sizeof(struct ip) >> 2;
 668}
 669