19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "ip.h"
99ef1f84bSDavid du Colombier
109ef1f84bSDavid du Colombier #define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0)
119ef1f84bSDavid du Colombier
129ef1f84bSDavid du Colombier static char *statnames[] =
139ef1f84bSDavid du Colombier {
149ef1f84bSDavid du Colombier [Forwarding] "Forwarding",
159ef1f84bSDavid du Colombier [DefaultTTL] "DefaultTTL",
169ef1f84bSDavid du Colombier [InReceives] "InReceives",
179ef1f84bSDavid du Colombier [InHdrErrors] "InHdrErrors",
189ef1f84bSDavid du Colombier [InAddrErrors] "InAddrErrors",
199ef1f84bSDavid du Colombier [ForwDatagrams] "ForwDatagrams",
209ef1f84bSDavid du Colombier [InUnknownProtos] "InUnknownProtos",
219ef1f84bSDavid du Colombier [InDiscards] "InDiscards",
229ef1f84bSDavid du Colombier [InDelivers] "InDelivers",
239ef1f84bSDavid du Colombier [OutRequests] "OutRequests",
249ef1f84bSDavid du Colombier [OutDiscards] "OutDiscards",
259ef1f84bSDavid du Colombier [OutNoRoutes] "OutNoRoutes",
269ef1f84bSDavid du Colombier [ReasmTimeout] "ReasmTimeout",
279ef1f84bSDavid du Colombier [ReasmReqds] "ReasmReqds",
289ef1f84bSDavid du Colombier [ReasmOKs] "ReasmOKs",
299ef1f84bSDavid du Colombier [ReasmFails] "ReasmFails",
309ef1f84bSDavid du Colombier [FragOKs] "FragOKs",
319ef1f84bSDavid du Colombier [FragFails] "FragFails",
329ef1f84bSDavid du Colombier [FragCreates] "FragCreates",
339ef1f84bSDavid du Colombier };
349ef1f84bSDavid du Colombier
359ef1f84bSDavid du Colombier #define BLKIP(xp) ((Ip4hdr*)((xp)->rp))
369ef1f84bSDavid du Colombier /*
379ef1f84bSDavid du Colombier * This sleazy macro relies on the media header size being
389ef1f84bSDavid du Colombier * larger than sizeof(Ipfrag). ipreassemble checks this is true
399ef1f84bSDavid du Colombier */
409ef1f84bSDavid du Colombier #define BKFG(xp) ((Ipfrag*)((xp)->base))
419ef1f84bSDavid du Colombier
429ef1f84bSDavid du Colombier ushort ipcsum(uchar*);
439ef1f84bSDavid du Colombier Block* ip4reassemble(IP*, int, Block*, Ip4hdr*);
449ef1f84bSDavid du Colombier void ipfragfree4(IP*, Fragment4*);
459ef1f84bSDavid du Colombier Fragment4* ipfragallo4(IP*);
469ef1f84bSDavid du Colombier
479ef1f84bSDavid du Colombier void
ip_init_6(Fs * f)489ef1f84bSDavid du Colombier ip_init_6(Fs *f)
499ef1f84bSDavid du Colombier {
509ef1f84bSDavid du Colombier v6params *v6p;
519ef1f84bSDavid du Colombier
529ef1f84bSDavid du Colombier v6p = smalloc(sizeof(v6params));
539ef1f84bSDavid du Colombier
549ef1f84bSDavid du Colombier v6p->rp.mflag = 0; /* default not managed */
559ef1f84bSDavid du Colombier v6p->rp.oflag = 0;
569ef1f84bSDavid du Colombier v6p->rp.maxraint = 600000; /* millisecs */
579ef1f84bSDavid du Colombier v6p->rp.minraint = 200000;
589ef1f84bSDavid du Colombier v6p->rp.linkmtu = 0; /* no mtu sent */
599ef1f84bSDavid du Colombier v6p->rp.reachtime = 0;
609ef1f84bSDavid du Colombier v6p->rp.rxmitra = 0;
619ef1f84bSDavid du Colombier v6p->rp.ttl = MAXTTL;
629ef1f84bSDavid du Colombier v6p->rp.routerlt = 3 * v6p->rp.maxraint;
639ef1f84bSDavid du Colombier
649ef1f84bSDavid du Colombier v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */
659ef1f84bSDavid du Colombier
669ef1f84bSDavid du Colombier v6p->cdrouter = -1;
679ef1f84bSDavid du Colombier
689ef1f84bSDavid du Colombier f->v6p = v6p;
699ef1f84bSDavid du Colombier }
709ef1f84bSDavid du Colombier
719ef1f84bSDavid du Colombier void
initfrag(IP * ip,int size)729ef1f84bSDavid du Colombier initfrag(IP *ip, int size)
739ef1f84bSDavid du Colombier {
749ef1f84bSDavid du Colombier Fragment4 *fq4, *eq4;
759ef1f84bSDavid du Colombier Fragment6 *fq6, *eq6;
769ef1f84bSDavid du Colombier
779ef1f84bSDavid du Colombier ip->fragfree4 = (Fragment4*)malloc(sizeof(Fragment4) * size);
789ef1f84bSDavid du Colombier if(ip->fragfree4 == nil)
799ef1f84bSDavid du Colombier panic("initfrag");
809ef1f84bSDavid du Colombier
819ef1f84bSDavid du Colombier eq4 = &ip->fragfree4[size];
829ef1f84bSDavid du Colombier for(fq4 = ip->fragfree4; fq4 < eq4; fq4++)
839ef1f84bSDavid du Colombier fq4->next = fq4+1;
849ef1f84bSDavid du Colombier
859ef1f84bSDavid du Colombier ip->fragfree4[size-1].next = nil;
869ef1f84bSDavid du Colombier
879ef1f84bSDavid du Colombier ip->fragfree6 = (Fragment6*)malloc(sizeof(Fragment6) * size);
889ef1f84bSDavid du Colombier if(ip->fragfree6 == nil)
899ef1f84bSDavid du Colombier panic("initfrag");
909ef1f84bSDavid du Colombier
919ef1f84bSDavid du Colombier eq6 = &ip->fragfree6[size];
929ef1f84bSDavid du Colombier for(fq6 = ip->fragfree6; fq6 < eq6; fq6++)
939ef1f84bSDavid du Colombier fq6->next = fq6+1;
949ef1f84bSDavid du Colombier
959ef1f84bSDavid du Colombier ip->fragfree6[size-1].next = nil;
969ef1f84bSDavid du Colombier }
979ef1f84bSDavid du Colombier
989ef1f84bSDavid du Colombier void
ip_init(Fs * f)999ef1f84bSDavid du Colombier ip_init(Fs *f)
1009ef1f84bSDavid du Colombier {
1019ef1f84bSDavid du Colombier IP *ip;
1029ef1f84bSDavid du Colombier
1039ef1f84bSDavid du Colombier ip = smalloc(sizeof(IP));
1049ef1f84bSDavid du Colombier initfrag(ip, 100);
1059ef1f84bSDavid du Colombier f->ip = ip;
1069ef1f84bSDavid du Colombier
1079ef1f84bSDavid du Colombier ip_init_6(f);
1089ef1f84bSDavid du Colombier }
1099ef1f84bSDavid du Colombier
1109ef1f84bSDavid du Colombier void
iprouting(Fs * f,int on)1119ef1f84bSDavid du Colombier iprouting(Fs *f, int on)
1129ef1f84bSDavid du Colombier {
1139ef1f84bSDavid du Colombier f->ip->iprouting = on;
1149ef1f84bSDavid du Colombier if(f->ip->iprouting==0)
1159ef1f84bSDavid du Colombier f->ip->stats[Forwarding] = 2;
1169ef1f84bSDavid du Colombier else
1179ef1f84bSDavid du Colombier f->ip->stats[Forwarding] = 1;
1189ef1f84bSDavid du Colombier }
1199ef1f84bSDavid du Colombier
1209ef1f84bSDavid du Colombier int
ipoput4(Fs * f,Block * bp,int gating,int ttl,int tos,Conv * c)1219ef1f84bSDavid du Colombier ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
1229ef1f84bSDavid du Colombier {
1239ef1f84bSDavid du Colombier Ipifc *ifc;
1249ef1f84bSDavid du Colombier uchar *gate;
1259ef1f84bSDavid du Colombier ulong fragoff;
1269ef1f84bSDavid du Colombier Block *xp, *nb;
1279ef1f84bSDavid du Colombier Ip4hdr *eh, *feh;
1289ef1f84bSDavid du Colombier int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
1299ef1f84bSDavid du Colombier Route *r, *sr;
1309ef1f84bSDavid du Colombier IP *ip;
1319ef1f84bSDavid du Colombier int rv = 0;
132*55ba833bSDavid du Colombier uchar v4dst[IPv4addrlen];
1339ef1f84bSDavid du Colombier
1349ef1f84bSDavid du Colombier ip = f->ip;
1359ef1f84bSDavid du Colombier
1369ef1f84bSDavid du Colombier /* Fill out the ip header */
1379ef1f84bSDavid du Colombier eh = (Ip4hdr*)(bp->rp);
1389ef1f84bSDavid du Colombier
1399ef1f84bSDavid du Colombier ip->stats[OutRequests]++;
1409ef1f84bSDavid du Colombier
1419ef1f84bSDavid du Colombier /* Number of uchars in data and ip header to write */
1429ef1f84bSDavid du Colombier len = blocklen(bp);
1439ef1f84bSDavid du Colombier
1449ef1f84bSDavid du Colombier if(gating){
1459ef1f84bSDavid du Colombier chunk = nhgets(eh->length);
1469ef1f84bSDavid du Colombier if(chunk > len){
1479ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
1489ef1f84bSDavid du Colombier netlog(f, Logip, "short gated packet\n");
1499ef1f84bSDavid du Colombier goto free;
1509ef1f84bSDavid du Colombier }
1519ef1f84bSDavid du Colombier if(chunk < len)
1529ef1f84bSDavid du Colombier len = chunk;
1539ef1f84bSDavid du Colombier }
1549ef1f84bSDavid du Colombier if(len >= IP_MAX){
1559ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
1569ef1f84bSDavid du Colombier netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
1579ef1f84bSDavid du Colombier goto free;
1589ef1f84bSDavid du Colombier }
1599ef1f84bSDavid du Colombier
1609ef1f84bSDavid du Colombier r = v4lookup(f, eh->dst, c);
1619ef1f84bSDavid du Colombier if(r == nil){
1629ef1f84bSDavid du Colombier ip->stats[OutNoRoutes]++;
1639ef1f84bSDavid du Colombier netlog(f, Logip, "no interface %V\n", eh->dst);
1649ef1f84bSDavid du Colombier rv = -1;
1659ef1f84bSDavid du Colombier goto free;
1669ef1f84bSDavid du Colombier }
1679ef1f84bSDavid du Colombier
1689ef1f84bSDavid du Colombier ifc = r->ifc;
1699ef1f84bSDavid du Colombier if(r->type & (Rifc|Runi))
1709ef1f84bSDavid du Colombier gate = eh->dst;
1719ef1f84bSDavid du Colombier else
1729ef1f84bSDavid du Colombier if(r->type & (Rbcast|Rmulti)) {
173*55ba833bSDavid du Colombier if(nhgetl(r->v4.gate) == 0){
174*55ba833bSDavid du Colombier hnputl(v4dst, r->v4.address);
175*55ba833bSDavid du Colombier gate = v4dst;
176*55ba833bSDavid du Colombier }else
1779ef1f84bSDavid du Colombier gate = eh->dst;
1789ef1f84bSDavid du Colombier sr = v4lookup(f, eh->src, nil);
1799ef1f84bSDavid du Colombier if(sr != nil && (sr->type & Runi))
1809ef1f84bSDavid du Colombier ifc = sr->ifc;
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier else
1839ef1f84bSDavid du Colombier gate = r->v4.gate;
1849ef1f84bSDavid du Colombier
1859ef1f84bSDavid du Colombier if(!gating)
1869ef1f84bSDavid du Colombier eh->vihl = IP_VER4|IP_HLEN4;
1879ef1f84bSDavid du Colombier eh->ttl = ttl;
1889ef1f84bSDavid du Colombier if(!gating)
1899ef1f84bSDavid du Colombier eh->tos = tos;
1909ef1f84bSDavid du Colombier
1919ef1f84bSDavid du Colombier if(!canrlock(ifc))
1929ef1f84bSDavid du Colombier goto free;
1939ef1f84bSDavid du Colombier if(waserror()){
1949ef1f84bSDavid du Colombier runlock(ifc);
1959ef1f84bSDavid du Colombier nexterror();
1969ef1f84bSDavid du Colombier }
1979ef1f84bSDavid du Colombier if(ifc->medium == nil)
1989ef1f84bSDavid du Colombier goto raise;
1999ef1f84bSDavid du Colombier
2009ef1f84bSDavid du Colombier /* If we dont need to fragment just send it */
2019ef1f84bSDavid du Colombier if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
2029ef1f84bSDavid du Colombier medialen = c->maxfragsize - ifc->medium->hsize;
2039ef1f84bSDavid du Colombier else
2049ef1f84bSDavid du Colombier medialen = ifc->maxtu - ifc->medium->hsize;
2059ef1f84bSDavid du Colombier if(len <= medialen) {
2069ef1f84bSDavid du Colombier if(!gating)
2079ef1f84bSDavid du Colombier hnputs(eh->id, incref(&ip->id4));
2089ef1f84bSDavid du Colombier hnputs(eh->length, len);
2099ef1f84bSDavid du Colombier if(!gating){
2109ef1f84bSDavid du Colombier eh->frag[0] = 0;
2119ef1f84bSDavid du Colombier eh->frag[1] = 0;
2129ef1f84bSDavid du Colombier }
2139ef1f84bSDavid du Colombier eh->cksum[0] = 0;
2149ef1f84bSDavid du Colombier eh->cksum[1] = 0;
2159ef1f84bSDavid du Colombier hnputs(eh->cksum, ipcsum(&eh->vihl));
2169ef1f84bSDavid du Colombier assert(bp->next == nil);
2179ef1f84bSDavid du Colombier ifc->medium->bwrite(ifc, bp, V4, gate);
2189ef1f84bSDavid du Colombier runlock(ifc);
2199ef1f84bSDavid du Colombier poperror();
2209ef1f84bSDavid du Colombier return 0;
2219ef1f84bSDavid du Colombier }
2229ef1f84bSDavid du Colombier
223a3323688SDavid du Colombier if((eh->frag[0] & (IP_DF>>8)) && !gating)
224a3323688SDavid du Colombier print("%V: DF set\n", eh->dst);
2259ef1f84bSDavid du Colombier
2269ef1f84bSDavid du Colombier if(eh->frag[0] & (IP_DF>>8)){
2279ef1f84bSDavid du Colombier ip->stats[FragFails]++;
2289ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
2299ef1f84bSDavid du Colombier icmpcantfrag(f, bp, medialen);
2309ef1f84bSDavid du Colombier netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
2319ef1f84bSDavid du Colombier goto raise;
2329ef1f84bSDavid du Colombier }
2339ef1f84bSDavid du Colombier
2349ef1f84bSDavid du Colombier seglen = (medialen - IP4HDR) & ~7;
2359ef1f84bSDavid du Colombier if(seglen < 8){
2369ef1f84bSDavid du Colombier ip->stats[FragFails]++;
2379ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
2389ef1f84bSDavid du Colombier netlog(f, Logip, "%V seglen < 8\n", eh->dst);
2399ef1f84bSDavid du Colombier goto raise;
2409ef1f84bSDavid du Colombier }
2419ef1f84bSDavid du Colombier
2429ef1f84bSDavid du Colombier dlen = len - IP4HDR;
2439ef1f84bSDavid du Colombier xp = bp;
2449ef1f84bSDavid du Colombier if(gating)
2459ef1f84bSDavid du Colombier lid = nhgets(eh->id);
2469ef1f84bSDavid du Colombier else
2479ef1f84bSDavid du Colombier lid = incref(&ip->id4);
2489ef1f84bSDavid du Colombier
2499ef1f84bSDavid du Colombier offset = IP4HDR;
2509ef1f84bSDavid du Colombier while(xp != nil && offset && offset >= BLEN(xp)) {
2519ef1f84bSDavid du Colombier offset -= BLEN(xp);
2529ef1f84bSDavid du Colombier xp = xp->next;
2539ef1f84bSDavid du Colombier }
2549ef1f84bSDavid du Colombier xp->rp += offset;
2559ef1f84bSDavid du Colombier
2569ef1f84bSDavid du Colombier if(gating)
2579ef1f84bSDavid du Colombier fragoff = nhgets(eh->frag)<<3;
2589ef1f84bSDavid du Colombier else
2599ef1f84bSDavid du Colombier fragoff = 0;
2609ef1f84bSDavid du Colombier dlen += fragoff;
2619ef1f84bSDavid du Colombier for(; fragoff < dlen; fragoff += seglen) {
2629ef1f84bSDavid du Colombier nb = allocb(IP4HDR+seglen);
2639ef1f84bSDavid du Colombier feh = (Ip4hdr*)(nb->rp);
2649ef1f84bSDavid du Colombier
2659ef1f84bSDavid du Colombier memmove(nb->wp, eh, IP4HDR);
2669ef1f84bSDavid du Colombier nb->wp += IP4HDR;
2679ef1f84bSDavid du Colombier
2689ef1f84bSDavid du Colombier if((fragoff + seglen) >= dlen) {
2699ef1f84bSDavid du Colombier seglen = dlen - fragoff;
2709ef1f84bSDavid du Colombier hnputs(feh->frag, fragoff>>3);
2719ef1f84bSDavid du Colombier }
2729ef1f84bSDavid du Colombier else
2739ef1f84bSDavid du Colombier hnputs(feh->frag, (fragoff>>3)|IP_MF);
2749ef1f84bSDavid du Colombier
2759ef1f84bSDavid du Colombier hnputs(feh->length, seglen + IP4HDR);
2769ef1f84bSDavid du Colombier hnputs(feh->id, lid);
2779ef1f84bSDavid du Colombier
2789ef1f84bSDavid du Colombier /* Copy up the data area */
2799ef1f84bSDavid du Colombier chunk = seglen;
2809ef1f84bSDavid du Colombier while(chunk) {
2819ef1f84bSDavid du Colombier if(!xp) {
2829ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
2839ef1f84bSDavid du Colombier ip->stats[FragFails]++;
2849ef1f84bSDavid du Colombier freeblist(nb);
2859ef1f84bSDavid du Colombier netlog(f, Logip, "!xp: chunk %d\n", chunk);
2869ef1f84bSDavid du Colombier goto raise;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier blklen = chunk;
2899ef1f84bSDavid du Colombier if(BLEN(xp) < chunk)
2909ef1f84bSDavid du Colombier blklen = BLEN(xp);
2919ef1f84bSDavid du Colombier memmove(nb->wp, xp->rp, blklen);
2929ef1f84bSDavid du Colombier nb->wp += blklen;
2939ef1f84bSDavid du Colombier xp->rp += blklen;
2949ef1f84bSDavid du Colombier chunk -= blklen;
2959ef1f84bSDavid du Colombier if(xp->rp == xp->wp)
2969ef1f84bSDavid du Colombier xp = xp->next;
2979ef1f84bSDavid du Colombier }
2989ef1f84bSDavid du Colombier
2999ef1f84bSDavid du Colombier feh->cksum[0] = 0;
3009ef1f84bSDavid du Colombier feh->cksum[1] = 0;
3019ef1f84bSDavid du Colombier hnputs(feh->cksum, ipcsum(&feh->vihl));
3029ef1f84bSDavid du Colombier ifc->medium->bwrite(ifc, nb, V4, gate);
3039ef1f84bSDavid du Colombier ip->stats[FragCreates]++;
3049ef1f84bSDavid du Colombier }
3059ef1f84bSDavid du Colombier ip->stats[FragOKs]++;
3069ef1f84bSDavid du Colombier raise:
3079ef1f84bSDavid du Colombier runlock(ifc);
3089ef1f84bSDavid du Colombier poperror();
3099ef1f84bSDavid du Colombier free:
3109ef1f84bSDavid du Colombier freeblist(bp);
3119ef1f84bSDavid du Colombier return rv;
3129ef1f84bSDavid du Colombier }
3139ef1f84bSDavid du Colombier
3149ef1f84bSDavid du Colombier void
ipiput4(Fs * f,Ipifc * ifc,Block * bp)3159ef1f84bSDavid du Colombier ipiput4(Fs *f, Ipifc *ifc, Block *bp)
3169ef1f84bSDavid du Colombier {
3179ef1f84bSDavid du Colombier int hl;
3189ef1f84bSDavid du Colombier int hop, tos, proto, olen;
3199ef1f84bSDavid du Colombier Ip4hdr *h;
3209ef1f84bSDavid du Colombier Proto *p;
3219ef1f84bSDavid du Colombier ushort frag;
3229ef1f84bSDavid du Colombier int notforme;
3239ef1f84bSDavid du Colombier uchar *dp, v6dst[IPaddrlen];
3249ef1f84bSDavid du Colombier IP *ip;
3259ef1f84bSDavid du Colombier Route *r;
3269ef1f84bSDavid du Colombier Conv conv;
3279ef1f84bSDavid du Colombier
3289ef1f84bSDavid du Colombier if(BLKIPVER(bp) != IP_VER4) {
3299ef1f84bSDavid du Colombier ipiput6(f, ifc, bp);
3309ef1f84bSDavid du Colombier return;
3319ef1f84bSDavid du Colombier }
3329ef1f84bSDavid du Colombier
3339ef1f84bSDavid du Colombier ip = f->ip;
3349ef1f84bSDavid du Colombier ip->stats[InReceives]++;
3359ef1f84bSDavid du Colombier
3369ef1f84bSDavid du Colombier /*
3379ef1f84bSDavid du Colombier * Ensure we have all the header info in the first
3389ef1f84bSDavid du Colombier * block. Make life easier for other protocols by
3399ef1f84bSDavid du Colombier * collecting up to the first 64 bytes in the first block.
3409ef1f84bSDavid du Colombier */
3419ef1f84bSDavid du Colombier if(BLEN(bp) < 64) {
3429ef1f84bSDavid du Colombier hl = blocklen(bp);
3439ef1f84bSDavid du Colombier if(hl < IP4HDR)
3449ef1f84bSDavid du Colombier hl = IP4HDR;
3459ef1f84bSDavid du Colombier if(hl > 64)
3469ef1f84bSDavid du Colombier hl = 64;
3479ef1f84bSDavid du Colombier bp = pullupblock(bp, hl);
3489ef1f84bSDavid du Colombier if(bp == nil)
3499ef1f84bSDavid du Colombier return;
3509ef1f84bSDavid du Colombier }
3519ef1f84bSDavid du Colombier
3529ef1f84bSDavid du Colombier h = (Ip4hdr*)(bp->rp);
3539ef1f84bSDavid du Colombier
3549ef1f84bSDavid du Colombier /* dump anything that whose header doesn't checksum */
3559ef1f84bSDavid du Colombier if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
3569ef1f84bSDavid du Colombier ip->stats[InHdrErrors]++;
3579ef1f84bSDavid du Colombier netlog(f, Logip, "ip: checksum error %V\n", h->src);
3589ef1f84bSDavid du Colombier freeblist(bp);
3599ef1f84bSDavid du Colombier return;
3609ef1f84bSDavid du Colombier }
3619ef1f84bSDavid du Colombier v4tov6(v6dst, h->dst);
3629ef1f84bSDavid du Colombier notforme = ipforme(f, v6dst) == 0;
3639ef1f84bSDavid du Colombier
3649ef1f84bSDavid du Colombier /* Check header length and version */
3659ef1f84bSDavid du Colombier if((h->vihl&0x0F) != IP_HLEN4) {
3669ef1f84bSDavid du Colombier hl = (h->vihl&0xF)<<2;
3679ef1f84bSDavid du Colombier if(hl < (IP_HLEN4<<2)) {
3689ef1f84bSDavid du Colombier ip->stats[InHdrErrors]++;
3699ef1f84bSDavid du Colombier netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
3709ef1f84bSDavid du Colombier freeblist(bp);
3719ef1f84bSDavid du Colombier return;
3729ef1f84bSDavid du Colombier }
3739ef1f84bSDavid du Colombier /* If this is not routed strip off the options */
3749ef1f84bSDavid du Colombier if(notforme == 0) {
3759ef1f84bSDavid du Colombier olen = nhgets(h->length);
3769ef1f84bSDavid du Colombier dp = bp->rp + (hl - (IP_HLEN4<<2));
3779ef1f84bSDavid du Colombier memmove(dp, h, IP_HLEN4<<2);
3789ef1f84bSDavid du Colombier bp->rp = dp;
3799ef1f84bSDavid du Colombier h = (Ip4hdr*)(bp->rp);
3809ef1f84bSDavid du Colombier h->vihl = (IP_VER4|IP_HLEN4);
3819ef1f84bSDavid du Colombier hnputs(h->length, olen-hl+(IP_HLEN4<<2));
3829ef1f84bSDavid du Colombier }
3839ef1f84bSDavid du Colombier }
3849ef1f84bSDavid du Colombier
3859ef1f84bSDavid du Colombier /* route */
3869ef1f84bSDavid du Colombier if(notforme) {
3879ef1f84bSDavid du Colombier if(!ip->iprouting){
3889ef1f84bSDavid du Colombier freeblist(bp);
3899ef1f84bSDavid du Colombier return;
3909ef1f84bSDavid du Colombier }
3919ef1f84bSDavid du Colombier
3929ef1f84bSDavid du Colombier /* don't forward to source's network */
3939ef1f84bSDavid du Colombier memset(&conv, 0, sizeof conv);
3949ef1f84bSDavid du Colombier conv.r = nil;
3959ef1f84bSDavid du Colombier r = v4lookup(f, h->dst, &conv);
3969ef1f84bSDavid du Colombier if(r == nil || r->ifc == ifc){
3979ef1f84bSDavid du Colombier ip->stats[OutDiscards]++;
3989ef1f84bSDavid du Colombier freeblist(bp);
3999ef1f84bSDavid du Colombier return;
4009ef1f84bSDavid du Colombier }
4019ef1f84bSDavid du Colombier
4029ef1f84bSDavid du Colombier /* don't forward if packet has timed out */
4039ef1f84bSDavid du Colombier hop = h->ttl;
4049ef1f84bSDavid du Colombier if(hop < 1) {
4059ef1f84bSDavid du Colombier ip->stats[InHdrErrors]++;
4069ef1f84bSDavid du Colombier icmpttlexceeded(f, ifc->lifc->local, bp);
4079ef1f84bSDavid du Colombier freeblist(bp);
4089ef1f84bSDavid du Colombier return;
4099ef1f84bSDavid du Colombier }
4109ef1f84bSDavid du Colombier
4119ef1f84bSDavid du Colombier /* reassemble if the interface expects it */
4129ef1f84bSDavid du Colombier if(r->ifc == nil) panic("nil route rfc");
4139ef1f84bSDavid du Colombier if(r->ifc->reassemble){
4149ef1f84bSDavid du Colombier frag = nhgets(h->frag);
4159ef1f84bSDavid du Colombier if(frag) {
4169ef1f84bSDavid du Colombier h->tos = 0;
4179ef1f84bSDavid du Colombier if(frag & IP_MF)
4189ef1f84bSDavid du Colombier h->tos = 1;
4199ef1f84bSDavid du Colombier bp = ip4reassemble(ip, frag, bp, h);
4209ef1f84bSDavid du Colombier if(bp == nil)
4219ef1f84bSDavid du Colombier return;
4229ef1f84bSDavid du Colombier h = (Ip4hdr*)(bp->rp);
4239ef1f84bSDavid du Colombier }
4249ef1f84bSDavid du Colombier }
4259ef1f84bSDavid du Colombier
4269ef1f84bSDavid du Colombier ip->stats[ForwDatagrams]++;
4279ef1f84bSDavid du Colombier tos = h->tos;
4289ef1f84bSDavid du Colombier hop = h->ttl;
4299ef1f84bSDavid du Colombier ipoput4(f, bp, 1, hop - 1, tos, &conv);
4309ef1f84bSDavid du Colombier return;
4319ef1f84bSDavid du Colombier }
4329ef1f84bSDavid du Colombier
4339ef1f84bSDavid du Colombier frag = nhgets(h->frag);
4349ef1f84bSDavid du Colombier if(frag) {
4359ef1f84bSDavid du Colombier h->tos = 0;
4369ef1f84bSDavid du Colombier if(frag & IP_MF)
4379ef1f84bSDavid du Colombier h->tos = 1;
4389ef1f84bSDavid du Colombier bp = ip4reassemble(ip, frag, bp, h);
4399ef1f84bSDavid du Colombier if(bp == nil)
4409ef1f84bSDavid du Colombier return;
4419ef1f84bSDavid du Colombier h = (Ip4hdr*)(bp->rp);
4429ef1f84bSDavid du Colombier }
4439ef1f84bSDavid du Colombier
4449ef1f84bSDavid du Colombier /* don't let any frag info go up the stack */
4459ef1f84bSDavid du Colombier h->frag[0] = 0;
4469ef1f84bSDavid du Colombier h->frag[1] = 0;
4479ef1f84bSDavid du Colombier
4489ef1f84bSDavid du Colombier proto = h->proto;
4499ef1f84bSDavid du Colombier p = Fsrcvpcol(f, proto);
4509ef1f84bSDavid du Colombier if(p != nil && p->rcv != nil) {
4519ef1f84bSDavid du Colombier ip->stats[InDelivers]++;
4529ef1f84bSDavid du Colombier (*p->rcv)(p, ifc, bp);
4539ef1f84bSDavid du Colombier return;
4549ef1f84bSDavid du Colombier }
4559ef1f84bSDavid du Colombier ip->stats[InDiscards]++;
4569ef1f84bSDavid du Colombier ip->stats[InUnknownProtos]++;
4579ef1f84bSDavid du Colombier freeblist(bp);
4589ef1f84bSDavid du Colombier }
4599ef1f84bSDavid du Colombier
4609ef1f84bSDavid du Colombier int
ipstats(Fs * f,char * buf,int len)4619ef1f84bSDavid du Colombier ipstats(Fs *f, char *buf, int len)
4629ef1f84bSDavid du Colombier {
4639ef1f84bSDavid du Colombier IP *ip;
4649ef1f84bSDavid du Colombier char *p, *e;
4659ef1f84bSDavid du Colombier int i;
4669ef1f84bSDavid du Colombier
4679ef1f84bSDavid du Colombier ip = f->ip;
4689ef1f84bSDavid du Colombier ip->stats[DefaultTTL] = MAXTTL;
4699ef1f84bSDavid du Colombier
4709ef1f84bSDavid du Colombier p = buf;
4719ef1f84bSDavid du Colombier e = p+len;
4729ef1f84bSDavid du Colombier for(i = 0; i < Nipstats; i++)
4739ef1f84bSDavid du Colombier p = seprint(p, e, "%s: %llud\n", statnames[i], ip->stats[i]);
4749ef1f84bSDavid du Colombier return p - buf;
4759ef1f84bSDavid du Colombier }
4769ef1f84bSDavid du Colombier
4779ef1f84bSDavid du Colombier Block*
ip4reassemble(IP * ip,int offset,Block * bp,Ip4hdr * ih)4789ef1f84bSDavid du Colombier ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
4799ef1f84bSDavid du Colombier {
4809ef1f84bSDavid du Colombier int fend;
4819ef1f84bSDavid du Colombier ushort id;
4829ef1f84bSDavid du Colombier Fragment4 *f, *fnext;
4839ef1f84bSDavid du Colombier ulong src, dst;
4849ef1f84bSDavid du Colombier Block *bl, **l, *last, *prev;
4859ef1f84bSDavid du Colombier int ovlap, len, fragsize, pktposn;
4869ef1f84bSDavid du Colombier
4879ef1f84bSDavid du Colombier src = nhgetl(ih->src);
4889ef1f84bSDavid du Colombier dst = nhgetl(ih->dst);
4899ef1f84bSDavid du Colombier id = nhgets(ih->id);
4909ef1f84bSDavid du Colombier
4919ef1f84bSDavid du Colombier /*
4929ef1f84bSDavid du Colombier * block lists are too hard, pullupblock into a single block
4939ef1f84bSDavid du Colombier */
4949ef1f84bSDavid du Colombier if(bp->next){
4959ef1f84bSDavid du Colombier bp = pullupblock(bp, blocklen(bp));
4969ef1f84bSDavid du Colombier ih = (Ip4hdr*)(bp->rp);
4979ef1f84bSDavid du Colombier }
4989ef1f84bSDavid du Colombier
4999ef1f84bSDavid du Colombier qlock(&ip->fraglock4);
5009ef1f84bSDavid du Colombier
5019ef1f84bSDavid du Colombier /*
5029ef1f84bSDavid du Colombier * find a reassembly queue for this fragment
5039ef1f84bSDavid du Colombier */
5049ef1f84bSDavid du Colombier for(f = ip->flisthead4; f; f = fnext){
5059ef1f84bSDavid du Colombier fnext = f->next; /* because ipfragfree4 changes the list */
5069ef1f84bSDavid du Colombier if(f->src == src && f->dst == dst && f->id == id)
5079ef1f84bSDavid du Colombier break;
5089ef1f84bSDavid du Colombier if(f->age < NOW){
5099ef1f84bSDavid du Colombier ip->stats[ReasmTimeout]++;
5109ef1f84bSDavid du Colombier ipfragfree4(ip, f);
5119ef1f84bSDavid du Colombier }
5129ef1f84bSDavid du Colombier }
5139ef1f84bSDavid du Colombier
5149ef1f84bSDavid du Colombier /*
5159ef1f84bSDavid du Colombier * if this isn't a fragmented packet, accept it
5169ef1f84bSDavid du Colombier * and get rid of any fragments that might go
5179ef1f84bSDavid du Colombier * with it.
5189ef1f84bSDavid du Colombier */
5199ef1f84bSDavid du Colombier if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
5209ef1f84bSDavid du Colombier if(f != nil) {
5219ef1f84bSDavid du Colombier ipfragfree4(ip, f);
5229ef1f84bSDavid du Colombier ip->stats[ReasmFails]++;
5239ef1f84bSDavid du Colombier }
5249ef1f84bSDavid du Colombier qunlock(&ip->fraglock4);
5259ef1f84bSDavid du Colombier return bp;
5269ef1f84bSDavid du Colombier }
5279ef1f84bSDavid du Colombier
5289ef1f84bSDavid du Colombier if(bp->base+IPFRAGSZ >= bp->rp){
5299ef1f84bSDavid du Colombier bp = padblock(bp, IPFRAGSZ);
5309ef1f84bSDavid du Colombier bp->rp += IPFRAGSZ;
5319ef1f84bSDavid du Colombier }
5329ef1f84bSDavid du Colombier
5339ef1f84bSDavid du Colombier BKFG(bp)->foff = offset<<3;
5349ef1f84bSDavid du Colombier BKFG(bp)->flen = nhgets(ih->length)-IP4HDR;
5359ef1f84bSDavid du Colombier
5369ef1f84bSDavid du Colombier /* First fragment allocates a reassembly queue */
5379ef1f84bSDavid du Colombier if(f == nil) {
5389ef1f84bSDavid du Colombier f = ipfragallo4(ip);
5399ef1f84bSDavid du Colombier f->id = id;
5409ef1f84bSDavid du Colombier f->src = src;
5419ef1f84bSDavid du Colombier f->dst = dst;
5429ef1f84bSDavid du Colombier
5439ef1f84bSDavid du Colombier f->blist = bp;
5449ef1f84bSDavid du Colombier
5459ef1f84bSDavid du Colombier qunlock(&ip->fraglock4);
5469ef1f84bSDavid du Colombier ip->stats[ReasmReqds]++;
5479ef1f84bSDavid du Colombier return nil;
5489ef1f84bSDavid du Colombier }
5499ef1f84bSDavid du Colombier
5509ef1f84bSDavid du Colombier /*
5519ef1f84bSDavid du Colombier * find the new fragment's position in the queue
5529ef1f84bSDavid du Colombier */
5539ef1f84bSDavid du Colombier prev = nil;
5549ef1f84bSDavid du Colombier l = &f->blist;
5559ef1f84bSDavid du Colombier bl = f->blist;
5569ef1f84bSDavid du Colombier while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) {
5579ef1f84bSDavid du Colombier prev = bl;
5589ef1f84bSDavid du Colombier l = &bl->next;
5599ef1f84bSDavid du Colombier bl = bl->next;
5609ef1f84bSDavid du Colombier }
5619ef1f84bSDavid du Colombier
5629ef1f84bSDavid du Colombier /* Check overlap of a previous fragment - trim away as necessary */
5639ef1f84bSDavid du Colombier if(prev) {
5649ef1f84bSDavid du Colombier ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
5659ef1f84bSDavid du Colombier if(ovlap > 0) {
5669ef1f84bSDavid du Colombier if(ovlap >= BKFG(bp)->flen) {
5679ef1f84bSDavid du Colombier freeblist(bp);
5689ef1f84bSDavid du Colombier qunlock(&ip->fraglock4);
5699ef1f84bSDavid du Colombier return nil;
5709ef1f84bSDavid du Colombier }
5719ef1f84bSDavid du Colombier BKFG(prev)->flen -= ovlap;
5729ef1f84bSDavid du Colombier }
5739ef1f84bSDavid du Colombier }
5749ef1f84bSDavid du Colombier
5759ef1f84bSDavid du Colombier /* Link onto assembly queue */
5769ef1f84bSDavid du Colombier bp->next = *l;
5779ef1f84bSDavid du Colombier *l = bp;
5789ef1f84bSDavid du Colombier
5799ef1f84bSDavid du Colombier /* Check to see if succeeding segments overlap */
5809ef1f84bSDavid du Colombier if(bp->next) {
5819ef1f84bSDavid du Colombier l = &bp->next;
5829ef1f84bSDavid du Colombier fend = BKFG(bp)->foff + BKFG(bp)->flen;
5839ef1f84bSDavid du Colombier /* Take completely covered segments out */
5849ef1f84bSDavid du Colombier while(*l) {
5859ef1f84bSDavid du Colombier ovlap = fend - BKFG(*l)->foff;
5869ef1f84bSDavid du Colombier if(ovlap <= 0)
5879ef1f84bSDavid du Colombier break;
5889ef1f84bSDavid du Colombier if(ovlap < BKFG(*l)->flen) {
5899ef1f84bSDavid du Colombier BKFG(*l)->flen -= ovlap;
5909ef1f84bSDavid du Colombier BKFG(*l)->foff += ovlap;
5919ef1f84bSDavid du Colombier /* move up ih hdrs */
5929ef1f84bSDavid du Colombier memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
5939ef1f84bSDavid du Colombier (*l)->rp += ovlap;
5949ef1f84bSDavid du Colombier break;
5959ef1f84bSDavid du Colombier }
5969ef1f84bSDavid du Colombier last = (*l)->next;
5979ef1f84bSDavid du Colombier (*l)->next = nil;
5989ef1f84bSDavid du Colombier freeblist(*l);
5999ef1f84bSDavid du Colombier *l = last;
6009ef1f84bSDavid du Colombier }
6019ef1f84bSDavid du Colombier }
6029ef1f84bSDavid du Colombier
6039ef1f84bSDavid du Colombier /*
6049ef1f84bSDavid du Colombier * look for a complete packet. if we get to a fragment
6059ef1f84bSDavid du Colombier * without IP_MF set, we're done.
6069ef1f84bSDavid du Colombier */
6079ef1f84bSDavid du Colombier pktposn = 0;
6089ef1f84bSDavid du Colombier for(bl = f->blist; bl; bl = bl->next) {
6099ef1f84bSDavid du Colombier if(BKFG(bl)->foff != pktposn)
6109ef1f84bSDavid du Colombier break;
6119ef1f84bSDavid du Colombier if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) {
6129ef1f84bSDavid du Colombier bl = f->blist;
6139ef1f84bSDavid du Colombier len = nhgets(BLKIP(bl)->length);
6149ef1f84bSDavid du Colombier bl->wp = bl->rp + len;
6159ef1f84bSDavid du Colombier
6169ef1f84bSDavid du Colombier /* Pullup all the fragment headers and
6179ef1f84bSDavid du Colombier * return a complete packet
6189ef1f84bSDavid du Colombier */
6199ef1f84bSDavid du Colombier for(bl = bl->next; bl; bl = bl->next) {
6209ef1f84bSDavid du Colombier fragsize = BKFG(bl)->flen;
6219ef1f84bSDavid du Colombier len += fragsize;
6229ef1f84bSDavid du Colombier bl->rp += IP4HDR;
6239ef1f84bSDavid du Colombier bl->wp = bl->rp + fragsize;
6249ef1f84bSDavid du Colombier }
6259ef1f84bSDavid du Colombier
6269ef1f84bSDavid du Colombier bl = f->blist;
6279ef1f84bSDavid du Colombier f->blist = nil;
6289ef1f84bSDavid du Colombier ipfragfree4(ip, f);
6299ef1f84bSDavid du Colombier ih = BLKIP(bl);
6309ef1f84bSDavid du Colombier hnputs(ih->length, len);
6319ef1f84bSDavid du Colombier qunlock(&ip->fraglock4);
6329ef1f84bSDavid du Colombier ip->stats[ReasmOKs]++;
6339ef1f84bSDavid du Colombier return bl;
6349ef1f84bSDavid du Colombier }
6359ef1f84bSDavid du Colombier pktposn += BKFG(bl)->flen;
6369ef1f84bSDavid du Colombier }
6379ef1f84bSDavid du Colombier qunlock(&ip->fraglock4);
6389ef1f84bSDavid du Colombier return nil;
6399ef1f84bSDavid du Colombier }
6409ef1f84bSDavid du Colombier
6419ef1f84bSDavid du Colombier /*
6429ef1f84bSDavid du Colombier * ipfragfree4 - Free a list of fragments - assume hold fraglock4
6439ef1f84bSDavid du Colombier */
6449ef1f84bSDavid du Colombier void
ipfragfree4(IP * ip,Fragment4 * frag)6459ef1f84bSDavid du Colombier ipfragfree4(IP *ip, Fragment4 *frag)
6469ef1f84bSDavid du Colombier {
6479ef1f84bSDavid du Colombier Fragment4 *fl, **l;
6489ef1f84bSDavid du Colombier
6499ef1f84bSDavid du Colombier if(frag->blist)
6509ef1f84bSDavid du Colombier freeblist(frag->blist);
6519ef1f84bSDavid du Colombier
6529ef1f84bSDavid du Colombier frag->src = 0;
6539ef1f84bSDavid du Colombier frag->id = 0;
6549ef1f84bSDavid du Colombier frag->blist = nil;
6559ef1f84bSDavid du Colombier
6569ef1f84bSDavid du Colombier l = &ip->flisthead4;
6579ef1f84bSDavid du Colombier for(fl = *l; fl; fl = fl->next) {
6589ef1f84bSDavid du Colombier if(fl == frag) {
6599ef1f84bSDavid du Colombier *l = frag->next;
6609ef1f84bSDavid du Colombier break;
6619ef1f84bSDavid du Colombier }
6629ef1f84bSDavid du Colombier l = &fl->next;
6639ef1f84bSDavid du Colombier }
6649ef1f84bSDavid du Colombier
6659ef1f84bSDavid du Colombier frag->next = ip->fragfree4;
6669ef1f84bSDavid du Colombier ip->fragfree4 = frag;
6679ef1f84bSDavid du Colombier
6689ef1f84bSDavid du Colombier }
6699ef1f84bSDavid du Colombier
6709ef1f84bSDavid du Colombier /*
6719ef1f84bSDavid du Colombier * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
6729ef1f84bSDavid du Colombier */
6739ef1f84bSDavid du Colombier Fragment4 *
ipfragallo4(IP * ip)6749ef1f84bSDavid du Colombier ipfragallo4(IP *ip)
6759ef1f84bSDavid du Colombier {
6769ef1f84bSDavid du Colombier Fragment4 *f;
6779ef1f84bSDavid du Colombier
6789ef1f84bSDavid du Colombier while(ip->fragfree4 == nil) {
6799ef1f84bSDavid du Colombier /* free last entry on fraglist */
6809ef1f84bSDavid du Colombier for(f = ip->flisthead4; f->next; f = f->next)
6819ef1f84bSDavid du Colombier ;
6829ef1f84bSDavid du Colombier ipfragfree4(ip, f);
6839ef1f84bSDavid du Colombier }
6849ef1f84bSDavid du Colombier f = ip->fragfree4;
6859ef1f84bSDavid du Colombier ip->fragfree4 = f->next;
6869ef1f84bSDavid du Colombier f->next = ip->flisthead4;
6879ef1f84bSDavid du Colombier ip->flisthead4 = f;
6889ef1f84bSDavid du Colombier f->age = NOW + 30000;
6899ef1f84bSDavid du Colombier
6909ef1f84bSDavid du Colombier return f;
6919ef1f84bSDavid du Colombier }
6929ef1f84bSDavid du Colombier
6939ef1f84bSDavid du Colombier ushort
ipcsum(uchar * addr)6949ef1f84bSDavid du Colombier ipcsum(uchar *addr)
6959ef1f84bSDavid du Colombier {
6969ef1f84bSDavid du Colombier int len;
6979ef1f84bSDavid du Colombier ulong sum;
6989ef1f84bSDavid du Colombier
6999ef1f84bSDavid du Colombier sum = 0;
7009ef1f84bSDavid du Colombier len = (addr[0]&0xf)<<2;
7019ef1f84bSDavid du Colombier
7029ef1f84bSDavid du Colombier while(len > 0) {
7039ef1f84bSDavid du Colombier sum += addr[0]<<8 | addr[1] ;
7049ef1f84bSDavid du Colombier len -= 2;
7059ef1f84bSDavid du Colombier addr += 2;
7069ef1f84bSDavid du Colombier }
7079ef1f84bSDavid du Colombier
7089ef1f84bSDavid du Colombier sum = (sum & 0xffff) + (sum >> 16);
7099ef1f84bSDavid du Colombier sum = (sum & 0xffff) + (sum >> 16);
7109ef1f84bSDavid du Colombier
7119ef1f84bSDavid du Colombier return (sum^0xffff);
7129ef1f84bSDavid du Colombier }
713