/* Used to update neighbor when non-hello AODV message is received... */ void hello_process_non_hello(AODV_msg *aodv_msg, u_int32_t source) { rt_table_t *entry = NULL; u_int32_t seqno = 0; switch(aodv_msg->type) { case AODV_RREQ: if(((RREQ *)aodv_msg)->src_addr == source) seqno = ((RREQ *)aodv_msg)->src_seqno; break; case AODV_RREP: break; case AODV_RERR: break; default: break; } entry = rt_table_find(source); /* Check message type, and if we can retrieve a sequence number */ if(entry == NULL) entry = rt_table_insert(source, source, 1, seqno, ACTIVE_ROUTE_TIMEOUT, NEIGHBOR); else { /* Don't update anything if this is a uni-directional link... */ if(entry->flags & UNIDIR) return; if(seqno == 0) rt_table_update_timeout(entry, ACTIVE_ROUTE_TIMEOUT); else rt_table_update(entry, source, 1, seqno, ACTIVE_ROUTE_TIMEOUT, NEIGHBOR); } hello_update_timeout(entry, ALLOWED_HELLO_LOSS*HELLO_INTERVAL); }
void rt_table_insert_neighbor(u_int32_t neigh) { if(rt_table_find(neigh) == NULL) rt_table_insert(neigh, neigh, 1, 0, ALLOWED_HELLO_LOSS*HELLO_INTERVAL, NEIGHBOR); }
void rrep_process(RREP * rrep, int rreplen, u_int32_t ip_src, u_int32_t ip_dst, int ip_ttl, unsigned int ifindex) { u_int32_t rrep_dest, rrep_orig, rrep_lifetime, rrep_seqno; rt_table_t *fwd_rt, *rev_rt; /* Convert to correct byte order on affeected fields: */ rrep_dest = ntohl(rrep->dest_addr); rrep_orig = ntohl(rrep->orig_addr); rrep_seqno = ntohl(rrep->dest_seqno); rrep_lifetime = ntohl(rrep->lifetime); if (rreplen < RREP_SIZE) { log(LOG_WARNING, 0, "rrep_process: IP data field too short (%u bytes)" " from %s to %s", rreplen, ip_to_str(ip_src), ip_to_str(ip_dst)); return; } /* Ignore messages which aim to a create a route to one self */ if (memcmp(&rrep_dest, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0 && memcmp(&rrep_orig, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0) return; /* Check if this was a hello message... */ if (ip_ttl == 1) { if (memcmp(&ip_src, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) != 0) hello_process(rrep, rreplen, ifindex); return; } #ifdef DEBUG log(LOG_DEBUG, 0, "RREP_process: from=%s about %s->%s", ip_to_str(ip_src), ip_to_str(rrep_orig), ip_to_str(rrep_dest)); log_pkt_fields((AODV_msg *) rrep); #endif /* When a node receives a RREP, it first increments the hop count in the RREP, to account for the extra hop */ rrep->hcnt++; /* ---------- CHECK IF WE SHOULD MAKE A FORWARD ROUTE ------------ We update or insert a forward route only if: (i) the Destination Sequence Number in the RREP is greater than the node's copy of the destination sequence number, or (ii) the sequence numbers are the same, but the route is no longer active or the Hop Count in RREP is smaller than the hop count in route table entry. */ fwd_rt = rt_table_find(rrep_dest); if (fwd_rt == NULL) { /* We didn't have an existing entry, so we insert a new one. */ fwd_rt = rt_table_insert(rrep_dest, ip_src, rrep->hcnt, rrep_seqno, rrep_lifetime, FWD_ROUTE, ifindex); } else if ((rrep_seqno > fwd_rt->dest_seqno) || (((rrep_seqno == fwd_rt->dest_seqno) && IS_INFTY(fwd_rt->hcnt)) || (fwd_rt->flags & UNIDIR) || (rrep->hcnt < fwd_rt->hcnt))) { fwd_rt = rt_table_update(fwd_rt, ip_src, rrep->hcnt, rrep_seqno, rrep_lifetime, FWD_ROUTE); } else return; /* Check if this RREP was for us (i.e. we previously made a RREQ for this host). */ if (memcmp(&rrep_orig, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0) { /* Remove destination from seeking list since a route has been found. */ if (seek_list_remove(rrep_dest)) packet_buff_send(rrep_dest); /* If the RREP_ACK flag is set we must send a RREP acknowledgement to the destination that replied... */ if (rrep->a) { RREP_ack *rrep_ack; rrep_ack = rrep_ack_create(); aodv_socket_send((AODV_msg *) rrep_ack, fwd_rt->next_hop, NEXT_HOP_WAIT, MAXTTL, &DEV_IFINDEX(fwd_rt->ifindex)); /* Remove RREP_ACK flag... */ rrep->a = 0; } } else { /* --- Here we FORWARD the RREP on the REVERSE route --- */ /* If the current node is not the source node as indicated by the Source IP Address in the RREP message AND a forward route has been created or updated as described before, the node consults its route table entry for the source node to determine the next hop for the RREP packet, and then forwards the RREP towards the source with its Hop Count incremented by one. */ if ((rev_rt = rt_table_find_active(rrep_orig)) != NULL) { /* Here we should do a check if we should request a RREP_ACK, i.e we suspect a unidirectional link.. But how? */ if (0) { rt_table_t *neighbor; /* If the source of the RREP is not a neighbor we must find the neighbor (link) entry which is the next hop towards the RREP source... */ if (rev_rt->dest_addr != rev_rt->next_hop) neighbor = rt_table_find(rev_rt->next_hop); else neighbor = rev_rt; if (neighbor != NULL && !neighbor->ack_timer.used) { /* If the node we received a RREQ for is a neighbor we are probably facing a unidirectional link... Better request a RREP-ack */ rrep->a = 1; neighbor->flags |= UNIDIR; timer_add_msec(&neighbor->ack_timer, NEXT_HOP_WAIT); } } rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, rreplen); aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, RREP_SIZE, --ip_ttl, &DEV_IFINDEX(rev_rt->ifindex)); /* The neighboring nodes to which a RREP was forwarded should be added as a precursor node. */ if (fwd_rt != NULL) precursor_add(fwd_rt, rev_rt->next_hop); /* At each node the (reverse) route used to forward the RREP has its lifetime changed to current time plus ACTIVE_ROUTE_TIMEOUT. */ rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); } } }
/* Process a hello message */ void hello_process(RREP *hello, int rreplen) { u_int32_t hello_dst; u_int32_t hello_interval = HELLO_INTERVAL; u_int32_t ext_neighbor; rt_table_t *entry; AODV_ext *ext = NULL; int i, unidir_link = 1; hello_dst = ntohl(hello->dest_addr); /* Check for hello interval extension: */ ext = (AODV_ext *)((char *)hello + RREP_SIZE); while(rreplen > RREP_SIZE) { switch(ext->type) { case RREP_HELLO_INTERVAL_EXT: if(ext->length == 4) { memcpy(&hello_interval, AODV_EXT_DATA(ext), 4); #ifdef DEBUG_HELLO log(LOG_INFO, 0, "HELLO_process: Hello extension interval=%lu!", hello_interval); #endif } else log(LOG_WARNING, 0, "hello_process: Bad hello interval extension!"); break; case RREP_HELLO_NEIGHBOR_SET_EXT: #ifdef DEBUG_HELLO log(LOG_INFO, 0, "HELLO_process: RREP_HELLO_NEIGHBOR_SET_EXT"); #endif for(i = 0; i < ext->length; i = i + 4) { ext_neighbor = ntohl(*(u_int32_t *)((char *)AODV_EXT_DATA(ext) + i)); if(memcmp(&ext_neighbor, &this_host->ipaddr, 4) == 0) unidir_link = 0; } break; default: log(LOG_WARNING, 0, "hello_process: Bad extension!! type=%d, length=%d", ext->type, ext->length); ext = NULL; break; } if(ext == NULL) break; rreplen -= AODV_EXT_SIZE(ext); ext = AODV_EXT_NEXT(ext); } #ifdef DEBUG_HELLO log(LOG_DEBUG, 0, "processHello: rcvd HELLO from %s, seqno %lu", ip_to_str(hello_dst), hello->dest_seqno); #endif if((entry = rt_table_find(hello_dst)) == NULL) { /* No active or expired route in the routing table. So we add a new entry... */ if(unidir_hack && unidir_link) { entry = rt_table_insert(hello_dst, hello_dst, 1, hello->dest_seqno, ACTIVE_ROUTE_TIMEOUT, NEIGHBOR | UNIDIR); #ifdef DEBUG log(LOG_INFO, 0, "hello_process: %s is UNI-DIR!!!", ip_to_str(entry->dest)); #endif } else { entry = rt_table_insert(hello_dst, hello_dst, 1, hello->dest_seqno, ACTIVE_ROUTE_TIMEOUT, NEIGHBOR); #ifdef DEBUG log(LOG_INFO, 0, "hello_process: %s is BI-DIR!!!", ip_to_str(entry->dest)); #endif } } else { if(unidir_hack && unidir_link) { #ifdef DEBUG if(!(entry->flags & UNIDIR)) log(LOG_INFO, 0, "hello_process: %s is UNI-DIR!!!", ip_to_str(entry->dest)); #endif entry->flags |= UNIDIR; } else if(entry->flags & UNIDIR) { entry->flags ^= UNIDIR; #ifdef DEBUG log(LOG_INFO, 0, "hello_process: %s is BI-DIR!!!", ip_to_str(entry->dest)); #endif } /* Update sequence numbers if the hello contained new info... */ if(hello->dest_seqno < entry->dest_seqno) hello->dest_seqno = entry->dest_seqno; if(entry->flags & UNIDIR) entry->dest_seqno = hello->dest_seqno; else { rt_table_update(entry, hello_dst, 1, hello->dest_seqno, ACTIVE_ROUTE_TIMEOUT, NEIGHBOR); } } /* Only update hello timeout for routes which are not unidir */ /* if(!(entry->flags & UNIDIR)) */ hello_update_timeout(entry, ALLOWED_HELLO_LOSS*hello_interval); return; }
void hello_process(RREP *hello, s32_t len) { u32_t hello_seqno, timeout, hello_interval = HELLO_INTERVAL; u8_t state, flags = 0; struct in_addr hello_dest; rt_table_t *rt; struct timeval now; gettimeofday(&now, NULL); hello_dest.s_addr = hello->dest_addr; hello_seqno = ntohl(hello->dest_seqno); rt = rt_table_check(hello_dest); if(rt) flags = rt->flags; if(receive_n_hellos) state = INVALID; else state = VALID; timeout = ALLOWED_HELLO_LOSS * hello_interval + ROUTE_TIMEOUT_SLACK; if(!rt) { rt = rt_table_insert(hello_dest, hello_dest, 1, hello_seqno, timeout, state, flags); if(flags & RT_UNIDIR) { DEBUG(LOG_INFO, 0, "%s new NEIGHBOR, link UNI_DIR", ip_to_str(rt->dest_addr)); } else { DEBUG(LOG_INFO, 0, "%s new NEIGHBOR", ip_to_str(rt->dest_addr)); } rt->hello_cnt = 1; } else { if((flags & RT_UNIDIR) && rt->state == VALID && rt->hopcnt > 1) { hello_update_timeout(rt, &now, ALLOWED_HELLO_LOSS *hello_interval); return; } if(receive_n_hellos && rt->hello_cnt < (receive_n_hellos - 1)) { if(timeval_diff(&now, &rt->last_hello_time) < (long)(hello_interval + hello_interval / 2)) rt->hello_cnt++; else rt->hello_cnt = 1; memcpy(&rt->last_hello_time, &now, sizeof(struct timeval)); return; } rt_table_update(rt, hello_dest, 1, hello_seqno, timeout, VALID, flags); hello_update_timeout(rt, &now, ALLOWED_HELLO_LOSS * hello_interval); } }
void NS_CLASS rrep_process(RREP * rrep, int rreplen, struct in_addr ip_src, struct in_addr ip_dst, int ip_ttl, unsigned int ifindex) { u_int32_t rrep_lifetime, rrep_seqno, rrep_new_hcnt; u_int8_t pre_repair_hcnt = 0, pre_repair_flags = 0; rt_table_t *fwd_rt, *rev_rt; AODV_ext *ext; unsigned int extlen = 0; int rt_flags = 0; struct in_addr rrep_dest, rrep_orig; #ifdef CONFIG_GATEWAY struct in_addr inet_dest_addr; int inet_rrep = 0; #endif /* Convert to correct byte order on affeected fields: */ rrep_dest.s_addr = rrep->dest_addr; rrep_orig.s_addr = rrep->orig_addr; rrep_seqno = ntohl(rrep->dest_seqno); rrep_lifetime = ntohl(rrep->lifetime); /* Increment RREP hop count to account for intermediate node... */ rrep_new_hcnt = rrep->hcnt + 1; if (rreplen < (int)RREP_SIZE) { alog(LOG_WARNING, 0, __FUNCTION__, "IP data field too short (%u bytes)" " from %s to %s", rreplen, ip_to_str(ip_src), ip_to_str(ip_dst)); return; } /* Ignore messages which aim to a create a route to one self */ if (rrep_dest.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr) return; DEBUG(LOG_DEBUG, 0, "from %s about %s->%s", ip_to_str(ip_src), ip_to_str(rrep_orig), ip_to_str(rrep_dest)); #ifdef DEBUG_OUTPUT log_pkt_fields((AODV_msg *) rrep); #endif /* Determine whether there are any extensions */ ext = (AODV_ext *) ((char *)rrep + RREP_SIZE); while ((rreplen - extlen) > RREP_SIZE) { switch (ext->type) { case RREP_EXT: DEBUG(LOG_INFO, 0, "RREP include EXTENSION"); /* Do something here */ break; #ifdef CONFIG_GATEWAY case RREP_INET_DEST_EXT: if (ext->length == sizeof(u_int32_t)) { /* Destination address in RREP is the gateway address, while the * extension holds the real destination */ memcpy(&inet_dest_addr, AODV_EXT_DATA(ext), ext->length); DEBUG(LOG_DEBUG, 0, "RREP_INET_DEST_EXT: <%s>", ip_to_str(inet_dest_addr)); /* This was a RREP from a gateway */ rt_flags |= RT_GATEWAY; inet_rrep = 1; break; } #endif default: alog(LOG_WARNING, 0, __FUNCTION__, "Unknown or bad extension %d", ext->type); break; } extlen += AODV_EXT_SIZE(ext); ext = AODV_EXT_NEXT(ext); } /* ---------- CHECK IF WE SHOULD MAKE A FORWARD ROUTE ------------ */ fwd_rt = rt_table_find(rrep_dest); rev_rt = rt_table_find(rrep_orig); if (!fwd_rt) { /* We didn't have an existing entry, so we insert a new one. */ fwd_rt = rt_table_insert(rrep_dest, ip_src, rrep_new_hcnt, rrep_seqno, rrep_lifetime, VALID, rt_flags, ifindex); } else if (fwd_rt->dest_seqno == 0 || (int32_t) rrep_seqno > (int32_t) fwd_rt->dest_seqno || (rrep_seqno == fwd_rt->dest_seqno && (fwd_rt->state == INVALID || fwd_rt->flags & RT_UNIDIR || rrep_new_hcnt < fwd_rt->hcnt))) { pre_repair_hcnt = fwd_rt->hcnt; pre_repair_flags = fwd_rt->flags; fwd_rt = rt_table_update(fwd_rt, ip_src, rrep_new_hcnt, rrep_seqno, rrep_lifetime, VALID, rt_flags | fwd_rt->flags); } else { if (fwd_rt->hcnt > 1) { DEBUG(LOG_DEBUG, 0, "Dropping RREP, fwd_rt->hcnt=%d fwd_rt->seqno=%ld", fwd_rt->hcnt, fwd_rt->dest_seqno); } return; } /* If the RREP_ACK flag is set we must send a RREP acknowledgement to the destination that replied... */ if (rrep->a) { RREP_ack *rrep_ack; rrep_ack = rrep_ack_create(); aodv_socket_send((AODV_msg *) rrep_ack, fwd_rt->next_hop, NEXT_HOP_WAIT, MAXTTL, &DEV_IFINDEX(fwd_rt->ifindex)); /* Remove RREP_ACK flag... */ rrep->a = 0; } /* Check if this RREP was for us (i.e. we previously made a RREQ for this host). */ if (rrep_orig.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr) { #ifdef CONFIG_GATEWAY if (inet_rrep) { rt_table_t *inet_rt; inet_rt = rt_table_find(inet_dest_addr); /* Add a "fake" route indicating that this is an Internet * destination, thus should be encapsulated and routed through a * gateway... */ if (!inet_rt) rt_table_insert(inet_dest_addr, rrep_dest, rrep_new_hcnt, 0, rrep_lifetime, VALID, RT_INET_DEST, ifindex); else if (inet_rt->state == INVALID || rrep_new_hcnt < inet_rt->hcnt) { rt_table_update(inet_rt, rrep_dest, rrep_new_hcnt, 0, rrep_lifetime, VALID, RT_INET_DEST | inet_rt->flags); } else { DEBUG(LOG_DEBUG, 0, "INET Response, but no update %s", ip_to_str(inet_dest_addr)); } } #endif /* CONFIG_GATEWAY */ /* If the route was previously in repair, a NO DELETE RERR should be sent to the source of the route, so that it may choose to reinitiate route discovery for the destination. Fixed a bug here that caused the repair flag to be unset and the RERR never being sent. Thanks to McWood <*****@*****.**> for discovering this. */ if (pre_repair_flags & RT_REPAIR) { if (fwd_rt->hcnt > pre_repair_hcnt) { RERR *rerr; u_int8_t rerr_flags = 0; struct in_addr dest; dest.s_addr = AODV_BROADCAST; rerr_flags |= RERR_NODELETE; rerr = rerr_create(rerr_flags, fwd_rt->dest_addr, fwd_rt->dest_seqno); if (fwd_rt->nprec) aodv_socket_send((AODV_msg *) rerr, dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(fwd_rt-> ifindex)); } } } else { /* --- Here we FORWARD the RREP on the REVERSE route --- */ if (rev_rt && rev_rt->state == VALID) { rrep_forward(rrep, rreplen, rev_rt, fwd_rt, --ip_ttl); } else { DEBUG(LOG_DEBUG, 0, "Could not forward RREP - NO ROUTE!!!"); } } if (!llfeedback && optimized_hellos) hello_start(); }