BlinkenArea - GitList
Repositories
Blog
Wiki
flaneth
Code
Commits
Branches
Tags
Search
Tree:
ed647c2
Branches
Tags
master
flaneth
firmware
arp.c
save memory, to avoid stack hitting data segment
Stefan Schuermans
commited
ed647c2
at 2012-05-06 17:28:25
arp.c
Blame
History
Raw
/* flaneth - flash and ethernet Copyright (C) 2007-2012 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[4]; // 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; }