BlinkenArea - GitList
Repositories
Blog
Wiki
mips_sys
Code
Commits
Branches
Tags
Search
Tree:
c2b0401
Branches
Tags
master
mips_sys
fw
arp.c
added file headers
Stefan Schuermans
commited
c2b0401
at 2012-04-08 11:54:40
arp.c
Blame
History
Raw
/* MIPS I system * Copyright 2011-2012 Stefan Schuermans <stefan@schuermans.info> * Copyleft GNU public license V2 or later * http://www.gnu.org/copyleft/gpl.html */ #include "arp.h" #include "config.h" #include "ethernet.h" #include "ip.h" #include "macros.h" #include "nethelp.h" // timing parameters #define ARP_TICKS_MAX (150) /**< maximum age of ARP table entries (in 200ms steps) */ #define ARP_NO_MAC_TICKS_MAX (50) /**< maximum age of ARP table entries without MAC (in 200ms steps) */ #define ARP_RETRY_TICKS (8) /**< time after which to retry ARP query (must be power of 2, in 200ms steps) */ /// ARP table #define ARP_TAB_FLAG_IN_USE (1) #define ARP_TAB_FLAG_MAC_OK (2) struct arp_table { unsigned int flags; /// flags - see constants unsigned int ticks; /// age of entry in 200ms steps unsigned char mac[6]; unsigned char ip[4]; } arp_tab[16]; /** * @brief send an ARP request * @param[in] ip IP address to query MAC for */ static void arp_send_request(unsigned char ip[4]) { struct arp_packet arp_request; // build ARP request arp_request.arp_hdr.hw_type = htons(0x0001); // ethernet arp_request.arp_hdr.proto_type = htons(0x0800); // IP arp_request.arp_hdr.hw_len = 0x06; // length of a MAC address arp_request.arp_hdr.proto_len = 0x04; // length of an IP address arp_request.arp_hdr.op = htons(0x0001); // ARP request mac_cpy(arp_request.arp_hdr.src_mac, config_mac.mac); // own MAC ip_cpy(arp_request.arp_hdr.src_ip, config_ip.ip); // own IP mac_cpy(arp_request.arp_hdr.dest_mac, "\xFF\xFF\xFF\xFF\xFF\xFF"); // broadcast MAC ip_cpy(arp_request.arp_hdr.dest_ip, ip); // requested IP // send ARP request mac_cpy(arp_request.eth_hdr.dest, arp_request.arp_hdr.dest_mac); arp_request.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP ethernet_send(&arp_request, sizeof(arp_request)); } /// initialize void arp_init(void) { unsigned int i; // empty ARP table for (i = 0; i < count(arp_tab); ++i) arp_tab[i].flags = 0; } /// tick procedure - call every 200ms void arp_tick200(void) { unsigned int i; // increase age of ARP table entires and remove timed out ones for (i = 0; i < count(arp_tab); ++i) { // entry in use if (arp_tab[i].flags & ARP_TAB_FLAG_IN_USE) { arp_tab[i].ticks++; // increase age // entry has a MAC if (arp_tab[i].flags & ARP_TAB_FLAG_MAC_OK) { if (arp_tab[i].ticks > ARP_TICKS_MAX) // too old arp_tab[i].flags = 0; // remove entry } // entry does not have a MAC else { if (arp_tab[i].ticks > ARP_NO_MAC_TICKS_MAX) // too old arp_tab[i].flags = 0; // remove entry else if ((arp_tab[i].ticks & (ARP_RETRY_TICKS - 1)) == 0) // re-request arp_send_request(arp_tab[i].ip); } } } } /** * @brief process a received ARP packet * @param[in] ptr pointer to data of packet * @param[in] sz size of packet */ void arp_recv(void *ptr, unsigned int sz) { struct arp_packet *arp_pack; // packet too short if (sz < sizeof(struct arp_packet)) return; arp_pack = ptr; // not IP over ethernet if (arp_pack->arp_hdr.hw_type != htons(0x0001) || // ethernet arp_pack->arp_hdr.proto_type != htons(0x0800) || // IP arp_pack->arp_hdr.hw_len != 0x06 || // length of a MAC address arp_pack->arp_hdr.proto_len != 0x04) // length of an IP address // we do not support other protocols than IP over ethernet return; // source MAC is broadcast MAC -> broken packet / attac -> get lost if (arp_pack->arp_hdr.src_mac[0] == 0xFF && arp_pack->arp_hdr.src_mac[1] == 0xFF && arp_pack->arp_hdr.src_mac[2] == 0xFF && arp_pack->arp_hdr.src_mac[3] == 0xFF && arp_pack->arp_hdr.src_mac[4] == 0xFF && arp_pack->arp_hdr.src_mac[5] == 0xFF) return; // ARP request for own IP address if (arp_pack->arp_hdr.op == htons(0x0001) && // ARP request ip_eq(arp_pack->arp_hdr.dest_ip, config_ip.ip)) { // own IP address struct arp_packet arp_reply; // build ARP reply arp_reply.arp_hdr.hw_type = htons(0x0001); // ethernet arp_reply.arp_hdr.proto_type = htons(0x0800); // IP arp_reply.arp_hdr.hw_len = 0x06; // length of a MAC address arp_reply.arp_hdr.proto_len = 0x04; // length of an IP address arp_reply.arp_hdr.op = htons(0x0002); // ARP reply mac_cpy(arp_reply.arp_hdr.src_mac, config_mac.mac); // own MAC ip_cpy(arp_reply.arp_hdr.src_ip, config_ip.ip); // own IP mac_cpy(arp_reply.arp_hdr.dest_mac, arp_pack->arp_hdr.src_mac); // requestor's MAC ip_cpy(arp_reply.arp_hdr.dest_ip, arp_pack->arp_hdr.src_ip); // requestor's IP // send ARP reply mac_cpy(arp_reply.eth_hdr.dest, arp_reply.arp_hdr.dest_mac); // ethernet destination address arp_reply.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP ethernet_send(&arp_reply, sizeof(arp_reply)); return; } // ARP reply to own MAC address and own IP address if (arp_pack->arp_hdr.op == htons(0x0002) && // ARP reply mac_eq(arp_pack->arp_hdr.dest_mac, config_mac.mac) && // own MAC address ip_eq(arp_pack->arp_hdr.dest_ip, config_ip.ip)) { // own IP address // store MAC for IP arp_store(arp_pack->arp_hdr.src_ip, arp_pack->arp_hdr.src_mac); // notify IP // - IP might be waiting for the MAC to transmit a packet ip_got_mac(arp_pack->arp_hdr.src_ip, arp_pack->arp_hdr.src_mac); return; } } /** * @brief look up the MAC for an IP address * @param[in] ip IP address to look up * @param[out] mac MAC address for this IP address * @return 0 in case of success, 1 if the MAC address is unknown */ int arp_lookup(unsigned char ip[4], unsigned char mac[6]) { unsigned int i, j; // own IP if (ip_eq(ip, config_ip.ip)) // own IP may not be looked up via ARP return 1; // search IP in ARP tabale for (i = 0; i < count(arp_tab); ++i) if ((arp_tab[i].flags & ARP_TAB_FLAG_IN_USE) && ip_eq(ip, arp_tab[i].ip)) break; // not found if (i >= count(arp_tab)) { // find a free entry for (i = 0; i < count(arp_tab); ++i) if (!(arp_tab[i].flags & ARP_TAB_FLAG_IN_USE)) break; // no free entry if (i >= count(arp_tab)) { // find oldest entry i = 0; for (j = 1; j < count(arp_tab); ++j) if (arp_tab[j].ticks > arp_tab[i].ticks ) i = j; } // set up this entry arp_tab[i].flags = ARP_TAB_FLAG_IN_USE; arp_tab[i].ticks = 0; ip_cpy(arp_tab[i].ip, ip); } // MAC available if (arp_tab[i].flags & ARP_TAB_FLAG_MAC_OK) { // return MAC and success mac_cpy(mac, arp_tab[i].mac); return 0; } // send ARP request arp_send_request(ip); // no success yet return 1; } /** * @brief store the MAC for an IP address * @param[in] ip IP address to store MAC for * @param[out] mac MAC address for this IP address */ void arp_store(unsigned char ip[4], unsigned char mac[6]) { unsigned int i, j; // do not store broadcast MAC if (mac[0] == 0xFF && mac[1] == 0xFF && mac[2] == 0xFF && mac[3] == 0xFF && mac[4] == 0xFF && mac[5] == 0xFF) return; // do not store link-local broadcast IP if (ip[0] == 0xFF && ip[1] == 0xFF && ip[2] == 0xFF && ip[3] == 0xFF) return; // do not store non-local IPs if ((ip[0] & config_ip.mask[0]) != (config_ip.ip[0] & config_ip.mask[0]) || (ip[1] & config_ip.mask[1]) != (config_ip.ip[1] & config_ip.mask[1]) || (ip[2] & config_ip.mask[2]) != (config_ip.ip[2] & config_ip.mask[2]) || (ip[3] & config_ip.mask[3]) != (config_ip.ip[3] & config_ip.mask[3])) return; // do not store broadcast IP if (ip[0] == (config_ip.ip[0] | ~config_ip.mask[0]) && ip[1] == (config_ip.ip[1] | ~config_ip.mask[1]) && ip[2] == (config_ip.ip[2] | ~config_ip.mask[2]) && ip[3] == (config_ip.ip[3] | ~config_ip.mask[3])) return; // search IP in ARP table for (i = 0; i < count(arp_tab); ++i) { if ((arp_tab[i].flags & ARP_TAB_FLAG_IN_USE) && ip_eq(ip, arp_tab[i].ip)) break; } // not found if (i >= count(arp_tab)) { // find a free entry for (i = 0; i < count(arp_tab); ++i) if (!(arp_tab[i].flags & ARP_TAB_FLAG_IN_USE)) break; // no free entry if (i >= count(arp_tab)) { // find oldest entry i = 0; for (j = 1; j < count(arp_tab); ++j) if (arp_tab[j].ticks > arp_tab[i].ticks ) i = j; } // set up this entry arp_tab[i].flags = ARP_TAB_FLAG_IN_USE; arp_tab[i].ticks = 0; ip_cpy(arp_tab[i].ip, ip); } // update ARP table entry arp_tab[i].flags = ARP_TAB_FLAG_IN_USE | ARP_TAB_FLAG_MAC_OK; arp_tab[i].ticks = 0; mac_cpy(arp_tab[i].mac, mac); }