BlinkenArea - GitList
Repositories
Blog
Wiki
mips_sys
Code
Commits
Branches
Tags
Search
Tree:
00d70be
Branches
Tags
master
mips_sys
fw
arp.c
implemented IP + ICMP, fixed ARP (padding overwriting stack)
Stefan Schuermans
commited
00d70be
at 2012-03-24 13:58:46
arp.c
Blame
History
Raw
#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 char flags; /// flags - see constants unsigned char ticks; /// age of entry in 200ms steps unsigned char mac[6]; unsigned char ip[4]; } arp_tab[12]; /** * @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_pad arp_request; // build ARP request arp_request.p.arp_hdr.hw_type = htons(0x0001); // ethernet arp_request.p.arp_hdr.proto_type = htons(0x0800); // IP arp_request.p.arp_hdr.hw_len = 0x06; // length of a MAC address arp_request.p.arp_hdr.proto_len = 0x04; // length of an IP address arp_request.p.arp_hdr.op = htons(0x0001); // ARP request mac_cpy(arp_request.p.arp_hdr.src_mac, config_mac.mac); // own MAC ip_cpy(arp_request.p.arp_hdr.src_ip, config_ip.ip); // own IP mac_cpy(arp_request.p.arp_hdr.dest_mac, "\xFF\xFF\xFF\xFF\xFF\xFF"); // broadcast MAC ip_cpy(arp_request.p.arp_hdr.dest_ip, ip); // requested IP // send ARP request mac_cpy(arp_request.p.eth_hdr.dest, arp_request.p.arp_hdr.dest_mac); arp_request.p.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP ethernet_send(&arp_request.p, sizeof(arp_request.p)); } /// 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 (mac_eq(arp_pack->arp_hdr.src_mac, "\xFF\xFF\xFF\xFF\xFF\xFF")) 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_pad arp_reply; // build ARP reply arp_reply.p.arp_hdr.hw_type = htons(0x0001); // ethernet arp_reply.p.arp_hdr.proto_type = htons(0x0800); // IP arp_reply.p.arp_hdr.hw_len = 0x06; // length of a MAC address arp_reply.p.arp_hdr.proto_len = 0x04; // length of an IP address arp_reply.p.arp_hdr.op = htons(0x0002); // ARP reply mac_cpy(arp_reply.p.arp_hdr.src_mac, config_mac.mac); // own MAC ip_cpy(arp_reply.p.arp_hdr.src_ip, config_ip.ip); // own IP mac_cpy(arp_reply.p.arp_hdr.dest_mac, arp_pack->arp_hdr.src_mac); // requestor's MAC ip_cpy(arp_reply.p.arp_hdr.dest_ip, arp_pack->arp_hdr.src_ip); // requestor's IP // send ARP reply mac_cpy(arp_reply.p.eth_hdr.dest, arp_reply.p.arp_hdr.dest_mac); // ethernet destination address arp_reply.p.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP ethernet_send(&arp_reply.p, sizeof(arp_reply.p)); 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 unsigned int i; // 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(arp_pack->arp_hdr.src_ip, arp_tab[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(arp_tab)) { // 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, arp_pack->arp_hdr.src_mac); // notify IP // - IP might be waiting for the MAC to transmit a packet ip_got_mac(arp_tab[i].ip, arp_tab[i].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; }