/* Copyright 2000 (c) by David Schweikert, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Net/IP/NetIPdown.c,v $ Author(s): Affiliation: ETH Zuerich, TIK Version: $Revision: 1.1 $ Creation Date: Last Date of Change: $Date: 2000/03/31 17:50:37 $ by: $Author: gfa $ $Log: NetIPdown.c,v $ Revision 1.1 2000/03/31 17:50:37 gfa Merged with /Net from several term projects */ #include "NetIP.h" #include "NetIPchecksum.h" #include #include #include #include #include #include #include #include #include static int netipFillHeader(NetBuf buf, NetAttrs attrs); static void netipDownSend(NetBuf buf, NetAttrs attrs); static void netipDownSendFragment(NetBuf buf, NetAttrs attrs, int hlen, unsigned short off, int more); static void netipDownFragmentPacket(NetBuf buf, NetAttrs attrs, int hlen, int dlen, int mtu); /* Note: these are a classic example of BAD macros :-) */ #define MAX(a,b) (a>b?a:b) #define MIN(a,b) (a>b?b:a) void netipDown(NetBuf buf, NetAttrs attrs) { /* Add and fill header */ netdbgDisplay(NETDEBUG_IP, "netip : Adding header to downgoing packet.\n"); netbufAddHead(&buf,sizeof(NetIPHdr)); if(!netipFillHeader(buf,attrs)) { netbufFree(buf); netattrFree(attrs); return; } /* Send... */ netipDownSend(buf,attrs); } static int netipFillHeader(NetBuf buf, NetAttrs attrs) { NetIPHdr *hdr=(NetIPHdr *) NETBUF_DATA(buf); unsigned short val, hlen; /* version */ BNIBSET(hdr->bitfield1,0,4); /* header length */ hlen = sizeof(NetIPHdr); BNIBSET(hdr->bitfield1,1,hlen>>2); /* id */ if(netattrGet(attrs,NETATTR_IP_ID, &val)) hdr->id = htons(val); else hdr->id = ++netip_last_id; /* type of service */ if(netattrGet(attrs,NETATTR_IP_TOS,&val)) hdr->tos = val; else hdr->tos = 0; /* total length */ hdr->tot_len = htons(netbufLen(buf)); /* TTL */ if(netattrGet(attrs,NETATTR_IP_TTL, &val)) hdr->ttl = val; else hdr->ttl = NETIP_DEFAULT_TTL; /* protocol */ if(!netattrGet(attrs,NETATTR_IP_PROTOCOL, &val)) { netdbgDisplay(NETDEBUG_IP, "netip: NETATTR_IP_PROTOCOL not specified!\n"); return 0; } hdr->protocol = val; /* source ip address (to be filled in netipDownSend) */ hdr->saddr0 = 0; /* destination ip address */ if(!netattrGet(attrs,NETATTR_IP_TO_0,&val)) { netdbgDisplay(NETDEBUG_IP, "netip: NETATTR_IP_TO not specified!\n"); return 0; } hdr->daddr0 = val; netattrGet(attrs,NETATTR_IP_TO_1,&val); /* daddr1 = daddr1<<8 | val; */ hdr->daddr1 = val; netattrGet(attrs,NETATTR_IP_TO_2,&val); hdr->daddr2 = val; netattrGet(attrs,NETATTR_IP_TO_3,&val); hdr->daddr3 = val; return 1; } /* Send down IP packet (header already built) */ static void netipDownSend(NetBuf buf, NetAttrs attrs) { NetIPHdr *hdr=(NetIPHdr *) NETBUF_DATA(buf); int iface, len; unsigned short hlen,mtu,tmp; /* Determine Route */ iface=netipRoute(attrs); if(iface<0) { /* Dest. unreachable */ netdbgDisplay(NETDEBUG_GENERIC, "Destination unreachable.\n"); netbufFree(buf); netattrFree(attrs); return; } netattrSet(attrs,NETATTR_IF_TO, iface); /* If source address not set, set it to iface address */ if(hdr->saddr0 == 0) { netifGetAttr(iface,NETATTR_IP_FROM_0,&tmp); hdr->saddr0 = tmp; netifGetAttr(iface,NETATTR_IP_FROM_1,&tmp); hdr->saddr1 = tmp; netifGetAttr(iface,NETATTR_IP_FROM_2,&tmp); hdr->saddr2 = tmp; netifGetAttr(iface,NETATTR_IP_FROM_3,&tmp); hdr->saddr3 = tmp; } /* Determine MTU of iface */ if(!netifGetAttr(iface,NETATTR_IF_MTU,&mtu)) mtu=NETIP_DEFAULT_MTU; /* Determine header length */ hlen = BNIBGET(hdr->bitfield1,1); hlen <<= 2; /* Determine Total length */ len = netbufLen(buf); if(len<=mtu) { /* don't need to fragment */ netipDownSendFragment(buf,attrs,hlen,0,0); } else { /* fragment packet */ netipDownFragmentPacket(buf,attrs,hlen,len,mtu); } } static void netipDownSendFragment(NetBuf buf, NetAttrs attrs, int hlen, unsigned short off, int more) { NetIPHdr *hdr=(NetIPHdr *) NETBUF_DATA(buf); unsigned short tmp, df, mf; /* DF: Don't Fragment */ if(netattrGet(attrs,NETATTR_IP_DF,&tmp)) df=1U<<14; else df=0; /* MF: More Fragments */ mf=(more?1:0); mf<<=15; /* Set off, DF and MF */ hdr->frag_off = htons(off|df|mf); /* Checksum */ hdr->checksum=0; hdr->checksum=netipChecksum(buf,hlen); /* Send down packet */ netcfgSendNextDown(NETMODULE_IP, buf, attrs); } static void netipDownFragmentPacket(NetBuf buf, NetAttrs attrs, int hlen, int dlen, int mtu) { NetBuf frag_data, frag_hdr; NetAttrs frag_attrs; int pos, frag_len, frag_nr=0; mtu -= hlen; pos = hlen; while(hlen>0) { frag_len=MIN(dlen,mtu); frag_len^=7; /* round down to multiple of 8 */ /* make a copy of the fragment data */ if(!netbufCopy(&frag_data, buf, pos, frag_len)) break; /* insert at head of the fragment data a copy of the * packet header */ if(!netbufCopy(&frag_hdr, buf, 0, hlen)) { netbufFree(frag_data); break; } frag_hdr->next = frag_data; /* make a copy of the attributes */ if(!netbufClone((NetBuf *) &frag_attrs, (NetBuf) attrs)) { netbufFree(frag_data); netbufFree(frag_hdr); break; } dlen -= frag_len; /* send it */ netipDownSendFragment(frag_hdr,frag_attrs,hlen,frag_nr,dlen>0); frag_nr++; pos+=frag_len; } /* free original packet */ netbufFree(buf); netattrFree(attrs); }