Пример #1
0
void NS_CLASS local_repair_timeout(void *arg)
{
    rt_table_t *rt;
    struct in_addr rerr_dest;
    RERR *rerr = NULL;

    rt = (rt_table_t *) arg;

    if (!rt)
        return;

    rerr_dest.s_addr = AODV_BROADCAST;	/* Default destination */

    /* Unset the REPAIR flag */
    rt->flags &= ~RT_REPAIR;

#ifndef NS_PORT
    nl_send_del_route_msg(rt->dest_addr, rt->next_hop, rt->hcnt);
#endif
    /* Route should already be invalidated. */

    if (rt->nprec) {

        rerr = rerr_create(0, rt->dest_addr, rt->dest_seqno);

        if (rt->nprec == 1) {
            rerr_dest = FIRST_PREC(rt->precursors)->neighbor;

            aodv_socket_send((AODV_msg *) rerr, rerr_dest,
                             RERR_CALC_SIZE(rerr), 1,
                             &DEV_IFINDEX(rt->ifindex));
        } else {
            int i;

            for (i = 0; i < MAX_NR_INTERFACES; i++) {
                if (!DEV_NR(i).enabled)
                    continue;
                aodv_socket_send((AODV_msg *) rerr, rerr_dest,
                                 RERR_CALC_SIZE(rerr), 1,
                                 &DEV_NR(i));
            }
        }
        DEBUG(LOG_DEBUG, 0, "Sending RERR about %s to %s",
              ip_to_str(rt->dest_addr), ip_to_str(rerr_dest));
    }
    precursor_list_destroy(rt);

    /* Purge any packets that may be queued */
    /* packet_queue_set_verdict(rt->dest_addr, PQ_DROP); */

    rt->rt_timer.handler = &NS_CLASS route_delete_timeout;
    timer_set_timeout(&rt->rt_timer, DELETE_PERIOD);

    DEBUG(LOG_DEBUG, 0, "%s removed in %u msecs",
          ip_to_str(rt->dest_addr), DELETE_PERIOD);
}
Пример #2
0
void NS_CLASS local_repair_timeout(void *arg)
{
    rt_table_t *rt;
    u_int32_t rerr_dest = AODV_BROADCAST;
    RERR *rerr = NULL;

    rt = (rt_table_t *) arg;

    if (!rt)
	return;

    /* Unset the REPAIR flag */
    rt->flags &= ~RT_REPAIR;

    rt->rt_timer.handler = &NS_CLASS route_delete_timeout;
    timer_set_timeout(&rt->rt_timer, DELETE_PERIOD);

    DEBUG(LOG_DEBUG, 0, "%s removed in %u msecs",
	  ip_to_str(rt->dest_addr), DELETE_PERIOD);

    /* Route should already be invalidated. */

    if (rt->nprec) {

	rerr = rerr_create(0, rt->dest_addr, rt->dest_seqno);

	if (rt->nprec == 1) {
	    rerr_dest = FIRST_PREC(rt->precursors)->neighbor;

	    aodv_socket_send((AODV_msg *) rerr, rerr_dest, 
			     RERR_CALC_SIZE(rerr), 1,
			     &DEV_IFINDEX(rt->ifindex));
	} else {
	    int i;

	    for (i = 0; i < MAX_NR_INTERFACES; i++) {
		if (!DEV_NR(i).enabled)
		    continue;
		aodv_socket_send((AODV_msg *) rerr, rerr_dest,
				 RERR_CALC_SIZE(rerr), 1, &DEV_NR(i));
	    }
	}
	DEBUG(LOG_DEBUG, 0, "Sending RERR about %s to %s",
	      ip_to_str(rt->dest_addr), ip_to_str(rerr_dest));
    }
    precursor_list_destroy(rt);
}
Пример #3
0
void rerr_add_udest(RERR * rerr, u_int32_t udest, u_int32_t udest_seqno)
{
    RERR_udest *ud;

    ud = (RERR_udest *) ((char *) rerr + RERR_CALC_SIZE(rerr));
    ud->dest_addr = htonl(udest);
    ud->dest_seqno = htonl(udest_seqno);
    rerr->dest_count++;
}
Пример #4
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();
    }
}
Пример #5
0
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;
}
Пример #6
0
void
rerr_process(RERR * rerr, int rerrlen, u_int32_t ip_src, u_int32_t ip_dst)
{
    RERR *new_rerr = NULL;
    rt_table_t *entry;
    u_int32_t rerr_dest, rerr_dest_seqno;
    int i;
    RERR_udest *udest;

#ifdef DEBUG
    log(LOG_DEBUG, 0, "rerr_process: ip_src=%s", ip_to_str(ip_src));
    log_pkt_fields((AODV_msg *) rerr);
#endif

    if (rerrlen < RERR_CALC_SIZE(rerr)) {
	log(LOG_WARNING, 0,
	    "rerr_process: IP data too short (%u bytes) from %s to %s. Should be %d bytes.",
	    rerrlen, ip_to_str(ip_src), ip_to_str(ip_dst),
	    RERR_CALC_SIZE(rerr));

	return;
    }

    /* Check which destinations that are unreachable.  */
    udest = RERR_UDEST_FIRST(rerr);

    while (rerr->dest_count) {

	rerr_dest = ntohl(udest->dest_addr);
	rerr_dest_seqno = ntohl(udest->dest_seqno);
#ifdef DEBUG
	log(LOG_DEBUG, 0, "rerr_process: unreachable dest=%s seqno=%ld",
	    ip_to_str(rerr_dest), rerr_dest_seqno);
#endif

	if ((entry = rt_table_find_active(rerr_dest)) != NULL &&
	    memcmp(&entry->next_hop, &ip_src, sizeof(u_int32_t)) == 0) {

	    /* (a) updates the corresponding destination sequence number
	       with the Destination Sequence Number in the packet, and */
	    /* UGLY HACK: we decrement the seqno by one here, since it will
	       be incremented upon calling rt_table_invalidate() below... */
	    entry->dest_seqno = rerr_dest_seqno - 1;

	    /* (d) check precursor list for emptiness. If not empty, include
	       the destination as an unreachable destination in the
	       RERR... */
	    if (entry->precursors != NULL) {
		if (new_rerr == NULL)
		    new_rerr =
			rerr_create(0, entry->dest_addr,
				    entry->dest_seqno);
		else
		    rerr_add_udest(new_rerr, entry->dest_addr,
				   entry->dest_seqno);
	    }
#ifdef DEBUG
	    log(LOG_DEBUG, 0,
		"rerr_process: removing rte %s - WAS IN RERR!!",
		ip_to_str(rerr_dest));
#endif
	    /* Invalidate route: Hop count -> INFTY */
	    rt_table_invalidate(entry);
	}
	udest = RERR_UDEST_NEXT(udest);
	rerr->dest_count--;
    }				/* End while() */

    /* If a RERR was created, then send it now... */
    /* FIXME: Unicast if possible... And send on only those interfaces
       where it is necessary. */
    if (new_rerr) {
	for (i = 0; i < MAX_NR_INTERFACES; i++) {
	    if (!DEV_NR(i).enabled)
		continue;
	    aodv_socket_send((AODV_msg *) new_rerr, AODV_BROADCAST,
			     RERR_CALC_SIZE(rerr), 1, &DEV_NR(i));
	}
    }
}
Пример #7
0
void route_expire_timeout(void *arg) {
    rt_table_t *rt_entry;
#ifdef DEBUG
    u_int32_t now = get_currtime();
#endif

    rt_entry = (rt_table_t *)arg;

    if(rt_entry == NULL) {
        log(LOG_WARNING, 0, "route_expire_timer: arg was NULL, ignoring timeout!");
        return;
    }

#ifdef DEBUG
    log(LOG_DEBUG, 0, "route_expire_timeout: %s curT=%lu exp=%lu",
        ip_to_str(rt_entry->dest_addr), now, rt_entry->expire);
#endif

    /* If hopcount = 1, this is a direct neighbor and a link break has
       occured. Send a RERR with the incremented sequence number */
    if(rt_entry->hcnt == 1) {
        RERR *rerr;
        rt_table_t *u_entry;
        int i;

#ifdef DEBUG
        log(LOG_DEBUG, 0, "route_expire_timeout: LINK FAILURE for %s, seqno=%d",
            ip_to_str(rt_entry->dest_addr), rt_entry->dest_seqno);
#endif
        /* Create a route error msg */
        rerr = rerr_create(0, rt_entry->dest_addr, rt_entry->dest_seqno);

        /* Check the routing table for entries which have the unreachable
           destination (dest) as next hop. These entries (destinations)
           cannot be reached either since dest is down. They should
           therefore also be included in the RERR. */
        for(i = 0; i < RT_TABLESIZE; i++) {
            for (u_entry = routing_table[i]; u_entry != NULL;
                    u_entry = u_entry->next) {

                if ((u_entry->next_hop == rt_entry->dest_addr) &&
                        (u_entry->dest_addr != rt_entry->dest_addr)) {

                    if(u_entry->precursors != NULL) {

                        rerr_add_udest(rerr, u_entry->dest_addr, u_entry->dest_seqno);
#ifdef DEBUG
                        log(LOG_DEBUG, 0, "route_expire_timeout: Added %s as unreachable, seqno=%d", ip_to_str(u_entry->dest_addr), u_entry->dest_seqno);
#endif
                        rerr->dest_count++;
                    }
                    rt_table_invalidate(u_entry);
                }
            }
        }
        /* FIXME: Check if we should unicast the RERR. This check does not
           catch all cases when we could unicast (like when several
           unreachable destinations have the same precursor). */
        if(rerr->dest_count == 1 &&
                rt_entry->precursors != NULL &&
                rt_entry->precursors->next == NULL)
            aodv_socket_send((AODV_msg *)rerr, rt_entry->precursors->neighbor,
                             RERR_CALC_SIZE(rerr), 1);

        else if(rerr->dest_count > 1 &&
                (rt_entry->precursors != NULL))
            aodv_socket_send((AODV_msg *)rerr, AODV_BROADCAST,
                             RERR_CALC_SIZE(rerr), 1);
#ifdef DEBUG
        else
            log(LOG_DEBUG, 0, "route_expire_timeout: No precursors, dropping RERR");
#endif

    }
    /* Now also invalidate the entry of the link that broke... */
    rt_table_invalidate(rt_entry);
}
Пример #8
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();
}
Пример #9
0
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);
	}
}