Exemple #1
0
void NS_CLASS rrep_send(RREP * rrep, rt_table_t * rev_rt,
			rt_table_t * fwd_rt, int size)
{
	u_int8_t rrep_flags = 0;
	struct in_addr dest;

	if (!rev_rt) {
		DEBUG(LOG_WARNING, 0, "Can't send RREP, rev_rt = NULL!");
		return;
	}

	dest.s_addr = rrep->dest_addr;

	/* Check if we should request a RREP-ACK */
	if ((rev_rt->state == VALID && rev_rt->flags & RT_UNIDIR) ||
	    (rev_rt->hcnt == 1 && unidir_hack)) {
		rt_table_t *neighbor = rt_table_find(rev_rt->next_hop);

		if (neighbor && neighbor->state == VALID
		    && !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_flags |= RREP_ACK;
			neighbor->flags |= RT_UNIDIR;

			/* Must remove any pending hello timeouts when we set the
			   RT_UNIDIR flag, else the route may expire after we begin to
			   ignore hellos... */
			timer_remove(&neighbor->hello_timer);
			neighbor_link_break(neighbor);

			DEBUG(LOG_DEBUG, 0, "Link to %s is unidirectional!",
			      ip_to_str(neighbor->dest_addr));

			timer_set_timeout(&neighbor->ack_timer, NEXT_HOP_WAIT);
		}
	}

	DEBUG(LOG_DEBUG, 0, "Sending RREP to next hop %s about %s->%s",
	      ip_to_str(rev_rt->next_hop), ip_to_str(rev_rt->dest_addr),
	      ip_to_str(dest));

	aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, MAXTTL,
			 &DEV_IFINDEX(rev_rt->ifindex));

	/* Update precursor lists */
	if (fwd_rt) {
		precursor_add(fwd_rt, rev_rt->next_hop);
		precursor_add(rev_rt, fwd_rt->next_hop);
	}

	if (!llfeedback && optimized_hellos)
		hello_start();
}
Exemple #2
0
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();
    }
}
Exemple #3
0
int main(int argc, char **argv)
{
    static char *ifname = NULL;	/* Name of interface to attach to */
    fd_set rfds, readers;
    int n, nfds = 0, i;
    int daemonize = 0;
    struct timeval *timeout;
    struct timespec timeout_spec;
    struct sigaction sigact;
    sigset_t mask, origmask;

    /* Remember the name of the executable... */
    progname = strrchr(argv[0], '/');

    if (progname)
	progname++;
    else
	progname = argv[0];

    /* Use debug output as default */
    debug = 1;

    memset (&sigact, 0, sizeof(struct sigaction));
    sigact.sa_handler = signal_handler;
        
    /* This server should shut down on these signals. */
    sigaction(SIGTERM, &sigact, 0);
    sigaction(SIGHUP, &sigact, 0);
    sigaction(SIGINT, &sigact, 0);
    
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    /* Only capture segmentation faults when we are not debugging... */
#ifndef DEBUG
    sigaddset(&mask, SIGSEGV);
#endif

    /* Block the signals we are watching here so that we can
     * handle them in pselect instead. */
    sigprocmask(SIG_BLOCK, &mask, &origmask);

    /* Parse command line: */
    while (1) {
	int opt;

	opt = getopt_long(argc, argv, "i:fjln:dghoq:r:s:c:uwxDLRV", longopts, 0);

	if (opt == EOF)
	    break;

	switch (opt) {
	case 0:
	    break;
	case 'd':
	    debug = 0;
	    daemonize = 1;
	    break;
	case 'f':
	    llfeedback = 1;
	    active_route_timeout = ACTIVE_ROUTE_TIMEOUT_LLF;
	    break;
	case 'g':
	    rreq_gratuitous = !rreq_gratuitous;
	    break;
	case 'i':
	    ifname = optarg;
	    break;
	case 'j':
	    hello_jittering = !hello_jittering;
	    break;
	case 'l':
	    log_to_file = !log_to_file;
	    break;
	case 'n':
	    if (optarg && isdigit(*optarg)) {
		receive_n_hellos = atoi(optarg);
		if (receive_n_hellos < 2) {
		    fprintf(stderr, "-n should be at least 2!\n");
		    exit(-1);
		}
	    }
	    break;
	case 'o':
	    optimized_hellos = !optimized_hellos;
	    break;
	case 'q':
	    if (optarg && isdigit(*optarg))
		qual_threshold = atoi(optarg);
	    break;
	case 'r':
	    if (optarg && isdigit(*optarg))
		rt_log_interval = atof(optarg) * 1000;
	    break;
	case 's':
		if (optarg && isdigit(*optarg))
		inet_aton(optarg, &server_addr);
		break;
	case 'c':
		if (optarg && isdigit(*optarg))
		{
			node_discovery_mode = !node_discovery_mode;
			discovery_internal = atof(optarg) * 1000 * 60;
		}
		break;
	case 'u':
	    unidir_hack = !unidir_hack;
	    break;
	case 'w':
	    internet_gw_mode = !internet_gw_mode;
	    break;
	case 'x':
	    expanding_ring_search = !expanding_ring_search;
	    break;
	case 'L':
	    local_repair = !local_repair;
	    break;
	case 'D':
	    wait_on_reboot = !wait_on_reboot;
	    break;
	case 'R':
	    ratelimit = !ratelimit;
	    break;
	case 'V':
	    printf
		("\nAODV-UU v%s, %s © Uppsala University & Ericsson AB.\nAuthor: Erik Nordström, <*****@*****.**>\n\n",
		 AODV_UU_VERSION, DRAFT_VERSION);
	    exit(0);
	    break;
	case '?':
	case ':':
	    exit(0);
	default:
	    usage(0);
	}
    }
    /* Check that we are running as root */
    if (geteuid() != 0) {
	fprintf(stderr, "must be root\n");
	exit(1);
    }

    /* Detach from terminal */
    if (daemonize) {
	if (fork() != 0)
	    exit(0);
	/* Close stdin, stdout and stderr... */
	/*  close(0); */
	close(1); 
	close(2);
	setsid();
    }
    /* Make sure we cleanup at exit... */
    atexit((void *) &cleanup);

    /* Initialize data structures and services... */
    rt_table_init();
    log_init();
    /*   packet_queue_init(); */
    host_init(ifname);
    /*   packet_input_init(); */
    nl_init();
    nl_send_conf_msg();
    aodv_socket_init();
#ifdef LLFEEDBACK
    if (llfeedback) {
	llf_init();
    }
#endif

    /* Set sockets to watch... */
    FD_ZERO(&readers);
    for (i = 0; i < nr_callbacks; i++) {
	FD_SET(callbacks[i].fd, &readers);
	if (callbacks[i].fd >= nfds)
	    nfds = callbacks[i].fd + 1;
    }

    /* Set the wait on reboot timer... */
    if (wait_on_reboot) {
		timer_init(&worb_timer, wait_on_reboot_timeout, &wait_on_reboot);
		timer_set_timeout(&worb_timer, DELETE_PERIOD);
		alog(LOG_NOTICE, 0, __FUNCTION__,
			 "In wait on reboot for %d milliseconds. Disable with \"-D\".",
			 DELETE_PERIOD);
    }
    
    if(node_discovery_mode && internet_gw_mode)
    {
		timer_init(&discovery_timer, node_discovery_timeout, NULL);
		timer_set_timeout(&discovery_timer, discovery_internal);
		DEBUG(LOG_DEBUG, 0, "This is gateway and set with node discovery\n");
	}

    /* Schedule the first Hello */
    if (!optimized_hellos && !llfeedback)
	hello_start();

    if (rt_log_interval)
	log_rt_table_init();

    while (1) {
	memcpy((char *) &rfds, (char *) &readers, sizeof(rfds));

	timeout = timer_age_queue();
	
	timeout_spec.tv_sec = timeout->tv_sec;
	timeout_spec.tv_nsec = timeout->tv_usec * 1000;

	if ((n = pselect(nfds, &rfds, NULL, NULL, &timeout_spec, &origmask)) < 0) {
	    if (errno != EINTR)
		alog(LOG_WARNING, errno, __FUNCTION__,
		     "Failed select (main loop)");
	    continue;
	}

	if (n > 0) {
	    for (i = 0; i < nr_callbacks; i++) {
		if (FD_ISSET(callbacks[i].fd, &rfds)) {
		    /* We don't want any timer SIGALRM's while executing the
		       callback functions, therefore we block the timer... */
		    (*callbacks[i].func) (callbacks[i].fd);
		}
	    }
	}
    }				/* Main loop */
    return 0;
}
Exemple #4
0
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();
}