int rrep_add_hello_ext(RREP * rrep, int offset, u_int32_t interval) { AODV_ext *ext; ext = (AODV_ext *) ((char *) rrep + RREP_SIZE + offset); ext->type = RREP_HELLO_INTERVAL_EXT; ext->length = sizeof(interval); memcpy(AODV_EXT_DATA(ext), &interval, sizeof(interval)); return (offset + AODV_EXT_SIZE(ext)); }
AODV_ext *NS_CLASS rrep_add_ext(RREP * rrep, int type, unsigned int offset, int len, char *data) { AODV_ext *ext = NULL; if (offset < RREP_SIZE) return NULL; ext = (AODV_ext *) ((char *)rrep + offset); ext->type = type; ext->length = len; memcpy(AODV_EXT_DATA(ext), data, len); return ext; }
/* 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; }
/** * send a hello packet * * @param arg not used! */ void aodv_hello_send (void *arg) { int i, j; struct pbuf *p; struct in_addr addr; struct in_addr dest_broadcast; struct aodv_ext *ext = NULL; u16_t ext_size = 0; if (aodv_wait_on_reboot_get()) { goto __reset_timer; } /* RFC3561 * * dest ip == local ip * dest seqno == aodv_host_state.seqno * hops == 0 * lifetime == ALLOWED_HELLO_LOSS * HELLO_INTERVAL * */ dest_broadcast.s_addr = INADDR_BROADCAST; /* broadcast */ #if AODV_HELLO_NEIGHBOR /* extension which contain our neighbor set */ for (j = 0; j < AODV_RT_TABLESIZE; j++) { struct aodv_rtnode *rt; for (rt = aodv_rt_tbl.hash_tbl[j]; rt != NULL; rt = rt->next) { /* If an entry has an active hello timer, we assume that we are receiving hello messages from that node... */ if (__AODV_TIMER_ISINQ(&rt->hello_timer)) { ext_size += sizeof(struct in_addr); if (ext_size >= 252) { /* max save 63 node */ break; } } } } if (ext_size) { /* have RREP_HELLO_NEIGHBOR_SET_EXT extern */ ext_size += AODV_EXT_HDR_SIZE; } #else (void)j; /* no warning */ #endif /* AODV_HELLO_NEIGHBOR */ /* extension which contain hello interval */ ext_size += (AODV_EXT_HDR_SIZE + 4); /* TODO: in lwip broadcast packet is always used defaute netif output, * so adov netif must be default one! */ for (i = 0; i < AODV_MAX_NETIF; i++) { if (aodv_netif[i]) { addr.s_addr = aodv_netif[i]->ip_addr.addr; p = aodv_rrep_create(0, 0, 0, &addr, aodv_host_state.seqno, &addr, ALLOWED_HELLO_LOSS * HELLO_INTERVAL, ext_size, NULL); if (p) { u32_t interval = htonl(HELLO_INTERVAL); struct aodv_rrep *rrep = (struct aodv_rrep *)p->payload; ext = (struct aodv_ext *)((char *)rrep + RREP_SIZE); #if AODV_HELLO_NEIGHBOR ext->type = RREP_HELLO_NEIGHBOR_SET_EXT; ext->length = 0; /* Assemble a RREP extension which contain our neighbor set... */ for (j = 0; j < AODV_RT_TABLESIZE; j++) { struct aodv_rtnode *rt; for (rt = aodv_rt_tbl.hash_tbl[j]; rt != NULL; rt = rt->next) { if (__AODV_TIMER_ISINQ(&rt->hello_timer)) { memcpy((AODV_EXT_DATA(ext) + ext->length), &rt->dest_addr, sizeof(struct in_addr)); ext->length += sizeof(struct in_addr); if (ext->length >= 252) { /* max save 63 node */ break; } } } } /* add hello interval extern */ if (ext->length != 0) { /* have RREP_HELLO_NEIGHBOR_SET_EXT extern */ ext = AODV_EXT_NEXT(ext); } #endif /* AODV_HELLO_NEIGHBOR */ ext->type = RREP_HELLO_INTERVAL_EXT; ext->length = 4; memcpy(AODV_EXT_DATA(ext), &interval, 4); aodv_udp_sendto(p, &dest_broadcast, 1, i); pbuf_free(p); } } } __reset_timer: aodv_timer_set_timeout(&hello_timer, HELLO_INTERVAL + HELLO_RAND()); }
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(); }