/* 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/ARP/NetARP.c,v $ Author(s): Affiliation: ETH Zuerich, TIK Version: $Revision: 1.1 $ Creation Date: Last Date of Change: $Date: 2000/03/31 17:50:36 $ by: $Author: gfa $ $Log: NetARP.c,v $ Revision 1.1 2000/03/31 17:50:36 gfa Merged with /Net from several term projects */ /* Skeleton for a net module. */ /* 1. Replace 'arp' with abbrevation (eth) */ /* 2. Replace 'arp' with full-name (ethernet) */ /* 3. Fill in netarpUp and netarpDown */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define NETARP_OP_REQUEST 1 #define NETARP_OP_REPLY 2 void netarpRead(ThreadId id, unsigned long int length); static void netarpMain(ThreadArg arg); static void netarpUp(NetBuf buf, NetAttrs attrs); static void netarpDown(NetBuf buf, NetAttrs attrs); void netarpInit() { ThreadId netarpId; /* Start main thread */ if (tmStart(&netarpId, netarpMain, (ThreadArg)0, "netarp") != TM_STARTOK) { netdbgDisplay(NETDEBUG_GENERIC, "Start: couldn't start arp thread\n"); return; } } static void netarpMain(ThreadArg arg) { ThreadId myThreadId, parentThreadId; NetModMsg msg; tmGetInfo(SELF, &myThreadId, &parentThreadId); // Add to list of modules netmodAdd(NETMODULE_ARP, myThreadId); netdbgPrintf(NETDEBUG_MODULES, "ARP module started (moduleId=%d, threadId=%d).\n", NETMODULE_ARP, myThreadId); while(1) { if(!netmodMsgRecv(&msg)) return; switch (msg.id) { case NETMOD_SENDUP: netarpUp(msg.buf, msg.attrs); break; case NETMOD_SENDDOWN: netarpDown(msg.buf, msg.attrs); break; default: netdbgPrintf(NETDEBUG_GENERIC, "*** ERROR: ARP: Unknown message (%d)!\n", msg.id); break; } } } static int netarpUpETHIP(NetBuf buf, NetAttrs attrs); static void netarpUp(NetBuf buf, NetAttrs attrs) { NetARPHdr *hdr = (NetARPHdr *) NETBUF_DATA(buf); int sendreply=0; unsigned short iface; netdbgDisplay(NETDEBUG_ARP, "netarp: Got upcoming packet.\n"); if(NETBUF_LEN(buf) >= sizeof(NetARPHdr) && ntohs(hdr->hw_type)==NETARP_HWTYPE_ETH) { switch(ntohs(hdr->pr_type)) { case NETETH_TYPE_IP: sendreply=netarpUpETHIP(buf,attrs); break; } } if(sendreply) { /* send to module which sent request */ if(!netattrGet(attrs,NETATTR_IF_FROM,&iface)) goto discard; netattrSet(attrs,NETATTR_IF_TO,iface); netdbgDisplay(NETDEBUG_ARP, "netarp: Sending reply...\n"); /* Send down packet */ netcfgSendNextDown(NETMODULE_ARP, buf, attrs); return; } discard: netdbgDisplay(NETDEBUG_ARP, "netarp: Discarding upcoming packet.\n"); netbufFree(buf); netbufFree((NetBuf)attrs); } int netarpDownFillSourceETHIP(NetBuf buf, NetAttrs attrs); static void netarpDown(NetBuf buf, NetAttrs attrs) { unsigned short hw_type, hw_len, pr_type, pr_len, tmp, pkt_len; NetARPHdr *hdr; char *data; netdbgDisplay(NETDEBUG_ARP, "netarp: Got request to send ARP.\n"); /* buf should be 0... */ if(buf) { netbufFree(buf); buf=0; } /* get header data */ if(!netattrGet(attrs,NETATTR_ARP_HW_TYPE,&hw_type)) goto error; if(!netattrGet(attrs,NETATTR_ARP_HW_LEN, &hw_len)) goto error; if(!netattrGet(attrs,NETATTR_ARP_PR_TYPE,&pr_type)) goto error; if(!netattrGet(attrs,NETATTR_ARP_PR_LEN, &pr_len)) goto error; /* realloc a buf of suitable size */ pkt_len = sizeof(NetARPHdr)+hw_len*2+pr_len*2; if(!netbufAlloc(&buf, pkt_len)) { buf=0; goto error; } //buf->end = buf->start+pkt_len; /* put arp request at end of buffer to leave space for ethernet header */ buf->end = NETBUF_SIZE(buf)+NETBUF_HEADERSIZE; buf->start = buf->end-pkt_len; /* fill header */ hdr = (NetARPHdr *) NETBUF_DATA(buf); hdr->hw_type = hw_type; hdr->hw_len = hw_len; hdr->pr_type = pr_type; hdr->pr_len = pr_len; hdr->op = NETARP_OP_REQUEST; /* target can be made protocol independent */ /* fill target */ data = NETBUF_DATA(buf) + sizeof(NetARPHdr) + hw_len*2 + pr_len; /* at the moment only pr_len=4 is supported */ if(pr_len!=4) goto error; if(!netattrGet(attrs,NETATTR_ARP_PR_0,&tmp)) goto error; data[0]=tmp%256; data[1]=tmp>>8; if(!netattrGet(attrs,NETATTR_ARP_PR_1,&tmp)) goto error; data[2]=tmp%256; data[3]=tmp>>8; /* fill source (protocol dependent) */ if(hw_type==NETARP_HWTYPE_ETH && pr_type==NETETH_TYPE_IP) { if(!netarpDownFillSourceETHIP(buf,attrs)) goto error; } else { goto error; } /* Ethernet: it's ARP and it's a broadcast... */ if(hw_type==NETARP_HWTYPE_ETH) { netattrSet(attrs, NETATTR_ETH_TYPE, NETETH_TYPE_ARP); netattrSet(attrs, NETATTR_ETH_TO_0, (unsigned short) 0xFFFF); netattrSet(attrs, NETATTR_ETH_TO_1, (unsigned short) 0xFFFF); netattrSet(attrs, NETATTR_ETH_TO_2, (unsigned short) 0xFFFF); } netdbgDisplay(NETDEBUG_ARP, "netarp: Sending ARP request.\n"); netcfgSendNextDown(NETMODULE_ARP, buf, attrs); return; error: netdbgDisplay(NETDEBUG_ARP, "netarp: Discarding downgoing packet.\n"); if(buf) netbufFree(buf); netattrFree(attrs); } /***************** IPv4 on ETHERNET (ETHIP) ******************/ struct NetARP_ETHIP { NetARPHdr hdr; unsigned char shw[6]; unsigned char sip[4]; unsigned char thw[6]; unsigned char tip[4]; }; static int netarpUpETHIP(NetBuf buf, NetAttrs attrs) { unsigned short iface,tmp,i; struct NetARP_ETHIP *arp = (struct NetARP_ETHIP *) NETBUF_DATA(buf); if(NETBUF_LEN(buf)shw[0], arp->shw[1], arp->shw[2], arp->shw[3], arp->shw[4], arp->shw[5], arp->sip[0], arp->sip[1], arp->sip[2], arp->sip[3]); netcfgarpAddCacheETHIP(arp->shw,arp->sip); if(arp->hdr.op != NETARP_OP_REQUEST) { netcfgarpAddCacheETHIP(arp->thw,arp->tip); } netdbgPrintf(NETDEBUG_ARP, "netarp: target=(%02x:%02x:%02x:%02x:%02x:%02x,%d.%d.%d.%d)\n", arp->thw[0], arp->thw[1], arp->thw[2], arp->thw[3], arp->thw[4], arp->thw[5], arp->tip[0], arp->tip[1], arp->tip[2], arp->tip[3]); /* Get iface nr. */ if(!netattrGet(attrs,NETATTR_IF_FROM,&iface)) return 0; /* discard */ /* We could cache this somehow... ARP shouldn't come frequently though. */ /* Get our IP addr. and compare */ if(!netifGetAttr(iface,NETATTR_IP_FROM_0,&tmp)) return 0; if(tmp!=arp->tip[0]) return 0; if(!netifGetAttr(iface,NETATTR_IP_FROM_1,&tmp)) return 0; if(tmp!=arp->tip[1]) return 0; if(!netifGetAttr(iface,NETATTR_IP_FROM_2,&tmp)) return 0; if(tmp!=arp->tip[2]) return 0; if(!netifGetAttr(iface,NETATTR_IP_FROM_3,&tmp)) return 0; if(tmp!=arp->tip[3]) return 0; /* If it's a REPLY, it is already processed... */ if(arp->hdr.op != NETARP_OP_REQUEST) return 0; /* The request is for us!! Send reply... (Stevens-1, 57) */ /* Swap source/target */ for(i=0;i<4;i++) { tmp=arp->tip[i]; arp->tip[i]=arp->sip[i]; arp->sip[i]=tmp; } for(i=0;i<6;i++) { arp->thw[i]=arp->shw[i]; } /* Fill in HW address */ if(!netifGetAttr(iface,NETATTR_ETH_FROM_0,&tmp)) return 0; arp->shw[0]=tmp%256; arp->shw[1]=tmp>>8; if(!netifGetAttr(iface,NETATTR_ETH_FROM_1,&tmp)) return 0; arp->shw[2]=tmp%256; arp->shw[3]=tmp>>8; if(!netifGetAttr(iface,NETATTR_ETH_FROM_2,&tmp)) return 0; arp->shw[4]=tmp%256; arp->shw[5]=tmp>>8; /* Set 'op' to REPLY */ arp->hdr.op = NETARP_OP_REPLY; /* Set attributes */ tmp = arp->thw[1]; tmp <<= 8; tmp += arp->thw[0]; netattrSet(attrs, NETATTR_ETH_TO_0, tmp); tmp = arp->thw[3]; tmp <<= 8; tmp += arp->thw[2]; netattrSet(attrs, NETATTR_ETH_TO_1, tmp); tmp = arp->thw[5]; tmp <<= 8; tmp += arp->thw[4]; netattrSet(attrs, NETATTR_ETH_TO_2, tmp); netdbgDisplay(NETDEBUG_ARP, "ARP: Sending reply.\n"); return 1; } int netarpDownFillSourceETHIP(NetBuf buf, NetAttrs attrs) { unsigned short iface, tmp; struct NetARP_ETHIP *arp = (struct NetARP_ETHIP *) NETBUF_DATA(buf); if(!netattrGet(attrs,NETATTR_IF_TO,&iface)) return 0; /* set source hw address */ if(!netifGetAttr(iface,NETATTR_ETH_FROM_0,&tmp)) return 0; arp->shw[0]=tmp%256; arp->shw[1]=tmp>>8; if(!netifGetAttr(iface,NETATTR_ETH_FROM_1,&tmp)) return 0; arp->shw[2]=tmp%256; arp->shw[3]=tmp>>8; if(!netifGetAttr(iface,NETATTR_ETH_FROM_2,&tmp)) return 0; arp->shw[4]=tmp%256; arp->shw[5]=tmp>>8; /* set source ip address */ if(!netifGetAttr(iface,NETATTR_IP_FROM_0,&tmp)) return 0; arp->sip[0]=tmp; if(!netifGetAttr(iface,NETATTR_IP_FROM_1,&tmp)) return 0; arp->sip[1]=tmp; if(!netifGetAttr(iface,NETATTR_IP_FROM_2,&tmp)) return 0; arp->sip[2]=tmp; if(!netifGetAttr(iface,NETATTR_IP_FROM_3,&tmp)) return 0; arp->sip[3]=tmp; return 1; }