/* 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 "rerr.h" /**************************************************** rerr ---------------------------------------------------- Handles the generation of RERR messages ****************************************************/ extern u_int32_t g_broadcast_ip; extern u_int32_t g_my_ip; void free_rerrhdr(struct rerrhdr *tmp_rerrhdr); int send_rerr(struct rerrhdr *tmp_rerrhdr, u_int32_t sent_to); /**************************************************** link_break ---------------------------------------------------- link_break is called when a broken link to a neighbouring is detected. All active routes that have the unreachable node as next hop are invalidated. All precursors for this entry are removed. The RERR meassage including the unreachable destinations and their incremented seq numbers is finally rebroadcast. ****************************************************/ int link_break( u_int32_t brk_dst_ip) { struct route_table_entry *tmp_entry; struct rerrhdr *new_rerrhdr = NULL; struct precursor_entry *tmp_precursor; struct precursor_entry *dead_precursor; u_int32_t last_precursor; u_int8_t precursor_num=0; int rerrhdr_created = 0; // remove the borken link from all the route table entries delete_precursor_entry_from_route_table(brk_dst_ip); tmp_entry=get_first_route_table_entry(); //go through list while(tmp_entry != NULL) { //if the route has the broken IP for the next hop and is active if((tmp_entry->next_hop == brk_dst_ip) && (tmp_entry->route_valid)) { printk(KERN_INFO "RERR: Broken link as next hop for - %s \n",inet_ntoa(tmp_entry->dst_ip)); //expire the route route_expiry(tmp_entry); if(tmp_entry->precursors!=NULL) { //if the rerr header has not been created yet if(!rerrhdr_created) { if((new_rerrhdr =create_rerrhdr(tmp_entry->dst_ip,tmp_entry->dst_seq)) == NULL) return 1; rerrhdr_created = 1; } else { append_unr_dst(new_rerrhdr, tmp_entry->dst_ip, tmp_entry->dst_seq); } } //remove all the precursors from the route tmp_precursor=tmp_entry->precursors; while (tmp_precursor!=NULL) { last_precursor=tmp_precursor->ip; dead_precursor=tmp_precursor; tmp_precursor=tmp_precursor->next; kfree(dead_precursor); } tmp_entry->precursors=NULL; } //move on to the next entry tmp_entry = tmp_entry->next; } //if there was a RERR created, send it out if(rerrhdr_created) { if (precursor_num==1) send_rerr(new_rerrhdr,last_precursor); else send_rerr(new_rerrhdr,g_broadcast_ip); free_rerrhdr(new_rerrhdr); } return 0; } /**************************************************** route_expiry ---------------------------------------------------- route_expiry invalidates an active route, i e an entry in the routing table. ****************************************************/ void route_expiry(struct route_table_entry *tmp_entry) { //marks a route as expired tmp_entry->lifetime = (getcurrtime() + DELETE_PERIOD); tmp_entry->dst_seq++; tmp_entry->route_valid=FALSE; delete_kernel_route_entry(tmp_entry->dst_ip, tmp_entry->next_hop); } /**************************************************** host_unr ---------------------------------------------------- host_unr is called when a packet is received destined for a node which the forwarding node does not have an active route to. A RERR message is created to inform neighbours. ****************************************************/ int host_unr(u_int32_t brk_dst_ip) { struct rerrhdr *new_rerrhdr = NULL; struct route_table_entry *tmp_entry; tmp_entry = find_route_table_entry(brk_dst_ip); if((new_rerrhdr = create_rerrhdr(brk_dst_ip, 1)) == NULL) return -ENOMEM; send_rerr(new_rerrhdr,g_broadcast_ip); free_rerrhdr(new_rerrhdr); return 0; } /**************************************************** rec_rerr ---------------------------------------------------- rec_rerr is called when the node receives a RERR packet from another node. If the precursor list for a broken destinations is not empty a new RERR is created for that destination. ****************************************************/ int recv_rerr(struct event_queue_entry *working_packet) { struct rerr *tmp_hdr; struct rerrhdr *new_rerrhdr = NULL; struct rerrdst *tmp_dst; struct route_table_entry *tmp_route; struct interface_list_entry *tmp_interface; int new_rerr_created = 0; int i; tmp_interface=find_interface_by_dev(working_packet->dev); if (tmp_interface==NULL) { printk(KERN_WARNING "AODV: Recieved RERR on an unknown device!\n"); return -ENODEV; } tmp_hdr =(struct rerr *) ((char *) working_packet->data); tmp_dst = (struct rerrdst *) ((char *) tmp_hdr + sizeof (struct rerr)); printk(KERN_INFO "AODV: recieved a route error from %s, count= %u\n",inet_ntoa(working_packet->src_ip),tmp_hdr->dst_count); for(i = 0; i < tmp_hdr->dst_count; i++) { //go through all the unr dst in the rerr printk(KERN_INFO " -> %s",inet_ntoa(tmp_dst->unr_dst_ip)); tmp_route = find_route_table_entry(tmp_dst->unr_dst_ip); //Is the sender of the rerr the next hop for a broken destination for the current node? if(tmp_route != NULL) { if( !tmp_route->self_route ) { if (tmp_route->next_hop == working_packet->src_ip) { printk(KERN_INFO " Removing route"); tmp_route->dst_seq = ntohl(tmp_dst->unr_dst_seq); tmp_route->route_valid=FALSE; tmp_route->lifetime = (getcurrtime() + DELETE_PERIOD); delete_kernel_route_entry(tmp_route->dst_ip, tmp_route->next_hop); if(tmp_route->precursors != NULL) { // precursors exist if(!new_rerr_created) { new_rerr_created = 1; new_rerrhdr = create_rerrhdr(tmp_dst->unr_dst_ip,ntohl( tmp_dst->unr_dst_seq)); } else { append_unr_dst(new_rerrhdr, tmp_dst->unr_dst_ip, ntohl(tmp_dst->unr_dst_seq)); } } } } } printk(KERN_INFO" \n"); tmp_dst =(struct rerrdst *) ((char *) tmp_dst + sizeof (struct rerrdst)); } if(new_rerr_created) { send_rerr(new_rerrhdr,g_broadcast_ip); free_rerrhdr(new_rerrhdr); } return 0; } /**************************************************** create_rerrhdr ---------------------------------------------------- create_rerrhdr is used to create a new RERR message ****************************************************/ struct rerrhdr* create_rerrhdr(u_int32_t tmp_ip, u_int32_t tmp_dst_seq) { struct rerr_unr_dst *tmp_rerr_unr_dst; struct rerrhdr *tmp_rerrhdr; //create header if((tmp_rerrhdr = kmalloc(sizeof(struct rerrhdr),GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "AODV: Error creating tmp_rerrhdr \n"); return NULL; } //create spot for first entry if((tmp_rerr_unr_dst = kmalloc(sizeof(struct rerr_unr_dst),GFP_ATOMIC)) == NULL) { kfree(tmp_rerrhdr); printk(KERN_WARNING "AODV: Error creating temp_rerr_unr_dst\n"); return NULL; } //fill in info for first entry tmp_rerr_unr_dst->unr_dst_ip = tmp_ip; tmp_rerr_unr_dst->unr_dst_seq = tmp_dst_seq; tmp_rerr_unr_dst->next = NULL; //fill in info for header tmp_rerrhdr->unr_dst = tmp_rerr_unr_dst; tmp_rerrhdr->type = 3; tmp_rerrhdr->dst_count = 1; return tmp_rerrhdr; } /**************************************************** append_unr_dst ---------------------------------------------------- append_unr_dst adds an unreachable node to the previously created RERR message. ****************************************************/ int append_unr_dst(struct rerrhdr *tmp_rerrhdr, u_int32_t tmp_ip,u_int32_t tmp_dst_seq) { struct rerr_unr_dst *tmp_rerr_unr_dst; //get memory for new entry if((tmp_rerr_unr_dst = kmalloc(sizeof(struct rerr_unr_dst),GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "AODV: Error appending new unr_dst\n"); return -ENOMEM; } //fill in info for entry tmp_rerr_unr_dst->next = tmp_rerrhdr->unr_dst; tmp_rerrhdr->unr_dst = tmp_rerr_unr_dst; tmp_rerrhdr->dst_count++; tmp_rerr_unr_dst->unr_dst_ip = tmp_ip; tmp_rerr_unr_dst->unr_dst_seq = tmp_dst_seq; return 0; } /**************************************************** free_rerrhdr ---------------------------------------------------- free_rerrhdr frees the allocated memory for the rerrhdr list structure. ****************************************************/ void free_rerrhdr(struct rerrhdr *tmp_rerrhdr) { struct rerr_unr_dst *tmp_unr_dst; struct rerr_unr_dst *dead_dst; //for all the unreachable destinataion in the rerr tmp_unr_dst=tmp_rerrhdr->unr_dst; while (tmp_unr_dst!=NULL) { dead_dst=tmp_unr_dst; tmp_unr_dst = tmp_unr_dst->next; kfree(dead_dst); //Bug Fix thanks to Soyeon Ahn! } kfree(tmp_rerrhdr); } /**************************************************** send_rerr ---------------------------------------------------- send_rerr copies the incoming RERR message to a connected data area, which is a suitable format for the function send_datagram. ****************************************************/ int send_rerr(struct rerrhdr *tmp_rerrhdr, u_int32_t sent_to) { struct rerr *out_hdr; struct rerrdst *out_dst; struct rerr_unr_dst *tmp_dst; void *data; int datalen, i; datalen = sizeof(struct rerr) + sizeof(struct rerrdst) * (tmp_rerrhdr->dst_count); //get the needed memory if((data = kmalloc(datalen,GFP_ATOMIC)) == NULL) { printk(KERN_WARNING"AODV: Error creating packet to send RERR\n"); return -ENOMEM; } out_hdr =(struct rerr *) ((char *) data); out_hdr->type = 3; out_hdr->dst_count = tmp_rerrhdr->dst_count; out_hdr->reserved =0; out_dst=(struct rerrdst *) ((char *) out_hdr + sizeof(struct rerr)); tmp_dst = tmp_rerrhdr->unr_dst; for(i = 0; i < tmp_rerrhdr->dst_count; i++) { out_dst->unr_dst_ip=tmp_dst->unr_dst_ip; printk(KERN_INFO "AODV: adding... %s to RERR\n",inet_ntoa(out_dst->unr_dst_ip)); //convert it to network byte order out_dst->unr_dst_seq=htonl(tmp_dst->unr_dst_seq); out_dst =(struct rerrdst *) ((char *) out_dst + sizeof(struct rerrdst)); tmp_dst = tmp_dst->next; } if (sent_to==g_broadcast_ip) local_broadcast(NET_DIAMETER, data, datalen); else send_message(sent_to,NET_DIAMETER, data, datalen); kfree(data); return 0; } /* * print_rerrhdr * * Description: * print_rerrhdr prints a RERR message * * Arguments: * struct rerrhdr *new_rerrhdr - Pointer to the rerrhdr * * Returns: void */ void print_rerrhdr(struct rerrhdr *new_rerrhdr) { struct rerr_unr_dst *tmp_rerr_unr_dst; struct in_addr tmp_in_addr; int i; printk(KERN_INFO "Outgoing RERR message: type: %d dst_cnt: %d\n", new_rerrhdr->type, new_rerrhdr->dst_count); for(i = 0, tmp_rerr_unr_dst = new_rerrhdr->unr_dst; i < new_rerrhdr->dst_count; i++, tmp_rerr_unr_dst = tmp_rerr_unr_dst->next) { tmp_in_addr.s_addr = tmp_rerr_unr_dst->unr_dst_ip; printk(KERN_INFO "unr_dst_ip: %s unr_dst_seq %d\n", inet_ntoa(tmp_in_addr.s_addr), tmp_rerr_unr_dst->unr_dst_seq); } }