/* Kernel AODV v2.1 National Institute of Standards and Technology Luke Klein-Berndt ----------------------------------------------------- Version 2.1 new features: * Much more stable! * Added locks around important areas * Multihop Internet gatewaying now works * Multicast hack added * Many bug fixes! ----------------------------------------------------- Originally based upon MadHoc code. I am not sure how much of it is left anymore, but MadHoc proved to be a great starting point. MadHoc was written by - Fredrik Lilieblad, Oskar Mattsson, Petra Nylund, Dan Ouchterlony and Anders Roxenhag Mail: mad-hoc@flyinglinux.net This software is Open Source under the GNU General Public Licence. */ #include "rrep.h" /**************************************************** rrep ---------------------------------------------------- Handles sending and recieving RREPs ****************************************************/ extern struct route_table_entry *g_my_entry; extern u_int32_t g_my_ip; extern u_int32_t g_broadcast_ip; int recv_hello(struct event_queue_entry *working_packet) { struct route_table_entry *recv_route; struct rrep *tmp_rrep; struct neighbor_list_entry *tmp_entry; unsigned char *ucp; tmp_rrep=working_packet->data; ucp=(unsigned char *)&(tmp_rrep->dst_ip); tmp_entry=find_neighbor_list_entry(tmp_rrep->dst_ip); if (tmp_entry==NULL) { tmp_entry=create_neighbor_list_entry(tmp_rrep->dst_ip); memcpy(&(tmp_entry->hw_addr),&(working_packet->src_hw_addr),sizeof(unsigned char) * ETH_ALEN); tmp_entry->dev=working_packet->dev; #ifdef AODV_SIGNAL set_spy(); #endif } delete_timer_queue_entry_of_id(tmp_entry->ip, EVENT_NEIGHBOR); insert_timer_queue_entry(tmp_rrep->lifetime+getcurrtime()+20,NULL,0,tmp_entry->ip,0,0,EVENT_NEIGHBOR); update_timer_queue(); recv_route = find_route_table_entry(tmp_rrep->dst_ip); if (recv_route==NULL) { // No entry in RT found, generate a new recv_route = create_route_table_entry(); recv_route->dst_ip = tmp_rrep->dst_ip; recv_route->lifetime = 0; recv_route->dev = working_packet->dev; recv_route->next_hop = working_packet->src_ip; recv_route->hop_count = tmp_rrep->hop_count ; recv_route->route_valid = TRUE; recv_route->route_seq_valid = TRUE; insert_kernel_route_entry(recv_route->dst_ip, recv_route->next_hop,recv_route->dev->name); } if ((tmp_rrep->hop_count < recv_route->hop_count) || (recv_route->route_valid==FALSE))// || (( tmp_rrep->dst_seq>=recv_route->dst_seq) && (recv_route->next_hop!=recv_route->dst_ip))) { delete_kernel_route_entry(recv_route->dst_ip, recv_route->next_hop); recv_route->dev = working_packet->dev; recv_route->next_hop = working_packet->src_ip; recv_route->hop_count = tmp_rrep->hop_count ; recv_route->route_valid = TRUE; recv_route->route_seq_valid = TRUE; insert_kernel_route_entry(recv_route->dst_ip, recv_route->next_hop,recv_route->dev->name); } tmp_entry->route_entry=recv_route; recv_route->lifetime = MAX(recv_route->lifetime,(tmp_rrep->lifetime+getcurrtime()+20)); recv_route->dst_seq = tmp_rrep->dst_seq; return 0; } void convert_rrep_to_host(struct rrep *tmp_rrep) { tmp_rrep->dst_seq=ntohl(tmp_rrep->dst_seq); tmp_rrep->lifetime=ntohl(tmp_rrep->lifetime); } void convert_rrep_to_network(struct rrep *tmp_rrep) { tmp_rrep->dst_seq=htonl(tmp_rrep->dst_seq); tmp_rrep->lifetime=htonl(tmp_rrep->lifetime); } /**************************************************** recv_rrep ---------------------------------------------------- Handles recieving route replies. It is passed packets from the AODV thread ****************************************************/ int recv_rrep(struct event_queue_entry *working_packet) { struct route_table_entry *send_route; struct route_table_entry *recv_route; struct rrep *tmp_rrep; struct interface_list_entry *tmp_interface; u_int64_t curr_time; u_int32_t tmp_ip=0; #ifdef MESSAGES char rt_ip[16]; #endif #ifndef TRACE char dst_ip[16]; char src_ip[16]; #endif tmp_interface=find_interface_by_dev(working_packet->dev); //check to make sure the interface found if (tmp_interface==NULL) { printk(KERN_WARNING "AODV: Error finding interface RREP recieved on!\n"); return 0; } tmp_ip=tmp_interface->ip; tmp_rrep=working_packet->data; convert_rrep_to_host(tmp_rrep); // increase the hop count on the rrep tmp_rrep->hop_count = tmp_rrep->hop_count + 1; if (tmp_rrep->hop_count==1) { //its a hello messages! HELLO WORLD! recv_hello(working_packet); return 0; } if ((tmp_ip!=0) && (working_packet->src_ip==tmp_ip)) { printk(KERN_WARNING "AODV: Reading our own RREP! \n"); return 0; } update_route_entry(tmp_rrep->dst_ip, working_packet->src_ip, tmp_rrep->hop_count, tmp_rrep->dst_seq, working_packet->dev); delete_timer_queue_entry_of_id(tmp_rrep->dst_ip,EVENT_RREQ); recv_route = find_route_table_entry(tmp_rrep->dst_ip); /* If I'm not the destination of the RREP I forward it */ if((tmp_rrep->src_ip != tmp_ip) && (tmp_rrep->src_ip!=tmp_rrep->dst_ip)) { strcpy(src_ip,inet_ntoa(tmp_rrep->src_ip)); strcpy(dst_ip,inet_ntoa(tmp_rrep->dst_ip)); printk(KERN_INFO "AODV: Forwarding a route to: %s from node: %s \n",dst_ip,src_ip); /* Get the entry to the source from RT */ send_route = find_route_table_entry(tmp_rrep->src_ip); if ((send_route!=NULL) && (recv_route!=NULL)) //thanks to Madanlal Musuvathi and the CMC program for catching this! I didn't check recv_route for NULL { /* Add to precursors... */ if (insert_precursor_entry(recv_route, send_route->next_hop) == 1) { /* Couldn't add precursor. Ignore and continue */ } recv_route->lifetime = curr_time + ACTIVE_ROUTE_TIMEOUT; convert_rrep_to_network(tmp_rrep); send_message(tmp_rrep->src_ip,NET_DIAMETER, working_packet->data, working_packet->size); } else printk(KERN_WARNING "AODV: ERROR finding RREP sending address!\n"); } return 0; } /**************************************************** gen_rrep ---------------------------------------------------- Generates a route reply ****************************************************/ int gen_rrep(u_int32_t src_ip, u_int32_t dst_ip, u_int32_t packet_src_ip, u_int32_t dst_seq, int grat_rrep) { struct rrep tmp_rrep; struct route_table_entry *src_route; struct route_table_entry *dst_route; struct interface_list_entry *tmp_interface=NULL; u_int64_t curr_time; /* Current time */ char srcip[16]; char dstip[16]; curr_time = getcurrtime(); /* Get current time */ /* Get the source and destination IP address from the RREQ */ src_route = find_route_table_entry(src_ip); dst_route = find_route_table_entry(dst_ip); if ((dst_route==NULL) && (src_route==NULL)) { printk(KERN_WARNING "AODV: RREP No Source or DST route! src: %s\n",inet_ntoa(src_ip)); return -EHOSTUNREACH; } if (dst_route!=NULL) tmp_interface=find_interface_by_dev(dst_route->dev); else tmp_interface=find_interface_by_dev(src_route->dev); if (dst_route==NULL) printk(KERN_WARNING "AODV: GEN_RREP - DST route invalid!\n"); if(src_route==NULL) printk(KERN_WARNING "AODV: GEN_RREP SRC route invalid!\n"); if ((dst_ip != tmp_interface->ip) && (dst_ip != g_broadcast_ip) && (grat_rrep)) { /* Now send a datagram to the requested host telling it it has been asked for */ tmp_rrep.type = 2; tmp_rrep.r = 0; tmp_rrep.prefix_sz = 0; tmp_rrep.reserved1=0; tmp_rrep.reserved2=0; /* Set the source to be the destination of the rreq (it has asked for it itself)*/ tmp_rrep.src_ip = dst_ip; /* Insert the rreq's source attributes */ tmp_rrep.dst_ip = src_ip; //we want it to be in network byte order! tmp_rrep.dst_seq = htonl(src_route->dst_seq); tmp_rrep.hop_count = src_route->hop_count; //we want it to be in network byte order! tmp_rrep.lifetime = htonl(src_route->lifetime - curr_time); /* Get info on the destination */ strcpy(srcip,inet_ntoa(tmp_rrep.src_ip)); strcpy(dstip,inet_ntoa(tmp_rrep.dst_ip)); printk(KERN_WARNING "AODV: Sending out a Grat RREP - src: %s dst: %s \n",srcip,dstip); send_message(dst_route->dst_ip,NET_DIAMETER, &tmp_rrep, sizeof(struct rrep)); } /* Check if the destination IP of RREQ was this node */ if (dst_ip == tmp_interface->ip) { /* The RREQ was for this node */ /* Set the reply structure */ if (seq_greater(dst_seq,dst_route->dst_seq)) dst_route->dst_seq = dst_seq; //we want it to be in network byte order! tmp_rrep.dst_seq = htonl(dst_route->dst_seq); tmp_rrep.hop_count = 0; //we want it to be in network byte order! tmp_rrep.lifetime = htonl(MY_ROUTE_TIMEOUT); } else { /* The RREQ was for a node in RT */ /* Set the reply structure */ //we want it to be in network byte order! tmp_rrep.dst_seq = htonl(dst_route->dst_seq); tmp_rrep.lifetime = htonl(dst_route->lifetime - curr_time); tmp_rrep.hop_count = dst_route->hop_count; /* Add to precursors... */ insert_precursor_entry(dst_route, packet_src_ip); insert_precursor_entry(src_route, dst_route->next_hop); } /* Set the rest of the RREP structure */ tmp_rrep.src_ip = src_ip; tmp_rrep.dst_ip = dst_ip; tmp_rrep.type = 2; tmp_rrep.r = 0; tmp_rrep.prefix_sz = 0; send_message(packet_src_ip,NET_DIAMETER, &tmp_rrep, sizeof(struct rrep)); return 0; }