Overhaul lock_test.R
[akaros.git] / kern / src / net / ip.c
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
41 typedef struct IP IP;
42 typedef struct Fragment4 Fragment4;
43 typedef struct Fragment6 Fragment6;
44 typedef struct Ipfrag Ipfrag;
45
46 enum {
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 */
60 enum {
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
84 struct 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
93 struct 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
102 struct Ipfrag {
103         uint16_t foff;
104         uint16_t flen;
105 };
106
107 /* an instance of IP */
108 struct 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
124 static 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
153 uint16_t ipcsum(uint8_t * unused_uint8_p_t);
154 struct block *ip4reassemble(struct IP *, int unused_int, struct block *,
155                             struct Ip4hdr *);
156 void ipfragfree4(struct IP *, struct fragment4 *);
157 struct fragment4 *ipfragallo4(struct IP *);
158
159 void 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
183 void 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
211 void 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
224 void 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
233 int 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]++;
395 raise:
396         runlock(&ifc->rwlock);
397         poperror();
398 free:
399         freeblist(bp);
400         return rv;
401 }
402
403 void 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
551 int 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
567 struct 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  */
734 void 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  */
762 struct 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  */
783 uint16_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  */
805 uint16_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 }