Пример #1
0
void NS_CLASS recvAODVUUPacket(Packet * p)
{
    int len, i, ttl = 0;
    u_int32_t src, dst;
    struct hdr_cmn *ch = HDR_CMN(p);
    struct hdr_ip *ih = HDR_IP(p);
    hdr_aodvuu *ah = HDR_AODVUU(p);

    src = ih->saddr();
    dst = ih->daddr();
    len = ch->size() - IP_HDR_LEN;
    ttl = ih->ttl();

    AODV_msg *aodv_msg = (AODV_msg *) recv_buf;

    /* Only handle AODVUU packets */
    assert(ch->ptype() == PT_AODVUU);

    /* Only process incoming packets */
    assert(ch->direction() == hdr_cmn::UP);

    /* Copy message to receive buffer */
    memcpy(recv_buf, ah, RECV_BUF_SIZE);

    /* Drop or deallocate packet, depending on the TTL */
    /*   if (ttl == 1) */
/* 	drop(p, DROP_RTR_TTL); */
/*     else */
    Packet::free(p);

    /* Ignore messages generated locally */
    for (i = 0; i < MAX_NR_INTERFACES; i++)
	if (this_host.devs[i].enabled &&
	    memcmp(&src, &this_host.devs[i].ipaddr, sizeof(u_int32_t)) == 0)
	    return;

    aodv_socket_process_packet(aodv_msg, len, src, dst, ttl, NS_IFINDEX);
}
Пример #2
0
void NS_CLASS recvAODVUUPacket(Packet * p)
{
    int len, i, ttl = 0;
    struct in_addr src, dst;
    struct hdr_cmn *ch = HDR_CMN(p);
    struct hdr_ip *ih = HDR_IP(p);
    hdr_aodvuu *ah = HDR_AODVUU(p);

    src.s_addr = ih->saddr();
    dst.s_addr = ih->daddr();
    len = ch->size() - IP_HDR_LEN;
    ttl = ih->ttl();

    AODV_msg *aodv_msg = (AODV_msg *) recv_buf;

    /* Only handle AODVUU packets */
    assert(ch->ptype() == PT_AODVUU);

    /* Only process incoming packets */
    assert(ch->direction() == hdr_cmn::UP);

    /* Copy message to receive buffer */
    memcpy(recv_buf, ah, RECV_BUF_SIZE);

    /* Deallocate packet, we have the information we need... */
    Packet::free(p);

    /* Ignore messages generated locally */
    for (i = 0; i < MAX_NR_INTERFACES; i++)
	if (this_host.devs[i].enabled &&
	    memcmp(&src, &this_host.devs[i].ipaddr,
		   sizeof(struct in_addr)) == 0)
	    return;

    aodv_socket_process_packet(aodv_msg, len, src, dst, ttl, NS_IFINDEX);
}
Пример #3
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();
    }
}
Пример #4
0
void NS_CLASS aodv_socket_send(AODV_msg * aodv_msg, u_int32_t dst, int len,
			       u_int8_t ttl, struct dev_info *dev)
{
    int retval = 0;
    struct timeval now;
    /* Rate limit stuff: */
  
#ifndef NS_PORT
    struct sockaddr_in dst_addr;

#ifdef RAW_SOCKET
    struct iphdr *iph;
    struct udphdr *udph;

    if (wait_on_reboot && aodv_msg->type == AODV_RREP)
	return;

    /* Create a IP header around the packet... The AODV msg is already
       located in the send buffer and referenced by the in parameter
       "aodv_msg". */
    iph = (struct iphdr *) send_buf;
    iph->tot_len = htons(IPHDR_SIZE + sizeof(struct udphdr) + len);
    iph->saddr = htonl(dev->ipaddr);
    iph->daddr = htonl(dst);
    iph->ttl = ttl;

    udph = (struct udphdr *) (send_buf + IPHDR_SIZE);

    udph->len = htons(len + sizeof(struct udphdr));

#else

    /* If we are in waiting phase after reboot, don't send any control
       messages */
    if (wait_on_reboot)
	return;

    /* Set the ttl we want to send with */
    if (setsockopt(dev->sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
	log(LOG_WARNING, 0, __FUNCTION__, "Failed to set TTL!!!");
	return;
    }
#endif				/* RAW_SOCKET */

    memset(&dst_addr, 0, sizeof(dst_addr));
    dst_addr.sin_family = AF_INET;
    dst_addr.sin_addr.s_addr = htonl(dst);
    dst_addr.sin_port = htons(AODV_PORT);

#else

    /*
       NS_PORT: Sending of AODV_msg messages to other AODV-UU routing agents
       by encapsulating them in a Packet.

       Note: This method is _only_ for sending AODV packets to other routing
       agents, _not_ for forwarding "regular" IP packets!
     */

    /* If we are in waiting phase after reboot, don't send any RREPs */
    if (wait_on_reboot && aodv_msg->type == AODV_RREP)
	return;

    /*
       NS_PORT: Don't allocate packet until now. Otherwise packet uid
       (unique ID) space is unnecessarily exhausted at the beginning of
       the simulation, resulting in uid:s starting at values greater than 0.
     */
    Packet *p = allocpkt();
    struct hdr_cmn *ch = HDR_CMN(p);
    struct hdr_ip *ih = HDR_IP(p);
    hdr_aodvuu *ah = HDR_AODVUU(p);

    // Clear AODVUU part of packet
    memset(ah, '\0', ah->size());

    // Copy message contents into packet
    memcpy(ah, aodv_msg, len);

    // Set common header fields
    ch->ptype() = PT_AODVUU;
    ch->direction() = hdr_cmn::DOWN;
    ch->size() = IP_HDR_LEN + len;
    ch->iface() = -2;
    ch->error() = 0;
    ch->prev_hop_ = (nsaddr_t) dev->ipaddr;

    // Set IP header fields
    ih->saddr() = (nsaddr_t) dev->ipaddr;
    ih->daddr() = (nsaddr_t) dst;
    ih->ttl() = ttl;

    // Note: Port number for routing agents, not AODV port number!
    ih->sport() = RT_PORT;
    ih->dport() = RT_PORT;

    // Fake success
    retval = len;
#endif				/* NS_PORT */

    /* If rate limiting is enabled, check if we are sending either a
       RREQ or a RERR. In that case, drop the outgoing control packet
       if the time since last transmit of that type of packet is less
       than the allowed RATE LIMIT time... */

    if (ratelimit) {
    
	gettimeofday(&now, NULL);
    
	switch (aodv_msg->type) {
	case AODV_RREQ:
	    if (timeval_diff(&now, &time_last_rreq) < 1000 / RREQ_RATELIMIT) {
		DEBUG(LOG_DEBUG, 0, "Dropping RREQ due to RATELIMIT %ld ms",
		      timeval_diff(&now, &time_last_rreq));
		return;
	    }
	    memcpy(&time_last_rreq, &now, sizeof(struct timeval));
	    break;
	case AODV_RERR:
	    if (timeval_diff(&now, &time_last_rerr) < 1000 / RERR_RATELIMIT) {

		DEBUG(LOG_DEBUG, 0, "Dropping RERR due to RATELIMIT %ld ms",
		      timeval_diff(&now, &time_last_rerr));
		return;
	    }
	    memcpy(&time_last_rerr, &now, sizeof(struct timeval));
	    break;
	}
    }
    

/* Alternative RATE LIMIT ALGORITHM: This algorithm will start to
 * count time (forward 1 second) from the first packet sent. If more
 * than RATELIMIT allowed packets are sent during that period, the
 * last packet is dropped and the packet counter and time are
 * reset. The time and packet count are also reset if 1 second lasts
 * without the limit being reached... The problem is that if there are
 * many packets at the end of an "interval" and at the start of the
 * next, although the limit is not reached in either interval, there
 * can be more than RATELIMIT packets sent if the second half of the
 * first interval is joined with the first of the following
 * interval... */
    
   /*  if (ratelimit) { */

/* 	gettimeofday(&now, NULL); */

/* 	switch (aodv_msg->type) { */
/* 	case AODV_RREQ: */
/* 	    if (timeval_diff(&now, &time_last_rreq) > 1000) { */
/* 		num_rreq = 1; */
/* 		memcpy(&time_last_rreq, &now, sizeof(struct timeval)); */
/* 	    } else { */
/* 		num_rreq++; */
/* 		DEBUG(LOG_DEBUG, 0, "RATELIMIT RREQ: time=%ld ms num=%d", */
/* 		      timeval_diff(&now, &time_last_rreq), num_rreq); */
/* 		if (num_rreq > RREQ_RATELIMIT) { */
/* 		    num_rreq = 0; */
/* 		    DEBUG(LOG_DEBUG, 0, "Dropping RREQ due to RATELIMIT"); */
/* 		    return; */
/* 		} */
/* 	    } */
/* 	    break; */
/* 	case AODV_RERR: */
/* 	    if (timeval_diff(&now, &time_last_rerr) > 1000) { */
/* 		num_rerr = 1; */
/* 		memcpy(&time_last_rerr, &now, sizeof(struct timeval)); */
/* 	    } else { */
/* 		num_rerr++; */
/* 		DEBUG(LOG_DEBUG, 0, "RATELIMIT RERR: time=%ld ms num=%d", */
/* 		      timeval_diff(&now, &time_last_rerr), num_rerr); */
/* 		if (num_rerr > RERR_RATELIMIT) { */
/* 		    num_rerr = 0; */
/* 		    DEBUG(LOG_DEBUG, 0, "Dropping RERR due to RATELIMIT"); */
/* 		    return; */
/* 		} */
/* 	    } */
/* 	    break; */
/* 	} */
/*      } */

    /* If we broadcast this message we update the time of last broadcast
       to prevent unnecessary broadcasts of HELLO msg's */
    if (dst == AODV_BROADCAST) {

	gettimeofday(&this_host.bcast_time, NULL);

#ifdef NS_PORT
	ch->addr_type() = NS_AF_NONE;

	sendPacket(p, 0, 0.0);
#else
	retval = sendto(dev->sock, send_buf, len, 0,
			(struct sockaddr *) &dst_addr, sizeof(dst_addr));

	if (retval < 0) {
	    log(LOG_WARNING, errno, __FUNCTION__, "Failed send to %s",
		ip_to_str(dst));
	    return;
	}
#endif

    } else {

#ifdef NS_PORT
	ch->addr_type() = NS_AF_INET;
	/* We trust the decision of next hop for all AODV messages... */
	/* Add jitter, even for unicast control messages. */
	sendPacket(p, dst, 0.03 * Random::uniform());
#else
	retval = sendto(dev->sock, send_buf, len, 0,
			(struct sockaddr *) &dst_addr, sizeof(dst_addr));

	if (retval < 0) {
	    log(LOG_WARNING, errno, __FUNCTION__, "Failed send to %s",
		ip_to_str(dst));
	    return;
	}
#endif
    }

    /* Do not print hello msgs... */
    if (!(aodv_msg->type == AODV_RREP && (dst == AODV_BROADCAST)))
	DEBUG(LOG_INFO, 0, "AODV msg to %s ttl=%d (%d bytes)",
	      ip_to_str(dst), ttl, retval);

    return;
}
Пример #5
0
void NS_CLASS aodv_socket_send(AODV_msg * aodv_msg, struct in_addr dst,
			       int len, u_int8_t ttl, struct dev_info *dev)
{
    int retval = 0;
    struct timeval now;
    /* Rate limit stuff: */

#ifndef NS_PORT

    struct sockaddr_in dst_addr;

    if (wait_on_reboot && aodv_msg->type == AODV_RREP)
	return;

    memset(&dst_addr, 0, sizeof(dst_addr));
    dst_addr.sin_family = AF_INET;
    dst_addr.sin_addr = dst;
    dst_addr.sin_port = htons(AODV_PORT);

    /* Set ttl */
    if (setsockopt(dev->sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
	alog(LOG_WARNING, 0, __FUNCTION__, "ERROR setting ttl!");
	return;
    }
#else

    /*
       NS_PORT: Sending of AODV_msg messages to other AODV-UU routing agents
       by encapsulating them in a Packet.

       Note: This method is _only_ for sending AODV packets to other routing
       agents, _not_ for forwarding "regular" IP packets!
     */

    /* If we are in waiting phase after reboot, don't send any RREPs */
    if (wait_on_reboot && aodv_msg->type == AODV_RREP)
	return;

    /*
       NS_PORT: Don't allocate packet until now. Otherwise packet uid
       (unique ID) space is unnecessarily exhausted at the beginning of
       the simulation, resulting in uid:s starting at values greater than 0.
     */
    Packet *p = allocpkt();
    struct hdr_cmn *ch = HDR_CMN(p);
    struct hdr_ip *ih = HDR_IP(p);
    hdr_aodvuu *ah = HDR_AODVUU(p);

    // Clear AODVUU part of packet
    memset(ah, '\0', ah->size());

    // Copy message contents into packet
    memcpy(ah, aodv_msg, len);

    // Set common header fields
    ch->ptype() = PT_AODVUU;
    ch->direction() = hdr_cmn::DOWN;
    ch->size() = IP_HDR_LEN + len;
    ch->iface() = -2;
    ch->error() = 0;
    ch->prev_hop_ = (nsaddr_t) dev->ipaddr.s_addr;

    // Set IP header fields
    ih->saddr() = (nsaddr_t) dev->ipaddr.s_addr;
    ih->daddr() = (nsaddr_t) dst.s_addr;
    ih->ttl() = ttl;

    // Note: Port number for routing agents, not AODV port number!
    ih->sport() = RT_PORT;
    ih->dport() = RT_PORT;

    // Fake success
    retval = len;
#endif				/* NS_PORT */

    /* If rate limiting is enabled, check if we are sending either a
       RREQ or a RERR. In that case, drop the outgoing control packet
       if the time since last transmit of that type of packet is less
       than the allowed RATE LIMIT time... */

    if (ratelimit) {

	gettimeofday(&now, NULL);

	switch (aodv_msg->type) {
	case AODV_RREQ:
	    if (num_rreq == (RREQ_RATELIMIT - 1)) {
		if (timeval_diff(&now, &rreq_ratel[0]) < 1000) {
		    DEBUG(LOG_DEBUG, 0, "RATELIMIT: Dropping RREQ %ld ms",
			  timeval_diff(&now, &rreq_ratel[0]));
		    return;
		} else {
		    memmove(rreq_ratel, &rreq_ratel[1],
			    sizeof(struct timeval) * (num_rreq - 1));
		    memcpy(&rreq_ratel[num_rreq - 1], &now,
			   sizeof(struct timeval));
		}
	    } else {
		memcpy(&rreq_ratel[num_rreq], &now, sizeof(struct timeval));
		num_rreq++;
	    }
	    break;
	case AODV_RERR:
	    if (num_rerr == (RERR_RATELIMIT - 1)) {
		if (timeval_diff(&now, &rerr_ratel[0]) < 1000) {
		    DEBUG(LOG_DEBUG, 0, "RATELIMIT: Dropping RERR %ld ms",
			  timeval_diff(&now, &rerr_ratel[0]));
		    return;
		} else {
		    memmove(rerr_ratel, &rerr_ratel[1],
			    sizeof(struct timeval) * (num_rerr - 1));
		    memcpy(&rerr_ratel[num_rerr - 1], &now,
			   sizeof(struct timeval));
		}
	    } else {
		memcpy(&rerr_ratel[num_rerr], &now, sizeof(struct timeval));
		num_rerr++;
	    }
	    break;
	}
    }

    /* If we broadcast this message we update the time of last broadcast
       to prevent unnecessary broadcasts of HELLO msg's */
    if (dst.s_addr == AODV_BROADCAST) {

	gettimeofday(&this_host.bcast_time, NULL);

#ifdef NS_PORT
	ch->addr_type() = NS_AF_NONE;

	sendPacket(p, dst, 0.0);
#else

	retval = sendto(dev->sock, send_buf, len, 0,
			(struct sockaddr *) &dst_addr, sizeof(dst_addr));

	if (retval < 0) {

	    alog(LOG_WARNING, errno, __FUNCTION__, "Failed send to bc %s",
		 ip_to_str(dst));
	    return;
	}
#endif

    } else {

#ifdef NS_PORT
	ch->addr_type() = NS_AF_INET;
	/* We trust the decision of next hop for all AODV messages... */

	if (dst.s_addr == AODV_BROADCAST)
	    sendPacket(p, dst, 0.001 * Random::uniform());
	else
	    sendPacket(p, dst, 0.0);
#else
	retval = sendto(dev->sock, send_buf, len, 0,
			(struct sockaddr *) &dst_addr, sizeof(dst_addr));

	if (retval < 0) {
	    alog(LOG_WARNING, errno, __FUNCTION__, "Failed send to %s",
		 ip_to_str(dst));
	    return;
	}
#endif
    }

    /* Do not print hello msgs... */
    if (!(aodv_msg->type == AODV_RREP && (dst.s_addr == AODV_BROADCAST)))
	DEBUG(LOG_INFO, 0, "AODV msg to %s ttl=%d size=%u",
	      ip_to_str(dst), ttl, retval, len);

    return;
}
Пример #6
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;
}