예제 #1
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);
}
예제 #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();
    }
}
예제 #3
0
/* Process a hello message */
void hello_process(RREP *hello, int rreplen) {
  u_int32_t hello_dst;
  u_int32_t hello_interval = HELLO_INTERVAL;
  u_int32_t ext_neighbor;
  rt_table_t *entry;
  AODV_ext *ext = NULL;
  int i, unidir_link = 1;
  
  hello_dst = ntohl(hello->dest_addr);

  /* Check for hello interval extension: */
  ext = (AODV_ext *)((char *)hello + RREP_SIZE);
  
  while(rreplen > RREP_SIZE) {
    switch(ext->type) {
    case RREP_HELLO_INTERVAL_EXT:
      if(ext->length == 4) {
	memcpy(&hello_interval, AODV_EXT_DATA(ext), 4);
#ifdef DEBUG_HELLO
	log(LOG_INFO, 0, "HELLO_process: Hello extension interval=%lu!", 
	    hello_interval);
#endif
      } else
	log(LOG_WARNING, 0, "hello_process: Bad hello interval extension!");
      break;
    case RREP_HELLO_NEIGHBOR_SET_EXT:
#ifdef DEBUG_HELLO
      log(LOG_INFO, 0, "HELLO_process: RREP_HELLO_NEIGHBOR_SET_EXT");
#endif
      for(i = 0; i < ext->length; i = i + 4) {
	ext_neighbor = ntohl(*(u_int32_t *)((char *)AODV_EXT_DATA(ext) + i));

	if(memcmp(&ext_neighbor, &this_host->ipaddr, 4) == 0)
	  unidir_link = 0;
      }
      break;
    default:
      log(LOG_WARNING, 0, "hello_process: Bad extension!! type=%d, length=%d", 
	  ext->type, ext->length);
      ext = NULL;
      break;
    }
    if(ext == NULL)
      break;

    rreplen -= AODV_EXT_SIZE(ext);
    ext = AODV_EXT_NEXT(ext);
    
  }
  
#ifdef DEBUG_HELLO
  log(LOG_DEBUG, 0, "processHello: rcvd HELLO from %s, seqno %lu", 
      ip_to_str(hello_dst), hello->dest_seqno);
#endif

  if((entry = rt_table_find(hello_dst)) == NULL) {
    /* No active or expired route in the routing table. So we add a
       new entry... */
    if(unidir_hack && unidir_link) {
      entry = rt_table_insert(hello_dst, hello_dst, 1, hello->dest_seqno,  
			      ACTIVE_ROUTE_TIMEOUT, NEIGHBOR | UNIDIR);  
#ifdef DEBUG
      log(LOG_INFO, 0, "hello_process: %s is UNI-DIR!!!", 
	  ip_to_str(entry->dest));
#endif
    } else {
      entry = rt_table_insert(hello_dst, hello_dst, 1, hello->dest_seqno,  
			    ACTIVE_ROUTE_TIMEOUT, NEIGHBOR);  
#ifdef DEBUG
        log(LOG_INFO, 0, "hello_process: %s is BI-DIR!!!", 
	  ip_to_str(entry->dest));
#endif
    }
      
  } else {

    if(unidir_hack && unidir_link) {
#ifdef DEBUG
      if(!(entry->flags & UNIDIR))
	log(LOG_INFO, 0, "hello_process: %s is UNI-DIR!!!", 
	    ip_to_str(entry->dest));
#endif
      entry->flags |= UNIDIR;
    } else if(entry->flags & UNIDIR) {
      entry->flags ^= UNIDIR;
#ifdef DEBUG
      log(LOG_INFO, 0, "hello_process: %s is BI-DIR!!!", 
	  ip_to_str(entry->dest));
#endif
    }
    /* Update sequence numbers if the hello contained new info... */
    if(hello->dest_seqno < entry->dest_seqno)
      hello->dest_seqno = entry->dest_seqno;
    
    if(entry->flags & UNIDIR)
      entry->dest_seqno = hello->dest_seqno;
    else {
      rt_table_update(entry, hello_dst, 1, hello->dest_seqno,
		      ACTIVE_ROUTE_TIMEOUT, NEIGHBOR);
    } 
  }
  /* Only update hello timeout for routes which are not unidir */
  /* if(!(entry->flags & UNIDIR)) */
  hello_update_timeout(entry, ALLOWED_HELLO_LOSS*hello_interval);
  
  return;
}
예제 #4
0
파일: aodv_hello.c 프로젝트: lvniqi/aodv
void hello_process(RREP *hello, s32_t len)
{
	u32_t hello_seqno, timeout, hello_interval = HELLO_INTERVAL;
	u8_t state, flags = 0;
	struct in_addr hello_dest;
	rt_table_t *rt;
	struct  timeval now;

	gettimeofday(&now, NULL);

	hello_dest.s_addr = hello->dest_addr;
	hello_seqno = ntohl(hello->dest_seqno);

	rt = rt_table_check(hello_dest);

	if(rt)
		flags = rt->flags;

	if(receive_n_hellos)
		state = INVALID;
	else
		state = VALID;

	timeout = ALLOWED_HELLO_LOSS * hello_interval + ROUTE_TIMEOUT_SLACK;

	if(!rt)
	{
		rt = rt_table_insert(hello_dest, hello_dest, 1, hello_seqno, timeout, state, flags);

		if(flags & RT_UNIDIR)
		{
			DEBUG(LOG_INFO, 0, "%s new NEIGHBOR, link UNI_DIR", ip_to_str(rt->dest_addr));
		}
		else
		{
			DEBUG(LOG_INFO, 0, "%s new NEIGHBOR", ip_to_str(rt->dest_addr));
		}

		rt->hello_cnt = 1;
	}
	else
	{
		if((flags & RT_UNIDIR) && rt->state == VALID && rt->hopcnt > 1)
		{
			hello_update_timeout(rt, &now, ALLOWED_HELLO_LOSS *hello_interval);
			return;
		}

		if(receive_n_hellos && rt->hello_cnt < (receive_n_hellos - 1))
		{
			if(timeval_diff(&now, &rt->last_hello_time) < (long)(hello_interval + hello_interval / 2))
				rt->hello_cnt++;
			else
				rt->hello_cnt = 1;

			memcpy(&rt->last_hello_time, &now, sizeof(struct timeval));
			return;
		}

		rt_table_update(rt, hello_dest, 1, hello_seqno, timeout, VALID, flags);

		hello_update_timeout(rt, &now, ALLOWED_HELLO_LOSS * hello_interval);
	}	
}