示例#1
0
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;
}
示例#2
0
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);
}
示例#3
0
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;
}
示例#4
0
/* 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);
}
示例#5
0
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);
        }
    }
}
示例#6
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();
    }
}
示例#7
0
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);
	}
    }

}
示例#8
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;
}
示例#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);
	}
}