/*----------------------------------------------------------------------------- * Method: void checkCachedPackets(struct sr_instance* sr, int cachedArp) * * searches our packet cache for a matching ip in arpCache[cachedArp]. if we * find a match, we forward the packet. if we do not find a match we need an * arp cache entry for it. make sure we have been waiting at least 3 seconds * before we send the src icmp unreachable packets. this does not drop the * packet, it just looks every 3rd second to see if we have a response. every * time we look, we try to increment the arp counter *---------------------------------------------------------------------------*/ void checkCachedPackets(struct sr_instance* sr, int cachedArp) { int i, arpMatch; for (i = 0; i < PACKET_CACHE_SIZE; i++) { if (packetCache[i].len > 0) { // if we have a packet waiting if (packetCache[i].arps <= 5) { // and we have not sent 5 arps for this packet yet if ((arpMatch = arpSearchCache(packetCache[i].tip)) > -1) { // and we have an arp match for our packet's next hop forwardPacket(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len, // send it along packetCache[i].nexthop->interface, arpReturnEntryMac(arpMatch)); packetCache[i].len = 0; } else { /* wait three seconds between each arp request */ if ((int)(difftime(time(NULL), packetCache[i].timeCached))%3 < 1) { arpSendRequest(sr, sr_get_interface(sr, packetCache[i].nexthop->interface), packetCache[i].nexthop->gw.s_addr); packetCache[i].arps++; } } } else { /* then */ icmpSendUnreachable(sr, (uint8_t*)&packetCache[i].packet, packetCache[i].len, packetCache[i].nexthop->interface, ICMP_HOST_UNREACHABLE); packetCache[i].len = 0; } } } }
/*----------------------------------------------------------------------------- * Method: void cachePacket(struct sr_instance* sr, uint8_t* packet, * unsigned int len, struct sr_rt* rtptr) * * sends a request for the hwaddr of the ipaddr we have, stores our packet * until we have an arp entry that matches the ip, then sends the packet *---------------------------------------------------------------------------*/ void cachePacket( struct sr_instance* sr, uint8_t* packet, unsigned int len, struct sr_rt* rtptr) { struct ip* ipHdr = (struct ip*)(packet+14); int i; /* request arp for the unidentified packet */ arpSendRequest(sr, sr_get_interface(sr, rtptr->interface), rtptr->gw.s_addr); /* look through packet cache for the first empty entry */ for (i = 0; i < PACKET_CACHE_SIZE; i++) { if (packetCache[i].len == 0) break; } /* copy packet data to cache */ memcpy(&packetCache[i].packet, packet, len); packetCache[i].nexthop = rtptr; packetCache[i].tip = ipHdr->ip_dst.s_addr; packetCache[i].len = len; packetCache[i].arps = 1; packetCache[i].timeCached = time(NULL); /* dump cache uint8_t* ptr = packetCache[i].packet; printf("\nnexthop: %s\n", inet_ntoa(packetCache[i].nexthop->gw)); printf("tip: %8.8x\n", packetCache[i].tip); printf("len: %d\n", packetCache[i].len); printf("arps: %d\n", packetCache[i].arps); for (i = 0; i < len; i++) printf("%2.2x", *ptr++); printf("\n"); */ }
void arpTick(NetInterface *interface) { uint_t i; time_t time; ArpCacheEntry *entry; //Get current time time = osGetTickCount(); //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Go through ARP cache for(i = 0; i < ARP_CACHE_SIZE; i++) { //Point to the current entry entry = &interface->arpCache[i]; //INCOMPLETE state? if(entry->state == ARP_STATE_INCOMPLETE) { //The request timed out? if((time - entry->timestamp) >= entry->timeout) { //Increment retransmission counter entry->retransmitCount++; //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount < ARP_MAX_REQUESTS) { //Retransmit ARP request arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &MAC_BROADCAST_ADDR); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_REQUEST_TIMEOUT; } else { //Drop packets that are waiting for address resolution arpFlushQueuedPackets(interface, entry); //The entry should be deleted since address resolution has failed entry->state = ARP_STATE_NONE; } } } //REACHABLE state? else if(entry->state == ARP_STATE_REACHABLE) { //Periodically time out ARP cache entries if((time - entry->timestamp) >= entry->timeout) { //Save current time entry->timestamp = osGetTickCount(); //Enter STALE state entry->state = ARP_STATE_STALE; } } //DELAY state? else if(entry->state == ARP_STATE_DELAY) { //Wait for the specified delay before sending the first probe if((time - entry->timestamp) >= entry->timeout) { //Send a point-to-point ARP request to the host arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &entry->macAddr); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_PROBE_TIMEOUT; //Switch to the PROBE state entry->state = ARP_STATE_PROBE; } } //PROBE state? else if(entry->state == ARP_STATE_PROBE) { //The request timed out? if((time - entry->timestamp) >= entry->timeout) { //Increment retransmission counter entry->retransmitCount++; //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount < ARP_MAX_PROBES) { //Send a point-to-point ARP request to the host arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &entry->macAddr); //Save the time at which the packet was sent entry->timestamp = time; //Set timeout value entry->timeout = ARP_PROBE_TIMEOUT; } else { //The entry should be deleted since the host is not reachable anymore entry->state = ARP_STATE_NONE; } } } } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); }
error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr) { ArpCacheEntry *entry; //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Search the ARP cache for the specified IPv4 address entry = arpFindEntry(interface, ipAddr); //Check whether a matching entry has been found if(entry) { //Check the state of the ARP entry if(entry->state == ARP_STATE_INCOMPLETE) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //The address resolution is already in progress return ERROR_IN_PROGRESS; } else if(entry->state == ARP_STATE_STALE) { //Copy the MAC address associated with the specified IPv4 address *macAddr = entry->macAddr; //Start delay timer entry->timestamp = osGetTickCount(); //Delay before sending the first probe entry->timeout = ARP_DELAY_FIRST_PROBE_TIME; //Switch to the DELAY state entry->state = ARP_STATE_DELAY; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Successful address resolution return NO_ERROR; } else { //Copy the MAC address associated with the specified IPv4 address *macAddr = entry->macAddr; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Successful address resolution return NO_ERROR; } } //If no entry exists, then create a new one entry = arpCreateEntry(interface); //Any error to report? if(!entry) { //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //Report an error to the calling function return ERROR_OUT_OF_RESOURCES; } //Record the IPv4 address whose MAC address is unknown entry->ipAddr = ipAddr; entry->macAddr = MAC_UNSPECIFIED_ADDR; //Reset retransmission counter entry->retransmitCount = 0; //No packet are pending in the transmit queue entry->queueSize = 0; //Send an ARP request arpSendRequest(interface, interface->ipv4Config.addr, entry->ipAddr, &MAC_BROADCAST_ADDR); //Save the time at which the packet was sent entry->timestamp = osGetTickCount(); //Set timeout value entry->timeout = ARP_REQUEST_TIMEOUT; //Enter INCOMPLETE state entry->state = ARP_STATE_INCOMPLETE; //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); //The address resolution is in progress return ERROR_IN_PROGRESS; }