/*--------------------------------------------------------------------- * 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); } }
int arp_validpacket(uint8_t *packet, unsigned int len){ /* Ensure the packet is long enough */ if (len < sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arp_hdr)){ return 0; } struct sr_arp_hdr *arp_hdr = arp_header(packet); /* Ensure the ARP header setting is correct */ if (ntohs(arp_hdr->ar_hrd) != arp_hrd_ethernet){ return 0; } if (ntohs(arp_hdr->ar_pro) != arp_pro_ip){ return 0; } return 1; }
/*--------------------------------------------------------------------- * Method: valid_arp(uint8_t * packet, unsigned int len) * Scope: Internal * * This function processes an arp packet given the full ethernet frame. * It returns true it has a valid length, valid protocol type, hardware type. * False otherwise. * *---------------------------------------------------------------------*/ int valid_arp(uint8_t *packet, unsigned int len) { struct sr_arp_hdr *arp_hdr; /* Ensure that the packet is long enough for an arp header */ if (len < sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arp_hdr)) return 0; /* Is the hardware type ethernet? */ arp_hdr = arp_header(packet); if (arp_hrd(arp_hdr) != arp_hrd_ethernet) return 0; /* Is it IP? */ if (arp_pro(arp_hdr) != arp_pro_ip) return 0; return 1; }
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"); } } } }