#include #include #include #include #include "sr_if.h" #include "sr_rt.h" #include "sr_router.h" #include "sr_protocol.h" #include "sr_icmp.h" #include "sr_checksum.h" #include "sr_pq.h" /** * Queue up a packet. * Author: Nicholas **/ void sr_enqueue_packet(struct sr_pq *queue, uint8_t *packet, unsigned int len){ struct pq_element *ptr; /** * Create a new packet queue record. **/ ptr = (struct pq_element*)malloc(sizeof(struct sr_pq)); /** * If the queue is empty add the new entry to the beggining. */ if (queue->length == 0){ queue->head = queue->tail = ptr; } /** * If the queue is not empty add the entry to end. **/ else{ queue->tail->next = ptr; } queue->tail = ptr; /** * Increase the length of the queue. **/ queue->length++; /** * If its the first element in the queue set the expiry time. **/ if (queue->length == 1){ queue->expires = time(NULL) + 1; } ptr->next = NULL; ptr->arp_count = 5; ptr->len = len; ptr->packet = packet; } /** * Remove a packet from the queue. * Author: Nicholas **/ uint8_t *sr_dequeue_packet(struct sr_pq *queue, unsigned int *len){ struct pq_element *ptr; uint8_t *packet; ptr = queue->head; queue->head = queue->head->next; packet = ptr->packet; *len = ptr->len; /** * Free entry in queue. Note this does not free the packet. **/ free(ptr); /** * Decreament the queue. **/ queue->length--; /** * Return the dequeue packet. **/ return packet; } /** * Print the packet queue entries. * Author: Nicholas **/ void sr_print_pq(struct sr_pq *queue){ struct pq_element *ptr = queue->head; /** * Print table headers. **/ printf("%-10s %-10s %-10s\n", "ARP COUNT", "LENGTH", "PACKET"); printf("%-10s %-10s %-10s\n", "----------", "----------", "----------"); /** * Print all entries in queue. **/ while(ptr != NULL){ printf("%-10u %-10u %-10p\n", ptr->arp_count, ptr->len, ptr->packet); ptr = ptr->next; } } /** * Send all packets in the queue. * Author: Nicholas **/ void sr_send_packets(struct sr_instance* sr, struct sr_pq *queue, char* interface, unsigned char dest_mac[ETHER_ADDR_LEN]){ uint8_t *packet; unsigned int len; struct sr_ethernet_hdr *ether_header; struct sr_if* iface = sr_get_interface(sr, interface); puts("*** Send Queued Packets ***"); /** * Send all the packets in the queue. **/ while(queue->length != 0){ /** * Remove packet from queue. **/ packet = sr_dequeue_packet(queue, &len); /** * Update packet ethernet header. **/ ether_header = (struct sr_ethernet_hdr *)packet; memcpy(ether_header->ether_dhost, dest_mac, sizeof(char) * ETHER_ADDR_LEN); memcpy(ether_header->ether_shost, iface->addr, sizeof(char) * ETHER_ADDR_LEN); /** * Send the packet. **/ if (sr_send_packet(sr, packet, len, interface) != 0){ puts("*** Packet Send Failed ***"); } /** * Free packet memory. **/ free(packet); } } /** * Convert a MAC address to a nicely formated string. * Author: Nicholas **/ char *strmac(unsigned char mac[ETHER_ADDR_LEN]){ static char buffer[255]; sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return buffer; } /** * Convert an IP address to a buffered string. * Author: Nicholas **/ char *strip(uint32_t ip){ static char buffer[255]; inet_ntop(AF_INET, &ip, buffer, 255); return buffer; } /** * Send ARP requests and ICMP unreachable errors for queued packets. * Author: Nicholas **/ void sr_update_pq(struct sr_instance* sr, struct sr_pq *queue, char *interface, uint32_t dst_ip){ /** * Lenght of packet. **/ unsigned int len; /** * packet buffer pointer. **/ uint8_t *packet; /** * ICMP packet buffer pointer. **/ uint8_t *icmp_packet; /** * Queue element pointer. **/ struct pq_element *ptr; /** * ARP packet structure. **/ struct { struct sr_ethernet_hdr ethernet; struct sr_arphdr arp; } __attribute__ ((packed)) arp_packet; /** * Get the needed interface for this queue. **/ struct sr_if* iface = sr_get_interface(sr, interface); /** * IP packet structure. **/ struct ip_packet{ struct sr_ethernet_hdr ethernet; struct ip ip; } __attribute__ ((packed)); /** * IP packet structure pointer. **/ struct ip_packet *ipp; /** * If the time has expired process next packet in queue. **/ if (difftime(queue->expires, time(NULL)) <= 0){ ptr = queue->head; /** * If there are no valid ARP requests left then send a ICMP host * unreachable error. **/ if(queue->head->arp_count == 0){ /** * Remove packet from queue. **/ packet = sr_dequeue_packet(queue, &len); /** * Get packet IP structure. **/ ipp = (struct ip_packet*)packet; puts("*** Sending ICMP Destination Unreachable ***"); /** * Get sending host gateway interface. **/ iface = sr_get_interface(sr, sr_get_gateway_interface(sr, sr_get_gateway_ip(sr, ipp->ip.ip_src.s_addr))); /** * Construct ICMP host unreachable packet. **/ icmp_packet = sr_construct_ICMP(&len, ipp->ethernet.ether_shost, iface->addr, ipp->ip.ip_src.s_addr, iface->ip, 3, 1, &(ipp->ip)); /** * Send ICMP packet. **/ if (sr_send_packet(sr, icmp_packet, len, iface->name) != 0){ puts("*** ICMP Packet Send Failed ***"); } /** * Free memory. **/ free(icmp_packet); free(packet); } else{ /** * Set ARP packet ethernet values. **/ memset(arp_packet.ethernet.ether_dhost, 0xFF, sizeof(unsigned char) * ETHER_ADDR_LEN); memcpy(&(arp_packet.ethernet.ether_shost), &(iface->addr), sizeof(unsigned char) * ETHER_ADDR_LEN); arp_packet.ethernet.ether_type = 0x0608; /** * Send ARP packet ARP values. **/ arp_packet.arp.ar_hrd = 0x0100; arp_packet.arp.ar_pro = 0x0008; arp_packet.arp.ar_hln = ETHER_ADDR_LEN; arp_packet.arp.ar_pln = 4; arp_packet.arp.ar_op = 0x0100; /*ntohs*/ memcpy(&(arp_packet.arp.ar_sha), &(iface->addr), sizeof(unsigned char) * ETHER_ADDR_LEN); arp_packet.arp.ar_sip = iface->ip; memset(arp_packet.arp.ar_tha, 0, sizeof(unsigned char) * ETHER_ADDR_LEN); arp_packet.arp.ar_tip = dst_ip; /** * Send the ARP Request. **/ printf("*** Sending ARP Request :: %s ***\n", strip(arp_packet.arp.ar_tip)); if (sr_send_packet(sr, (uint8_t*)&arp_packet, sizeof(arp_packet), interface) != 0){ puts("*** Packet Send Failed ***"); } /** * Adjust the ARP send count and expiry. **/ queue->head->arp_count--; } queue->expires = time(NULL) + 1; } }