rt_table_t *rt_table_update(rt_table_t * rt_entry, u_int32_t next, u_int8_t hops, u_int32_t seqno, u_int32_t newlife, u_int16_t flags) { int ret; /* If this previously was an expired route, but will now be active again we must add it to the kernel routing table... */ if (rt_entry->hcnt == INFTY && hops != INFTY) { rt_entry->rt_timer.handler = route_expire_timeout; ret = k_add_rte(rt_entry->dest_addr, next, 0, hops, rt_entry->ifindex); if (ret < 0) log(LOG_WARNING, errno, "rt_table_update: Could not add kernel route!"); #ifdef DEBUG else log(LOG_INFO, 0, "rt_table_update: Added kernel route for expired %s", ip_to_str(rt_entry->dest_addr)); #endif } else if (rt_entry->next_hop != 0 && rt_entry->next_hop != next) { #ifdef DEBUG log(LOG_INFO, 0, "rt_table_update: rt_entry->nxt_addr=%s, next=%s", ip_to_str(rt_entry->next_hop), ip_to_str(next)); #endif precursor_list_destroy(rt_entry); ret = k_chg_rte(rt_entry->dest_addr, next, 0, hops, rt_entry->ifindex); if (ret < 0) log(LOG_WARNING, errno, "rt_table_update: Could not update kernel route!"); } rt_entry->dest_seqno = seqno; rt_entry->last_life = newlife; rt_entry->flags = flags; rt_entry->next_hop = next; rt_entry->last_hcnt = rt_entry->hcnt; rt_entry->hcnt = hops; if (hops > 1) { rt_entry->last_hello_time.tv_sec = 0; rt_entry->last_hello_time.tv_usec = 0; rt_entry->hello_cnt = 0; } /* If newlife = 0 the timer and the expire time should not be updated... */ if (newlife != 0) rt_table_update_timeout(rt_entry, newlife); return rt_entry; }
void NS_CLASS rrep_forward(RREP * rrep, int size, rt_table_t * rev_rt, rt_table_t * fwd_rt, int ttl) { /* Sanity checks... */ if (!fwd_rt || !rev_rt) { DEBUG(LOG_WARNING, 0, "Could not forward RREP because of NULL route!"); return; } if (!rrep) { DEBUG(LOG_WARNING, 0, "No RREP to forward!"); return; } DEBUG(LOG_DEBUG, 0, "Forwarding RREP to %s", ip_to_str(rev_rt->next_hop)); /* 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.s_addr != rev_rt->next_hop.s_addr) neighbor = rt_table_find(rev_rt->next_hop); else neighbor = rev_rt; if (neighbor && !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 |= RT_UNIDIR; timer_set_timeout(&neighbor->ack_timer, NEXT_HOP_WAIT); } } rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, size); rrep->hcnt = fwd_rt->hcnt; /* Update the hopcount */ aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, ttl, &DEV_IFINDEX(rev_rt->ifindex)); precursor_add(fwd_rt, rev_rt->next_hop); precursor_add(rev_rt, fwd_rt->next_hop); rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); }
rt_table_t* rt_table_update(rt_table_t *entry, u_int32_t next, u_int8_t hops, u_int32_t seqno, u_int32_t newlife, u_int16_t flags) { /* If the next hop for some reason has changed - update kernel routing table. */ if ((entry->next_hop != 0) && (entry->next_hop != next) && !IS_INFTY(entry->hcnt)) { #ifdef DEBUG log(LOG_INFO, 0, "rt_table_update: entry->nxt_addr=%s, next=%s", ip_to_str(entry->next_hop), ip_to_str(next)); #endif if(k_chg_rte(entry->dest, next, 0, hops) < 0) fprintf(stderr, "rt_table_update: Could not update kernel routing table!!!\n"); } /* If this previously was an expired route, but will now be active again we must add it to the kernel routing table... */ if(IS_INFTY(entry->hcnt) && !IS_INFTY(hops)) { /* We should also update our own sequence number whenever our neighbor set changes. (AODV draft v.8, section 8.4.1.) */ if(hops == 1) this_host->seqno++; #ifdef DEBUG log(LOG_INFO, 0, "rt_table_update: Adding KERNEL route for expired %s", ip_to_str(entry->dest)); #endif if(entry->dest == next) k_add_rte(entry->dest, 0, 0, hops); else k_add_rte(entry->dest, next, 0, hops); } entry->dest_seqno = seqno; entry->last_life = newlife; entry->flags |= flags; entry->next_hop = next; entry->last_hcnt = entry->hcnt; entry->hcnt = hops; /* If newlife = 0 the timer and the expire time should not be updated... */ if(newlife != 0) rt_table_update_timeout(entry, newlife); return entry; }
/* 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 NS_CLASS route_discovery_timeout(void *arg) { struct timeval now; seek_list_t *seek_entry; rt_table_t *rt, *repair_rt; seek_entry = (seek_list_t *) arg; #define TTL_VALUE seek_entry->ttl /* Sanity check... */ if (!seek_entry) return; gettimeofday(&now, NULL); DEBUG(LOG_DEBUG, 0, "%s", ip_to_str(seek_entry->dest_addr)); if (seek_entry->reqs < RREQ_RETRIES) { if (expanding_ring_search) { if (TTL_VALUE < TTL_THRESHOLD) TTL_VALUE += TTL_INCREMENT; else { TTL_VALUE = NET_DIAMETER; seek_entry->reqs++; } /* Set a new timer for seeking this destination */ timer_set_timeout(&seek_entry->seek_timer, RING_TRAVERSAL_TIME); } else { seek_entry->reqs++; timer_set_timeout(&seek_entry->seek_timer, seek_entry->reqs * 2 * NET_TRAVERSAL_TIME); } /* AODV should use a binary exponential backoff RREP waiting time. */ DEBUG(LOG_DEBUG, 0, "Seeking %s ttl=%d wait=%d", ip_to_str(seek_entry->dest_addr), TTL_VALUE, 2 * TTL_VALUE * NODE_TRAVERSAL_TIME); /* A routing table entry waiting for a RREP should not be expunged before 2 * NET_TRAVERSAL_TIME... */ rt = rt_table_find(seek_entry->dest_addr); if (rt && timeval_diff(&rt->rt_timer.timeout, &now) < (2 * NET_TRAVERSAL_TIME)) rt_table_update_timeout(rt, 2 * NET_TRAVERSAL_TIME); rreq_send(seek_entry->dest_addr, seek_entry->dest_seqno, TTL_VALUE, seek_entry->flags); } else { DEBUG(LOG_DEBUG, 0, "NO ROUTE FOUND!"); #ifdef NS_PORT packet_queue_set_verdict(seek_entry->dest_addr, PQ_DROP); #else nl_send_no_route_found_msg(seek_entry->dest_addr); #endif repair_rt = rt_table_find(seek_entry->dest_addr); seek_list_remove(seek_entry); /* If this route has been in repair, then we should timeout the route at this point. */ if (repair_rt && (repair_rt->flags & RT_REPAIR)) { DEBUG(LOG_DEBUG, 0, "REPAIR for %s failed!", ip_to_str(repair_rt->dest_addr)); local_repair_timeout(repair_rt); } } }
static void packet_input(int fd) #endif { rt_table_t *fwd_rt, *rev_rt, *next_hop_rt = NULL; struct in_addr dest_addr, src_addr; u_int8_t rreq_flags = 0; unsigned int ifindex; struct ip_data *ipd = NULL; int pkt_flags = 0; #ifdef NS_PORT ifindex = NS_IFINDEX; /* Always use ns interface */ fwd_rt = NULL; /* For broadcast we provide no next hop */ ipd = NULL; /* No ICMP messaging */ struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); src_addr.s_addr = ih->saddr(); dest_addr.s_addr = ih->daddr(); /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ if (ch->ptype() == PT_TCP) { rreq_flags |= RREQ_GRATUITOUS; } #else int status; char buf[sizeof(struct nlmsghdr)+sizeof(ipq_packet_msg_t)+BUFSIZE]; char *dev_name; ipq_packet_msg_t *pkt; struct iphdr *ip; struct udphdr *udp; struct icmphdr *icmp = NULL; status = ipq_read(h, buf, sizeof(buf), -1); if (status < 0) { DEBUG(LOG_DEBUG, 0, "%s", ipq_errstr()); ipq_perror(NULL); return; } if (ipq_message_type(buf) == NLMSG_ERROR) { fprintf(stderr, "ERROR packet_input: Check that the ip_queue.o module is loaded.\n"); die(h); } pkt = ipq_get_packet(buf); #ifdef DEBUG_PACKET DEBUG(LOG_DEBUG, 0, "Protocol %u indev=%s outdev=%s\n", pkt->hw_protocol, pkt->indev_name, pkt->outdev_name); #endif if (pkt->hook == 0) dev_name = pkt->indev_name; else if (pkt->hook == 3) dev_name = pkt->outdev_name; else dev_name = NULL; /* We know from kaodv.c that this is an IP packet */ ip = (struct iphdr *) pkt->payload; dest_addr.s_addr = ip->daddr; src_addr.s_addr = ip->saddr; switch (ip->protocol) { /* Don't process AODV control packets (UDP on port 654). They are accounted for on the aodv socket */ case IPPROTO_UDP: udp = (struct udphdr *) ((char *) ip + (ip->ihl << 2)); if (ntohs(udp->dest) == AODV_PORT || ntohs(udp->source) == AODV_PORT) goto accept; break; /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ case IPPROTO_TCP: rreq_flags |= RREQ_GRATUITOUS; break; /* We set the gratuitous flag also on ICMP ECHO requests, since the destination will also need a route back for the reply... */ case IPPROTO_ICMP: icmp = (struct icmphdr *) ((char *) ip + (ip->ihl << 2)); if (icmp->type == ICMP_ECHO) rreq_flags |= RREQ_GRATUITOUS; #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "setting G flag for RREQ to %s", ip_to_str(dest_addr)); #endif break; #ifdef CONFIG_GATEWAY case IPPROTO_MIPE: if (internet_gw_mode) { ip = ip_pkt_decapsulate(ip); if (ip == NULL) { DEBUG(LOG_ERR, 0, "Decapsulation failed..."); exit(-1); } pkt_flags |= PKT_DEC; } break; #endif /* CONFIG_GATEWAY */ } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "pkt to %s", ip_to_str(dest_addr)); #endif if (dev_name) { ifindex = name2index(dev_name); if (ifindex < 0) { DEBUG(LOG_ERR, 0, "name2index error!"); return; } } else ifindex = 0; #endif /* NS_PORT */ /* If the packet is not interesting we just let it go through... */ if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(ifindex).broadcast.s_addr) { #ifdef NS_PORT /* Limit Non AODV broadcast packets (Rolf Winter * <[email protected]). */ ih->ttl() = ih->ttl() - 1; if(ih->ttl() < 1) Packet::free(p); else sendPacket(p, dest_addr, 0.0); return; #else goto accept; #endif } /* Find the entry of the neighboring node and the destination (if any). */ rev_rt = rt_table_find(src_addr); fwd_rt = rt_table_find(dest_addr); #ifdef CONFIG_GATEWAY /* Check if we have a route and it is an Internet destination (Should be * encapsulated and routed through the gateway). */ if (fwd_rt && (fwd_rt->state == VALID) && (fwd_rt->flags & RT_INET_DEST)) { /* The destination should be relayed through the IG */ rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); #ifdef NS_PORT p = pkt_encapsulate(p, fwd_rt->next_hop); if (p == NULL) { DEBUG(LOG_ERR, 0, "IP Encapsulation failed!"); return; } /* Update pointers to headers */ ch = HDR_CMN(p); ih = HDR_IP(p); #else ip = ip_pkt_encapsulate(ip, fwd_rt->next_hop, BUFSIZE); if (ip == NULL) { DEBUG(LOG_ERR, 0, "Minimal IP Encapsulation failed!"); exit(-1); } #endif dest_addr = fwd_rt->next_hop; fwd_rt = rt_table_find(dest_addr); pkt_flags |= PKT_ENC; } #endif /* CONFIG_GATEWAY */ /* UPDATE TIMERS on active forward and reverse routes... */ /* When forwarding a packet, we update the lifetime of the destination's routing table entry, as well as the entry for the next hop neighbor (if not the same). AODV draft 10, section 6.2. */ if (fwd_rt && fwd_rt->state == VALID && dest_addr.s_addr != DEV_IFINDEX(ifindex).ipaddr.s_addr) { rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find(fwd_rt->next_hop); if (next_hop_rt && next_hop_rt->state == VALID && next_hop_rt->dest_addr.s_addr != fwd_rt->dest_addr.s_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } /* Also update the reverse route and reverse next hop along the path back, since routes between originators and the destination are expected to be symmetric. */ if (rev_rt && rev_rt->state == VALID) { rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find(rev_rt->next_hop); if (next_hop_rt && next_hop_rt->state == VALID && rev_rt && next_hop_rt->dest_addr.s_addr != rev_rt->dest_addr.s_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); /* Update HELLO timer of next hop neighbor if active */ if (!llfeedback && next_hop_rt->hello_timer.used) { struct timeval now; gettimeofday(&now, NULL); hello_update_timeout(next_hop_rt, &now, ALLOWED_HELLO_LOSS * HELLO_INTERVAL); } } /* OK, the timeouts have been updated. Now see if either: 1. The packet is for this node -> ACCEPT. 2. The packet is not for this node -> Send RERR (someone want's this node to forward packets although there is no route) or Send RREQ. */ /* If the packet is destined for this node, then just accept it. */ if (memcmp(&dest_addr, &DEV_IFINDEX(ifindex).ipaddr, sizeof(struct in_addr)) == 0) { #ifdef NS_PORT ch->size() -= IP_HDR_LEN; // cut off IP header size 4/7/99 -dam target_->recv(p, (Handler*)0); p = 0; return; #else goto accept; #endif } if (!fwd_rt || fwd_rt->state == INVALID || (fwd_rt->hcnt == 1 && (fwd_rt->flags & RT_UNIDIR))) { /* Check if the route is marked for repair or is INVALID. In * that case, do a route discovery. */ if (fwd_rt && (fwd_rt->flags & RT_REPAIR)) goto route_discovery; /* If a packet is received on the NF_IP_PRE_ROUTING hook, i.e. inbound on the interface and we don't have a route to the destination, we should send an RERR to the source and then drop the package... */ /* NF_IP_PRE_ROUTING = 0 */ #ifdef NS_PORT #define PACKET_IS_INBOUND ch->direction() == hdr_cmn::UP #else #define PACKET_IS_INBOUND pkt->hook == 0 #endif if (PACKET_IS_INBOUND) { struct in_addr rerr_dest; RERR *rerr; #ifdef NS_PORT struct in_addr nh; nh.s_addr = ch->prev_hop_; DEBUG(LOG_DEBUG, 0, "No route, src=%s dest=%s prev_hop=%s - DROPPING!", ip_to_str(src_addr), ip_to_str(dest_addr), ip_to_str(nh)); #endif if (fwd_rt) { rerr = rerr_create(0, fwd_rt->dest_addr, fwd_rt->dest_seqno); rt_table_update_timeout(fwd_rt, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); DEBUG(LOG_DEBUG, 0, "Sending RERR to prev hop %s for unknown dest %s", ip_to_str(src_addr), ip_to_str(dest_addr)); /* Unicast the RERR to the source of the data transmission * if possible, otherwise we broadcast it. */ if (rev_rt && rev_rt->state == VALID) rerr_dest = rev_rt->next_hop; else rerr_dest.s_addr = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "Wait on reboot timer reset."); timer_set_timeout(&worb_timer, DELETE_PERIOD); } #ifdef NS_PORT /* DEBUG(LOG_DEBUG, 0, "Dropping pkt uid=%d", ch->uid()); */ drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); if (status < 0) die(h); #endif return; } route_discovery: /* Buffer packets... Packets are queued by the ip_queue.o module already. We only need to save the handle id, and return the proper verdict when we know what to do... */ #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr, ip); #ifdef CONFIG_GATEWAY /* In gateway mode we handle packets in userspace */ ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); #endif /* Already seeking the destination? Then do not allocate any memory or generate a RREQ. */ if (seek_list_find(dest_addr)) return; /* If the request is generated locally by an application, we save the IP header + 64 bits of data for sending an ICMP Destination Host Unreachable in case we don't find a route... */ if (src_addr.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr && ip && pkt->data_len >= (ip->ihl << 2) + 8) { ipd = (struct ip_data *) malloc(sizeof(struct ip_data)); if (ipd == NULL) { perror("Malloc for IP data failed!"); exit(-1); } /* IP header + 64 bits data (8 bytes) */ ipd->len = (ip->ihl << 2) + 8; memcpy(ipd->data, ip, ipd->len); } else ipd = NULL; #endif if (fwd_rt && (fwd_rt->flags & RT_REPAIR)) rreq_local_repair(fwd_rt, src_addr, ipd); else rreq_route_discovery(dest_addr, rreq_flags, ipd); return; } else { #ifdef NS_PORT /* DEBUG(LOG_DEBUG, 0, "Sending pkt uid=%d", ch->uid()); */ sendPacket(p, fwd_rt->next_hop, 0.0); #else accept: if (pkt_flags & PKT_ENC || (pkt_flags & PKT_DEC)) status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, ntohs(ip->tot_len), (unsigned char *)ip); else status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, 0, NULL); if (status < 0) die(h); #endif /* When forwarding data, make sure we are sending HELLO messages */ gettimeofday(&this_host.fwd_time, NULL); if (!llfeedback && optimized_hellos) hello_start(); } }
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); } } }
static void packet_input(int fd) #endif { rt_table_t *fwd_rt, *rev_rt, *repair_rt, *next_hop_rt; u_int32_t dest_addr, src_addr; u_int8_t rreq_flags = 0; unsigned int ifindex; struct ip_data *ipd = NULL; #ifdef NS_PORT ifindex = NS_IFINDEX; // Always use ns interface fwd_rt = NULL; // In case of broadcast we provide no next hop ipd = NULL; // No ICMP messaging struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); src_addr = ih->saddr(); dest_addr = ih->daddr(); /* Any packets with our IP address as destination arriving here are packets that weren't caught by any agent attached to the node. Throw away those. */ if (dest_addr == DEV_IFINDEX(ifindex).ipaddr) { DEBUG(LOG_WARNING, 0, "processPacket: Received orphan packet. Throwing it away."); Packet::free(p); return; } /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ if (ch->ptype() == PT_TCP) { rreq_flags |= RREQ_GRATUITOUS; } #else int status; char buf[BUFSIZE], *dev_name; ipq_packet_msg_t *pkt; struct iphdr *ip; struct udphdr *udp; struct icmphdr *icmp = NULL; ipq_read(h, buf, BUFSIZE, 0); status = ipq_message_type(buf); if (status == NLMSG_ERROR) { fprintf(stderr, "ERROR packet_input: Check that the ip_queue.o module is loaded.\n"); die(h); } pkt = ipq_get_packet(buf); #ifdef DEBUG_PACKET DEBUG(LOG_DEBUG, 0, "Protocol %u indev=%s outdev=%s\n", pkt->hw_protocol, pkt->indev_name, pkt->outdev_name); #endif if (pkt->hook == 0) dev_name = pkt->indev_name; else if (pkt->hook == 3) dev_name = pkt->outdev_name; else dev_name = NULL; /* We know from kaodv.c that this is an IP packet */ ip = (struct iphdr *) pkt->payload; dest_addr = ntohl(ip->daddr); src_addr = ntohl(ip->saddr); switch (ip->protocol) { /* Don't process AODV control packets (UDP on port 654). They are accounted for on the aodv socket */ case IPPROTO_UDP: udp = (struct udphdr *) ((char *) ip + (ip->ihl << 2)); if (ntohs(udp->dest) == AODV_PORT || ntohs(udp->source) == AODV_PORT) goto accept; break; /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ case IPPROTO_TCP: rreq_flags |= RREQ_GRATUITOUS; break; /* We set the gratuitous flag also on ICMP ECHO requests, since the destination will also need a route back for the reply... */ case IPPROTO_ICMP: icmp = (struct icmphdr *) ((char *) ip + (ip->ihl << 2)); if (icmp->type == ICMP_ECHO) rreq_flags |= RREQ_GRATUITOUS; #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: setting G flag for RREQ to %s", ip_to_str(dest_addr)); #endif break; default: } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: pkt to %s", ip_to_str(dest_addr)); #endif if (dev_name) ifindex = if_nametoindex(dev_name); else ifindex = 0; #endif /* NS_PORT */ /* If the packet is not interesting we just let it go through... */ if ((dest_addr == AODV_BROADCAST) || (dest_addr == DEV_IFINDEX(ifindex).ipaddr) || (dest_addr == DEV_IFINDEX(ifindex).broadcast) || ((internet_gw_mode && this_host.gateway_mode) && ((dest_addr & DEV_IFINDEX(ifindex).netmask) != DEV_IFINDEX(ifindex).broadcast))) goto accept; /* Find the entry of the neighboring node and the destination (if any). */ rev_rt = rt_table_find_active(src_addr); fwd_rt = rt_table_find_active(dest_addr); /* If a packet is received on the NF_IP_PRE_ROUTING hook, i.e. inbound on the interface and we don't have a route to the destination, we should send an RERR to the source and then drop the package... */ /* NF_IP_PRE_ROUTING = 0 */ #ifdef NS_PORT #define PACKET_IS_INBOUND ch->direction() == hdr_cmn::UP #else #define PACKET_IS_INBOUND pkt->hook == 0 #endif if ((dest_addr != DEV_IFINDEX(ifindex).ipaddr) && (!fwd_rt && PACKET_IS_INBOUND)) { rt_table_t *rt_entry; u_int32_t rerr_dest; RERR *rerr; DEBUG(LOG_DEBUG, 0, "packet_input: Sending RERR for unknown dest %s", ip_to_str(dest_addr)); /* There is an expired entry in the routing table we want to send along the seqno in the RERR... */ rt_entry = rt_table_find(dest_addr); if (rt_entry) { rerr = rerr_create(0, rt_entry->dest_addr, rt_entry->dest_seqno); rt_table_update_timeout(rt_entry, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); /* Unicast the RERR to the source of the data transmission if * possible, otherwise we broadcast it. */ if (rev_rt) rerr_dest = rev_rt->next_hop; else rerr_dest = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "packet_input: Wait on reboot timer reset."); timer_add_msec(&worb_timer, DELETE_PERIOD); } #ifdef NS_PORT drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); if (status < 0) die(h); #endif return; } /* Check if the route is currently in repair. In that case just buffer the packet */ repair_rt = rt_table_find(dest_addr); if (repair_rt && (repair_rt->flags & LREPAIR)) { #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr); #endif return; } /* update_timers: */ /* When forwarding a packet, we update the lifetime of the destination's routing table entry, as well as the entry for the next hop neighbor (if not the same). AODV draft 10, section 6.2. */ if (fwd_rt && dest_addr != DEV_IFINDEX(ifindex).ipaddr) { rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find_active(fwd_rt->next_hop); if (next_hop_rt && next_hop_rt->dest_addr != fwd_rt->dest_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } /* Also update the reverse route and reverse next hop along the path back, since routes between originators and the destination are expected to be symmetric. */ if (rev_rt) { rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find_active(rev_rt->next_hop); if (next_hop_rt && next_hop_rt->dest_addr != fwd_rt->dest_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: d=%s s=%s", ip_to_str(dest_addr), ip_to_str(src_addr)); #endif /* DEBUG_PACKET */ if (!fwd_rt || (fwd_rt->hcnt == 1 && (fwd_rt->flags & UNIDIR))) { /* Buffer packets... Packets are queued by the ip_queue_aodv.o module already. We only need to save the handle id, and return the proper verdict when we know what to do... */ #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr); /* If the request is generated locally by an application, we save the IP header + 64 bits of data for sending an ICMP Destination Host Unreachable in case we don't find a route... */ if (src_addr == DEV_IFINDEX(ifindex).ipaddr) { ipd = (struct ip_data *) malloc(sizeof(struct ip_data)); if (ipd < 0) { perror("Malloc for IP data failed!"); exit(-1); } ipd->len = (ip->ihl << 2) + 8; /* IP header + 64 bits data (8 bytes) */ memcpy(ipd->data, ip, ipd->len); } else ipd = NULL; #endif rreq_route_discovery(dest_addr, rreq_flags, ipd); return; } accept: #ifdef NS_PORT if (fwd_rt) sendPacket(p, fwd_rt->next_hop, 0.0); else drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, 0, NULL); if (status < 0) die(h); #endif return; }
static void nl_callback(int sock) { int len, attrlen; socklen_t addrlen; struct nlmsghdr *nlm; struct nlmsgerr *nlmerr; char buf[BUFLEN]; struct in_addr dest_addr, src_addr; struct ifaddrmsg *ifm; struct rtattr *rta; kaodv_rt_msg_t *m; rt_table_t *rt, *fwd_rt, *rev_rt = NULL; addrlen = sizeof(peer); len = recvfrom(sock, buf, BUFLEN, 0, (struct sockaddr *)&peer, &addrlen); if (len <= 0) return; nlm = (struct nlmsghdr *)buf; switch (nlm->nlmsg_type) { case NLMSG_ERROR: nlmerr = NLMSG_DATA(nlm); if (nlmerr->error == 0) { DEBUG(LOG_DEBUG, 0, "NLMSG_ACK"); } else DEBUG(LOG_DEBUG, 0, "NLMSG_ERROR, error=%d", nlmerr->error); break; case RTM_NEWLINK: DEBUG(LOG_DEBUG, 0, "RTM_NEWADDR"); break; case RTM_NEWADDR: DEBUG(LOG_DEBUG, 0, "RTM_NEWADDR"); ifm = NLMSG_DATA(nlm); rta = (struct rtattr *)((char *)ifm + sizeof(ifm)); attrlen = nlm->nlmsg_len - sizeof(struct nlmsghdr) - sizeof(struct ifaddrmsg); for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { if (rta->rta_type == IFA_ADDRESS) { struct in_addr ifaddr; memcpy(&ifaddr, RTA_DATA(rta), RTA_PAYLOAD(rta)); DEBUG(LOG_DEBUG, 0, "Interface index %d changed address to %s", ifm->ifa_index, ip_to_str(ifaddr)); } } break; case KAODVM_TIMEOUT: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; DEBUG(LOG_DEBUG, 0, "Got TIMEOUT msg from kernel for %s", ip_to_str(dest_addr)); rt = rt_table_find(dest_addr); if (rt && rt->state == VALID) route_expire_timeout(rt); else DEBUG(LOG_DEBUG, 0, "Got rt timeoute event but there is no route"); break; case KAODVM_NOROUTE: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; DEBUG(LOG_DEBUG, 0, "Got NOROUTE msg from kernel for %s", ip_to_str(dest_addr)); rreq_route_discovery(dest_addr, 0, NULL); break; case KAODVM_REPAIR: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; DEBUG(LOG_DEBUG, 0, "Got REPAIR msg from kernel for %s", ip_to_str(dest_addr)); fwd_rt = rt_table_find(dest_addr); if (fwd_rt) rreq_local_repair(fwd_rt, src_addr, NULL); break; case KAODVM_ROUTE_UPDATE: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(m->ifindex).broadcast.s_addr) return; fwd_rt = rt_table_find(dest_addr); rev_rt = rt_table_find(src_addr); rt_table_update_route_timeouts(fwd_rt, rev_rt); break; case KAODVM_SEND_RERR: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(m->ifindex).broadcast.s_addr) return; fwd_rt = rt_table_find(dest_addr); rev_rt = rt_table_find(src_addr); do { struct in_addr rerr_dest; RERR *rerr; DEBUG(LOG_DEBUG, 0, "Sending RERR for unsolicited message from %s to dest %s", ip_to_str(src_addr), ip_to_str(dest_addr)); if (fwd_rt) { rerr = rerr_create(0, fwd_rt->dest_addr, fwd_rt->dest_seqno); rt_table_update_timeout(fwd_rt, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); /* Unicast the RERR to the source of the data transmission * if possible, otherwise we broadcast it. */ if (rev_rt && rev_rt->state == VALID) rerr_dest = rev_rt->next_hop; else rerr_dest.s_addr = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(m->ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "Wait on reboot timer reset."); timer_set_timeout(&worb_timer, DELETE_PERIOD); } } while (0); break; default: DEBUG(LOG_DEBUG, 0, "Got mesg type=%d\n", nlm->nlmsg_type); } }