/* 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); }
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); } }
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 ++; } } }
/* 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; }