/******************************************************************* * Buffers a packet that is waiting on destination MAC address from ARP. *******************************************************************/ struct packet_buffer * buf_packet(struct packet_state *ps, uint8_t* pac, const struct in_addr dest_ip, const struct sr_if* iface, struct sr_ethernet_hdr *orig_eth) { struct packet_buffer* buf_walker=0; assert(ps); assert(pac); if(ps->sr->queue==0) /* If Buffer is Empty.*/ { ps->sr->queue=(struct packet_buffer*)malloc(sizeof(struct packet_buffer)); assert(ps->sr->queue); ps->sr->queue->next=0; ps->sr->queue->packet=(uint8_t*)malloc(ps->res_len); memmove(ps->sr->queue->packet, pac, ps->res_len); ps->sr->queue->pack_len=ps->res_len; struct sr_rt* rt_entry=get_routing_if(ps, dest_ip); ps->sr->queue->gw_IP=rt_entry->gw.s_addr; ps->sr->queue->interface=(char *)malloc(sr_IFACE_NAMELEN); memmove(ps->sr->queue->interface, rt_entry->interface, sr_IFACE_NAMELEN); ps->sr->queue->ip_dst=dest_ip; ps->sr->queue->num_arp_reqs=0; ps->sr->queue->old_eth=(struct sr_ethernet_hdr*)malloc(sizeof(struct sr_ethernet_hdr)); memmove(ps->sr->queue->old_eth, orig_eth, sizeof(struct sr_ethernet_hdr)); return ps->sr->queue; } else /* Buffer is not Empty so Add to End. */ { buf_walker=ps->sr->queue; while(buf_walker->next) { buf_walker=buf_walker->next; } buf_walker->next=(struct packet_buffer*)malloc(sizeof(struct packet_buffer)); assert(buf_walker->next); buf_walker=buf_walker->next; buf_walker->next=0; buf_walker->packet=(uint8_t*)malloc(ps->res_len); memmove(buf_walker->packet, pac, ps->res_len); buf_walker->pack_len=ps->res_len; buf_walker->interface=(char *)malloc(sr_IFACE_NAMELEN); memmove(buf_walker->interface, iface->name, sr_IFACE_NAMELEN); buf_walker->ip_dst=dest_ip; ps->sr->queue->gw_IP=ps->rt_entry->gw.s_addr; buf_walker->num_arp_reqs=0; buf_walker->old_eth=(struct sr_ethernet_hdr*)malloc(sizeof(struct sr_ethernet_hdr)); memmove(buf_walker->old_eth, orig_eth, sizeof(struct sr_ethernet_hdr)); return buf_walker; } ps->res_len = 0; /* Reset packet state's response length to 0 */ return NULL; }
/******************************************************************* * Constructs appropriate ARP Request based on a packet to be forwarded. *******************************************************************/ void send_request(struct packet_state* ps, const uint32_t dest_ip) { /*Construct ARP Header*/ struct sr_arphdr* request; request=(struct sr_arphdr*)malloc(sizeof(struct sr_arphdr)); request->ar_hrd=htons(ARP_HRD_ETH); request->ar_pro=htons(ARP_PRO_IP); request->ar_hln=ETHER_ADDR_LEN; request->ar_pln=ARP_IP_LEN; request->ar_op=htons(ARP_REQUEST); /* Find source interface */ struct in_addr ip_d; ip_d.s_addr=dest_ip; struct sr_rt* iface_rt_entry=get_routing_if(ps, ip_d); /*Find rt entry to send request from. */ struct sr_if* iface=sr_get_interface(ps->sr, iface_rt_entry->interface); /*Find iface associated with rt entry */ assert(iface); memmove(request->ar_sha, iface->addr, ETHER_ADDR_LEN); /*Set ARP source address to interface's hardware address */ request->ar_sip=iface->ip; /*Set ARP source IP address to interface's IP address */ /* Set ARP dest MAC address to 00:00:00:00:00:00 */ int i=0; for(i=0; i<ETHER_ADDR_LEN; i++) { request->ar_tha[i]=0x00; } /*Set ARP target IP address to interface's gateway IP address */ request->ar_tip=iface_rt_entry->gw.s_addr; /*ARP Constructed, Now Construct Ethernet Header */ struct sr_ethernet_hdr* new_eth; new_eth=(struct sr_ethernet_hdr*)malloc(sizeof(struct sr_ethernet_hdr)); memmove(new_eth->ether_shost, iface->addr,ETHER_ADDR_LEN); /*Ethernet Source Address is Interface's Address */ ps->rt_entry = iface_rt_entry; /*******************/ /*Set Ethernet dest MAC address to ff:ff:ff:ff:ff:ff (Broadcast) */ for(i=0; i<ETHER_ADDR_LEN; i++) { new_eth->ether_dhost[i]=0xff; } new_eth->ether_type=htons(ETHERTYPE_ARP); int eth_offset=sizeof(struct sr_ethernet_hdr); /* Put new Ethernet and ARP Header in Response */ memmove(ps->response, new_eth, eth_offset); memmove((ps->response + eth_offset), request, sizeof(struct sr_arphdr)); /*Free Construct ARP and Ethernet Headers */ if(request) free(request); if(new_eth) free(new_eth); ps->res_len=eth_offset + sizeof(struct sr_arphdr); }
/******************************************************************* * Every time handle_packet() is called, update_buffer() is called. The function walks through * the packet buffer and checks if the necessary mac address is now in the arp cache. If it is, * then the MAC address is added to the ethernet header and the packet is send and removed * from the buffer. If the address is not in the cache and less than 5 arp requests have already * been sent, then another arp request is sent. Otherwise the packet is deleted from the buffer * and an ICMP port unreachable is sent. *******************************************************************/ void update_buffer(struct packet_state* ps,struct packet_buffer* queue) { struct packet_buffer* buf_walker=0; buf_walker=queue; while(buf_walker) { uint32_t search_ip=buf_walker->gw_IP; struct arp_cache_entry* ent=search_cache(ps, search_ip); if(ent!=NULL) /*MAC Address is in ARP Cache. Send packet. */ { struct sr_ethernet_hdr *eth = (struct sr_ethernet_hdr *)(buf_walker->packet); memmove(eth->ether_dhost, ent->mac, ETHER_ADDR_LEN); struct sr_if *iface=sr_get_interface(ps->sr, buf_walker->interface); memmove(eth->ether_shost, iface->addr, ETHER_ADDR_LEN); eth->ether_type = htons(ETHERTYPE_IP); sr_send_packet(ps->sr, buf_walker->packet, buf_walker->pack_len, buf_walker->interface); buf_walker=delete_from_buffer(ps,buf_walker); } else if(buf_walker->num_arp_reqs < 5) /*Send another arp request. */ { buf_walker->num_arp_reqs++; sr_send_packet(ps->sr, buf_walker->arp_req, buf_walker->arp_len, buf_walker->interface); buf_walker=buf_walker->next; } else /* 5 ARP Request already sent, send ICMP Port Unreachable and Delete from Buffer.*/ { int off = sizeof(struct sr_ethernet_hdr) + sizeof(struct ip); ps->res_len=off; ps->response += sizeof(struct sr_ethernet_hdr); struct ip *res_ip = (struct ip*) ps->response; /*IP Header for ICMP Port Unreachable*/ ps->response += sizeof(struct ip); ps->packet = buf_walker->packet; ps->packet += sizeof(struct sr_ethernet_hdr); struct ip *ip_hdr = (struct ip*) (ps->packet); /*IP Header from original packet. */ ps->packet += sizeof(struct ip); icmp_response(ps, ip_hdr, ICMPT_DESTUN, ICMPC_HOSTUN); /*Construct ICMP */ memmove(res_ip, ip_hdr, sizeof(struct ip)); res_ip->ip_len = htons(ps->res_len - sizeof(struct sr_ethernet_hdr)); res_ip->ip_ttl = INIT_TTL; res_ip->ip_tos = ip_hdr->ip_tos; res_ip->ip_p = IPPROTO_ICMP; /* Finding interface to send ICMP out of*/ struct sr_rt* iface_rt_entry=get_routing_if(ps, ip_hdr->ip_src); struct sr_if* iface=sr_get_interface(ps->sr, iface_rt_entry->interface); res_ip->ip_src.s_addr = iface->ip; res_ip->ip_dst = ip_hdr->ip_src; res_ip->ip_sum = 0; res_ip->ip_sum = cksum((uint8_t *)res_ip, sizeof(struct ip)); res_ip->ip_sum = htons(res_ip->ip_sum); ps->response = (uint8_t *) res_ip - sizeof(struct sr_ethernet_hdr); struct sr_ethernet_hdr* eth_resp=(struct sr_ethernet_hdr*)ps->response; memmove(eth_resp->ether_dhost,buf_walker->old_eth->ether_shost,ETHER_ADDR_LEN); memmove(eth_resp->ether_shost,iface->addr, ETHER_ADDR_LEN); eth_resp->ether_type=htons(ETHERTYPE_IP); sr_send_packet(ps->sr, ps->response, ps->res_len, iface_rt_entry->interface); buf_walker=delete_from_buffer(ps,buf_walker); } } }