2 #include "../port/lib.h"
6 #include "../port/error.h"
10 #define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0)
12 static char *statnames[] =
14 [Forwarding] "Forwarding",
15 [DefaultTTL] "DefaultTTL",
16 [InReceives] "InReceives",
17 [InHdrErrors] "InHdrErrors",
18 [InAddrErrors] "InAddrErrors",
19 [ForwDatagrams] "ForwDatagrams",
20 [InUnknownProtos] "InUnknownProtos",
21 [InDiscards] "InDiscards",
22 [InDelivers] "InDelivers",
23 [OutRequests] "OutRequests",
24 [OutDiscards] "OutDiscards",
25 [OutNoRoutes] "OutNoRoutes",
26 [ReasmTimeout] "ReasmTimeout",
27 [ReasmReqds] "ReasmReqds",
28 [ReasmOKs] "ReasmOKs",
29 [ReasmFails] "ReasmFails",
31 [FragFails] "FragFails",
32 [FragCreates] "FragCreates",
35 #define BLKIP(xp) ((Ip4hdr*)((xp)->rp))
37 * This sleazy macro relies on the media header size being
38 * larger than sizeof(Ipfrag). ipreassemble checks this is true
40 #define BKFG(xp) ((Ipfrag*)((xp)->base))
42 ushort ipcsum(uchar*);
43 Block* ip4reassemble(IP*, int, Block*, Ip4hdr*);
44 void ipfragfree4(IP*, Fragment4*);
45 Fragment4* ipfragallo4(IP*);
52 v6p = smalloc(sizeof(v6params));
54 v6p->rp.mflag = 0; /* default not managed */
56 v6p->rp.maxraint = 600000; /* millisecs */
57 v6p->rp.minraint = 200000;
58 v6p->rp.linkmtu = 0; /* no mtu sent */
59 v6p->rp.reachtime = 0;
62 v6p->rp.routerlt = 3 * v6p->rp.maxraint;
64 v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */
72 initfrag(IP *ip, int size)
77 ip->fragfree4 = (Fragment4*)malloc(sizeof(Fragment4) * size);
78 if(ip->fragfree4 == nil)
81 eq4 = &ip->fragfree4[size];
82 for(fq4 = ip->fragfree4; fq4 < eq4; fq4++)
85 ip->fragfree4[size-1].next = nil;
87 ip->fragfree6 = (Fragment6*)malloc(sizeof(Fragment6) * size);
88 if(ip->fragfree6 == nil)
91 eq6 = &ip->fragfree6[size];
92 for(fq6 = ip->fragfree6; fq6 < eq6; fq6++)
95 ip->fragfree6[size-1].next = nil;
103 ip = smalloc(sizeof(IP));
111 iprouting(Fs *f, int on)
113 f->ip->iprouting = on;
114 if(f->ip->iprouting==0)
115 f->ip->stats[Forwarding] = 2;
117 f->ip->stats[Forwarding] = 1;
121 ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
128 int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
135 /* Fill out the ip header */
136 eh = (Ip4hdr*)(bp->rp);
138 ip->stats[OutRequests]++;
140 /* Number of uchars in data and ip header to write */
144 chunk = nhgets(eh->length);
146 ip->stats[OutDiscards]++;
147 netlog(f, Logip, "short gated packet\n");
154 ip->stats[OutDiscards]++;
155 netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
159 r = v4lookup(f, eh->dst, c);
161 ip->stats[OutNoRoutes]++;
162 netlog(f, Logip, "no interface %V\n", eh->dst);
168 if(r->type & (Rifc|Runi))
171 if(r->type & (Rbcast|Rmulti)) {
173 sr = v4lookup(f, eh->src, nil);
174 if(sr != nil && (sr->type & Runi))
181 eh->vihl = IP_VER4|IP_HLEN4;
195 /* If we dont need to fragment just send it */
196 if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
197 medialen = c->maxfragsize - ifc->m->hsize;
199 medialen = ifc->maxtu - ifc->m->hsize;
200 if(len <= medialen) {
202 hnputs(eh->id, incref(&ip->id4));
203 hnputs(eh->length, len);
210 hnputs(eh->cksum, ipcsum(&eh->vihl));
211 ifc->m->bwrite(ifc, bp, V4, gate);
217 if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst);
219 if(eh->frag[0] & (IP_DF>>8)){
220 ip->stats[FragFails]++;
221 ip->stats[OutDiscards]++;
222 icmpcantfrag(f, bp, medialen);
223 netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
227 seglen = (medialen - IP4HDR) & ~7;
229 ip->stats[FragFails]++;
230 ip->stats[OutDiscards]++;
231 netlog(f, Logip, "%V seglen < 8\n", eh->dst);
238 lid = nhgets(eh->id);
240 lid = incref(&ip->id4);
243 while(xp != nil && offset && offset >= BLEN(xp)) {
250 fragoff = nhgets(eh->frag)<<3;
254 for(; fragoff < dlen; fragoff += seglen) {
255 nb = allocb(IP4HDR+seglen);
256 feh = (Ip4hdr*)(nb->rp);
258 memmove(nb->wp, eh, IP4HDR);
261 if((fragoff + seglen) >= dlen) {
262 seglen = dlen - fragoff;
263 hnputs(feh->frag, fragoff>>3);
266 hnputs(feh->frag, (fragoff>>3)|IP_MF);
268 hnputs(feh->length, seglen + IP4HDR);
269 hnputs(feh->id, lid);
271 /* Copy up the data area */
275 ip->stats[OutDiscards]++;
276 ip->stats[FragFails]++;
278 netlog(f, Logip, "!xp: chunk %d\n", chunk);
284 memmove(nb->wp, xp->rp, blklen);
294 hnputs(feh->cksum, ipcsum(&feh->vihl));
295 ifc->m->bwrite(ifc, nb, V4, gate);
296 ip->stats[FragCreates]++;
298 ip->stats[FragOKs]++;
308 ipiput4(Fs *f, Ipifc *ifc, Block *bp)
311 int hop, tos, proto, olen;
316 uchar *dp, v6dst[IPaddrlen];
321 if(BLKIPVER(bp) != IP_VER4) {
327 ip->stats[InReceives]++;
330 * Ensure we have all the header info in the first
331 * block. Make life easier for other protocols by
332 * collecting up to the first 64 bytes in the first block.
340 bp = pullupblock(bp, hl);
345 h = (Ip4hdr*)(bp->rp);
347 /* dump anything that whose header doesn't checksum */
348 if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
349 ip->stats[InHdrErrors]++;
350 netlog(f, Logip, "ip: checksum error %V\n", h->src);
354 v4tov6(v6dst, h->dst);
355 notforme = ipforme(f, v6dst) == 0;
357 /* Check header length and version */
358 if((h->vihl&0x0F) != IP_HLEN4) {
359 hl = (h->vihl&0xF)<<2;
360 if(hl < (IP_HLEN4<<2)) {
361 ip->stats[InHdrErrors]++;
362 netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
366 /* If this is not routed strip off the options */
368 olen = nhgets(h->length);
369 dp = bp->rp + (hl - (IP_HLEN4<<2));
370 memmove(dp, h, IP_HLEN4<<2);
372 h = (Ip4hdr*)(bp->rp);
373 h->vihl = (IP_VER4|IP_HLEN4);
374 hnputs(h->length, olen-hl+(IP_HLEN4<<2));
385 /* don't forward to source's network */
386 memmove(&conv, ifc->conv, sizeof conv);
388 r = v4lookup(f, h->dst, &conv);
389 if(r == nil || r->ifc == ifc){
390 ip->stats[OutDiscards]++;
395 /* don't forward if packet has timed out */
398 ip->stats[InHdrErrors]++;
399 icmpttlexceeded(f, ifc->lifc->local, bp);
404 /* reassemble if the interface expects it */
405 if(r->ifc == nil) panic("nil route rfc");
406 if(r->ifc->reassemble){
407 frag = nhgets(h->frag);
412 bp = ip4reassemble(ip, frag, bp, h);
415 h = (Ip4hdr*)(bp->rp);
419 ip->stats[ForwDatagrams]++;
422 ipoput4(f, bp, 1, hop - 1, tos, &conv);
426 frag = nhgets(h->frag);
431 bp = ip4reassemble(ip, frag, bp, h);
434 h = (Ip4hdr*)(bp->rp);
437 /* don't let any frag info go up the stack */
442 p = Fsrcvpcol(f, proto);
443 if(p != nil && p->rcv != nil) {
444 ip->stats[InDelivers]++;
445 (*p->rcv)(p, ifc, bp);
448 ip->stats[InDiscards]++;
449 ip->stats[InUnknownProtos]++;
454 ipstats(Fs *f, char *buf, int len)
461 ip->stats[DefaultTTL] = MAXTTL;
465 for(i = 0; i < Nipstats; i++)
466 p = seprint(p, e, "%s: %llud\n", statnames[i], ip->stats[i]);
471 ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
475 Fragment4 *f, *fnext;
477 Block *bl, **l, *last, *prev;
478 int ovlap, len, fragsize, pktposn;
480 src = nhgetl(ih->src);
481 dst = nhgetl(ih->dst);
485 * block lists are too hard, pullupblock into a single block
488 bp = pullupblock(bp, blocklen(bp));
489 ih = (Ip4hdr*)(bp->rp);
492 qlock(&ip->fraglock4);
495 * find a reassembly queue for this fragment
497 for(f = ip->flisthead4; f; f = fnext){
498 fnext = f->next; /* because ipfragfree4 changes the list */
499 if(f->src == src && f->dst == dst && f->id == id)
502 ip->stats[ReasmTimeout]++;
508 * if this isn't a fragmented packet, accept it
509 * and get rid of any fragments that might go
512 if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
515 ip->stats[ReasmFails]++;
517 qunlock(&ip->fraglock4);
521 if(bp->base+IPFRAGSZ >= bp->rp){
522 bp = padblock(bp, IPFRAGSZ);
526 BKFG(bp)->foff = offset<<3;
527 BKFG(bp)->flen = nhgets(ih->length)-IP4HDR;
529 /* First fragment allocates a reassembly queue */
538 qunlock(&ip->fraglock4);
539 ip->stats[ReasmReqds]++;
544 * find the new fragment's position in the queue
549 while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) {
555 /* Check overlap of a previous fragment - trim away as necessary */
557 ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
559 if(ovlap >= BKFG(bp)->flen) {
561 qunlock(&ip->fraglock4);
564 BKFG(prev)->flen -= ovlap;
568 /* Link onto assembly queue */
572 /* Check to see if succeeding segments overlap */
575 fend = BKFG(bp)->foff + BKFG(bp)->flen;
576 /* Take completely covered segments out */
578 ovlap = fend - BKFG(*l)->foff;
581 if(ovlap < BKFG(*l)->flen) {
582 BKFG(*l)->flen -= ovlap;
583 BKFG(*l)->foff += ovlap;
584 /* move up ih hdrs */
585 memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
597 * look for a complete packet. if we get to a fragment
598 * without IP_MF set, we're done.
601 for(bl = f->blist; bl; bl = bl->next) {
602 if(BKFG(bl)->foff != pktposn)
604 if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) {
606 len = nhgets(BLKIP(bl)->length);
607 bl->wp = bl->rp + len;
609 /* Pullup all the fragment headers and
610 * return a complete packet
612 for(bl = bl->next; bl; bl = bl->next) {
613 fragsize = BKFG(bl)->flen;
616 bl->wp = bl->rp + fragsize;
623 hnputs(ih->length, len);
624 qunlock(&ip->fraglock4);
625 ip->stats[ReasmOKs]++;
628 pktposn += BKFG(bl)->flen;
630 qunlock(&ip->fraglock4);
635 * ipfragfree4 - Free a list of fragments - assume hold fraglock4
638 ipfragfree4(IP *ip, Fragment4 *frag)
643 freeblist(frag->blist);
650 for(fl = *l; fl; fl = fl->next) {
658 frag->next = ip->fragfree4;
659 ip->fragfree4 = frag;
664 * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
671 while(ip->fragfree4 == nil) {
672 /* free last entry on fraglist */
673 for(f = ip->flisthead4; f->next; f = f->next)
678 ip->fragfree4 = f->next;
679 f->next = ip->flisthead4;
681 f->age = NOW + 30000;
693 len = (addr[0]&0xf)<<2;
696 sum += addr[0]<<8 | addr[1] ;
701 sum = (sum & 0xffff) + (sum >> 16);
702 sum = (sum & 0xffff) + (sum >> 16);