示例#1
0
void sr_handlepacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  /* REQUIRES */
	assert(sr);
	assert(packet);
	assert(interface);
	printf("*** -> Received packet of length %d \n",len);
	
	//print_hex2(packet, len);
	EthernetFrame * frame = new EthernetFrame(packet, len);
	switch(frame->GetType())
	{
		case ARP_PACKET:
		{
			sr_arpcache_insert(&sr->cache, frame->GetSrcAddress(), flip_ip(get_int(frame->GetPayload()+12)));
			handle_arp_packet(sr, frame, interface);
			break;
		}
		case IP_PACKET:
		{
			//
			sr_arpcache_insert(&sr->cache, frame->GetSrcAddress(), flip_ip(get_int(frame->GetPayload()+12)));
			handle_ip_packet(sr, frame, interface);
		}
		break;
		default:
			cerr << "Not a packet" << endl;
	}
	delete frame;
}/* end sr_ForwardPacket */
示例#2
0
void processArp(struct sr_instance *sr , uint8_t *packet, unsigned int len, char *interface) {

	struct sr_arp_hdr *arpHeader = (struct sr_arp_hdr *) (packet + sizeof(struct sr_ethernet_hdr));

	/* Put ARP header into cache */
	struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arpHeader->ar_sha, ntohl(arpHeader->ar_sip));
	if (req != NULL) {

		/* Found requests in queue waiting for this reply. Send all waiting packets */ 
		struct sr_packet *waiting = req->packets;
		struct sr_rt *rt = findLongestMatchPrefix(sr->routing_table, htonl(req->ip));

		while (waiting != NULL) {
			send_packet_to_dest(sr, waiting->buf, waiting->len, rt->interface, arpHeader->ar_sha, arpHeader->ar_sip);
			waiting = waiting->next;
		}

		/* Destroy arp request when complete */
		sr_arpreq_destroy(&(sr->cache), req);
	}

	if (ntohs(arpHeader->ar_op) == arp_op_request) {
		/* Reply to sender with our information */
		arp_send_reply(sr, packet, len, interface);
	}

}
示例#3
0
void sr_handleARPpacket(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;
    sr_arp_hdr_t * arpHeader = (sr_arp_hdr_t *) (packet+14);

    enum sr_arp_opcode request = arp_op_request;
    enum sr_arp_opcode reply = arp_op_reply;

    struct sr_if *interface = sr_get_interface_from_ip(sr, htonl(arpHeader->ar_tip));

    /* handle an arp request.*/
    if (ntohs(arpHeader->ar_op) == request) {
        /* found an ip->mac mapping. send a reply to the requester's MAC addr */
        if (interface){
          arpHeader->ar_op = ntohs(reply);
          uint32_t temp = arpHeader->ar_sip;
          arpHeader->ar_sip = arpHeader->ar_tip;
          arpHeader->ar_tip = temp;
          memcpy(arpHeader->ar_tha, arpHeader->ar_sha,6);
          memcpy(arpHeader->ar_sha, iface->addr,6);

          /*swapping outgoing and incoming addr*/
          set_addr(ethHeader, iface->addr, ethHeader->ether_shost);
          sr_send_packet(sr,(uint8_t*)ethHeader,len,iface->name);
        }
    }
    /* handle an arp reply */
    else {
      struct sr_packet *req_packet = NULL;
      struct sr_arpreq *req = NULL;
      pthread_mutex_lock(&(sr->cache.lock));   
      
      for (req = sr->cache.requests; req != NULL; req = req->next){
        if(req->ip == arpHeader->ar_sip){
          /* find the interface the packets should be sent out of */
          struct sr_rt * rt = (struct sr_rt *)sr_find_routing_entry_int(sr, req->ip);
          if (rt) {
            iface = sr_get_interface(sr, rt->interface);
            /* send all packets waiting on the request that was replied to */
            for (req_packet = req->packets; req_packet != NULL; req_packet = req_packet->next) {
              sr_ethernet_hdr_t * outEther = (sr_ethernet_hdr_t *)req_packet->buf;
              memcpy(outEther->ether_shost, iface->addr,6);
              memcpy(outEther->ether_dhost, ethHeader->ether_shost,6);

              sr_ip_hdr_t * outIP = (sr_ip_hdr_t *)(req_packet->buf+14);
              outIP->ip_ttl = outIP->ip_ttl-1;
              outIP->ip_sum = 0;
              outIP->ip_sum = cksum((uint8_t *)outIP,20);
              
              sr_send_packet(sr,req_packet->buf,req_packet->len,iface->name);
            }
            sr_arpreq_destroy(&(sr->cache), req);
          }
          break;
        }
      }
      pthread_mutex_unlock(&(sr->cache.lock));
      sr_arpcache_insert(&(sr->cache),arpHeader->ar_sha,arpHeader->ar_sip);
    }
}
示例#4
0
/*
Expects entire ethernet frame and ARP header still in network order.
 */
void handle_arp_reply(struct sr_instance *sr, uint8_t *pkt) {

  struct sr_if *requested_inf = find_interface_with_ip(sr, ntohl(get_arp_hdr(pkt)->ar_tip));
  if (!requested_inf) {
    /*Only cache entry if the target IP is one of the router's addresses*/
    return;
  }

  struct sr_arpreq *arpreq = sr_arpcache_insert(&(sr->cache), get_arp_hdr(pkt)->ar_sha, get_arp_hdr(pkt)->ar_sip);

  if (arpreq) {
    struct sr_packet *outgoing_pkt = arpreq->packets;
    while (outgoing_pkt) {
      sr_ethernet_hdr_t *eth_hdr = get_ethernet_hdr(outgoing_pkt->buf);
      
      sr_arp_hdr_t *incoming_arp_hdr = get_arp_hdr(pkt);
      
      memcpy(eth_hdr->ether_dhost, incoming_arp_hdr->ar_sha, ETHER_ADDR_LEN);
      sr_send_packet(sr, outgoing_pkt->buf, outgoing_pkt->len, outgoing_pkt->iface);

      outgoing_pkt = outgoing_pkt->next;
    }
    free(pkt);
    sr_arpreq_destroy(&(sr->cache), arpreq);
  }
}
示例#5
0
文件: sr_router.c 项目: c2birlar/yah
/*Does all handling of incoming ARP packets, returns 1 if successful*/
int handle_ARP_packet(struct sr_instance* sr, 
		      uint8_t* packet,
		      int len, 
		      char* interface){
  int minLenARP = sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arp_hdr); 
  if (len < minLenARP){
      fprintf(stderr, "Failed to access ARP header, too small\n");
      drop_packet = 1;
      //return;
    }
    if (drop_packet == 0){
      if (destinedToRouter(dest_ip)){
	sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)packet;
	sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet + (uint8_t) eth_size);

	if (ntohl(arp_header->ar_op) == arp_op_reply){//We have a ARP reply
	  //process reply
	  //move entries from ARP request queue to ARP cache
	  struct sr_arpreq* req;
	  req = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha,
				   ntohl(arp_header->ar_sip));
	  if (req!=NULL){
	     struct sr_packet* traverser = req->packets;
	     while(traverser != NULL){
	       //normal IP forward, no errors detected
	       //change old contents
	       struct sr_arpentry *arp_entry;
	       arp_entry = sr_arpcache_lookup(&(sr->cache),dest_ip);
	       sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)(packet + (uint8_t) eth_size);
	       sr_ethernet_hdr_t* out_eth = (sr_ethernet_hdr_t*)packet;
	       uint16_t modCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
	       int ret = ip_forward(sr,packet,len,out_eth,arp_entry->mac,
				    dest_ip, modCksum,interface);
	       if (ret!= 0){
		 fprintf(stderr, "Didn't send ip packet properly\n");

	       }

	       traverser = traverser->next;
	     }
	     sr_arpreq_destroy(&(sr->cache), req);
	  }
	}else{
	  //process ARP request and send reply 
	  //(they want our MAC address) so sends reply packet
	  int ret =  arp_send(sr,packet,len,
			      ethernet_hdr,arp_header,dest_ip);
	  if (ret!= 0){
	    fprintf(stderr, "Didn't send arp packet properly\n");

	  }
	}
      }else{
	//pass
	//forward packet
      }
    }
    return 1;
}
示例#6
0
void handle_arp_reply(struct sr_instance *sr, uint8_t* ethernet_data_addr, struct sr_if* in_f){
  printf("in handle arp reply\n");

/*
  The ARP reply processing code should move entries from the ARP request
   queue to the ARP cache:

   # When servicing an arp reply that gives us an IP->MAC mapping
   req = arpcache_insert(ip, mac)

   if req:
       send all packets on the req->packets linked list
       arpreq_destroy(req)
*/

  /*Loop through sr_cache requests and look for an IP match to the ARP header source IP*/

  sr_arp_hdr_t *arp_header = (sr_arp_hdr_t *) ethernet_data_addr;

  struct sr_arpreq *req_ptr = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha, arp_header->ar_sip);

  /*If the IP in the reply matched something in our request queue*/
  if (req_ptr) {
    struct sr_packet *req_pkts = req_ptr->packets;
    struct sr_packet *req_pkt_ptr = req_pkts;

    for (; req_pkt_ptr; req_pkt_ptr = req_pkt_ptr->next) {

      sr_ethernet_hdr_t *packet_eth_hdr = (sr_ethernet_hdr_t *) req_pkts->buf;
      sr_ip_hdr_t *packet_ip_hdr = (sr_ip_hdr_t *) (req_pkts->buf + sizeof(sr_ethernet_hdr_t));

      /*ret_if will be populated if this was originally an echo request, else 0*/
      struct sr_if* ret_if = sr_get_interface_from_ip(sr, packet_ip_hdr->ip_dst);
      
      if (ret_if) {
        /*Doesn't have a code so just passing 0 as code*/
        send_icmp_echo_reply(sr, (uint8_t *) packet_eth_hdr, req_pkt_ptr->len, in_f, arp_header->ar_sha, echo_reply_type, 0);
      }
      
      else {
        memcpy(packet_eth_hdr->ether_dhost, arp_header->ar_sha, ETHER_ADDR_LEN);
        sr_send_packet(sr, (uint8_t *) packet_eth_hdr, req_pkt_ptr->len, in_f->name);
      } 
    }
    sr_arpreq_destroy(&(sr->cache), req_ptr);
  }
  /*Otherwise do nothing, the reply wasn't about anything in our queue*/
}
示例#7
0
/*---------------------------------------------------------------------
 * Method: process_arp(struct sr_instance* sr,
 *      			         uint8_t * packet,
 *      				 			 unsigned int len,
 *     			     			 char* interface)
 * Scope:  Internal
 *
 * This function processes an arp packe that was received. It handles 
 * two cases, one where it is a request and one where it is a response.
 *
 *---------------------------------------------------------------------*/
void process_arp(struct sr_instance* sr,
       			     uint8_t * packet,
        				 unsigned int len,
       			     char* interface)
{
	struct sr_arpentry *arp_entry;
	struct sr_arpreq *arp_req;
	struct sr_arp_hdr *arp_hdr;
	struct sr_if* rec_if;
	
	/* Validate the arp packet */
	if (!valid_arp(packet, len))
		return;
	
	/* Is the arp addressed to me? NOTE: I do not follow the RFC recommendation to
	 * update existing cache entries with the received arp packet's ip-mac mapping 
	 * before checking whether the packet was addressed me. This is because we do 
	 * not have a good way to strictly 'update' cache entries without inserting a new 
	 * one and I would like to avoid duplicate valid cache entries for the same ip. */
	rec_if = sr_get_interface(sr, interface);
	arp_hdr = arp_header(packet);
	if (rec_if->ip != arp_hdr->ar_tip)
		return;
		
	/* Add the sender's protocol address to my table. */
	arp_entry = sr_arpcache_lookup(&sr->cache, arp_hdr->ar_sip);
	
	/* Arp entry already exists. NOTE: arp_entry is a copy in this case so free it.*/
	if (arp_entry != 0) {
		free(arp_entry);
	
	/* Arp entry doesn't exist so add it. */
	} else {
		arp_req = sr_arpcache_insert(&sr->cache, arp_hdr->ar_sha, arp_hdr->ar_sip);
		
		/* There are packets waiting on this arp request. Send them. */
		if (arp_req != 0) {
			sr_arpreq_send_packets(sr, arp_req);
		}
	}
		
	/* Handle a request. */
	if (arp_opcode(arp_hdr) == arp_op_request) {
		process_arp_request(sr, arp_hdr, rec_if);
	}
}
示例#8
0
void sr_recv_arp(struct sr_instance *sr, struct sr_arp_hdr *arp){
    struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arp->ar_sha, arp->ar_sip);
    if(req){

        struct sr_packet *packet = req->packets;
        while(packet){

            sr_attempt_send(sr, req->ip, packet->buf, packet->len, packet->iface);


            packet = packet->next;
        }

        sr_arpreq_destroy(&(sr->cache), req);

    }

}
示例#9
0
int handle_arp_reply(struct sr_instance * sr, uint8_t * packet, unsigned int len){

      struct sr_arp_hdr *arp_hdr = (struct sr_arp_hdr *)(packet + sizeof(sr_ethernet_hdr_t));
      struct sr_arpentry *arpentry = sr_arpcache_lookup(&(sr->cache),arp_hdr->ar_sip);

      /* if entry isn't already in cache */
      if (arpentry) {

            return 0;
      }
      struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip);

      /* if there were requests pending on this IP */
      if(!req){
           
            return 0;
      }

      struct sr_packet * to_send = req->packets;
      struct sr_ethernet_hdr * ethr_to_send;
      int res;

      /* send all packets waiting on this IP */
      while (to_send){

            /* update the mac address of each ethernet frame */
            ethr_to_send = (struct sr_ethernet_hdr *) to_send->buf;
            memcpy(ethr_to_send->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);

            res = sr_send_packet(sr, to_send->buf, to_send->len, to_send->iface);

            if (res != 0){
                
                  continue;
            }
            to_send = to_send->next;
      }
      return 0;
}
示例#10
0
/*
 * handle arp reply
 */
