📄 arp.c
字号:
//////////////////////////////////////////////////////////////////////////////////// Copyright(c) 2001 Intrinsyc Software Inc. All rights reserved.//// Module name://// arp.c//// Description://// Handles ARP requests and transmissions (RFC 826).//// Author://// Mike Kirkland//// Created://// October 2001//// Modified:// Brad Remedios - March 25, 2002// - Added code to flush the ethernet controller when we know the// data is not valid and when we are done with it. This helps// us in the busy network cases.////////////////////////////////////////////////////////////////////////////////#include <debug.h>#include <arp.h>#include <ip.h>#include <ethernet.h>#include <types.h>#include <c_main.h>#include <timer.h>#include <util.h>#include <string.h>// ARP cacheu16 lastmac[3] = {0, 0, 0};u32 lastiaddr = 0;////////////////////////////////////////////////////////////////////////////////// catchreply// PURPOSE: Catches an arp reply destined for this host. Called after arp.// PARAMS: (OUT) u16 *macaddr - Ethernet address of remote host from arp reply.// This value is undefined on failure.// (IN) u32 iaddr - The desired host's IP addr, in network order.// RETURNS: int - 0 for failure (first packet was not an arp reply destined for// this host), 1 for success.// NOTES:// Arp is a Broadcasted protcol (response to ARP Request are sent as a // Broadcast) and thus the 1 in rx_packet_ethernet.////////////////////////////////////////////////////////////////////////////////inline static intcatchreply(u16 *macaddr, u32 iaddr){ u8 buf[MAX_PACKET_SIZE]; u8 *packet = buf; u16 size; arppacket *reply; u32 sourceiaddr, targetiaddr; u32 time = get_time_timer() + ARP_TIMEOUT; //we need the packet to be u32 aligned *after* the 42 byte header packet += ((u32)packet + ETHER_HEADER_SIZE) % sizeof(u32); reply = (arppacket *)(packet + ETHER_HEADER_SIZE); while (1) { size = MAX_PACKET_SIZE; while(!rx_packet_ethernet(packet, &size, 1)) { if(time < get_time_timer()) return 0; } // We're only interested in ARP packets right now if ((*(u16 *)(packet + ETHER_TYPE_OFFSET)) != ETHER_TYPE_ARP) { // TODO: this throws out all packets while waiting for a reply. // Normally, this happens quickly, but if the host doesn't exist, // there could be lots of pings, etc. that are lost. This should // be fixed one day. Be careful to avoid endless recursion, though. continue; } // Drop short packets if ((size - ETHER_HEADER_SIZE) < sizeof(arppacket)) { continue; } //this probably won't be aligned. sourceiaddr = htonl((reply->iaddr2 << 16) | (reply->iaddr1)); targetiaddr = htonl((reply->targetiaddr2 << 16) | (reply->targetiaddr1)); // Detect someone else using our address if (sourceiaddr != 0 && sourceiaddr == status.ciaddr) { itc_printf("Error: another host is using our IP address. Unconfiguring network.\r\n"); status.ciaddr = 0; return 0; } // This case is only valid during the Zeroconf probe state and detects // another host sending Zeroconf ARP probes for our address. if (reply->opcode == ARP_REQ && status.ciaddr == 0 && targetiaddr == iaddr && sourceiaddr == 0) { // Return a bogus MAC address and a success code to signal to // the Zeroconf code to try another address. DEBUG_2("Detected Zeroconf probe for this address\r\n"); memset8((u8 *)macaddr, 0, sizeof(u16) * 3); return 1; } //only catch replies if (reply->opcode != ARP_REPLY) { continue; } //only catch packets from our target if (sourceiaddr != iaddr) { continue; } itc_memcpy((u8 *)macaddr, (u8 *)reply->macaddr, sizeof(u16) * 3); return 1; }}////////////////////////////////////////////////////////////////////////////////// arp// PURPOSE: Sends an arp request.// PARAMS: (IN) u32 iaddr - IP address to send request for// (OUT) u16 *macaddr - Ethernet address from reply. Passed to// catchreply.// RETURNS: 1 for success, 0 for failure.////////////////////////////////////////////////////////////////////////////////intarp(u32 iaddr, u16 *macaddr){ u8 buf[ARP_SIZE]; u8 *packet = buf; arppacket *data = (arppacket *)(packet + ETHER_HEADER_SIZE); int i = 0; u16 broadcast[3] = {0xFFFF, 0xFFFF, 0xFFFF}; int responded = 0; int timeout = 0; // Broadcast address // Network broadcast is not supported. if(iaddr == IP_BROADCAST) { memset16((u16 *)macaddr, 0xFFFF, 3); return 1; } // Get gateway's MAC instead of host's if host is on another subnet if((iaddr & status.smask) != (status.ciaddr & status.smask)) { iaddr = status.giaddr; } // Try to satisfy the request from the cache if(iaddr == lastiaddr) { itc_memcpy((u8 *)macaddr, (u8 *)lastmac, sizeof(u16) * 3); return 1; } i = (u32)data % (sizeof(u32)); packet += i; (u32)data += i; /* * We flush the ethernet controller because anything that is in there is * complete garbage. */ flush_ethernet (); while(!responded && timeout++ < NET_TIMEOUT) { memset8(packet, 0, sizeof(arppacket)); data->hdtype = ARP_HDTYPE; data->protocol = ARP_PROTOCOL; data->haddrln = (u8)(ETHER_HABITLENGTH / 8); data->protoln = (u8)(IP_ADDRBITLENGTH / 8); data->opcode = ARP_REQ; itc_memcpy((u8 *)data->macaddr, (u8 *)status.macaddr, sizeof(u16) * 3); memset8((u8 *)data->targetmac, 0, sizeof(u16) * 3); //this will not be 32 bit aligned data->iaddr1 = htons((status.ciaddr & 0xFFFF0000) >> 16); data->iaddr2 = htons((status.ciaddr & 0x0000FFFF)); data->targetiaddr1 = htons((iaddr & 0xFFFF0000) >> 16); data->targetiaddr2 = htons(iaddr & 0x0000FFFF); etherpacket(packet, sizeof(arppacket), broadcast, status.macaddr, ETHER_TYPE_ARP); responded = catchreply(macaddr, iaddr); } /* * Since we are done with the ethernet controller lets turn on receive and * flush the internal memory so its nice and clean for the next function * to use. */ rx_ethernet_off (); flush_ethernet (); if(timeout < NET_TIMEOUT) { // Store the results in the cache for next time lastiaddr = iaddr; itc_memcpy((u8 *)lastmac, (u8 *)macaddr, sizeof(u16) * 3); return 1; } return 0;}////////////////////////////////////////////////////////////////////////////////// arpreply// PURPOSE: Handles an arp packet. Replies if it is directed at us.// PARAMS: (IN) u8 *packet - an arp packet// RETURNS: Nothing.////////////////////////////////////////////////////////////////////////////////voidarpreply(u8 *packet, u16 size){ arppacket *arppkt = (arppacket *)(packet + ETHER_HEADER_SIZE); u32 targetiaddr = (u32)((htons(arppkt->targetiaddr1) << 16) | htons(arppkt->targetiaddr2)); u32 sourceiaddr = (u32)((htons(arppkt->iaddr1) << 16) | htons(arppkt->iaddr2)); // Drop short packets if ((size - ETHER_HEADER_SIZE) < sizeof(arppacket)) { return; } // Detect someone else using our address if(sourceiaddr != 0 && sourceiaddr == status.ciaddr) { itc_printf("Error: another host is using our IP address. Unconfiguring network.\r\n"); status.ciaddr = 0; return; } //only reply to arp requests for this host if(targetiaddr == 0 || targetiaddr != status.ciaddr) { return; } //only reply to requests if(arppkt->opcode != ARP_REQ) { return; } arppkt->targetiaddr1 = arppkt->iaddr1; arppkt->targetiaddr2 = arppkt->iaddr2; itc_memcpy((u8 *)arppkt->targetmac, (u8 *)arppkt->macaddr, sizeof(u16) * 3); arppkt->iaddr1 = htons((u16)(status.ciaddr >> 16)); arppkt->iaddr2 = htons((u16)(status.ciaddr & 0x0000FFFF)); itc_memcpy((u8 *)arppkt->macaddr, (u8 *)status.macaddr, sizeof(u16) * 3); arppkt->opcode = ARP_REPLY; etherpacket(packet, sizeof(arppacket), arppkt->targetmac, status.macaddr, ETHER_TYPE_ARP);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -