Ejemplo n.º 1
0
/*Broadcasts an arp request because the destination IP isn't in our cache*/
void broadcast_arp_req(struct sr_instance* sr, uint32_t nexthopIP, sr_ethernet_hdr_t* packet_to_forward, unsigned int len, struct sr_rt * routing_node, struct sr_if* nexthopInterface){
  
  /*Insert the request into the arpcache with pre-made sr_arpcache_queuereq: cache pointer is returned*/
  struct sr_arpreq *cache_req_ptr = sr_arpcache_queuereq(&(sr->cache), nexthopIP, (uint8_t*) packet_to_forward, len, routing_node->interface);
  
  handle_arpreq(sr, cache_req_ptr);
}
Ejemplo n.º 2
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
    struct sr_arpreq *req;
    for (req = sr->cache.requests; req != NULL; req = req->next) {
        printf("**********************************\n*Sweepreqs calling handle_arpreq.*\n**********************************\n");
        handle_arpreq(sr,req);
    }
}
Ejemplo n.º 3
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
    /* Fill this in */
    struct sr_arpreq *cur = sr->cache.requests;
    while(cur) {
                struct sr_arpreq *next = cur->next;
                handle_arpreq(sr, cur);
                cur = next;
        }
}
Ejemplo n.º 4
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) {
	struct sr_arpreq *arpreq = sr->cache.requests; /* linked list of requests */
	while (arpreq) {
		/* Store next request because handle_arpreq may destroy current one */
		struct sr_arpreq *next_req = arpreq->next;
		handle_arpreq(sr, arpreq);
		arpreq = next_req;
	}
}
Ejemplo n.º 5
0
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
    struct sr_arpcache *sr_cache = &sr->cache;
    struct sr_arpreq *sr_req= sr_cache->requests;
    while (sr_req) {
        struct sr_arpreq *next_req =  sr_req->next;
        handle_arpreq (sr_req, sr);
        sr_req  = next_req;
    }
}
Ejemplo n.º 6
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
   struct sr_arpreq *currReq = sr->cache.requests;
   struct sr_arpreq *nextReq;

   while (currReq != NULL)
   {
       nextReq = currReq->next;
       handle_arpreq(sr, currReq);
       currReq = nextReq;
   }
}
Ejemplo n.º 7
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
    /* Fill this in */
    struct sr_arpreq *req;
    struct sr_arpreq *next_req;
    pthread_mutex_lock(&(sr->cache.lock));
    for (req = sr->cache.requests; req != NULL; req = next_req) {
      next_req = req->next;
      handle_arpreq(sr, req);
    }
    pthread_mutex_unlock(&(sr->cache.lock));
}
Ejemplo n.º 8
0
/*
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) {
    struct sr_arpreq *req = NULL;
    struct sr_arpreq *next = NULL;

    req = sr->cache.requests;

    while (req) {
        next = req->next;
        handle_arpreq(sr, req);
        req = next;
    }
}
Ejemplo n.º 9
0
/*
 This function gets called every second. For each request sent out, we keep
 checking whether we should resend an request or destroy the arp request.
 See the comments in the header file for an idea of what it should look like.
 */
void sr_arpcache_sweepreqs(struct sr_instance *sr) {
    
    struct sr_arpreq* req = sr->cache.requests;
    struct sr_arpreq* next_req = NULL;
    if (req != NULL) next_req = req->next;
    
    while (req != NULL) {
        handle_arpreq(sr, req);
        req = next_req;
        if (req != NULL) next_req = req->next;
    }
}
Ejemplo n.º 10
0
/*---------------------------------------------------------------------
 * Method: send_packet_to_ip_addr(struct sr_instance* sr,
    uint8_t* packet,
    unsigned int len,
    uint32_t dest_ip,
    char* iface)
 * Scope:  Global
 *
 * send the packet to the ip address. First consult the cache if not.
 *
 *---------------------------------------------------------------------*/
