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