Beispiel #1
0
/*
  Send a host unreachable ICMP to the given source address
*/
void send_echo_reply(uint8_t source_addr, uint8_t *packet, struct sr_instance *sr){
  
  /*Allocate a buffer to hold the packet*/
  uint8_t *buf = malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t));
  
  /*Create and send the host unreachable ICMP TO source, telling them that dest was unreachable*/
  /*First have to create the ICMP packet*/
  sr_icmp_t3_hdr_t *icmp_packet = (sr_icmp_hdr_t *)(buf + sizeof(sr_ip_hdr_t) + sizeof(sr_ethernet_hdr_t));
  icmp_packet->icmp_type = 1;
  icmp_packet->icmp_code = 1;
  icmp_packet->icmp_sum = 0;
  icmp_packet->icmp_sum = cksum((const void *)(icmp_packet.icmp_type + icmp_packet.icmp_code), 2);
  print_hdr_icmp(icmp_packet);
  /*Have to craft data.  Data will be the original packet header plus the first 8 bytes of the packet content.*/
  memcpy(icmp_packet->data, packet, ICMP_DATA_SIZE);
  
  /*Now have to form the ip packet to encase the icmp content*/
  sr_ip_hdr_t *ip_packet = (sr_ip_hdr_t *)(buf + sizeof(sr_ethernet_hdr_t));
  ip_packet->ip_p = 1;
  ip_packet->ip_tos;            /* type of service */
  ip_packet->ip_len;            /* total length */
  ip_packet->ip_id;         /* identification */
  ip_packet->ip_off;            /* fragment offset field */
  ip_packet->ip_ttl;            /* time to live */
  ip_packet->ip_p = 1;          /* protocol */
  ip_packet->ip_sum;            /* checksum */
  ip_packet->ip_src = sr->if_list[0]->ip;  /*Assign the packet source to one of the router's interfaces*/
  ip_packet->ip_dst = get_ip_addr(packet);  /*set the packet destination to the original source IP*/
  print_hdr_ip(ip_packet);
  memcpy((void *)arp_packet->ar_sha, (void *)sender_eth, ETHER_ADDR_LEN);
  /*Now make an ethernet frame to wrap the IP packet with the ICMP packet*/
  sr_ethernet_hdr_t *ether_packet = (sr_ethernet_hdr_t *)(buf);
  ether_packet->ether_dhost = source_addr;  /*Set ethernet destination*/
  ether_packet->ether_shost = sr->if_list[0]->addr;  /*Set ethernet source*/
  ether_packet->ether_type = sr_ethertype.ethertype_ip;
  print_hdr_eth(ether_packet);
  print_hdr_icmp(uint8_t *buf);
  /*Now send off the packet*/
  int size = 32+20+8+28; /*Size of the packet. Ether header = 32, ip header = 20, ICMP header = 8, ICMP data = 28.*/
  sr_send_packet(sr, buf, size, sr->if_list);
  

}
Beispiel #2
0
void sr_handleIPpacket(struct sr_instance* sr, uint8_t* packet,unsigned int len, struct sr_if * iface){
  assert(packet);
  sr_ethernet_hdr_t* ethHeader = (sr_ethernet_hdr_t*) packet;
  uint8_t* ip_packet = packet+sizeof(sr_ethernet_hdr_t);
  sr_ip_hdr_t * ipHeader = (sr_ip_hdr_t *) (ip_packet);  

  uint16_t incm_cksum = ipHeader->ip_sum;
  ipHeader->ip_sum = 0;
  uint16_t currentChecksum = cksum(ip_packet,20);
  ipHeader->ip_sum = incm_cksum;
  uint8_t* icmp_packet;

  /* if the destination address is not one of my routers interfaces */
  if (currentChecksum==incm_cksum && sr_get_interface_from_ip(sr,ntohl(ipHeader->ip_dst)) == NULL){
    /* check cache for ip->mac mapping for next hop */
    struct sr_arpentry *entry;
    entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst);
    struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst);

    /* found next hop. send packet */
    if (ipHeader->ip_ttl <= 1){   /* IP TTL died. send ICMP type 11, code 0 */
      icmp_packet = createICMP(11, 0, ip_packet,len-14);
      memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t));
      ipHeader->ip_p = 1;
      len = SIZE_ETH+SIZE_IP+SIZE_ICMP;/*(len-34<28?len-34:28);*/
      ipHeader->ip_len = htons(len-14);
      free(icmp_packet);      
    } else if (entry && rt) {    /* found next hop. send packet */
      iface = sr_get_interface(sr, rt->interface);
      ipHeader->ip_ttl = ipHeader->ip_ttl - 1;
      ipHeader->ip_sum = 0;
      ipHeader->ip_sum = cksum(ip_packet,20);

      set_addr(ethHeader, iface->addr, entry->mac);

      sr_send_packet(sr,packet,len,iface->name);
      free(entry);
      ip_packet = NULL;
    } else if (rt) { /* send an arp request to find out what the next hop should be */
      struct sr_arpreq *req;
      sr_arpcache_insert(&(sr->cache), ethHeader->ether_shost, ipHeader->ip_src);
      req = sr_arpcache_queuereq(&(sr->cache), ipHeader->ip_dst, packet, len, iface->name);
      /*handle_arpreq(sr, req);*/
      ip_packet = NULL;
    } else {  /* no route found. send ICMP type 3, code 0 */
      printf("No route found for:\n");
      icmp_packet = createICMP(3, 0, ip_packet,len-14);
      print_hdr_ip(((sr_icmp_t3_hdr_t*)icmp_packet)->data);
      memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t));
      ipHeader->ip_p = 1;
      len = SIZE_ETH+SIZE_IP+SIZE_ICMP;/*(len-34<28?len-34:28);*/
      ipHeader->ip_len = htons(len-14);
      free(icmp_packet);      
    }
  }
  else if(currentChecksum==incm_cksum){
    if(ipHeader->ip_p==6 || ipHeader->ip_p==17){  /* IP TCP/UDP */
      icmp_packet = createICMP(3,3,ip_packet,len-14);
      memcpy(ip_packet+20,icmp_packet,sizeof(sr_icmp_t3_hdr_t));
      ipHeader->ip_p = 1;
      len = SIZE_ETH+SIZE_IP+SIZE_ICMP;/*(len-34<28?len-34:28);*/
      ipHeader->ip_len = htons(len-14);
      free(icmp_packet);
    }else if(ipHeader->ip_tos==0 && ipHeader->ip_p==1){ /* IP ping */
	    sr_icmp_hdr_t * icmp_header = (sr_icmp_hdr_t *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
      incm_cksum = icmp_header->icmp_sum;
      icmp_header->icmp_sum = 0;
	    currentChecksum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
	    
      if(currentChecksum == incm_cksum && icmp_header->icmp_type == 8 && icmp_header->icmp_code == 0) {
	      icmp_header->icmp_type = 0;
        ipHeader->ip_sum = 0;
	      icmp_header->icmp_sum = cksum(icmp_header,len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t));
	    }
      else{
        printf("ICMP INVALID\n");
        printf("%d != %d OR %d != %d\n",currentChecksum,incm_cksum, icmp_header->icmp_type, 8);
      }
    } else {
      printf("IP Bad\n");
      ip_packet = NULL;
    }
  }
  else{
      printf("IP INVALID\n");
      ip_packet = NULL;
  }
  if(ip_packet){  /* send ICMP packet */
    ipHeader->ip_dst = ipHeader->ip_src;
    ipHeader->ip_src = iface->ip;
    ipHeader->ip_ttl = INIT_TTL;
    ipHeader->ip_sum = 0;
    ipHeader->ip_off = htons(IP_DF);
    ipHeader->ip_sum = cksum(ip_packet,20);

    struct sr_arpentry *entry;
    entry = sr_arpcache_lookup(&sr->cache, ipHeader->ip_dst);
    struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, ipHeader->ip_dst);

    if (entry && rt) {    /* found next hop. send packet */
      iface = sr_get_interface(sr, rt->interface);
      set_addr(ethHeader, iface->addr, entry->mac);
      sr_send_packet(sr,packet,len,iface->name);
      free(entry);
      ip_packet = NULL;
    } else if (rt) { /* send an arp request to find out what the next hop should be */
      struct sr_arpreq *req;
      sr_arpcache_insert(&(sr->cache), ethHeader->ether_shost, ipHeader->ip_src);
      req = sr_arpcache_queuereq(&(sr->cache), ipHeader->ip_dst, packet, len, iface->name);
      /*handle_arpreq(sr, req);*/
      ip_packet = NULL;
    }
  }
}
/* This will foreward the given IP packet 
It checks for the Destination IP address and finds appropriate interface (LPM) and sends out! */
int forward_packet(struct sr_instance* sr,uint8_t* packet,int len,int packet_src_iface)
{
	uint32_t ip;
	sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)packet;
	/* Get Dest IP */
	ip = ip_header->ip_dst;

	/* This target variable stores the next hop */
	struct sr_rt* target = NULL;
	/* Perform LPM and get the target routing table entry which has the interface to pass and next hop IP */
	target = LPM(sr->routing_table,ip);
	/* Now the next hop ip (dest->gw)  is known and the interface also */
	if( target == NULL )
	{
		/* ICMP Destination Unreachable */
		/* There is no routing table entry for this destination IP address
		Now we have to send this packet encapsulated in ICMP packet with 3,0( Destiantion Network Unreachable )
		with src address of the incoming interface address and destination address as the source */
		
		/* We have IP packet, Now encapsulate in the ICMP */
		sr_icmp_hdr_t* ih = (sr_icmp_hdr_t*)(packet+sizeof(sr_ip_hdr_t));
		if( (ip_header->ip_p == ICMP_PROTOCOL) && (ih->icmp_type != 8) )
		{
			/* Dont send an ICMP for ICMP */
			return;
		}
		print_hdr_ip(packet);
		int size = sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8;

		uint8_t* complete_packet = (uint8_t*) malloc(sizeof(uint8_t)*size);

		uint8_t* icmp_start = make_ICMP(sr,packet,len,3,0);
		
		
		struct sr_if* src_if = sr_get_interface(sr,packet_src_iface);
		

		uint8_t* ip_start = make_IP_packet(*((uint8_t*)ip_header),(0x0000), htons(size), 0x0000, 0x0000,64,0x01, \
								src_if->ip,ip_header->ip_src);
		
		/* Foreward the ICMP packet with 3,0 to the src host */
		/* If the entry is again wrong, then dont send the ICMP for ICMP */
		
		memcpy(complete_packet,ip_start,sizeof(sr_ip_hdr_t));
		memcpy(complete_packet+sizeof(sr_ip_hdr_t),icmp_start,sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8);
		
		forward_packet(sr,complete_packet,size,packet_src_iface);
		return;
	}

	/* Now query for the Ethernet details */
	/* Get the router interface from where the packet should leave */
	struct sr_if* src_interface = sr_get_interface(sr,target->interface);
	/* Get the ARP entry for the next hop IP */
	struct sr_arpentry* entry = sr_arpcache_lookup(&sr->cache,(target->gw.s_addr));
	/* Now build the ethernet header */	
	
	uint8_t* complete_packet = (uint8_t*)malloc(sizeof(sr_ethernet_hdr_t)+len);

	memcpy(complete_packet+sizeof(sr_ethernet_hdr_t),packet,len);	
	
	/* Fill in all the details of the ethernet */

	sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*)complete_packet;
	memcpy(eth_hdr->ether_shost,src_interface->addr,sizeof(uint8_t)*6);
	eth_hdr->ether_type = htons(IP_PROTOCOL);

	/* If entry is NULL, It means that there is no cache entry in ARP Table */
	/* If not NULL, Then use the entry for next hop MAC address */

	/*assert(entry!=NULL);*/
	
	if( entry == NULL )
	{
		/* Destination MAC is not known ! */
		memset(eth_hdr->ether_dhost,0,sizeof(uint8_t)*6);
		/* Cache doesnt have this entry, So request it */
		struct sr_arpreq* req = sr_arpcache_queuereq(&sr->cache,target->gw.s_addr,complete_packet,len+sizeof(sr_ethernet_hdr_t) \
								,target->interface);
		assert(req!=NULL);
		/* Free the packet, as we dont need it. It has been copied to other buffer in the request queue */
		handle_ARP_req(sr, &sr->cache,req);
	}
	else
	{
		/* Destination MAC is known, So use it! */	
		memcpy(eth_hdr->ether_dhost,entry->mac,sizeof(uint8_t)*6);
		/* Now send the packet to the target interface */
		sr_send_packet(sr,complete_packet,sizeof(sr_ethernet_hdr_t)+len,target->interface);
		free(entry);
	}
}
Beispiel #4
0
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) 
{
    if (difftime(time(0), req->sent) > 0.9) {

      /* Host is not reachable */
      if (req->times_sent >= 5) {

        printf("** Host Unreachable\n");
        
        /* Send ICMP host unreachable*/
        struct sr_packet *ip_packet, *next;
        ip_packet = req->packets;

        if(ip_packet != 0){
          next = ip_packet->next;
        }
        while(ip_packet != 0){
          sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(ip_packet->buf);
          struct sr_if *s_interface = sr_get_interface(sr, ip_packet->iface);
          uint32_t dst;
          
          /* Send ICMP host unreachable */
          struct sr_ip_hdr send_ip_hdr;
          
          send_ip_hdr.ip_hl = 5;
          send_ip_hdr.ip_v = ip_hdr->ip_v;
          send_ip_hdr.ip_tos = 0;
          send_ip_hdr.ip_id = 0;
          send_ip_hdr.ip_off = htons(IP_DF);
          send_ip_hdr.ip_ttl = 100;
          send_ip_hdr.ip_p = ip_protocol_icmp;
          send_ip_hdr.ip_sum = 0;
          send_ip_hdr.ip_dst = ip_hdr->ip_src;
          send_ip_hdr.ip_src = s_interface->ip;
          dst = ip_hdr->ip_src;
            
          /* Copy the packet over */
          uint8_t *cache_packet;
          uint16_t total_len;
          uint16_t icmp_len;

          icmp_len = sizeof(struct sr_icmp_t3_hdr);
          total_len = ICMP_IP_HDR_LEN_BYTE + icmp_len;
          send_ip_hdr.ip_len = htons(total_len);
          send_ip_hdr.ip_sum = cksum(&send_ip_hdr, ICMP_IP_HDR_LEN_BYTE);

          cache_packet = malloc(total_len);
          struct sr_icmp_t3_hdr icmp_error_packet = icmp_send_error_packet(ip_hdr, code_host_unreach);

          memcpy(cache_packet, &(send_ip_hdr), ICMP_IP_HDR_LEN_BYTE);
          memcpy(cache_packet + ICMP_IP_HDR_LEN_BYTE, &(icmp_error_packet), 
                sizeof(struct sr_icmp_t3_hdr));

          print_hdr_ip(cache_packet);

          struct sr_arpreq *icmp_req;
          struct sr_arpentry *arp_entry;

          /* Check ARP cache  */
          arp_entry = sr_arpcache_lookup(&sr->cache, dst);

          if (arp_entry != 0){
                
            /* Entry exists, we can send it out right now */
            sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);
          } else {

              /* Get the interface at which the original packet arrived */
              struct sr_rt *lpmatch;
              struct sr_if *r_iface;

              lpmatch = longest_prefix_matching(sr, dst);
              r_iface = sr_get_interface(sr, lpmatch->interface);           
              icmp_req = sr_arpcache_queuereq(&sr->cache, dst, 
                                        cache_packet, total_len, r_iface->name);
              sr_handle_arpreq(sr, icmp_req);
            }
          ip_packet = next;
          if(ip_packet != 0){
            next = ip_packet->next;
          } else {
              sr_arpreq_destroy(&sr->cache, req);
          }
        }  
      } else {
          arp_boardcast(sr, req);

	  printf("** APR boardcasted\n");

          req->sent = time(0);
          req->times_sent ++;
        }
    }
}
Beispiel #5
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;
}