BlinkenArea - GitList
Repositories
Blog
Wiki
flaneth
Code
Commits
Branches
Tags
Search
Tree:
e8658d5
Branches
Tags
master
flaneth
firmware.dartboard
arp.c
initial commit after making CF identify work
Stefan Schuermans
commited
e8658d5
at 2012-04-15 19:57:57
arp.c
Blame
History
Raw
/* flaneth - flash and ethernet - dartboard mod * version 0.1 date 2008-11-09 * Copyright (C) 2007-2008 Stefan Schuermans <stefan@schuermans.info> * Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html * a BlinkenArea project - http://www.blinkenarea.org/ */ #include "arp.h" #include "config.h" #include "debug.h" #include "ethernet.h" #include "ip.h" #include "macros.h" #include "nethelp.h" // timing parameters #define ArpTicksMax 150 // maximum age of ARP table entries (in 200ms steps) #define ArpNoMacTicksMax 50 // maximum age of ARP table entries without MAC (in 200ms steps) #define ArpRetryTicks 8 // time after which to retry ARP query (must be power of 2, in 200ms steps) // ARP table #define ArpTabFlagInUse 0x01 #define ArpTabFlagMacOk 0x02 struct ArpTable { unsigned char Flags; // flags - see constants unsigned char Ticks; // age of entry in 200ms steps unsigned char Mac[6]; unsigned char Ip[4]; } ArpTab[12]; // initialize void ArpInit( void ) // (extern) { unsigned char i; // empty ARP tabale for( i = 0; i < count( ArpTab ); i++ ) ArpTab[i].Flags = 0; } // send an ARP request static void ArpSendRequest( unsigned char * pIp ) { struct ArpPacket ArpRequest; debug_arp_printf( "send req ip=%u.%u.%u.%u", pIp[0], pIp[1], pIp[2], pIp[3] ); // build ARP request ArpRequest.ArpHdr.HwType = htons( 0x0001 ); // ethernet ArpRequest.ArpHdr.ProtoType = htons( 0x0800 ); // IP ArpRequest.ArpHdr.HwLen = 0x06; // length of a MAC address ArpRequest.ArpHdr.ProtoLen = 0x04; // length of an IP address ArpRequest.ArpHdr.Op = htons( 0x0001 ); // ARP request mac_cpy( ArpRequest.ArpHdr.SrcMac, ConfigMac ); // own MAC ip_cpy( ArpRequest.ArpHdr.SrcIp, ConfigIp ); // own IP mac_cpy( ArpRequest.ArpHdr.DestMac, "\xFF\xFF\xFF\xFF\xFF\xFF" ); // broadcast MAC ip_cpy( ArpRequest.ArpHdr.DestIp, pIp ); // requested IP // sent ARP request mac_cpy( ArpRequest.EthHdr.Dest, ArpRequest.ArpHdr.DestMac ); // ethernet destination address ArpRequest.EthHdr.Type = htons( 0x0806 ); // ethernet packet type: ARP EthernetSend( (unsigned char *)&ArpRequest, sizeof( ArpRequest ) ); } // tick procedure - call every 200ms void ArpTick200( void ) // (extern) { unsigned char i; // increase age of ARP table entires and remove timed out ones for( i = 0; i < count( ArpTab ); i++ ) { if( ArpTab[i].Flags & ArpTabFlagInUse ) // entry in use { ArpTab[i].Ticks++; // increase age if( ArpTab[i].Flags & ArpTabFlagMacOk ) // entry has got a MAC { if( ArpTab[i].Ticks > ArpTicksMax ) // too old ArpTab[i].Flags = 0; // remove entry } else // entry has not got a MAC { if( ArpTab[i].Ticks > ArpNoMacTicksMax ) // too old ArpTab[i].Flags = 0; // remove entry else if( (ArpTab[i].Ticks & (ArpRetryTicks - 1)) == 0 ) // retry ARP request ArpSendRequest( ArpTab[i].Ip ); } } } } // process a received ARP packet void ArpRecv( unsigned char * pData, unsigned short Length ) // (extern) { struct ArpPacket * pArpPack; // packet too short if( Length < sizeof( struct ArpPacket ) ) return; // convert pointer to ARP packet // (this saves us from always casting pData) pArpPack = (struct ArpPacket *)pData; // not IP over ethernet if( pArpPack->ArpHdr.HwType != htons( 0x0001 ) || // ethernet pArpPack->ArpHdr.ProtoType != htons( 0x0800 ) || // IP pArpPack->ArpHdr.HwLen != 0x06 || // length of a MAC address pArpPack->ArpHdr.ProtoLen != 0x04 ) // length of an IP address // we do not support other protocols than IP over ethernet return; // source MAC is broadcast MAC if( mac_eq( pArpPack->ArpHdr.SrcMac, "\xFF\xFF\xFF\xFF\xFF\xFF" ) ) // broadcast MAC cannot be source, this is some kind of attack, get lost! return; // ARP request for own IP address if( pArpPack->ArpHdr.Op == htons( 0x0001 ) && // ARP request ip_eq( pArpPack->ArpHdr.DestIp, ConfigIp ) ) // own IP address { struct ArpPacket ArpReply; // build ARP reply ArpReply.ArpHdr.HwType = htons( 0x0001 ); // ethernet ArpReply.ArpHdr.ProtoType = htons( 0x0800 ); // IP ArpReply.ArpHdr.HwLen = 0x06; // length of a MAC address ArpReply.ArpHdr.ProtoLen = 0x04; // length of an IP address ArpReply.ArpHdr.Op = htons( 0x0002 ); // ARP reply mac_cpy( ArpReply.ArpHdr.SrcMac, ConfigMac ); // own MAC ip_cpy( ArpReply.ArpHdr.SrcIp, ConfigIp ); // own IP mac_cpy( ArpReply.ArpHdr.DestMac, pArpPack->ArpHdr.SrcMac ); // requestor's MAC ip_cpy( ArpReply.ArpHdr.DestIp, pArpPack->ArpHdr.SrcIp ); // requestor's IP debug_arp_printf( "recv req src=%02X:%02X:%02X:%02X:%02X:%02X ip=%u.%u.%u.%u", pArpPack->ArpHdr.SrcMac[0], pArpPack->ArpHdr.SrcMac[1], pArpPack->ArpHdr.SrcMac[2], pArpPack->ArpHdr.SrcMac[3], pArpPack->ArpHdr.SrcMac[4], pArpPack->ArpHdr.SrcMac[5], pArpPack->ArpHdr.SrcIp[0], pArpPack->ArpHdr.SrcIp[1], pArpPack->ArpHdr.SrcIp[2], pArpPack->ArpHdr.SrcIp[3] ); // sent ARP reply mac_cpy( ArpReply.EthHdr.Dest, ArpReply.ArpHdr.DestMac ); // ethernet destination address ArpReply.EthHdr.Type = htons( 0x0806 ); // ethernet packet type: ARP EthernetSend( (unsigned char *)&ArpReply, sizeof( ArpReply ) ); return; } // ARP reply to own MAC address and own IP address if( pArpPack->ArpHdr.Op == htons( 0x0002 ) && // ARP reply mac_eq( pArpPack->ArpHdr.DestMac, ConfigMac ) && // own MAC address ip_eq( pArpPack->ArpHdr.DestIp, ConfigIp ) ) // own IP address { unsigned char i; debug_arp_printf( "recv reply src=%02X:%02X:%02X:%02X:%02X:%02X ip=%u.%u.%u.%u", pArpPack->ArpHdr.SrcMac[0], pArpPack->ArpHdr.SrcMac[1], pArpPack->ArpHdr.SrcMac[2], pArpPack->ArpHdr.SrcMac[3], pArpPack->ArpHdr.SrcMac[4], pArpPack->ArpHdr.SrcMac[5], pArpPack->ArpHdr.SrcIp[0], pArpPack->ArpHdr.SrcIp[1], pArpPack->ArpHdr.SrcIp[2], pArpPack->ArpHdr.SrcIp[3] ); // search IP in ARP tabale for( i = 0; i < count( ArpTab ); i++ ) if( (ArpTab[i].Flags & ArpTabFlagInUse) && ip_eq( pArpPack->ArpHdr.SrcIp, ArpTab[i].Ip ) ) break; // if found in ARP table // (we do not want to put an entry in the ARP table // if we have not asked for the MAC of this IP) if( i < count( ArpTab ) ) { // update ARP table entry ArpTab[i].Flags = ArpTabFlagInUse | ArpTabFlagMacOk; ArpTab[i].Ticks = 0; mac_cpy( ArpTab[i].Mac, pArpPack->ArpHdr.SrcMac ); // notify IP // - IP might be waiting for the MAC to transmit a packet IpGotMac( ArpTab[i].Ip, ArpTab[i].Mac ); } return; } } // lookup the MAC for an IP address // returns 0x00 in case of success, 0x01 if the MAC address is unknown unsigned char ArpLookup( unsigned char * pIp, unsigned char * pMac ) // (extern) { unsigned char i, j; // own IP if( ip_eq( pIp, ConfigIp ) ) // own IP may not be looked up via ARP return 0x01; // search IP in ARP tabale for( i = 0; i < count( ArpTab ); i++ ) if( (ArpTab[i].Flags & ArpTabFlagInUse) && ip_eq( pIp, ArpTab[i].Ip ) ) break; // not found if( i >= count( ArpTab ) ) { // find a free entry for( i = 0; i < count( ArpTab ); i++ ) if( ! (ArpTab[i].Flags & ArpTabFlagInUse) ) break; // no free entry if( i >= count( ArpTab ) ) { // find oldest entry i = 0; for( j = 1; j < count( ArpTab ); j++ ) if( ArpTab[j].Ticks > ArpTab[i].Ticks ) i = j; } // set up this entry ArpTab[i].Flags = ArpTabFlagInUse; ArpTab[i].Ticks = 0; ip_cpy( ArpTab[i].Ip, pIp ); } // MAC available if( ArpTab[i].Flags & ArpTabFlagMacOk ) { // return MAC and success mac_cpy( pMac, ArpTab[i].Mac ); return 0x00; } // send ARP request ArpSendRequest( pIp ); // return no success for now return 0x01; }