void sr_handle_arpreply(struct sr_instance* sr, unsigned char *mac, uint32_t ip, struct sr_if* iface)
{
	/*      
	if(ip == 167985324)
	{return;}
	*/
	 Debug("\nhandle_arpreply called\n");
	 Debug("mac: %s, ip: %d, interface: %s", mac, ip, iface->name); 
	    struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), mac, ip);

	
        struct sr_packet *packet;
        if(req)
		{
            Debug("\nhandle_arpreply -> sending out packets waiting for the arp_reply\n");
	    
            for(packet = req->packets; packet != NULL; packet = packet->next)
			{
		int i;
           	 for (i = 0; i < ETHER_ADDR_LEN; i++)
                        {
                packet->buf[i]= mac[i];
            }
                printf("---------------before send packet----------------\n");
				print_hdrs(packet->buf, packet->len);
				sr_send_packet(sr, packet->buf, packet->len, iface->name);    
                /*printf("--------------------i-------------------------: %d\n", i);i++;*/
				/*free(packet->buf);*/
		
            }

			sr_arpreq_destroy(&(sr->cache), req);
			Debug("Hey, finished sending packets");

        }
}
示例#11
0
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */,
					unsigned int len, char* interface/* lent */) {
	/* Function implemented by g1izzyw and gustan50404 */
	/* REQUIRES */
	assert(sr);
	assert(packet);
	assert(interface);
	
	struct sr_if *ether_interface = (struct sr_if *) sr_get_interface(sr, interface); 
	
	/* Check if it an ethernet interface. */
	if (ether_interface) {
		/* Now we deal with the ethernet header */
		struct sr_ethernet_hdr *ether_hdr = (struct sr_ethernet_hdr *) packet;
	    
		/* Check to see if we are dealing with an ARP request/reply */
		if (ether_hdr->ether_type == htons(ethertype_arp)) {
			
			fprintf(stderr, "We Got an ARP Packet\n");
			/* Handle ARP for ethernet */ 
			struct sr_arp_hdr * arp_hdr = (struct sr_arp_hdr *)(packet + sizeof(struct sr_ethernet_hdr));
			if (arp_hdr->ar_hrd == htons(arp_hrd_ethernet)) {

				if (arp_hdr->ar_op == htons(arp_op_request)) {
				/* arp request */
					struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip);	
					if (interface_for_ip) {
  			
						/* Target ip is one of the router interfaces */
						fprintf(stderr, "ARP req for one of our interfaces\n");

						/* Now we want to make an arp reply and send it back */
						uint8_t *buf = (uint8_t *) malloc(len);
						memcpy(buf, packet, len);
    			
						/*Make Arp Header*/
						make_arprply_hdr(interface_for_ip->addr, arp_hdr->ar_sha, interface_for_ip->ip,
														arp_hdr->ar_sip, buf);
														
						/*Make Ethernet Header*/
						make_ether_hdr(interface_for_ip->addr, ether_hdr->ether_shost, ethertype_arp, buf);

						/* Now we send the packet */
						sr_send_packet(sr, buf, len, interface_for_ip->name);
						free(buf);
						fprintf(stderr, "ARP reply sent\n");
					}
				} else if (arp_hdr->ar_op == htons(arp_op_reply)) {

					fprintf(stderr, "We got an ARP Reply, need to check for intfc tho \n");
					/* arp reply */
					struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip);	
					if (interface_for_ip) {
			
						fprintf(stderr, "We got an ARP Reply for one of our interfaces\n");
						/*We first want to insert into Arp cache*/
						struct sr_arpreq *request = sr_arpcache_insert(&(sr->cache), 
																		arp_hdr->ar_sha, 
																		arp_hdr->ar_sip);
						fprintf(stderr, "Signalling all waiting packets\n");
						if (request) {
							struct sr_packet *cur_packet = request->packets;
							while(cur_packet) {
								fprintf(stderr, "About to forward \n");
								print_hdrs(cur_packet->buf, cur_packet->len);
								forward_packet(sr, cur_packet->iface, arp_hdr->ar_sha, 
															cur_packet->len, cur_packet->buf); 
								fprintf(stderr, "Packet Forwarded\n");							
								cur_packet = cur_packet->next;
							}
						}
					}
				}		
			}      
    	} else if (ether_hdr->ether_type == htons(ethertype_ip)) {
					
			/* Get the ip header from the ethernet header*/
			sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
			/*IP Checksum Stuff*/
			uint16_t temp_ip_sum = ip_hdr->ip_sum;
			ip_hdr->ip_sum = 0;
			ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));																	
			if (temp_ip_sum == ip_hdr->ip_sum) {
			
				/*We got here means IP Cheksum is alright, so we extract the interface*/
				struct sr_if *interface_for_ip = get_interface_for_ip(sr, ip_hdr->ip_dst);
				
				/*Check to make sure interface is one of ours*/
				if (interface_for_ip) {
					
					fprintf(stderr, "IP Packet destined towards our interface\n");
					/*Check if our IP packet is UDP or TCP*/
					if (ip_hdr->ip_p == 6 || ip_hdr->ip_p == 17) {
						fprintf(stderr, "We Got TCP or UDP, sending ICMP error msg\n");
						send_icmp_error(3, 3, sr, interface, len, packet);
					
					} else {
						
						/* Get the ICMP header */
						sr_icmp_hdr_t *icmp_hdr = (struct sr_icmp_hdr *) (packet + 
																		sizeof(sr_ethernet_hdr_t) + 
																		sizeof(sr_ip_hdr_t));
						
						/*Now we do the ICMP checksum chek*/
						/*This covers the ICMP echo case*/
						uint16_t temp_icmp_sum = icmp_hdr->icmp_sum;
						temp_icmp_sum = icmp_hdr->icmp_sum;
						icmp_hdr->icmp_sum = 0;
						if (temp_icmp_sum == cksum(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), 
												len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t))) {
							/*Everything is fine so we send an ICMP echo back*/
							fprintf(stderr, "Sending ICMP echo reply\n");
	    					send_icmp_echo(sr, interface, len, packet);
	    				}
	    			}
				} else {
					/*IP Packet not destined towards one of our interfaces*/
					
					fprintf(stderr, "IP packet not destined to our interface\n");
					/*Decremenrt TTL by 1*/
					
					fprintf(stderr, "TTL modified \n");
					print_hdrs(packet, len);
					if (ip_hdr->ip_ttl <= 1) {
						fprintf(stderr, "Packte with TTL < 0 found, sending ICMP error \n");
						/*TTL is less than 0 so send an ICMP ERROR*/
						send_icmp_error(11, 0, sr, interface, len, packet);
						
					} else {
						
						/*Recompute Checksum over new header TTL is fine*/
						/*Check if it exists in the routing table*/
						ip_hdr->ip_ttl = ip_hdr->ip_ttl - 1;
						fprintf(stderr, "Recomputing Checksum after modifying TTl\n");
						ip_hdr->ip_sum = 0;																			
						ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t));
						struct sr_if *dst_if = (struct sr_if *)malloc(sizeof(struct sr_if));
						dst_if = next_hop(sr, interface, ip_hdr->ip_dst);
						
						if (!(dst_if)) {
						
							fprintf(stderr, "IP packet has no longest matching prefix sending ICMP error\n");
							/*dst ip has no longest macthing prefix*/
							/*So we send a type 3 code 0 ICMP error*/
							send_icmp_error(3, 0, sr, interface, len, packet);
							
						} else {
							
							/*This is the case where we do have a longest macthing prefix*/
							fprintf(stderr, "Found Longest mathcing prefix in RT\n");
							struct sr_arpcache *cache = &(sr->cache);
							struct sr_arpentry *in_cache = sr_arpcache_lookup(cache, ip_hdr->ip_dst);
							if (in_cache) {
							
								fprintf(stderr, "Found IP->MAC mapping in ARP cache forwarding packet \n");
								/*this is the case where ip->mac maping is already in cache*/
								forward_packet(sr, dst_if->name, in_cache->mac, len, packet);
								free(in_cache);
								
							} else {
							
								fprintf(stderr, "IP->MAC mapping not in ARP cache %u \n", ip_hdr->ip_dst);
								/*Case where ip->mapping is not in cache*/
								sr_arpcache_queuereq(cache, ip_hdr->ip_dst, packet, len, dst_if->name);
								fprintf(stderr, "Added Arp Req to queu \n"); 						
							}
						}					
					}
				}
			}
		}
	} 
	
} /* end sr_ForwardPacket */
示例#12
0
void sr_natHandleIP(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 one of my 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;
      ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28));
      free(icmp_packet);      
    } else if(ipHeader->ip_p==6){  /* IP TCP */
      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;
      ipHeader->ip_len = htons(20+8+(len-34<28?len-34:28));
      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 = 64;
    ipHeader->ip_sum = 0;
    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;
    }
  }
}
示例#13
0
void sr_handlepacket_arp(struct sr_instance* sr,
        sr_ethernet_hdr_t* eth_hdr,
        uint8_t* packet/* not even a malloc pointer */,
        unsigned int len,
        char* interface/* lent */)
{
    /* puts("handling ARP header"); */
    sr_arp_hdr_t *arp_hdr;

    /* REQUIRES */
    assert(packet);

    if (len < sizeof(sr_arp_hdr_t)) {
        /* puts("Ethernet payload (claiming to contain ARP) is smaller than ARP header. Discarding."); */
        return;
    }

    arp_hdr = (sr_arp_hdr_t*)packet;

    char* temp_ip = ip_to_str(arp_hdr->ar_sip);
    /* printf("from (network order) %s\n",temp_ip); */
    free(temp_ip);

    /* Endianness */
    unsigned short ar_op = ntohs(arp_hdr->ar_op);

    switch (ar_op) {

        /*
         * ARP Request handling
         */

        case arp_op_request:
            {
                /* puts("received ARP OP request."); */

                /* The VNS transport layer shouldn't allow any ARP packets that aren't for our
                 * interface, but it's still worth checking, just in case something goes wrong
                 * or *gasp* we write a unit test about it */

                struct sr_if* iface = sr_get_interface(sr, interface);
                if (iface->ip == arp_hdr->ar_tip) {

                    /* Flip around the source and destination IP, keeping both in network order */

                    uint32_t ip_buf = arp_hdr->ar_tip;
                    arp_hdr->ar_tip = arp_hdr->ar_sip;
                    arp_hdr->ar_sip = ip_buf;

                    /* Flip around source and dest MAC on the ETH header */

                    uint8_t ether_buf[ETHER_ADDR_LEN];
                    memcpy(ether_buf,eth_hdr->ether_shost,ETHER_ADDR_LEN);
                    memcpy(eth_hdr->ether_shost,iface->addr,ETHER_ADDR_LEN);
                    memcpy(eth_hdr->ether_dhost,ether_buf,ETHER_ADDR_LEN);

                    /* Flip around eth on ARP header */

                    memcpy(ether_buf,arp_hdr->ar_sha,ETHER_ADDR_LEN);
                    memcpy(arp_hdr->ar_sha,iface->addr,ETHER_ADDR_LEN);
                    memcpy(arp_hdr->ar_tha,ether_buf,ETHER_ADDR_LEN);

                    /* Change ARP operation to a reply */

                    arp_hdr->ar_op = htons(arp_op_reply);

                    /* Send the modified packet back out */

                    /* puts("sending ARP OP reply"); */
                    sr_send_packet(sr, (uint8_t*)eth_hdr, len + sizeof(sr_ethernet_hdr_t), interface);
                }
                else {
                    /* puts("ARP request received that's not for us."); */
                }

                break;
            }

        /*
         * ARP Reply handling
         */

        case arp_op_reply:
            {
                /* puts("received ARP OP reply."); */

                /* Insert the new IP->MAC mapping into the cache, using network endianness for IP */

                struct sr_arpreq* req = sr_arpcache_insert(&(sr->cache),eth_hdr->ether_shost,arp_hdr->ar_sip);

                /* If there were requests waiting on this mapping */

                if (req) {
                    struct sr_packet* packet_walker = req->packets;
                    while (packet_walker) {

                        /* Send the packet, which will do the lookup against the ARP table we just filled with the answer */

                        sr_try_send_ip_packet(sr, packet_walker->ip_dst, packet_walker->ip_src, packet_walker->payload, packet_walker->ip_hdr);

                        /* Remove the reference to the packet on this buffered request */

                        packet_walker->payload = NULL;
                        
                        /* Continue walking the linked list */

                        packet_walker = packet_walker->next;
                    }

                    /* Free the memory associated with these requests */

                    sr_arpreq_destroy(&(sr->cache),req);
                }
                else {
                    /* puts("no cached requests waiting on this ARP."); */
                }
                break;
            }
    }
}
示例#14
0
void sr_handlepacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  	/* REQUIRES */
	assert(sr);
	assert(packet);
	assert(interface);
	
	printf("*** -> Received packet of length %d \n",len);

	sr_ethernet_hdr_t* eth_header = (sr_ethernet_hdr_t*)packet;
	/* printf("The type is %x\n",ntohs(eth_header->ether_type));*/

	if( ntohs(eth_header->ether_type) == IP_PROTOCOL)
	{
		/* Its an IP Packet */
		printf("Its an IP Packet\n");
		/* Check the checksum of the packet */
		uint8_t* ip_packet = packet + sizeof(sr_ethernet_hdr_t);
		if(check_checksum(ip_packet,sizeof(sr_ip_hdr_t)) == 0)
		{
			/* Handle ICMP Error message */
			return;
		}
		else
		{
			/* Checksum is fine, Now do the functions */
			sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)ip_packet;
			/*print_hdr_ip(ip_packet);*/
			if( decrement_TTL(ip_header) == 0 )
			{
				/* Send ICMP packet for Time Limit Exceeded*/
				
				ip_header->ip_sum = 0;
				ip_header->ip_ttl = 1;
				ip_header->ip_sum = cksum(ip_packet,sizeof(sr_ip_hdr_t));
				/*make_ICMP_packet();
				make_IP_packet();*/
				/* Check wheather the Destination is this router  */
				if( check_match_all_interfaces ( sr->if_list, ip_header->ip_dst) == 1 )
				{
					printf("I am here in TTL 0 \n\n\\n");
					uint8_t protocol = ip_header->ip_p;
					if( protocol == TCP_PROTOCOL || protocol == UDP_PROTOCOL)
					{
						/* This is having UDP or TCP as payload */
						/* So, just include this packet as payload and send the ICMP packet */
						handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),3,3,interface,1);
					}
					else
					{
						/* Its ICMP protocol */
						/* Check if it is echo request , If it is then send echo reply */
						sr_icmp_hdr_t* icmp = (sr_icmp_hdr_t*)(ip_packet+sizeof(sr_ip_hdr_t));
						if( icmp->icmp_type == 8 && icmp->icmp_code == 0)
						{
							
							int length = len - sizeof(sr_ethernet_hdr_t);
							uint8_t* data = 0;
			uint8_t* icmp_start = make_ICMP_packet_echo(ip_packet+sizeof(sr_ip_hdr_t),length-sizeof(sr_ip_hdr_t));
			uint8_t* ip_start = make_IP_packet( *((uint8_t*)ip_header), ip_header->ip_tos, htons(length), \
							ip_header->ip_id,ip_header->ip_off, 64, ip_header->ip_p,\
							ip_header->ip_dst, ip_header->ip_src);
							uint8_t* final_packet = (uint8_t*)malloc(len);
							memcpy(final_packet,ip_start,sizeof(sr_ip_hdr_t));
						memcpy(final_packet + sizeof(sr_ip_hdr_t),icmp_start,\
								length-sizeof(sr_ip_hdr_t));
						free(ip_start);
						free(icmp_start);	
						forward_packet(sr,final_packet,length,interface);
						}
						else
							handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),11,0,interface,1);
					}
				}
				else
				{
					handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),11,0,interface,0);
				}
				return;
			}
			/* Calculate new checksum after TTL updation */
			ip_header->ip_sum = 0;
			ip_header->ip_sum = cksum(ip_packet,sizeof(sr_ip_hdr_t));

			/*print_hdr_ip(ip_packet);*/
			/* Check if the packet is destined to any of its interfaces */
			/* Dont free this */
			if( check_match_all_interfaces ( sr->if_list, ip_header->ip_dst) == 1 )
			{
				/* Now its destined to router, so router should handle it 
				It Should check for the Transport layer protocol and should appropriately send ICMP packets*/
				router_handle_packet(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),interface);
			}
			else
			{
				/* 
					Packet is subjected to NAT translation first and then forwarded 
					1) Check if there are any existing sessions for this packet, if any use them to translate the packets
					2) If there aren't any, then allocate a new session and translate the packet.
				*/
				
				forward_packet(sr,ip_packet,len,interface);
			}
		}
	}
	else
	{
		printf("Its an ARP Packet\n");
		/* Its an ARP Packet */

		uint8_t* arp_packet = packet + sizeof(sr_ethernet_hdr_t);
		/* Construct ARP structure */
		sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)arp_packet;
		
		/* Check if the packet is request to the router */
		int dst_ip = ntohl(arp_header->ar_tip);
		
		struct sr_if* arp_interface = sr_get_interface(sr,interface);
		int interface_ip = ntohl(arp_interface->ip);

		if( dst_ip == interface_ip )
		{
			/* It is destined correctly */

			uint8_t op_code = ntohs(arp_header->ar_op);
		
			if( op_code == 1 )
			{
				/* ARP Request */
				uint8_t* arp_reply_packet;
				arp_reply_packet = (uint8_t*)malloc(sizeof(sr_ethernet_hdr_t)+1500);
				bzero(arp_reply_packet,sizeof(sr_ethernet_hdr_t)+1500);
				/* Create both ethernet and ARP structures */
				sr_ethernet_hdr_t* new_eth = (sr_ethernet_hdr_t*)arp_reply_packet;
				/* Fill in all the details of ethernet frame */
				memcpy(new_eth->ether_dhost,eth_header->ether_shost,sizeof(uint8_t)*6);
				memcpy(new_eth->ether_shost,arp_interface->addr,sizeof(uint8_t)*6);
				new_eth->ether_type = htons(ARP_PROTOCOL);

				/* Fill in all the details of ARP */
				uint8_t* arp_reply_segment  = arp_reply_packet+ sizeof(sr_ethernet_hdr_t);
				memcpy(arp_reply_segment,arp_packet,sizeof(sr_arp_hdr_t));
				sr_arp_hdr_t* arp_reply_structure = (sr_arp_hdr_t*)arp_reply_segment;
				arp_reply_structure->ar_op = htons(2);
				memcpy(arp_reply_structure->ar_sha,arp_interface->addr,sizeof(uint8_t)*6);
				memcpy(arp_reply_structure->ar_tha,eth_header->ether_shost,sizeof(uint8_t)*6);
				arp_reply_structure->ar_sip = arp_interface->ip;
				arp_reply_structure->ar_tip = arp_header->ar_sip;
				/* Now send the packet */
				/* Beaware of the size of the frame, it should not be sizeof(arp_reply_packet)
				But the size used below */
				sr_send_packet(sr,arp_reply_packet,sizeof(sr_ethernet_hdr_t)+1500,interface);
			}
			else if( op_code == 2 )
			{
				/* ARP Reply */
				uint8_t* MAC = (uint8_t*)malloc(sizeof(uint8_t)*6);
				uint32_t IP;
				memcpy(MAC,arp_header->ar_sha,sizeof(uint8_t)*6);
				IP = arp_header->ar_sip;
				struct sr_arpreq* queue = sr_arpcache_insert(&sr->cache,MAC,IP);
				if( queue == NULL )
				{
					assert(queue!=NULL);
				}
				else
				{
					struct sr_packet* packet_i = queue->packets;
					while( packet_i!= NULL )
					{
						sr_ethernet_hdr_t* head = (sr_ethernet_hdr_t*)(packet_i->buf);
						memcpy(head->ether_dhost,MAC,sizeof(uint8_t)*6);
						sr_send_packet(sr,packet_i->buf,packet_i->len,packet_i->iface);
						packet_i = packet_i->next;
					}
					sr_arpreq_destroy(&sr->cache,queue);
				}
			}
		}
	}
}/* end sr_ForwardPacket */
示例#15
0
void sr_handlepacket(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
  /* REQUIRES */
  assert(sr);
  assert(packet);
  assert(interface);

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

  print_hdrs(packet, len);

  sr_arp_hdr_t* arpHdr = (sr_arp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
  sr_ethernet_hdr_t* ethHdr = (sr_ethernet_hdr_t*)packet;
  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));
 

  struct sr_rt* route = sr->routing_table;
  struct sr_arpentry* ent;
  char ifBuf[INET_ADDRSTRLEN];
  char ipBuf[INET_ADDRSTRLEN];



  if(strcmp(arpHdr->ar_tha, "\0") == 0){
    sr_arpcache_queuereq(&(sr->cache), arpHdr->ar_tip, packet, len, interface);
    printf("added arpreq to queue.\n\n");
    return;
  }
  printf("arp rep: %d\n", ntohs(arpHdr->ar_op));
  printf("opcode: %d\n", arp_op_reply);
  if(ntohs(arpHdr->ar_op) == arp_op_reply){
    ent = sr_arpcache_lookup(&sr->cache, arpHdr->ar_sip);
    if( ent == NULL){
      //      printf("Added %s to cache\n", ntohl(arpHdr->ar_sip));
      printf("Incoming arp response\n");
      //      sleep(2);
      

      struct sr_arpreq* req = sr->cache.requests;
      printf("%p, %p\n", req, sr->cache.requests);
      while(req != NULL){
	if(req->ip == arpHdr->ar_sip){
	  struct sr_packet* pkt = req->packets;
	  while(pkt != NULL){
	    if(route != NULL){
	      do{
		sr_ip_hdr_t* reqIpHdr = (sr_ip_hdr_t*)(pkt->buf + sizeof(sr_ethernet_hdr_t));
		sr_ethernet_hdr_t* reqEthHdr = (sr_ethernet_hdr_t*)(pkt->buf);
		//      sr_print_routing_entry(route);
		inet_ntop(AF_INET, &route->dest, ifBuf, sizeof(char) * INET_ADDRSTRLEN);
		convert_addr_ip_int(ntohl(reqIpHdr->ip_dst), ipBuf);
		printf("%s dest: %s\n",route->interface, ifBuf);
		printf("ip dest: %s\n", ipBuf);
		if(strcmp(ifBuf, ipBuf) == 0){
		  
		  memcpy(reqEthHdr->ether_shost, (uint8_t*)(sr_get_interface(sr, route->interface)->addr), sizeof(uint8_t) * ETHER_ADDR_LEN);
		  memcpy(reqEthHdr->ether_dhost, (uint8_t*)arpHdr->ar_sha, sizeof(uint8_t) * ETHER_ADDR_LEN);
		  print_hdrs(pkt->buf, pkt->len);
		  sr_send_packet(sr, pkt->buf, pkt->len, &(route->interface));
		  printf("pkt sent down %s\n\n", route->interface);
		  //	  free(ent);
		  //return;
		  break;
		}
		route = route->next;
	      } while(route != NULL);
	      pkt = pkt->next;
	    }

	  }
	  free(ent);
	  sr_arpreq_destroy(&sr->cache, req);
	  break;
	}
	req = req->next;
      }

    }
    sr_arpcache_insert(&(sr->cache), arpHdr->ar_sha, arpHdr->ar_sip);  




    //sr_arpcache_dump(&sr->cache);
    free(ent);
    return;
  }

  ent = sr_arpcache_lookup(&sr->cache, ipHdr->ip_dst);
  route = sr->routing_table;
  //Make and queue requests if dest isn't in arpcache
  if( ent == NULL ){
    if(route != NULL){
      do{
	inet_ntop(AF_INET, &route->dest, ifBuf, 100);
	convert_addr_ip_int(ntohl(ipHdr->ip_dst), ipBuf);
	if(strcmp(ifBuf, ipBuf) == 0){
	  sr_arpcache_queuereq(&sr->cache, ipHdr->ip_dst, packet, len, route->interface);
	  free(ent);
	  return;
	}
	route = route->next;
      } while(route != NULL);
      sr_arpcache_queuereq(&sr->cache, ipHdr->ip_dst, packet, len, "eth1");

    }
  }

  //Forwards packet to interface
  if(route != NULL){
    do{
      //      sr_print_routing_entry(route);
      inet_ntop(AF_INET, &route->dest, ifBuf, sizeof(char) * INET_ADDRSTRLEN);
      convert_addr_ip_int(ntohl(ipHdr->ip_dst), ipBuf);
      printf("%s dest: %s\n",route->interface, ifBuf);
      printf("ip dest: %s\n", ipBuf);
      if(strcmp(ifBuf, ipBuf) == 0){
	
	memcpy(ethHdr->ether_shost, (uint8_t*)(sr_get_interface(sr, route->interface)->addr), sizeof(uint8_t) * ETHER_ADDR_LEN);
	memcpy(ethHdr->ether_dhost, (uint8_t*)ent->mac, sizeof(uint8_t) * ETHER_ADDR_LEN);
	print_hdrs(packet, len);
	sr_send_packet(sr, packet, len, &(route->interface));
	printf("pkt sent down %s\n\n", route->interface);
	free(ent);
	return;
      }
      route = route->next;
    } while(route != NULL);
  }

  free(ent);
  


}/* end sr_ForwardPacket */
示例#16
0
void arp_handlepacket(struct sr_instance *sr,
        uint8_t *packet,
        unsigned int len,
        char *interface) 
{
    printf("** Recieved ARP packet\n");

    /* Initalize ARP header from the Packet */
    struct sr_arp_hdr *arp_hdr = arp_header(packet);
    /* Interface the packet arrived in */
    struct sr_if *r_iface = sr_get_interface(sr,interface);

    /* Check if interface->ip = arp header->ip */
    if (r_iface->ip != arp_hdr->ar_tip){
      return;
    }

    /* validate ARP packet */
    if (!arp_validpacket(packet, len))
      return;

    if (ntohs(arp_hdr->ar_op) == arp_op_request){

      if(sr_arp_req_not_for_us(sr, packet, len, interface))
        return;

      printf("** ARP packet request to me \n");   
      
      /* Build and send ARP packet  */
      build_arp_reply(sr, arp_hdr, r_iface);
      
    } else if (ntohs(arp_hdr->ar_op) == arp_op_reply) {
        printf("** ARP packet reply to me\n");

        struct sr_arpentry *arp_entry;
        struct sr_arpreq *arp_req;
        struct sr_if *s_interface;
        struct sr_packet *pkt_wait;
        struct sr_packet *temp;
        uint8_t *send_packet;
        unsigned int eth_pkt_len;

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

        if (arp_entry != 0){
          free(arp_entry);
        } else {
            arp_req = sr_arpcache_insert(&sr->cache, arp_hdr->ar_sha, arp_hdr->ar_sip);

            printf("** ARP entry created\n");

            /* Check ARP request queue, if not empty send out packets on it*/
            if (arp_req != 0) {
              pkt_wait = arp_req->packets;

              while (pkt_wait != 0) {

                printf("** ARP resolved, sending queued packets\n");
                /* Send the packets out */
                s_interface = sr_get_interface(sr, pkt_wait->iface);
                struct sr_ethernet_hdr sr_ether_hdr;

                /* Construct the ethernet packet */
                sr_ether_hdr.ether_type = htons(ethertype_ip);
                memcpy(sr_ether_hdr.ether_shost, s_interface->addr, ETHER_ADDR_LEN);
                memcpy(sr_ether_hdr.ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);

                /* Copy the packet into the sender buf */
                eth_pkt_len = pkt_wait->len + sizeof(struct sr_ethernet_hdr);
                send_packet = malloc(eth_pkt_len);
                memcpy(send_packet, &sr_ether_hdr, sizeof(struct sr_ethernet_hdr));
                memcpy(send_packet + sizeof(struct sr_ethernet_hdr), 
                      pkt_wait->buf, pkt_wait->len);

                sr_send_packet(sr, send_packet, eth_pkt_len, s_interface->name);

                temp = pkt_wait;
                pkt_wait = pkt_wait->next;
                free(temp);
              }

	    printf("** All queued packets sent\n");

            } 
          }   
      }
}
示例#17
0
void sr_handlearp(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        struct sr_if* iface/* lent */) {

  if (len < ( sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t) )) {
    fprintf(stderr, "Failed to process ARP header, insufficient length\n");
    return;
  }

  fprintf(stderr, "sr_handlearp: begin\n");

  sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  int isRequest = (ntohs(arp_hdr->ar_op) == arp_op_request);

  fprintf(stderr, "sr_handlearp: isRequest = 1\n");

  if (iface->ip != arp_hdr->ar_tip)  /* Not for me - ignore it */ {
    fprintf(stderr, "sr_handlearp: Not for me - ignore it\n");
    return;
  }

  if (isRequest) {  

    /* For me - genernate a reply */
    sr_send_arpreply(sr, arp_hdr, iface);

  } else {

    /* Reply - Add to ARP cache (Caches only if target is me) */
    /* This method performs two functions:
     1) Looks up this IP in the request queue. If it is found, returns a pointer
        to the sr_arpreq with this IP. Otherwise, returns NULL.
     2) Inserts this IP to MAC mapping in the cache, and marks it valid. */
    fprintf(stderr, "sr_handlearp: ARP Reply Received.\n");

    struct sr_arpreq *req = sr_arpcache_insert(&sr->cache, 
      (unsigned char *)(arp_hdr->ar_sha), 
      arp_hdr->ar_sip);

    if (req == NULL)
      return;

    /* Send out queued packets */
    struct sr_packet *pktq = req->packets;
    struct sr_packet *p_pkt;

    while (pktq != NULL) {
      p_pkt = pktq;

      /* Send out queued packet */
      struct sr_if* iface_s = sr_get_interface(sr, p_pkt->iface);
      assert(iface_s);
      sr_send_inetpkt(sr, p_pkt->buf, p_pkt->len, iface_s, 0);

      pktq = pktq->next;
      free(p_pkt);
    }

    free(req);
  }
}
示例#18
0
void sr_handle_arp_packet(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */,
        struct sr_if* iface)
{
  if (len < (sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)))
  {
    printf("Invalid ARP packet, insufficient length.\n");
    return;
  }

  /* ARP header */
  sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
  
  if (arp_hdr->ar_tip == iface->ip)
  {
    /* Received ARP Request */
    if (ntohs(arp_hdr->ar_op) == arp_op_request) 
    {
      /* Contruct ARP reply */
      printf("Received ARP request. Reply is being sent.\n");

      uint8_t* reply_arp_packet = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t));
      sr_ethernet_hdr_t* reply_ethernet_hdr = (sr_ethernet_hdr_t*)reply_arp_packet;
      sr_arp_hdr_t* reply_arp_hdr = (sr_arp_hdr_t*)(reply_arp_packet + sizeof(sr_ethernet_hdr_t));

      /* Ethernet header */
      memcpy(reply_ethernet_hdr->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);
      memcpy(reply_ethernet_hdr->ether_shost, iface->addr, ETHER_ADDR_LEN);
      reply_ethernet_hdr->ether_type = htons(ethertype_arp);

      /* ARP Header */
      reply_arp_hdr->ar_hrd = htons(arp_hrd_ethernet);
      reply_arp_hdr->ar_pro = htons(ethertype_ip);
      reply_arp_hdr->ar_hln = ETHER_ADDR_LEN;
      reply_arp_hdr->ar_pln = IP_ADDR_LEN;
      reply_arp_hdr->ar_op = htons(arp_op_reply);
      memcpy(reply_arp_hdr->ar_sha, iface->addr, ETHER_ADDR_LEN);
      reply_arp_hdr->ar_sip = iface->ip;
      memcpy(reply_arp_hdr->ar_tha, arp_hdr->ar_sha, ETHER_ADDR_LEN);
      reply_arp_hdr->ar_tip = arp_hdr->ar_sip;

      /* Send reply packet */
      sr_send_packet(sr, (uint8_t*)reply_arp_packet, (sizeof(sr_ethernet_hdr_t) 
        + sizeof(sr_arp_hdr_t)), interface);

      free(reply_arp_packet);
    }

    /* Received ARP Reply */
    else if (ntohs(arp_hdr->ar_op) == arp_op_reply)
    {
      /* Insert into ARP cache */
      printf("Received ARP reply. \n");
      struct sr_arpreq* request_pointer = sr_arpcache_insert(&sr->cache, 
        arp_hdr->ar_sha, ntohl(arp_hdr->ar_sip));

      if (request_pointer != NULL)
      {
        /* Send all oustanding packets from request */
        while (request_pointer->packets != NULL)
        {
          /* Set new Ethernet frame destination address */
          struct sr_packet* current_packet = request_pointer->packets;
          memcpy(
            ((sr_ethernet_hdr_t*) current_packet->buf),
            arp_hdr->ar_sha, ETHER_ADDR_LEN);

          sr_send_packet(sr, (uint8_t*)current_packet->buf, current_packet->len, current_packet->iface);

           /* Iterate to the next packet */
          request_pointer->packets = request_pointer->packets->next;

          /* Free sent packets */
          free(current_packet->buf);
          free(current_packet->iface);
          free(current_packet);
        }
        sr_arpreq_destroy(&sr->cache, request_pointer);
      }
      else
      {
        printf("Received ARP reply, missing associated ARP request.");
      }
    }
  }
}
示例#19
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));
}
示例#20
0
文件: sr_router.c 项目: cpomz/router
/*---------------------------------------------------------------------
 * Method: process_arp_packet(struct sr_instance* sr,
    uint8_t *packet_buffer,
    unsigned int len,
    char* interface) 
 * Scope:  Global
 *
 * function to process the arp packet
 *
 *---------------------------------------------------------------------*/
int process_arp_packet(
    struct sr_instance* sr,
    uint8_t *packet_buffer,
    unsigned int len,
    char* interface) {

  assert(sr);
  assert(packet_buffer);
  assert(interface);
  int etherLen = sizeof(sr_ethernet_hdr_t); //ethernet header size
  int ipLen = sizeof(sr_ip_hdr_t); //ip header length
  int arpLen  = sizeof(sr_arp_hdr_t); //arp header length
  if (len <  etherLen + arpLen) {
    fprintf(stderr, "Error: ARP header - insufficient length\n");
    return -1;
  }
  printf("ARP Packet Processing Initiated\n");
  // print_hdr_arp(packet + sizeof(sr_ethernet_hdr_t));

  // Create ARP Header and find interface
  sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet_buffer +  etherLen);
  struct sr_if* my_interface = sr_find_interface(sr, arp_header->ar_tip);

  if (my_interface) {
    printf("Found Interface: ");
    sr_print_if(my_interface);

    if (strcmp(my_interface->name, interface) == 0) {
      printf("Interface name's match up\n");
      unsigned short op_code = ntohs(arp_header->ar_op);

      if (op_code == arp_op_reply) { // Process ARP Reply 
        printf("Processing ARP Reply\n");

        // See if there's an ARP request in the queue. 
        struct sr_arpreq* req = sr_arpcache_insert(
            &(sr->cache), arp_header->ar_sha, arp_header->ar_sip);

        // Forward all packets waiting on req if req exists. 
        struct sr_packet* pckt = req ? req->packets : NULL;
        for (; pckt != NULL; pckt = pckt->next) {
          eth_frame_send_with_mac(
              sr, pckt->buf, pckt->len, arp_header->ar_sha, pckt->iface);
        }
      } else if (op_code == arp_op_request) { // Process ARP Request 
        printf("Processing ARP Request\n");

        // Set the target to the incoming ARP source. 
        memcpy(arp_header->ar_tha, arp_header->ar_sha, ETHER_ADDR_LEN);
        arp_header->ar_tip = arp_header->ar_sip;

        // Set the source to this interface. 
        memcpy(arp_header->ar_sha, my_interface->addr, ETHER_ADDR_LEN);
        arp_header->ar_sip = my_interface->ip;

        // Set ethernet frame MAC information 
        sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)(packet_buffer);
        memcpy(ethernet_hdr->ether_dhost, arp_header->ar_tha, ETHER_ADDR_LEN);
        memcpy(ethernet_hdr->ether_shost, arp_header->ar_sha, ETHER_ADDR_LEN);

        // Send the packet back on it's way. 
        arp_header->ar_op = htons(arp_op_reply);
        printf("Sending out ARP Reply\n");
        sr_send_packet(sr, packet_buffer, len, interface);
      } else {
        fprintf(stderr, "ARP Op Code Unknown: (%d)\n", arp_header->ar_op);
        return -1;
      }
    } else {
      fprintf(stderr, "ARP interface names didn't match: %s, %s\n",
          my_interface->name, interface);
      return -1;
    }
  } else {
    printf("ARP interface not found\n");
  }

  return 0;
}
示例#21
0
void sr_handle_arp(struct sr_instance *sr, uint8_t *packet, unsigned int len, struct sr_if *iface)
{
    assert(sr);
    assert(packet);
    assert(iface);
    
    /* check length */
    if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)) {
        fprintf(stderr, "Failed to process ARP header, insufficient length\n");
        return;
    }
    
    sr_arp_hdr_t *arp_hdr = (sr_arp_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));
    /* print_hdr_arp((uint8_t *)arp_hdr); */
    
    /* check hardware type */
    if (ntohs(arp_hdr->ar_hrd) != arp_hrd_ethernet) {
        return;
    }
    
    /* check protocol */
    if (ntohs(arp_hdr->ar_pro) != ethertype_ip) {
        return;
    }
    
    /* is it for me? */
    struct sr_if *tiface = sr_get_interface_from_ip(sr, arp_hdr->ar_tip);
    
    if (!tiface) {
        return;
    }
    
    unsigned short arp_op = ntohs(arp_hdr->ar_op);
    
    if (arp_op == arp_op_request) {
        sr_send_arp_reply(sr, packet, iface, tiface);
    } else if (arp_op == arp_op_reply) {
        struct sr_arpreq *req = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip);
        
        if (req) {
            struct sr_packet *pkt = NULL;
            struct sr_if *oiface = NULL;
            sr_ethernet_hdr_t *eth_hdr = NULL;
            
            pkt = req->packets;
            
            while (pkt) {
                oiface = sr_get_interface(sr, pkt->iface);
                
                eth_hdr = (sr_ethernet_hdr_t *)(pkt->buf);
                
                memcpy(eth_hdr->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);
                memcpy(eth_hdr->ether_shost, oiface->addr, ETHER_ADDR_LEN);
                
                sr_send_packet(sr, pkt->buf, pkt->len, pkt->iface);
                
                pkt = pkt->next;
            }
            
            sr_arpreq_destroy(&(sr->cache), req);
        }
    }
} /* -- sr_handle_arp -- */
示例#22
0
void process_ether_type_arp(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* iface/* lent */)
{
/* Router receives an ARP packet  */
  assert(sr);
  assert(packet);
  assert(iface);

  printf("ARP Packet Received...\n");
  /* Create ARP Header and find interface */
  sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
  fprintf(stderr, "\tsender hardware address: ");
  print_addr_eth(arp_header->ar_sha);
  fprintf(stderr, "\tsender ip address: ");
  print_addr_ip_int(ntohl(arp_header->ar_sip));
  fprintf(stderr, "\ttarget hardware address: ");
  print_addr_eth(arp_header->ar_tha);
  fprintf(stderr, "\ttarget ip address: ");
  print_addr_ip_int(ntohl(arp_header->ar_tip));

  struct sr_if* interface = NULL;
  struct sr_if* interface_list_iterator = sr->if_list;

  while (interface_list_iterator!=NULL) 
  {
    if (arp_header->ar_tip == interface_list_iterator->ip) 
        interface = interface_list_iterator;
    interface_list_iterator = interface_list_iterator->next;
  }

  unsigned short op_code = ntohs(arp_header->ar_op);

  /* If ARP req/response is meant for router the process else drop/forward */
  /* The following code gets executed when you first PING to a router's interface
    and the client does not know the router's MAC */

  if (interface!=0)
  {
    if (op_code == 0x0001) 
    { 
      printf("ARP Request for Router detected...\n");

      sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)(packet);
      memcpy(arp_header->ar_tha, arp_header->ar_sha, 6);
      memcpy(arp_header->ar_sha, interface->addr, 6);
      memcpy(ethernet_hdr->ether_dhost, arp_header->ar_tha, 6);
      memcpy(ethernet_hdr->ether_shost, arp_header->ar_sha, 6);
      arp_header->ar_tip = arp_header->ar_sip;
      arp_header->ar_sip = interface->ip;
      arp_header->ar_op = htons(0x0002);

      printf("Router sent ARP Reply...\n");
      sr_send_packet(sr, packet, len, iface);
    }

    if (op_code == 0x0002) 
    {
      printf("Router received ARP Reply...\n");

      /* See if there's an ARP request in the queue. */
      struct sr_arpreq* req = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha, arp_header->ar_sip);

      struct sr_packet* pckt = NULL;
      if (req!=NULL)
      {
        pckt = req->packets;
      }  
      else
      {  
        pckt = NULL;
      }  

      while (pckt != NULL) 
      {
        printf("Forwarding all packets waiting for this Reply...\n");
        sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t *)(pckt->buf);
        struct sr_if* sending_interface = sr_get_interface(sr, pckt->iface);
        memcpy(ethernet_hdr->ether_dhost, arp_header->ar_sha, 6);
        memcpy(ethernet_hdr->ether_shost, sending_interface->addr, 6);
        sr_send_packet(sr, pckt->buf, pckt->len, pckt->iface);
        pckt = pckt->next;
      }
    } 
  }
}
示例#23
0
void sr_handlearp(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
	sr_arp_hdr_t *arp_hdr, *arp_reply_hdr = 0;
	sr_ethernet_hdr_t *ether_hdr, *queuing_ether = 0;
	uint8_t *reply_packet = 0;
	struct sr_if *iface = 0;
	struct sr_arpreq *arpreq = 0;
	struct sr_packet *queuing_packet = 0;
	
	/* check if header has the correct size */
	if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t)) {
		fprintf(stderr, "Error: invalid ARP header length\n");
		return;
	}
	
	arp_hdr = (sr_arp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
	
	/* check if ARP hardware type is ethernet */
	if (arp_hdr->ar_hrd != htons(arp_hrd_ethernet)) {
		fprintf(stderr, "Error: unknown ARP hardware format\n");
		return;
	}
	
	/* check if arp protocol type is ip */
	if (arp_hdr->ar_pro != htons(ethertype_ip)) {
		fprintf(stderr, "Error: unknown ARP protocol format\n");
		return;
	}
	
	/* grab the receiving interface */
	if ((iface = sr_get_interface(sr, interface)) == 0) {
		fprintf(stderr, "Error: interface does not exist (sr_handlearp)\n");
		return;
	}
	
	/* handle received ARP request */
	if (arp_hdr->ar_op == htons(arp_op_request)) {
		
		/* create new reply packet */
		if ((reply_packet = malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t))) == NULL) {
			fprintf(stderr,"Error: out of memory (sr_handlearp)\n");
			return;
		}
				
		/* construct ARP header */
		arp_reply_hdr = (sr_arp_hdr_t*)(reply_packet + sizeof(sr_ethernet_hdr_t));
		arp_reply_hdr->ar_hrd = htons(arp_hrd_ethernet);            /* format of hardware address   */
		arp_reply_hdr->ar_pro = htons(ethertype_ip);		        /* format of protocol address   */
		arp_reply_hdr->ar_hln = htons(ETHER_ADDR_LEN);	            /* length of hardware address   */
		arp_reply_hdr->ar_pln = htons(4);             				/* length of protocol address   */
		arp_reply_hdr->ar_op = htons(arp_op_reply);             	/* ARP opcode (command)         */
		memcpy(arp_reply_hdr->ar_sha, iface->addr, sizeof(iface->addr));   				/* sender hardware address      */
		arp_reply_hdr->ar_sip = htonl(iface->ip);   				/* sender IP address            */
		memcpy(arp_reply_hdr->ar_tha, arp_hdr->ar_sha, ETHER_ADDR_LEN);   					/* target hardware address      */
		arp_reply_hdr->ar_tip = arp_hdr->ar_sip;        				/* target IP address            */
		
		/* construct ethernet header */
		ether_hdr = (sr_ethernet_hdr_t*)reply_packet;
		memcpy(ether_hdr->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);
		memcpy(ether_hdr->ether_shost, iface->addr, sizeof(iface->addr));
		ether_hdr->ether_type = htons(ethertype_arp);
		
		/* send the packet */
		if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
			fprintf(stderr, "Error: sending packet failed (sr_handlearp)\n");
		}
		free(reply_packet);
	}
	
	/* handle received ARP reply */
	else if (arp_hdr->ar_op == htons(arp_op_reply)) {
	
		/* check if the target ip matches ours */
		if (arp_hdr->ar_tha != iface->addr) {
			fprintf(stderr, "Error: ARP reply does not match our MAC (sr_handlearp)\n");
			return;
		}
	
		/* check if the target ip matches ours */
		if (arp_hdr->ar_tip != htonl(iface->ip)) {
			fprintf(stderr, "Error: ARP reply does not match our ip (sr_handlearp)\n");
			return;
		}
		
		/* check if the ip is already in our cache */
		if (sr_arpcache_lookup(&(sr->cache), arp_hdr->ar_sip) != NULL) {
			fprintf(stderr, "Error: ARP reply ip already in cache (sr_handlearp)\n");
			return;
		}
		
		/* Insert the reply to our ARP cache and grab the list of packets waiting for this IP */
		if ((arpreq = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip)) != NULL) {
		
			queuing_packet = arpreq->packets;
			
			/* loop through all queuing packets */
			while(queuing_packet != NULL) {
			
				/* fill in the MAC field */
				queuing_ether = (sr_ethernet_hdr_t *)(queuing_packet->buf);
				memcpy(queuing_ether->ether_dhost, arp_hdr->ar_sha, ETHER_ADDR_LEN);
				
				/* send the queuing packet */
				if (sr_send_packet(sr, queuing_packet->buf, queuing_packet->len, (const char*)queuing_packet->iface) == -1) {
					fprintf(stderr, "Error: sending queuing packet failed (sr_handlearp)\n");
				}
				
				queuing_packet = queuing_packet->next;
			}
			
			/* destroy the request queue */
			sr_arpreq_destroy(&(sr->cache), arpreq);
		}
	}
}