int send_packet_to_ip_addr(struct sr_instance* sr,
    uint8_t* packet,
    unsigned int len,
    uint32_t dest_ip,
    char* iface) {
  struct sr_arpentry* arp_entry = sr_arpcache_lookup(&(sr->cache), dest_ip);

  if (arp_entry) {
    printf("ARP Cache Hit\n");
    // Forward the packet 
    eth_frame_send_with_mac(sr, packet, len, arp_entry->mac, iface);

    // Free ARP entry
    free(arp_entry);
  } else {
    printf("ARP Cache Miss\n");
    struct sr_arpreq* req = sr_arpcache_queuereq(
        &(sr->cache), dest_ip, packet, len, iface);
    req->interface = iface;
    handle_arpreq(sr, req);
  }

  return 0;
}
Ejemplo n.º 11
0
void process_ether_type_ip(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  assert(sr);
  assert(packet);
  assert(interface);

  /* Create IP header struct for further processing */
  sr_ip_hdr_t *ip_header = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ethernet_hdr_t *eth_header = (sr_ethernet_hdr_t *)(packet);

  printf("IP Packet Received...\n");
  fprintf(stderr, "\tsource IP: ");
  print_addr_ip_int(ntohl(ip_header->ip_src));
  fprintf(stderr, "\tsource MAC: ");
  print_addr_eth(eth_header->ether_shost);
  fprintf(stderr, "\tdestination IP: ");
  print_addr_ip_int(ntohl(ip_header->ip_dst));
  fprintf(stderr, "\tdestination MAC: ");
  print_addr_eth(eth_header->ether_dhost);

  /* Decrement TTL and recompute checksum */
  ip_header->ip_sum = 0;
  ip_header->ip_sum = cksum((const void*)ip_header, sizeof(sr_ip_hdr_t));  

  struct sr_if* pkt_interface = 0;
  struct sr_if* interface_list_iterator = sr->if_list;

  /* If destination address belongs to Router's if_list */
  while (interface_list_iterator!=NULL) 
  {
    if (ip_header->ip_dst == interface_list_iterator->ip) 
        pkt_interface = interface_list_iterator;
    interface_list_iterator = interface_list_iterator->next;
  }

  /* IP packet destined for router's interface - NO GO */
  /* Processing only for ICMP echo request-reply otherwise no go */
  
  if (pkt_interface!=0) /* Interface record exists */
  { 
    printf("IP Packet meant for Router...\n");
    if (ip_header->ip_p == ip_protocol_icmp) /* echo req/reply */
    {
      printf("IP Packet contains ICMP...\n");
      sr_icmp_hdr_t* icmp_header = (sr_icmp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
      if (icmp_header->icmp_type == 8) /* PING */
      {
          printf("ICMP Echo request to Router...\n");

          uint8_t* send_packet = (uint8_t *)malloc(len);
          /* Same content as packet */
          memcpy(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t),len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
          /* ICMP header */
          sr_icmp_hdr_t* new_icmp = (sr_icmp_hdr_t *)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
          new_icmp->icmp_type = 0;
          new_icmp->icmp_code = 0;
          new_icmp->icmp_sum = cksum(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), len - sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
          /* Ethernet header */
          sr_ethernet_hdr_t *new_ethhdr = (sr_ethernet_hdr_t *) send_packet;
          new_ethhdr->ether_type = ntohs(0x0800);
          /* IP header */
          sr_ip_hdr_t *new_iphdr = (sr_ip_hdr_t *)(send_packet + sizeof(sr_ethernet_hdr_t));
          new_iphdr->ip_len = ntohs(len - sizeof(sr_ethernet_hdr_t));
          new_iphdr->ip_ttl = 64; /* 64 */
          new_iphdr->ip_v = 4;
          new_iphdr->ip_hl = 5;
          new_iphdr->ip_dst = ip_header->ip_src;
          new_iphdr->ip_src = ip_header->ip_dst;
          new_iphdr->ip_p = 0x0001;
          new_iphdr->ip_sum = 0;
          new_iphdr->ip_sum = cksum(send_packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));

          printf("ICMP Echo response prepared...\n");
          struct sr_arpentry* entry = sr_arpcache_lookup(&(sr->cache), new_iphdr->ip_dst);
          if (entry)
          {
            memcpy(new_ethhdr->ether_dhost, entry->mac, 6);
            struct sr_if* sending_interface = sr_get_interface(sr, interface);
            memcpy(new_ethhdr->ether_shost, sending_interface->addr, 6);
            sr_send_packet(sr, send_packet, len, interface);
            printf("ICMP Echo response sent (Cache lookup successful)...\n");
            free(entry);
          }
          else
          {
            printf("Entry not found in Cache for ICMP Echo response (Preparing ARP Request)...\n");
            struct sr_arpreq* req = sr_arpcache_queuereq(&(sr->cache), new_iphdr->ip_dst, send_packet, len, interface);
            req->iface = interface;
            handle_arpreq(sr, req);
          }
          free (send_packet);
          return;
      }
      else 
      {
        /* Drop DA packet*/
        printf("Non-PING ICMP to Router. Packet will be dropped...\n");
      }
    } 

    /*receive a TCP/UDP packet, send ICMP port unreachable back*/

    else if(ip_header->ip_p == 0x06 || ip_header->ip_p == 0x11)
    {
        printf("TCP/UDP packet to Router...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_t3_hdr_t* new_icmp_header = (sr_icmp_t3_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = htons(0x4000);
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 3;
        new_icmp_header->icmp_code = 3;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->next_mtu = htons(512);
        memcpy(new_icmp_header->data, (uint8_t *)ip_header, 28);
        /*memcpy(new_icmp_header->data + sizeof(sr_ip_hdr_t), send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), 8);*/
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Port Unreachable: Sending ICMP (3,3)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;
    } 
    else
    {
      printf("Unknown IP protocol number to Router. Packet will be dropeed...\n");
    }
  } 


  else 
  {
     printf("IP Packet not meant for router...\n");
    /* Forward the Packet  */
    printf("Preparing to forward...\n");

    struct sr_rt* next_hop = NULL;
    struct sr_rt* table_iterator = sr->routing_table;
    while (table_iterator) 
    {
      if ((ip_header->ip_dst & (table_iterator->mask).s_addr) == ((table_iterator->dest).s_addr & (table_iterator->mask).s_addr)) 
        next_hop = table_iterator;
      table_iterator = table_iterator->next;
    }

    /* If no matching entry in Routing Table. Send Destination Net Unreachable */

    if (next_hop == NULL)
    {
        printf("Non existent route to destination IP...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_t3_hdr_t* new_icmp_header = (sr_icmp_t3_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = 0;
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 3;
        new_icmp_header->icmp_code = 0;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->next_mtu = htons(512);
        memcpy(new_icmp_header->data, (uint8_t *)ip_header, 28);
        /*memcpy(new_icmp_header->data + sizeof(sr_ip_hdr_t), send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), 8);*/
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Net Unreachable: Sending ICMP (3,0)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;
    }

    /* Continue Forwarding otherwise */
    ip_header->ip_ttl--;

    if (ip_header->ip_ttl == 0) 
    {
        printf("Timed out (TTL = 0). IP packet will be discarded MUAHAHAHAH! ...\n");

        size_t tulen = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t);
        uint8_t* send_packet = malloc(tulen);
        sr_ethernet_hdr_t* new_ether_header = (sr_ethernet_hdr_t*)send_packet;
        sr_ip_hdr_t* new_ip_header = (sr_ip_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t));
        sr_icmp_hdr_t* new_icmp_header = (sr_icmp_hdr_t*)(send_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

        /*write ethernet header*/
        struct sr_if* sending_interface = sr_get_interface(sr, interface);
        memcpy(new_ether_header->ether_dhost, eth_header->ether_shost, 6);
        memcpy(new_ether_header->ether_shost, sending_interface->addr, 6);
        new_ether_header->ether_type = htons(0x0800);

        /*write ip header*/
        new_ip_header->ip_hl = 5;
        new_ip_header->ip_v = 4;
        new_ip_header->ip_tos = ip_header->ip_tos;
        new_ip_header->ip_len = htons( sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t));
        new_ip_header->ip_id = ip_header->ip_id;
        new_ip_header->ip_off = 0;
        new_ip_header->ip_ttl = 64;
        new_ip_header->ip_p = ip_protocol_icmp;
        new_ip_header->ip_sum = 0;
        new_ip_header->ip_src = sending_interface->ip;
        new_ip_header->ip_dst = ip_header->ip_src;
        new_ip_header->ip_sum = cksum(new_ip_header, sizeof(sr_ip_hdr_t));

        /*write icmp header*/
        new_icmp_header->icmp_type = 11;
        new_icmp_header->icmp_code = 0;
        new_icmp_header->icmp_sum = 0;
        new_icmp_header->icmp_sum = cksum(send_packet + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t), sizeof(sr_icmp_t3_hdr_t));

        printf("Time Exceeded: Sending ICMP (11,0)...\n");
        /*send packet*/
        sr_send_packet(sr, send_packet, tulen, interface);
        free(send_packet);
        return;      
    }

    ip_header->ip_sum = 0;
    ip_header->ip_sum = cksum((uint8_t*) ip_header, sizeof(sr_ip_hdr_t));

    struct sr_arpentry* entry = sr_arpcache_lookup(&(sr->cache), next_hop->gw.s_addr);
    if (entry) 
    {
      sr_ethernet_hdr_t* new_etheader = (sr_ethernet_hdr_t *)(packet);
      struct sr_if* interface = sr_get_interface(sr, next_hop->interface);
      memcpy(new_etheader->ether_dhost, entry->mac, 6);
      memcpy(new_etheader->ether_shost, interface->addr, 6);
      printf("Packet forwarded (Cache lookup successful)...\n");
      sr_send_packet(sr, packet, len, next_hop->interface);
      free(entry);
    }
    else 
    {
      printf("Forwarding Entry not found in Cache (Preparing ARP Request)...\n");
      struct sr_arpreq* req = sr_arpcache_queuereq(&(sr->cache), next_hop->gw.s_addr, packet, len, next_hop->interface);
      req->iface = next_hop->interface;
      handle_arpreq(sr, req);
    }
  }              
}
Ejemplo n.º 12
0
void sr_handlepacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  uint8_t buf[len];
  int cksumtemp = 0;
  int cksumcalculated = 0;
  struct sr_arpentry *entry;
  struct sr_arpreq *req;
  struct sr_arpcache *arp_cache = &(sr->cache);
  struct sr_if *sr_interface;
  struct sr_rt *rt_walker = 0;
  char *temp_if;

  /* REQUIRES */
  assert(sr);
  assert(packet);
  assert(interface);

  printf("\n*** -> Received packet of length %d \n",len);

  /* fill in code here */
  sr_ethernet_hdr_t *ethhdr = (sr_ethernet_hdr_t *)packet;
  sr_arp_hdr_t *arphdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  sr_icmp_hdr_t *icmphdr = (sr_icmp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

  sr_ethernet_hdr_t *arpreply_ethhdr = (sr_ethernet_hdr_t *)buf;
  sr_arp_hdr_t *arpreply_arphdr = (sr_arp_hdr_t *)(buf + sizeof(sr_ethernet_hdr_t));

  sr_ethernet_hdr_t *tempreq;

  if (len < sizeof(sr_ethernet_hdr_t)) {
    fprintf(stderr, "ETHERNET header is insufficient length\n");
    return;
  }

  if(ethertype(packet) == ethertype_arp) { /* ARP */
    if (len < (sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t))) {
      /* todo: call sr_arp_req_not_for_us, maybe later */
      fprintf(stderr, "ARP header is insufficient length\n");
      return;
    }
    else {
      printf("ARP packet received\n");
      if(ntohs(arphdr->ar_op) == arp_op_request) { /* ARP request */
	printf("\tARP request\n");
	/* send ARP reply */
	sr_interface = sr_get_interface(sr,interface);
	memcpy(buf,packet,len);

	memset(arpreply_ethhdr->ether_dhost,0xff,6);
	memcpy(arpreply_ethhdr->ether_shost,sr_interface->addr,6);
	arpreply_ethhdr->ether_type = htons(ethertype_arp);

	arpreply_arphdr->ar_op = htons(arp_op_reply);
	memcpy(arpreply_arphdr->ar_sha,sr_interface->addr,6);
	arpreply_arphdr->ar_sip = arphdr->ar_tip;
	memcpy(arpreply_arphdr->ar_tha,arphdr->ar_sha,6);
	arpreply_arphdr->ar_tip = arphdr->ar_sip;
	sr_send_packet(sr,buf,len,interface);

	printf("\tARP reply sent\n");
		/* sr_arpcache_dump(arp_cache); */
      }
      else if(ntohs(arphdr->ar_op) == arp_op_reply) { /* ARP reply */
	printf("\tARP reply\n");
	/* cache IP->MAC mapping and check if arp req in queue */
	req = sr_arpcache_insert(arp_cache,arphdr->ar_sha,ntohs(arphdr->ar_sip));
	tempreq = (sr_ethernet_hdr_t *)req->packets->buf;
	memcpy(tempreq->ether_dhost,ethhdr->ether_shost,6);
	if(req != NULL) {
	  /* send outstanding packets by call */
	  printf("\tARP req in queue\n");
	  sr_send_packet(sr,req->packets->buf,req->packets->len,interface);
	  sr_arpreq_destroy(arp_cache,req);
	}
	else
	  printf("\tARP req not in queue\n");
      }
      else /* not ARP request or reply */
	fprintf(stderr, "Unknown ARP opcode\n");
    }
  }

  else if(ethertype(packet) == ethertype_ip) { /* IP */
    if (len < (sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t))) {
      fprintf(stderr, "IP header is insufficient length\n");
      return;
    }
    else {
      printf("IP packet received\n");
      /* check checksum */
      cksumtemp = iphdr->ip_sum;
      iphdr->ip_sum = 0;
      cksumcalculated = cksum((void *)iphdr,4*iphdr->ip_hl);

      if(cksumtemp == cksumcalculated) {
	printf("\tChecksum good!\n");

	/* this part should not be here, it should be called though */
	if(iphdr->ip_ttl <= 1) {
	  fprintf(stderr, "ICMP time exceeded\n"); /* ICMP time exceeded */
	  return;
	}
	else
	  iphdr->ip_ttl -= 1; 
	
	/* update checksum */
	iphdr->ip_sum = cksum((void *)iphdr,4*iphdr->ip_hl);

	/* todo: LPM and find next hop ip, if no match ICMP net unreachable  */

	/* check routing table, save interface */
	rt_walker = sr->routing_table;
	while(rt_walker != NULL) {
	  if(iphdr->ip_dst == (uint32_t)rt_walker->dest.s_addr) { /* checks for dest IP addr, should be LPM ip not ip_dst */
	    temp_if = rt_walker->interface;
	  }
	  rt_walker = rt_walker->next;
	}
	sr_interface = sr_get_interface(sr,temp_if);

	/* check cache to avoid unnecessary arp req */
	entry = sr_arpcache_lookup(arp_cache,ntohs(iphdr->ip_dst)); /* should be LPM ip not ip_dst, but since next hop is destination... */

	if(entry != NULL) { /* cache hit, just send ip packet to next hop*/
	  printf("\tIP->MAC hit\n");
	  sr_send_packet(sr,packet,len,sr_interface);
	  free(entry);
	}
	else { /* cache miss, send ARP req and wait for reply */
	  printf("\tIP->MAC miss\n");
	  if(sr_interface == 0) { /* no match in routing table */
	    fprintf(stderr, "ICMP host unreachable\n");
	    return;
	  }
	  else { /* match in routing table */
	    /* construct arp req with new interface */
	    memset(arpreply_ethhdr->ether_dhost,0xff,6);
	    memcpy(arpreply_ethhdr->ether_shost,sr_interface->addr,6);
	    arpreply_ethhdr->ether_type = htons(ethertype_arp);

	    arpreply_arphdr->ar_hrd = htons(arp_hrd_ethernet);
	    arpreply_arphdr->ar_pro = htons(ethertype_ip);
	    arpreply_arphdr->ar_hln = 0x6;
	    arpreply_arphdr->ar_pln = 0x4;
	    arpreply_arphdr->ar_op = htons(arp_op_request);
	    memcpy(arpreply_arphdr->ar_sha,sr_interface->addr,6);
	    arpreply_arphdr->ar_sip = sr_interface->ip;
	    memset(arpreply_arphdr->ar_tha,0x00,6);
	    arpreply_arphdr->ar_tip = iphdr->ip_dst;

	    memcpy(ethhdr->ether_shost,sr_interface->addr,6);

	    printf("\tARP request sent\n");
	    /* add packet to queue list */
	    req = sr_arpcache_queuereq(arp_cache,ntohs(iphdr->ip_dst),packet,len,sr_interface);
	    handle_arpreq(arp_cache,sr,req,buf,sr_interface);
	  }
	}
      }
      else {
	/* drop packet */
	fprintf(stderr, "\tChecksum bad!\n");
	return;
      }
    }
  }

  else /* not IP or ARP */
    printf("Unrecognized Ethernet Type 0x%X\n",ethertype(packet));
}
Ejemplo n.º 13
0
/* 
  This function gets called every second. For each request sent out, we keep
  checking whether we should resend an request or destroy the arp request.
  See the comments in the header file for an idea of what it should look like.
*/
void sr_arpcache_sweepreqs(struct sr_instance *sr) { 
    /* Fill this in */
        /*Have to: go through each arprequest in the queue*/
      /*for each one: "handle" the arp request*/
        /*Handle: if arpreq time == current time => req just made, don't touch*/
        /*        else (time diff >= 1) : */
          /*if # times requested >= 5: need to drop request -> go through each packet for request, and tell the source that host unreachable.  Then destroy arpreq *(careful not to lose next requests on queue!)*/
          /*else(req not brand new but <5 re-sends) : send arprequest again, update time last send and sent count*/

    struct sr_arpreq *sweepreq;
    struct sr_arpreq *prevreq = sr->cache->requests;
    struct sr_nextreq *nextreq;
    /*There are no requests!*/
    if (prevreq == NULL){
      return;
    }
    
    sweepreq = prevreq;
    /*There are still request left*/
    while (sweepreq != NULL){
        if (handle_arpreq(sweepreq) == 1){
          /*request has been sent too many times. Destroy without losing the request queue. Have to point the previous req to the next req*/
          if (prevreq == sweepreq){
            /*Handle the case of the first request*/
            sr->cache->requests = sweepreq->next;
            sweepreq = sweepreq->next;
            nextreq = sweepreg->next;
            sr_arpreq_destroy(prevreq);
            prevreq = sweepreq;
          } else {
            nextreq = sweepreq->next;
            prevreq->next = nextreq;
            sr_arpreq_destroy(sweepreq);
            sweepreq = nextreq;
          }
        } else {
          /*No deletion to be made. Just update previous and current request*/
          prevreq = sweepreq;
          sweepreq = sweepreq->next;
        }
}


/* You should not need to touch the rest of this code. */

/* Checks if an IP->MAC mapping is in the cache. IP is in network byte order.
   You must free the returned structure if it is not NULL. */
struct sr_arpentry *sr_arpcache_lookup(struct sr_arpcache *cache, uint32_t ip) {
    pthread_mutex_lock(&(cache->lock));
    
    struct sr_arpentry *entry = NULL, *copy = NULL;
    
    int i;
    for (i = 0; i < SR_ARPCACHE_SZ; i++) {
        if ((cache->entries[i].valid) && (cache->entries[i].ip == ip)) {
            entry = &(cache->entries[i]);
        }
    }
    
    /* Must return a copy b/c another thread could jump in and modify
       table after we return. */
    if (entry) {
        copy = (struct sr_arpentry *) malloc(sizeof(struct sr_arpentry));
        memcpy(copy, entry, sizeof(struct sr_arpentry));
    }
        
    pthread_mutex_unlock(&(cache->lock));
    
    return copy;
}
Ejemplo n.º 14
0
void sr_handleip(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
	sr_ip_hdr_t *ip_hdr = 0;
	struct sr_if *iface = 0;
	sr_icmp_hdr_t *icmp_hdr = 0;
	uint8_t *reply_packet = 0;
	struct sr_rt *rt = 0;
	uint32_t nexthop_ip, longest_mask = 0;
	struct sr_arpentry *arp_entry = 0;
	struct sr_arpreq *arp_req = 0;
	sr_ethernet_hdr_t *ether_hdr = 0;
	int matched = 0;
	
	/* check if header has the correct size */
	if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)) {
		fprintf(stderr, "Error: invalid IP header length\n");
		return;
	}
	
	ip_hdr = (sr_ip_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
	
	/* perform ip header checksum */
	if (cksum(ip_hdr, ip_hdr->ip_hl) != 0xffff) {
		fprintf(stderr, "Error: IP checksum failed\n");
		return;
	}
	
	/* grab the receiving interface */
	if ((iface = sr_get_interface(sr, interface)) == 0) {
		fprintf(stderr, "Error: interface does not exist (sr_handleip)\n");
		return;
	}
	
	/* if the packet is destined to our ip */
	if (ip_hdr->ip_dst == htonl(iface->ip)) {
	
		/* if it is an ICMP */
		if (ip_hdr->ip_p == htons(ip_protocol_icmp)) {
			
			/* check if header has the correct size */
			if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t)) {
				fprintf(stderr, "Error: invalid ICMP header length\n");
				return;
			}
			
			icmp_hdr = (sr_icmp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
			
			/* if it is an ICMP echo request, send an ICMP echo reply */
			if (icmp_hdr->icmp_type == htons(8) && icmp_hdr->icmp_code == htons(0)) {
				
				/* perform ICMP header checksum */
				if (cksum(icmp_hdr, sizeof(icmp_hdr)) != 0xffff) {
					fprintf(stderr, "Error: ICMP checksum failed\n");
					return;
				}
				
				/* generate an echo reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 0, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP echo reply packet\n");
					return;
				}
				
				/* send an ICMP echo reply */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);				
			}
		}
		/* if it contains a TCP or UDP payload */
		else {
		
			/* generate Destination net unreachable (type 3, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 3)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);		
		}
	}
	/* packet not for us, forward it */
	else {
		
		/* if TTL reaches 0 */
		if (ip_hdr->ip_ttl <= htons(1)) {
		
			/* generate Time exceeded (type 11, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 11, 0)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);
		}
		/* if packet has enough TTL */
		else {
			
			/* decrement the TTL by 1 */
			ip_hdr->ip_ttl --;
			
			/* recompute the packet checksum */
			ip_hdr->ip_sum = htons(0);
			ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
			
			/* Find entry in the routing table with the longest prefix match */
			rt = sr->routing_table;
			while (rt != NULL) {
				
				/* update the gateway ip and the longest mask so far */
				if ((rt->dest.s_addr & rt->mask.s_addr) == (ntohl(ip_hdr->ip_dst) & rt->mask.s_addr) &&
					rt->mask.s_addr > longest_mask) {
					nexthop_ip = rt->gw.s_addr;
					longest_mask = rt->mask.s_addr;
					matched = 1;
				}
				
				rt = rt->next;
			}
			
			/* if a matching routing table entry was NOT found */
			if (matched == 0) {
				
				/* generate Destination net unreachable (type 3, code 0) reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP packet\n");
					return;
				}
				
				/* send an ICMP */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);
			}
			/* if a matching routing table entry was found */
			else {
				/* if the next hop is 0.0.0.0 */
				if(nexthop_ip == 0) {
					nexthop_ip = ip_hdr->ip_dst;
				}
				
				/* set the source MAC of ethernet header */
				ether_hdr = (sr_ethernet_hdr_t*)packet;
				memcpy(ether_hdr->ether_shost, iface->addr, ETHER_ADDR_LEN);
				
				/* if the next-hop IP CANNOT be found in ARP cache */
				if ((arp_entry = sr_arpcache_lookup(&(sr->cache), htonl(nexthop_ip))) == NULL) {
					
					/* send an ARP request */
					arp_req = sr_arpcache_queuereq(&(sr->cache), nexthop_ip, packet, len, iface);
					handle_arpreq(sr, arp_req);
				}
				/* if the next-hop IP can be found in ARP cache */
				else {
					
					/* set the destination MAC of ethernet header */
					memcpy(ether_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
					
					/* send the packet */
					if (sr_send_packet(sr, packet, sizeof(packet), (const char*)interface) == -1) {
						fprintf(stderr, "Error: sending packet failed (sr_handlearp)\n");
					}
					
					free(arp_entry);
				}
			}
		}
	}
}
Ejemplo n.º 15
0
/* Handle IP packet */
void sr_handle_ippacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */) 
{
    assert(sr);
    assert(packet);
    assert(interface);

    /* Get ethernet header */
    sr_ethernet_hdr_t *eth_hdr = get_eth_hdr(packet);
	if (eth_hdr == NULL) {
		printf("ethernet header NULL!!!\n");
		return;
	}

    /* Get ip header */
    sr_ip_hdr_t *ip_hdr = get_ip_hdr(packet);
	if (ip_hdr == NULL) {
		printf("ip header NULL!!!\n");
		return;
	}

	/* Before doing ttl decrement, check checksum */
	uint16_t old_ip_sum = ip_hdr->ip_sum;
	ip_hdr->ip_sum = 0;

	if (!verify_checksum(ip_hdr, sizeof(sr_ip_hdr_t), old_ip_sum)) {
		fprintf(stderr, "CHECKSUM FAILED!!\n");
		return;
	}
	ip_hdr->ip_sum = old_ip_sum;

    /* Get the arp cache */
    struct sr_arpcache *sr_arp_cache = &sr->cache;

    /* Get the destination interface on the router */
	struct sr_if *sr_iface = sr_get_router_if(sr, ip_hdr->ip_dst);
	/* Get the connected interface on the router */
	struct sr_if *sr_con_if = sr_get_interface(sr, interface);

    /* Check the time exceeded condition, if ttl==0, we need to form icmp 11 and send back */
    if (ip_hdr->ip_ttl <= 1) {
        /* time exceeded message and icmp type 11 */
        printf("TTL time exceeded\n");
        int packet_len = ICMP_T3_PACKET_LEN;
        uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

        create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_con_if);
        /* Create ip header */
        create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_con_if);

        /* Send icmp type 11 time exceeded */
        /* icmp_t3 type=11, code=0 */
        create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 11, 0);

        /* Send icmp type 11 packet */
		struct sr_arpentry *arp_entry = sr_arpcache_lookup(sr_arp_cache, ip_hdr->ip_src);
		if (arp_entry != NULL) {
			sr_send_packet(sr, icmp_t3_hdr, packet_len, sr_con_if->name);
			free(icmp_t3_hdr);
		} else {
			struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, sr_con_if->name);
			handle_arpreq(arp_req, sr);
		}
        return;
    }

    /* Get the protocol from IP */
    uint8_t ip_p = ip_hdr->ip_p;

    /* If the packet is sent to self, meaning the ip is sent to the router */
    if (sr_iface) {
        /* Check the protocol if it is icmp */
        if (ip_p == ip_protocol_icmp) {
            /* Get the icmp header */
            sr_icmp_hdr_t *icmp_hdr = get_icmp_hdr(packet);

            /* Check if it is ICMP echo request */
            /* icmp_echo_req = 8 */
            if (icmp_hdr->icmp_type == 8) {
				/* Do LPM on the routing table */
        		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
        		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

				if (longest_pref_match) {
					/* check ARP cache */
					struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
					struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

					/* If hit, meaning the arp mapping has been cached */
					if (arp_entry != NULL) {
						/* We need to send the icmp echo reply */
				        /* Modify ethernet header */
						memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
						memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN);

				        /* Modify ip header */
						ip_hdr->ip_off = htons(0b0100000000000000);        /* fragment offset field */
						ip_hdr->ip_ttl = 100;                    			/* time to live */
						uint32_t temp = ip_hdr->ip_src;
						ip_hdr->ip_src = ip_hdr->ip_dst;        /* source address */
						ip_hdr->ip_dst = temp;        			/* dest address */
						ip_hdr->ip_sum = 0;
						ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));			/* checksum */

				        /* Modify icmp header */
						unsigned int icmp_whole_size = len - IP_PACKET_LEN;
						icmp_hdr->icmp_type = 0;
						icmp_hdr->icmp_code = 0;
						icmp_hdr->icmp_sum = 0;
						icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size);

				        /* Send icmp echo reply */
				        sr_send_packet(sr, packet, len, out_iface->name);
				        return;
					}
					/* Else no hit, we cache it to the queue and send arp request */ 
					else {
						/* Add reply to the ARP queue */
						/* We need to send the icmp echo reply */
				        /* Modify ethernet header */
						memcpy(eth_hdr->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
						memcpy(eth_hdr->ether_shost, sr_con_if->addr, ETHER_ADDR_LEN);

				        /* Modify ip header */
						ip_hdr->ip_off = htons(0b0100000000000000);        /* fragment offset field */
						ip_hdr->ip_ttl = 100;                    			/* time to live */
						uint32_t temp = ip_hdr->ip_src;
						ip_hdr->ip_src = ip_hdr->ip_dst;        /* source address */
						ip_hdr->ip_dst = temp;        			/* dest address */
						ip_hdr->ip_sum = 0;
						ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));			/* checksum */

				        /* Modify icmp header */
						unsigned int icmp_whole_size = len - IP_PACKET_LEN;
						icmp_hdr->icmp_type = 0;
						icmp_hdr->icmp_code = 0;
						icmp_hdr->icmp_sum = 0;
						icmp_hdr->icmp_sum = cksum(icmp_hdr, icmp_whole_size);
						struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name);
						/* Send ARP request, which is a broadcast */
						handle_arpreq(arp_req, sr);
						return;
					}
				} else {
					fprintf(stderr, "Longest prefix doesnt match!!\n");
                	return;
				}

            } else {
                fprintf(stderr, "Not an ICMP request!\n");
                return;
            }
        }
        /* Else it is TCP/UDP request */
        else {
            fprintf(stderr, "*** -> Received TCP/UDP!\n");

			/* Do LPM on the routing table */
    		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
    		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

			if (longest_pref_match) {
				/* check ARP cache */
				struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
				struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);
				
				/* Send ICMP port unreachable */
				if (arp_entry != NULL) {

					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface);
					/*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
					memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface);
					/*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN);
					icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst;
					icmp_t3_hdr_ip->ip_sum = 0;
					icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/
					

					/* Should update source address to be interface address */

				    /* Send icmp type 3 port unreachable */
				    /* Create icmp port unreachable packet */
				    /* icmp_t3 type=3, code=3 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3);

				    /* Send icmp type 3 packet */
				    sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name);

				    free(icmp_t3_hdr);
				    return;
				} else {
				
					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, sr_iface);
					/*memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_dhost, eth_hdr->ether_shost, ETHER_ADDR_LEN);
					memcpy(((sr_ethernet_hdr_t *)icmp_t3_hdr)->ether_shost, eth_hdr->ether_dhost, ETHER_ADDR_LEN);*/

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), sr_iface);
					/*sr_ip_hdr_t *icmp_t3_hdr_ip = (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN);
					icmp_t3_hdr_ip->ip_src = ip_hdr->ip_dst;
					icmp_t3_hdr_ip->ip_sum = 0;
					icmp_t3_hdr_ip->ip_sum = cksum(icmp_t3_hdr_ip, sizeof(sr_ip_hdr_t));*/

				    /* Send icmp type 3 port unreachable */
				    /* Create icmp port unreachable packet */
				    /* icmp_t3 type=3, code=3 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 3);

					struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name);
					/* Send ARP request, which is a broadcast */
					handle_arpreq(arp_req, sr);
					return;
				}
			} else {
				fprintf(stderr, "Longest prefix doesnt match!!\n");
                return;
			}            
            
        }
    }
    /* Else Check the routing table, perfomr LPM */
    else {
        /* Sanity-check the packet */
        /* minimum length */
        if (!check_min_length(len, IP_PACKET_LEN)) {
            fprintf(stderr, "The packet length is not enough:(\n");
            return;
        }
		
        /* Do LPM on the routing table */
        /* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
        struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_dst);
        if (longest_pref_match) {
            /* check ARP cache */
			struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

            struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr); /* ip_hdr->ip_dst */
         
			/* If hit, meaning the arp_entry is found */
            if (arp_entry) {

				/*fprintf(stderr, "************ found the lpm router entry ***********\n");*/
                /* Send frame to next hop */
                /* update the eth_hdr source and destination ethernet address */
                /* use next_hop_ip->mac mapping in the entry to send the packet */

                ip_hdr->ip_ttl--;

                /* recompute the packet checksum over the modified header */
                ip_hdr->ip_sum = 0;
                uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
                ip_hdr->ip_sum = new_ip_sum;

                memcpy(eth_hdr->ether_shost, out_iface->addr, ETHER_ADDR_LEN);
                memcpy(eth_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
                sr_send_packet(sr, packet, len, out_iface->name);
				print_hdr_ip((uint8_t*)ip_hdr);
                /* free the entry */
                free(arp_entry);
                return;
            } else/* No Hit */ {
                /* send an ARP request for the next-hop IP */
                /* add the packet to the queue of packets waiting on this ARP request */
                /* Add request to ARP queue*/

                ip_hdr->ip_ttl--;

                /* recompute the packet checksum over the modified header */
                ip_hdr->ip_sum = 0;
                uint16_t new_ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
                ip_hdr->ip_sum = new_ip_sum;

                struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_dst, packet, len, out_iface->name);
                /* send ARP request, this is a broadcast */
                handle_arpreq(arp_req, sr);
                return;
            }
        } else /* if not matched */ {
            /* Send ICMP net unreachable */
			printf("--------------- Net Unreachable ---------------\n");

			/* Do LPM on the routing table */
    		/* Check the routing table and see if the incoming ip matches the routing table ip, and find LPM router entry */
    		struct sr_rt *longest_pref_match = sr_lpm(sr, ip_hdr->ip_src);

			if (longest_pref_match) {
				/* check ARP cache */
				struct sr_arpentry *arp_entry = sr_arpcache_lookup(&sr->cache, longest_pref_match->gw.s_addr);
				struct sr_if *out_iface = sr_get_interface(sr, longest_pref_match->interface);

				if (arp_entry) {
					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface);

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface);

				    /* Create icmp net unreachable */
				    /* icmp_t3 type=3, code=0 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0);

				    /* Send icmp type 3 packet */
				    sr_send_packet(sr, icmp_t3_hdr, packet_len, out_iface->name);

				    free(icmp_t3_hdr);
				    return;
				} else {

					int packet_len = ICMP_T3_PACKET_LEN;
				    uint8_t *icmp_t3_hdr = (uint8_t *)malloc(packet_len);

				    /* Create ethernet header */
				    create_ethernet_hdr(eth_hdr, (sr_ethernet_hdr_t *)icmp_t3_hdr, out_iface);

				    /* Create ip header */
				    create_echo_ip_hdr(ip_hdr, (sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN), out_iface);
					/*	((sr_ip_hdr_t *)((char *)icmp_t3_hdr+ETHER_PACKET_LEN))->ip_ttl += 1; */

				    /* Send icmp type 3 net unreachable */
				    /* Create icmp net unreachable packet */
				    /* icmp_t3 type=3, code=0 */
				    create_icmp_t3_hdr(ip_hdr, (sr_icmp_t3_hdr_t *)((char *)icmp_t3_hdr+IP_PACKET_LEN), 3, 0);

					struct sr_arpreq *arp_req = sr_arpcache_queuereq(sr_arp_cache, ip_hdr->ip_src, icmp_t3_hdr, packet_len, out_iface->name);
					/* Send ARP request, which is a broadcast */
					handle_arpreq(arp_req, sr);
					return;
				}
			} else {
				fprintf(stderr, "Longest prefix doesnt match!!\n");
                return;
			}
        }
    }

    return;
}