akaros/kern/src/net/ip.c
<<
>>
Prefs
   1/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
   2 * Portions Copyright © 1997-1999 Vita Nuova Limited
   3 * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
   4 *                                (www.vitanuova.com)
   5 * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
   6 *
   7 * Modified for the Akaros operating system:
   8 * Copyright (c) 2013-2014 The Regents of the University of California
   9 * Copyright (c) 2013-2015 Google Inc.
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27 * SOFTWARE. */
  28
  29#include <slab.h>
  30#include <kmalloc.h>
  31#include <kref.h>
  32#include <string.h>
  33#include <stdio.h>
  34#include <assert.h>
  35#include <error.h>
  36#include <cpio.h>
  37#include <pmap.h>
  38#include <smp.h>
  39#include <net/ip.h>
  40
  41typedef struct IP IP;
  42typedef struct Fragment4 Fragment4;
  43typedef struct Fragment6 Fragment6;
  44typedef struct Ipfrag Ipfrag;
  45
  46enum {
  47        IP4HDR = 20,            /* sizeof(Ip4hdr) */
  48        IP6HDR = 40,            /* sizeof(Ip6hdr) */
  49        IP_HLEN4 = 0x05,        /* Header length in words */
  50        IP_DF = 0x4000,         /* Don't fragment */
  51        IP_MF = 0x2000,         /* More fragments */
  52        IP6FHDR = 8,            /* sizeof(Fraghdr6) */
  53        IP_MAX = 64 * 1024,     /* Maximum Internet packet size */
  54};
  55
  56#define BLKIPVER(xp)    (((struct Ip4hdr*)((xp)->rp))->vihl&0xF0)
  57#define NEXT_ID(x) (__sync_add_and_fetch(&(x), 1))
  58
  59/* MIB II counters */
  60enum {
  61        Forwarding,
  62        DefaultTTL,
  63        InReceives,
  64        InHdrErrors,
  65        InAddrErrors,
  66        ForwDatagrams,
  67        InUnknownProtos,
  68        InDiscards,
  69        InDelivers,
  70        OutRequests,
  71        OutDiscards,
  72        OutNoRoutes,
  73        ReasmTimeout,
  74        ReasmReqds,
  75        ReasmOKs,
  76        ReasmFails,
  77        FragOKs,
  78        FragFails,
  79        FragCreates,
  80
  81        Nstats,
  82};
  83
  84struct fragment4 {
  85        struct block *blist;
  86        struct fragment4 *next;
  87        uint32_t src;
  88        uint32_t dst;
  89        uint16_t id;
  90        uint64_t age;
  91};
  92
  93struct fragment6 {
  94        struct block *blist;
  95        struct fragment6 *next;
  96        uint8_t src[IPaddrlen];
  97        uint8_t dst[IPaddrlen];
  98        unsigned int id;
  99        uint64_t age;
 100};
 101
 102struct Ipfrag {
 103        uint16_t foff;
 104        uint16_t flen;
 105};
 106
 107/* an instance of IP */
 108struct IP {
 109        uint32_t stats[Nstats];
 110
 111        qlock_t fraglock4;
 112        struct fragment4 *flisthead4;
 113        struct fragment4 *fragfree4;
 114        int id4;
 115
 116        qlock_t fraglock6;
 117        struct fragment6 *flisthead6;
 118        struct fragment6 *fragfree6;
 119        int id6;
 120
 121        int iprouting;          /* true if we route like a gateway */
 122};
 123
 124static char *statnames[] = {
 125        [Forwarding] "Forwarding",
 126        [DefaultTTL] "DefaultTTL",
 127        [InReceives] "InReceives",
 128        [InHdrErrors] "InHdrErrors",
 129        [InAddrErrors] "InAddrErrors",
 130        [ForwDatagrams] "ForwDatagrams",
 131        [InUnknownProtos] "InUnknownProtos",
 132        [InDiscards] "InDiscards",
 133        [InDelivers] "InDelivers",
 134        [OutRequests] "OutRequests",
 135        [OutDiscards] "OutDiscards",
 136        [OutNoRoutes] "OutNoRoutes",
 137        [ReasmTimeout] "ReasmTimeout",
 138        [ReasmReqds] "ReasmReqds",
 139        [ReasmOKs] "ReasmOKs",
 140        [ReasmFails] "ReasmFails",
 141        [FragOKs] "FragOKs",
 142        [FragFails] "FragFails",
 143        [FragCreates] "FragCreates",
 144};
 145
 146#define BLKIP(xp)       ((struct Ip4hdr*)((xp)->rp))
 147/*
 148 * This sleazy macro relies on the media header size being
 149 * larger than sizeof(Ipfrag). ipreassemble checks this is true
 150 */
 151#define BKFG(xp)        ((struct Ipfrag*)((xp)->base))
 152
 153uint16_t ipcsum(uint8_t * unused_uint8_p_t);
 154struct block *ip4reassemble(struct IP *, int unused_int, struct block *,
 155                            struct Ip4hdr *);
 156void ipfragfree4(struct IP *, struct fragment4 *);
 157struct fragment4 *ipfragallo4(struct IP *);
 158
 159void ip_init_6(struct Fs *f)
 160{
 161        struct V6params *v6p;
 162
 163        v6p = kzmalloc(sizeof(struct V6params), 0);
 164
 165        v6p->rp.mflag = 0;      // default not managed
 166        v6p->rp.oflag = 0;
 167        v6p->rp.maxraint = 600000;      // millisecs
 168        v6p->rp.minraint = 200000;
 169        v6p->rp.linkmtu = 0;    // no mtu sent
 170        v6p->rp.reachtime = 0;
 171        v6p->rp.rxmitra = 0;
 172        v6p->rp.ttl = MAXTTL;
 173        v6p->rp.routerlt = 3 * (v6p->rp.maxraint);
 174
 175        v6p->hp.rxmithost = 1000;       // v6 RETRANS_TIMER
 176
 177        v6p->cdrouter = -1;
 178
 179        f->v6p = v6p;
 180
 181}
 182
 183void initfrag(struct IP *ip, int size)
 184{
 185        struct fragment4 *fq4, *eq4;
 186        struct fragment6 *fq6, *eq6;
 187
 188        ip->fragfree4 =
 189            (struct fragment4 *)kzmalloc(sizeof(struct fragment4) * size, 0);
 190        if (ip->fragfree4 == NULL)
 191                panic("initfrag");
 192
 193        eq4 = &ip->fragfree4[size];
 194        for (fq4 = ip->fragfree4; fq4 < eq4; fq4++)
 195                fq4->next = fq4 + 1;
 196
 197        ip->fragfree4[size - 1].next = NULL;
 198
 199        ip->fragfree6 =
 200            (struct fragment6 *)kzmalloc(sizeof(struct fragment6) * size, 0);
 201        if (ip->fragfree6 == NULL)
 202                panic("initfrag");
 203
 204        eq6 = &ip->fragfree6[size];
 205        for (fq6 = ip->fragfree6; fq6 < eq6; fq6++)
 206                fq6->next = fq6 + 1;
 207
 208        ip->fragfree6[size - 1].next = NULL;
 209}
 210
 211void ip_init(struct Fs *f)
 212{
 213        struct IP *ip;
 214
 215        ip = kzmalloc(sizeof(struct IP), 0);
 216        qlock_init(&ip->fraglock4);
 217        qlock_init(&ip->fraglock6);
 218        initfrag(ip, 100);
 219        f->ip = ip;
 220
 221        ip_init_6(f);
 222}
 223
 224void iprouting(struct Fs *f, int on)
 225{
 226        f->ip->iprouting = on;
 227        if (f->ip->iprouting == 0)
 228                f->ip->stats[Forwarding] = 2;
 229        else
 230                f->ip->stats[Forwarding] = 1;
 231}
 232
 233int ipoput4(struct Fs *f, struct block *bp, int gating, int ttl, int tos, struct
 234            conv *c)
 235{
 236        ERRSTACK(1);
 237        struct Ipifc *ifc;
 238        uint8_t *gate;
 239        uint32_t fragoff;
 240        struct block *xp, *nb;
 241        struct Ip4hdr *eh, *feh;
 242        int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
 243        struct route *r, *sr;
 244        struct IP *ip;
 245        int rv = 0;
 246
 247        ip = f->ip;
 248
 249        /* Sanity check for our transport protocols. */
 250        if (bp->mss)
 251                assert(bp->flag & Btso);
 252        /* Fill out the ip header */
 253        eh = (struct Ip4hdr *)(bp->rp);
 254
 255        ip->stats[OutRequests]++;
 256
 257        /* Number of uint8_ts in data and ip header to write */
 258        len = blocklen(bp);
 259
 260        if (gating) {
 261                chunk = nhgets(eh->length);
 262                if (chunk > len) {
 263                        ip->stats[OutDiscards]++;
 264                        netlog(f, Logip, "short gated packet\n");
 265                        goto free;
 266                }
 267                if (chunk < len)
 268                        len = chunk;
 269        }
 270        if (len >= IP_MAX) {
 271                ip->stats[OutDiscards]++;
 272                netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
 273                goto free;
 274        }
 275
 276        r = v4lookup(f, eh->dst, c);
 277        if (r == NULL) {
 278                ip->stats[OutNoRoutes]++;
 279                netlog(f, Logip, "no interface %V\n", eh->dst);
 280                rv = -1;
 281                goto free;
 282        }
 283
 284        ifc = r->rt.ifc;
 285        if (r->rt.type & (Rifc | Runi))
 286                gate = eh->dst;
 287        else if (r->rt.type & (Rbcast | Rmulti)) {
 288                gate = eh->dst;
 289                sr = v4lookup(f, eh->src, NULL);
 290                if (sr != NULL && (sr->rt.type & Runi))
 291                        ifc = sr->rt.ifc;
 292        } else
 293                gate = r->v4.gate;
 294
 295        if (!gating)
 296                eh->vihl = IP_VER4 | IP_HLEN4;
 297        eh->ttl = ttl;
 298        if (!gating)
 299                eh->tos = tos;
 300
 301        if (!canrlock(&ifc->rwlock))
 302                goto free;
 303        if (waserror()) {
 304                runlock(&ifc->rwlock);
 305                nexterror();
 306        }
 307        if (ifc->m == NULL)
 308                goto raise;
 309
 310        /* If we dont need to fragment just send it */
 311        medialen = ifc->maxtu - ifc->m->hsize;
 312        if (bp->flag & Btso || len <= medialen) {
 313                if (!gating)
 314                        hnputs(eh->id, NEXT_ID(ip->id4));
 315                hnputs(eh->length, len);
 316                if (!gating) {
 317                        eh->frag[0] = 0x40;
 318                        eh->frag[1] = 0;
 319                }
 320                eh->cksum[0] = 0;
 321                eh->cksum[1] = 0;
 322                hnputs(eh->cksum, ipcsum(&eh->vihl));
 323                ifc->m->bwrite(ifc, bp, V4, gate);
 324                runlock(&ifc->rwlock);
 325                poperror();
 326                return 0;
 327        }
 328
 329        if ((eh->frag[0] & (IP_DF >> 8)) && !gating)
 330                printd("%V: DF set\n", eh->dst);
 331
 332        if (eh->frag[0] & (IP_DF >> 8)) {
 333                ip->stats[FragFails]++;
 334                ip->stats[OutDiscards]++;
 335                icmpcantfrag(f, bp, medialen);
 336                netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
 337                goto raise;
 338        }
 339
 340        seglen = (medialen - IP4HDR) & ~7;
 341        if (seglen < 8) {
 342                ip->stats[FragFails]++;
 343                ip->stats[OutDiscards]++;
 344                netlog(f, Logip, "%V seglen < 8\n", eh->dst);
 345                goto raise;
 346        }
 347
 348        /* compute tcp/udp checksum in software before fragmenting */
 349        ptclcsum_finalize(bp, 0);
 350
 351        dlen = len - IP4HDR;
 352        xp = bp;
 353        if (gating)
 354                lid = nhgets(eh->id);
 355        else
 356                lid = NEXT_ID(ip->id4);
 357
 358        /* advance through the blist enough to drop IP4HDR size.  this should
 359         * usually just be the first block. */
 360        offset = IP4HDR;
 361        while (xp != NULL && offset && offset >= BLEN(xp)) {
 362                offset -= BLEN(xp);
 363                xp = xp->next;
 364        }
 365        xp->rp += offset;
 366
 367        if (gating)
 368                fragoff = nhgets(eh->frag) << 3;
 369        else
 370                fragoff = 0;
 371        dlen += fragoff;
 372        for (; fragoff < dlen; fragoff += seglen) {
 373                nb = blist_clone(xp, IP4HDR, seglen, fragoff);
 374                feh = (struct Ip4hdr *)(nb->rp);
 375
 376                memmove(nb->wp, eh, IP4HDR);
 377                nb->wp += IP4HDR;
 378
 379                if ((fragoff + seglen) >= dlen) {
 380                        seglen = dlen - fragoff;
 381                        hnputs(feh->frag, fragoff >> 3);
 382                } else
 383                        hnputs(feh->frag, (fragoff >> 3) | IP_MF);
 384
 385                hnputs(feh->length, seglen + IP4HDR);
 386                hnputs(feh->id, lid);
 387
 388                feh->cksum[0] = 0;
 389                feh->cksum[1] = 0;
 390                hnputs(feh->cksum, ipcsum(&feh->vihl));
 391                ifc->m->bwrite(ifc, nb, V4, gate);
 392                ip->stats[FragCreates]++;
 393        }
 394        ip->stats[FragOKs]++;
 395raise:
 396        runlock(&ifc->rwlock);
 397        poperror();
 398free:
 399        freeblist(bp);
 400        return rv;
 401}
 402
 403void ipiput4(struct Fs *f, struct Ipifc *ifc, struct block *bp)
 404{
 405        int hl;
 406        int hop, tos, proto, olen;
 407        struct Ip4hdr *h;
 408        struct Proto *p;
 409        uint16_t frag;
 410        int notforme;
 411        uint8_t *dp, v6dst[IPaddrlen];
 412        struct IP *ip;
 413        struct route *r;
 414
 415        bp = pullupblock(bp, 1);
 416        if (BLKIPVER(bp) != IP_VER4) {
 417                ipiput6(f, ifc, bp);
 418                return;
 419        }
 420
 421        ip = f->ip;
 422        ip->stats[InReceives]++;
 423
 424        /*
 425         *  Ensure we have all the header info in the first
 426         *  block.  Make life easier for other protocols by
 427         *  collecting up to the first 64 bytes in the first block.
 428         */
 429        if (BLEN(bp) < 64) {
 430                hl = blocklen(bp);
 431                if (hl < IP4HDR)
 432                        hl = IP4HDR;
 433                if (hl > 64)
 434                        hl = 64;
 435                bp = pullupblock(bp, hl);
 436                if (bp == NULL)
 437                        return;
 438        }
 439
 440        h = (struct Ip4hdr *)(bp->rp);
 441
 442        /* dump anything that whose header doesn't checksum */
 443        if ((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
 444                ip->stats[InHdrErrors]++;
 445                netlog(f, Logip, "ip: checksum error %V\n", h->src);
 446                freeblist(bp);
 447                return;
 448        }
 449        v4tov6(v6dst, h->dst);
 450        notforme = ipforme(f, v6dst) == 0;
 451
 452        /* Check header length and version */
 453        if ((h->vihl & 0x0F) != IP_HLEN4) {
 454                hl = (h->vihl & 0xF) << 2;
 455                if (hl < (IP_HLEN4 << 2)) {
 456                        ip->stats[InHdrErrors]++;
 457                        netlog(f, Logip, "ip: %V bad hivl 0x%x\n", h->src,
 458                               h->vihl);
 459                        freeblist(bp);
 460                        return;
 461                }
 462                /* If this is not routed strip off the options */
 463                if (notforme == 0) {
 464                        olen = nhgets(h->length);
 465                        dp = bp->rp + (hl - (IP_HLEN4 << 2));
 466                        memmove(dp, h, IP_HLEN4 << 2);
 467                        bp->rp = dp;
 468                        h = (struct Ip4hdr *)(bp->rp);
 469                        h->vihl = (IP_VER4 | IP_HLEN4);
 470                        hnputs(h->length, olen - hl + (IP_HLEN4 << 2));
 471                }
 472        }
 473
 474        /* route */
 475        if (notforme) {
 476                struct conv conv;
 477
 478                if (!ip->iprouting) {
 479                        freeb(bp);
 480                        return;
 481                }
 482
 483                /* don't forward to source's network */
 484                conv.r = NULL;
 485                r = v4lookup(f, h->dst, &conv);
 486                if (r == NULL || r->rt.ifc == ifc) {
 487                        ip->stats[OutDiscards]++;
 488                        freeblist(bp);
 489                        return;
 490                }
 491
 492                /* don't forward if packet has timed out */
 493                hop = h->ttl;
 494                if (hop < 1) {
 495                        ip->stats[InHdrErrors]++;
 496                        icmpttlexceeded(f, ifc->lifc->local, bp);
 497                        freeblist(bp);
 498                        return;
 499                }
 500
 501                /* reassemble if the interface expects it */
 502                if (r->rt.ifc == NULL)
 503                        panic("NULL route rfc");
 504                if (r->rt.ifc->reassemble) {
 505                        frag = nhgets(h->frag);
 506                        if (frag) {
 507                                h->tos = 0;
 508                                if (frag & IP_MF)
 509                                        h->tos = 1;
 510                                bp = ip4reassemble(ip, frag, bp, h);
 511                                if (bp == NULL)
 512                                        return;
 513                                h = (struct Ip4hdr *)(bp->rp);
 514                        }
 515                }
 516
 517                ip->stats[ForwDatagrams]++;
 518                tos = h->tos;
 519                hop = h->ttl;
 520                ipoput4(f, bp, 1, hop - 1, tos, &conv);
 521                return;
 522        }
 523
 524        frag = nhgets(h->frag);
 525        if (frag && frag != IP_DF) {
 526                h->tos = 0;
 527                if (frag & IP_MF)
 528                        h->tos = 1;
 529                bp = ip4reassemble(ip, frag, bp, h);
 530                if (bp == NULL)
 531                        return;
 532                h = (struct Ip4hdr *)(bp->rp);
 533        }
 534
 535        /* don't let any frag info go up the stack */
 536        h->frag[0] = 0;
 537        h->frag[1] = 0;
 538
 539        proto = h->proto;
 540        p = Fsrcvpcol(f, proto);
 541        if (p != NULL && p->rcv != NULL) {
 542                ip->stats[InDelivers]++;
 543                (*p->rcv) (p, ifc, bp);
 544                return;
 545        }
 546        ip->stats[InDiscards]++;
 547        ip->stats[InUnknownProtos]++;
 548        freeblist(bp);
 549}
 550
 551int ipstats(struct Fs *f, char *buf, int len)
 552{
 553        struct IP *ip;
 554        char *p, *e;
 555        int i;
 556
 557        ip = f->ip;
 558        ip->stats[DefaultTTL] = MAXTTL;
 559
 560        p = buf;
 561        e = p + len;
 562        for (i = 0; i < Nstats; i++)
 563                p = seprintf(p, e, "%s: %u\n", statnames[i], ip->stats[i]);
 564        return p - buf;
 565}
 566
 567struct block *ip4reassemble(struct IP *ip, int offset, struct block *bp,
 568                                                        struct Ip4hdr *ih)
 569{
 570        int fend;
 571        uint16_t id;
 572        struct fragment4 *f, *fnext;
 573        uint32_t src, dst;
 574        struct block *bl, **l, *last, *prev;
 575        int ovlap, len, fragsize, pktposn;
 576
 577        src = nhgetl(ih->src);
 578        dst = nhgetl(ih->dst);
 579        id = nhgets(ih->id);
 580
 581        /*
 582         *  block lists are too hard, pullupblock into a single block
 583         */
 584        if (bp->next) {
 585                bp = pullupblock(bp, blocklen(bp));
 586                ih = (struct Ip4hdr *)(bp->rp);
 587        }
 588
 589        qlock(&ip->fraglock4);
 590
 591        /*
 592         *  find a reassembly queue for this fragment
 593         */
 594        for (f = ip->flisthead4; f; f = fnext) {
 595                fnext = f->next;/* because ipfragfree4 changes the list */
 596                if (f->src == src && f->dst == dst && f->id == id)
 597                        break;
 598                if (f->age < NOW) {
 599                        ip->stats[ReasmTimeout]++;
 600                        ipfragfree4(ip, f);
 601                }
 602        }
 603
 604        /*
 605         *  if this isn't a fragmented packet, accept it
 606         *  and get rid of any fragments that might go
 607         *  with it.
 608         */
 609        if (!ih->tos && (offset & ~(IP_MF | IP_DF)) == 0) {
 610                if (f != NULL) {
 611                        ipfragfree4(ip, f);
 612                        ip->stats[ReasmFails]++;
 613                }
 614                qunlock(&ip->fraglock4);
 615                return bp;
 616        }
 617
 618        if (bp->base + sizeof(struct Ipfrag) >= bp->rp) {
 619                bp = padblock(bp, sizeof(struct Ipfrag));
 620                bp->rp += sizeof(struct Ipfrag);
 621        }
 622
 623        BKFG(bp)->foff = offset << 3;
 624        BKFG(bp)->flen = nhgets(ih->length) - IP4HDR;
 625
 626        /* First fragment allocates a reassembly queue */
 627        if (f == NULL) {
 628                f = ipfragallo4(ip);
 629                f->id = id;
 630                f->src = src;
 631                f->dst = dst;
 632
 633                f->blist = bp;
 634
 635                qunlock(&ip->fraglock4);
 636                ip->stats[ReasmReqds]++;
 637                return NULL;
 638        }
 639
 640        /*
 641         *  find the new fragment's position in the queue
 642         */
 643        prev = NULL;
 644        l = &f->blist;
 645        bl = f->blist;
 646        while (bl != NULL && BKFG(bp)->foff > BKFG(bl)->foff) {
 647                prev = bl;
 648                l = &bl->next;
 649                bl = bl->next;
 650        }
 651
 652        /* Check overlap of a previous fragment - trim away as necessary */
 653        if (prev) {
 654                ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
 655                if (ovlap > 0) {
 656                        if (ovlap >= BKFG(bp)->flen) {
 657                                freeblist(bp);
 658                                qunlock(&ip->fraglock4);
 659                                return NULL;
 660                        }
 661                        BKFG(prev)->flen -= ovlap;
 662                }
 663        }
 664
 665        /* Link onto assembly queue */
 666        bp->next = *l;
 667        *l = bp;
 668
 669        /* Check to see if succeeding segments overlap */
 670        if (bp->next) {
 671                l = &bp->next;
 672                fend = BKFG(bp)->foff + BKFG(bp)->flen;
 673                /* Take completely covered segments out */
 674                while (*l) {
 675                        ovlap = fend - BKFG(*l)->foff;
 676                        if (ovlap <= 0)
 677                                break;
 678                        if (ovlap < BKFG(*l)->flen) {
 679                                BKFG(*l)->flen -= ovlap;
 680                                BKFG(*l)->foff += ovlap;
 681                                /* move up ih hdrs */
 682                                memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
 683                                (*l)->rp += ovlap;
 684                                break;
 685                        }
 686                        last = (*l)->next;
 687                        (*l)->next = NULL;
 688                        freeblist(*l);
 689                        *l = last;
 690                }
 691        }
 692
 693        /*
 694         *  look for a complete packet.  if we get to a fragment
 695         *  without IP_MF set, we're done.
 696         */
 697        pktposn = 0;
 698        for (bl = f->blist; bl; bl = bl->next) {
 699                if (BKFG(bl)->foff != pktposn)
 700                        break;
 701                if ((BLKIP(bl)->frag[0] & (IP_MF >> 8)) == 0) {
 702                        bl = f->blist;
 703                        len = nhgets(BLKIP(bl)->length);
 704                        bl->wp = bl->rp + len;
 705
 706                        /* Pullup all the fragment headers and
 707                         * return a complete packet
 708                         */
 709                        for (bl = bl->next; bl; bl = bl->next) {
 710                                fragsize = BKFG(bl)->flen;
 711                                len += fragsize;
 712                                bl->rp += IP4HDR;
 713                                bl->wp = bl->rp + fragsize;
 714                        }
 715
 716                        bl = f->blist;
 717                        f->blist = NULL;
 718                        ipfragfree4(ip, f);
 719                        ih = BLKIP(bl);
 720                        hnputs(ih->length, len);
 721                        qunlock(&ip->fraglock4);
 722                        ip->stats[ReasmOKs]++;
 723                        return bl;
 724                }
 725                pktposn += BKFG(bl)->flen;
 726        }
 727        qunlock(&ip->fraglock4);
 728        return NULL;
 729}
 730
 731/*
 732 * ipfragfree4 - Free a list of fragments - assume hold fraglock4
 733 */
 734void ipfragfree4(struct IP *ip, struct fragment4 *frag)
 735{
 736        struct fragment4 *fl, **l;
 737
 738        if (frag->blist)
 739                freeblist(frag->blist);
 740
 741        frag->src = 0;
 742        frag->id = 0;
 743        frag->blist = NULL;
 744
 745        l = &ip->flisthead4;
 746        for (fl = *l; fl; fl = fl->next) {
 747                if (fl == frag) {
 748                        *l = frag->next;
 749                        break;
 750                }
 751                l = &fl->next;
 752        }
 753
 754        frag->next = ip->fragfree4;
 755        ip->fragfree4 = frag;
 756
 757}
 758
 759/*
 760 * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
 761 */
 762struct fragment4 *ipfragallo4(struct IP *ip)
 763{
 764        struct fragment4 *f;
 765
 766        while (ip->fragfree4 == NULL) {
 767                /* free last entry on fraglist */
 768                for (f = ip->flisthead4; f->next; f = f->next) ;
 769                ipfragfree4(ip, f);
 770        }
 771        f = ip->fragfree4;
 772        ip->fragfree4 = f->next;
 773        f->next = ip->flisthead4;
 774        ip->flisthead4 = f;
 775        f->age = NOW + 30000;
 776
 777        return f;
 778}
 779
 780/* coreboot.c among other things needs this
 781 * type of checksum.
 782 */
 783uint16_t ipchecksum(uint8_t *addr, int len)
 784{
 785        uint16_t sum = 0;
 786
 787        while (len > 0) {
 788                sum += addr[0] << 8 | addr[1];
 789                len -= 2;
 790                addr += 2;
 791        }
 792
 793        sum = (sum & 0xffff) + (sum >> 16);
 794        sum = (sum & 0xffff) + (sum >> 16);
 795
 796        return (sum ^ 0xffff);
 797
 798}
 799
 800/* change this to call ipchecksum later.
 801 * but we have to be sure we're not doing something bad
 802 * that violates some ip stack assumption (such as
 803 * boundaries etc.)
 804 */
 805uint16_t ipcsum(uint8_t * addr)
 806{
 807        int len;
 808        uint32_t sum;
 809
 810        sum = 0;
 811        len = (addr[0] & 0xf) << 2;
 812
 813        while (len > 0) {
 814                sum += addr[0] << 8 | addr[1];
 815                len -= 2;
 816                addr += 2;
 817        }
 818
 819        sum = (sum & 0xffff) + (sum >> 16);
 820        sum = (sum & 0xffff) + (sum >> 16);
 821
 822        return (sum ^ 0xffff);
 823}
 824