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