struct ether_header *uni_get_mac(int fd, char *ip, char *port)
{
	char           *buf, *p;
	ssize_t         blen;

#ifdef __APPLE__
	ioctl(fd, BIOCGBLEN, &blen);
#elif __linux__
	blen = 1460;
#endif

	buf = malloc(blen + 1);

	send_probe(ip, port);

	if (read(fd, buf, blen) < 0)
		die_with_signal("read");

#ifdef __APPLE__
	struct bpf_hdr *bh = (struct bpf_hdr *)buf;

	p = buf + bh->bh_hdrlen;
#elif __linux__
	p = buf;
#endif

	struct ether_header *eh = calloc(1, sizeof(*eh));

	memcpy(eh, p, s_eth);
	memset(eh->ether_dhost, 0xff, ETH_ALEN);
	return eh;

}
Beispiel #2
0
/*---------------------------------------------------------------------------*/
static void
send_stream_probe(void *dummy)
{
  /* Turn on the radio for sending a probe packet and 
     anticipating a data packet from a neighbor. */
  turn_radio_on();
  
  /* Send a probe packet. */
  send_probe();

  is_streaming = 1;
}
Beispiel #3
0
int
traceroute_send_probe(struct traceroute *t, int ttl, int seq)
{
	struct outdata *o = &t->outdata;

	/* Prepare outgoing data */
	o->seq = seq;
	o->ttl = ttl;

	/* Avoid alignment problems by copying bytewise: */
	(void)gettimeofday(&t->timesent, NULL);
	memcpy(&o->tv, t, sizeof(o->tv));

	/* Finalize and send packet */
	(*t->proto->prepare)(t, o);
	return send_probe(t, seq, ttl);
}
Beispiel #4
0
int send_ra_solicit(int sock, uint8_t *buf)
{
    int err;
    struct in6_addr addr;
    /* set receiver address */
    inet_pton(AF_INET6, "ff02::02", &addr);

    /* build the message */
    struct nd_router_solicit *solicit;
    solicit = (struct nd_router_solicit*)buf;
    solicit->nd_rs_type = ND_ROUTER_SOLICIT;
    solicit->nd_rs_code = 0;
    solicit->nd_rs_cksum = 0;
    solicit->nd_rs_reserved = 0;
    uint8_t *p = (uint8_t*)buf + sizeof(struct nd_router_solicit);
    err = send_probe(sock, buf, &addr, p - buf, 255);
    return err;
}
int mmprobe_probe_V2(int id, void* data, int length, DataFormat_t* format_p){
  int retval = 0;

  if (!probe_list_opened) {
    if (open_probe_list() < 0)
      return -1;
  }

  if ((id > MM_PROBE_NUMBER_OF_SPEECH_PROBES) || (probe_list[id-1] == 1)) {
    probe_t* p = create_probe(id);

    add_data_to_probe(p, data, length, format_p);

    retval = send_probe(p);

    delete_probe(p);
  }

  return retval;
}
int queue_active_probe(int ifindex, __u32 addr)
{
	static struct timeval prev;
	static int buckets;
	struct timeval now;

	gettimeofday(&now, NULL);
	if (prev.tv_sec) {
		int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
		buckets += diff;
	} else {
		buckets = broadcast_burst;
	}
	if (buckets > broadcast_burst)
		buckets = broadcast_burst;
	if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
		buckets -= broadcast_rate;
		prev = now;
		return 0;
	}
	stats.probes_suppressed++;
	return -1;
}
Beispiel #7
0
void *sendThread(void *p)
{
   int i, j, n;
   // char _dest[MAXHOSTNAMELEN+1];
   char _dest_ip[INET_ADDRSTRLEN+1];
   struct sockaddr_in _destaddr;
   uchar o[4];
   uint ip;
   uchar _seq;
   int rv;

   n = g_num_packets;  /*num*/
   ip = _startAddr.s_addr;

   for (i = 0; i < n; i++) 
   {
      split_ip(ip,o);
      if (o[3] == 0) continue;
      if (!fBroadcastOk && (o[3] == 255)) continue;
      sprintf(_dest_ip,"%d.%d.%d.%d",o[0],o[1],o[2],o[3]);

      /* set _destaddr */
      _destaddr.sin_family = AF_INET;
      _destaddr.sin_port = htons(g_port);
      if ( !inet_aton( _dest_ip, &_destaddr.sin_addr)) {
          printerr("inet_aton error %s\n",_dest_ip);
          continue;
      }

     for (j=0; j<g_repeat; j++)
     {
      /* send ping buffer */
      _seq = 0;
      rv = send_probe(&_destaddr,_seq);
      g_npings++;
      if (fdebug) printerr("sendto[%d,%d] %s rv = %d\n",
			    g_npings,_seq,_dest_ip,rv);
      if (rv < 0) {  /*try to send again*/
          rv = send_probe(&_destaddr,++_seq);
          if (rv < 0) {
              printerr("sendto[%d,%d] %s error %s\n",
			g_npings,_seq,_dest_ip,showlasterr()); 
              continue;
          }
      } 

#ifdef NO_THREADS
      receiveThread(NULL);
      if (g_recv_status == 0 && !fBroadcastOk) {
          /* nothing returned, try again */
          if (fping) {
             rv = send_poke1(&_destaddr);
             if (fdebug) printerr("sendto[%d,%d] %s poke rv = %d\n",
				   g_npings,_seq,_dest_ip,rv);
          }
          rv = send_probe(&_destaddr,++_seq);
          if (fdebug) printerr("sendto[%d,%d] %s rv = %d\n",
				g_npings,_seq,_dest_ip,rv);
          if (rv >= 0) {
             receiveThread(NULL);
          }
      }
#endif

      /* sleep an interval (g_delay usec) */
      if (g_delay > 0) os_sleep(0,g_delay);
     }  /*end-for g_repeat*/

     ip++; /* increment to next IP */
   }
   return(p);
}
Beispiel #8
0
int
main(int argc, char *argv[])
{
	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
	int ch, i, on = 1, seq, rcvcmsglen, error, minlen;
	struct addrinfo hints, *res;
	static u_char *rcvcmsgbuf;
	u_long probe, hops, lport;
	struct hostent *hp;
	size_t size;
	uid_t uid;

	/*
	 * Receive ICMP
	 */
	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
		perror("socket(ICMPv6)");
		exit(5);
	}

	/* revoke privs */
	uid = getuid();
	if (setresuid(uid, uid, uid) == -1)
		err(1, "setresuid");

	size = sizeof(i);
	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
	max_hops = i;

	/* specify to tell receiving interface */
	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
	    sizeof(on)) < 0)
		err(1, "setsockopt(IPV6_RECVPKTINFO)");

	/* specify to tell value of hoplimit field of received IP6 hdr */
	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
	    sizeof(on)) < 0)
		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");

	seq = 0;

	while ((ch = getopt(argc, argv, "df:g:Ilm:np:q:rs:w:v")) != -1)
		switch (ch) {
		case 'd':
			options |= SO_DEBUG;
			break;
		case 'f':
			ep = NULL;
			errno = 0;
			first_hop = strtoul(optarg, &ep, 0);
			if (errno || !*optarg || *ep|| first_hop > 255) {
				fprintf(stderr,
				    "traceroute6: invalid min hoplimit.\n");
				exit(1);
			}
			break;
		case 'g':
			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
			if (hp == NULL) {
				fprintf(stderr,
				    "traceroute6: unknown host %s\n", optarg);
				exit(1);
			}
			if (rth == NULL) {
				/*
				 * XXX: We can't detect the number of
				 * intermediate nodes yet.
				 */
				if ((rth = inet6_rth_init((void *)rtbuf,
				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
				    0)) == NULL) {
					fprintf(stderr,
					    "inet6_rth_init failed.\n");
					exit(1);
				}
			}
			if (inet6_rth_add((void *)rth,
			    (struct in6_addr *)hp->h_addr)) {
				fprintf(stderr,
				    "inet6_rth_add failed for %s\n",
				    optarg);
				exit(1);
			}
			freehostent(hp);
			break;
		case 'I':
			useicmp++;
			ident = htons(getpid() & 0xffff); /* same as ping6 */
			break;
		case 'l':
			lflag++;
			break;
		case 'm':
			ep = NULL;
			errno = 0;
			max_hops = strtoul(optarg, &ep, 0);
			if (errno || !*optarg || *ep || max_hops > 255) {
				fprintf(stderr,
				    "traceroute6: invalid max hoplimit.\n");
				exit(1);
			}
			break;
		case 'n':
			nflag++;
			break;
		case 'p':
			ep = NULL;
			errno = 0;
			lport = strtoul(optarg, &ep, 0);
			if (errno || !*optarg || *ep) {
				fprintf(stderr, "traceroute6: invalid port.\n");
				exit(1);
			}
			if (lport == 0 || lport != (lport & 0xffff)) {
				fprintf(stderr,
				    "traceroute6: port out of range.\n");
				exit(1);
			}
			port = lport & 0xffff;
			break;
		case 'q':
			ep = NULL;
			errno = 0;
			nprobes = strtoul(optarg, &ep, 0);
			if (errno || !*optarg || *ep) {
				fprintf(stderr,
				    "traceroute6: invalid nprobes.\n");
				exit(1);
			}
			if (nprobes < 1) {
				fprintf(stderr,
				    "traceroute6: nprobes must be >0.\n");
				exit(1);
			}
			break;
		case 'r':
			options |= SO_DONTROUTE;
			break;
		case 's':
			/*
			 * set the ip source address of the outbound
			 * probe (e.g., on a multi-homed host).
			 */
			source = optarg;
			break;
		case 'v':
			verbose++;
			break;
		case 'w':
			ep = NULL;
			errno = 0;
			waittime = strtoul(optarg, &ep, 0);
			if (errno || !*optarg || *ep) {
				fprintf(stderr,
				    "traceroute6: invalid wait time.\n");
				exit(1);
			}
			if (waittime <= 1) {
				fprintf(stderr,
				    "traceroute6: wait must be >1 sec.\n");
				exit(1);
			}
			break;
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (max_hops < first_hop) {
		fprintf(stderr,
		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
		exit(1);
	}

	if (argc < 1 || argc > 2)
		usage();

#if 1
	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
#else
	setlinebuf(stdout);
#endif

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_INET6;
	hints.ai_socktype = SOCK_RAW;
	hints.ai_protocol = IPPROTO_ICMPV6;
	hints.ai_flags = AI_CANONNAME;
	error = getaddrinfo(*argv, NULL, &hints, &res);
	if (error) {
		fprintf(stderr,
		    "traceroute6: %s\n", gai_strerror(error));
		exit(1);
	}
	if (res->ai_addrlen != sizeof(Dst)) {
		fprintf(stderr,
		    "traceroute6: size of sockaddr mismatch\n");
		exit(1);
	}
	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
	if (!hostname) {
		fprintf(stderr, "traceroute6: not enough core\n");
		exit(1);
	}
	if (res->ai_next) {
		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
			strlcpy(hbuf, "?", sizeof(hbuf));
		fprintf(stderr, "traceroute6: Warning: %s has multiple "
		    "addresses; using %s\n", hostname, hbuf);
	}

	if (*++argv) {
		ep = NULL;
		errno = 0;
		datalen = strtoul(*argv, &ep, 0);
		if (errno || !*argv || *ep) {
			fprintf(stderr,
			    "traceroute6: invalid packet length.\n");
			exit(1);
		}
	}
	if (useicmp)
		minlen = ICMP6ECHOLEN + sizeof(struct tv32);
	else
		minlen = sizeof(struct opacket);
	if (datalen < minlen)
		datalen = minlen;
	else if (datalen >= MAXPACKET) {
		fprintf(stderr,
		    "traceroute6: packet size must be %d <= s < %ld.\n",
		    minlen, (long)MAXPACKET);
		exit(1);
	}
	outpacket = (struct opacket *)malloc((unsigned)datalen);
	if (!outpacket) {
		perror("malloc");
		exit(1);
	}
	(void) bzero((char *)outpacket, datalen);

	/* initialize msghdr for receiving packets */
	rcviov[0].iov_base = (caddr_t)packet;
	rcviov[0].iov_len = sizeof(packet);
	rcvmhdr.msg_name = (caddr_t)&Rcv;
	rcvmhdr.msg_namelen = sizeof(Rcv);
	rcvmhdr.msg_iov = rcviov;
	rcvmhdr.msg_iovlen = 1;
	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
	    CMSG_SPACE(sizeof(int));
	
	if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
		fprintf(stderr, "traceroute6: malloc failed\n");
		exit(1);
	}
	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
	rcvmhdr.msg_controllen = rcvcmsglen;

	if (options & SO_DEBUG)
		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
		    (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
		    (char *)&on, sizeof(on));

	/*
	 * Send UDP or ICMP
	 */
	if (useicmp) {
		sndsock = rcvsock;
	} else {
		if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
			perror("socket(SOCK_DGRAM)");
			exit(5);
		}
	}
#ifdef SO_SNDBUF
	i = datalen;
	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
	    sizeof(i)) < 0) {
		perror("setsockopt(SO_SNDBUF)");
		exit(6);
	}
#endif /* SO_SNDBUF */
	if (options & SO_DEBUG)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
		    (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
		    (char *)&on, sizeof(on));
	if (rth) {/* XXX: there is no library to finalize the header... */
		rth->ip6r_len = rth->ip6r_segleft * 2;
		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
			    strerror(errno));
			exit(1);
		}
	}

	/*
	 * Source selection
	 */
	bzero(&Src, sizeof(Src));
	if (source) {
		struct addrinfo hints, *res;
		int error;

		memset(&hints, 0, sizeof(hints));
		hints.ai_family = AF_INET6;
		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
		hints.ai_flags = AI_NUMERICHOST;
		error = getaddrinfo(source, "0", &hints, &res);
		if (error) {
			printf("traceroute6: %s: %s\n", source,
			    gai_strerror(error));
			exit(1);
		}
		if (res->ai_addrlen > sizeof(Src)) {
			printf("traceroute6: %s: %s\n", source,
			    gai_strerror(error));
			exit(1);
		}
		memcpy(&Src, res->ai_addr, res->ai_addrlen);
		freeaddrinfo(res);
	} else {
		struct sockaddr_in6 Nxt;
		int dummy;
		socklen_t len;

		Nxt = Dst;
		Nxt.sin6_port = htons(DUMMY_PORT);
		if (cmsg != NULL)
			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
			    sizeof(Nxt.sin6_addr));
		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
			perror("socket");
			exit(1);
		}
		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
			perror("connect");
			exit(1);
		}
		len = sizeof(Src);
		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
			perror("getsockname");
			exit(1);
		}
		if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
			fprintf(stderr, "getnameinfo failed for source\n");
			exit(1);
		}
		source = src0;
		close(dummy);
	}

	Src.sin6_port = htons(0);
	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
		perror("bind");
		exit(1);
	}

	{
		socklen_t len;

		len = sizeof(Src);
		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
			perror("getsockname");
			exit(1);
		}
		srcport = ntohs(Src.sin6_port);
	}

	/*
	 * Message to users
	 */
	if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
	fprintf(stderr, "traceroute6");
	fprintf(stderr, " to %s (%s)", hostname, hbuf);
	if (source)
		fprintf(stderr, " from %s", source);
	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
	    max_hops, datalen);
	(void) fflush(stderr);

	if (first_hop > 1)
		printf("Skipping %lu intermediate hops\n", first_hop - 1);

	/*
	 * Main loop
	 */
	for (hops = first_hop; hops <= max_hops; ++hops) {
		struct in6_addr lastaddr;
		int got_there = 0;
		int unreachable = 0;

		printf("%2lu ", hops);
		bzero(&lastaddr, sizeof(lastaddr));
		for (probe = 0; probe < nprobes; ++probe) {
			int cc;
			struct timeval t1, t2;

			(void) gettimeofday(&t1, NULL);
			send_probe(++seq, hops);
			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
				(void) gettimeofday(&t2, NULL);
				if ((i = packet_ok(&rcvmhdr, cc, seq))) {
					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
					    &lastaddr)) {
						print(&rcvmhdr, cc);
						lastaddr = Rcv.sin6_addr;
					}
					printf("  %g ms", deltaT(&t1, &t2));
					switch (i - 1) {
					case ICMP6_DST_UNREACH_NOROUTE:
						++unreachable;
						printf(" !N");
						break;
					case ICMP6_DST_UNREACH_ADMIN:
						++unreachable;
						printf(" !P");
						break;
					case ICMP6_DST_UNREACH_NOTNEIGHBOR:
						++unreachable;
						printf(" !S");
						break;
					case ICMP6_DST_UNREACH_ADDR:
						++unreachable;
						printf(" !A");
						break;
					case ICMP6_DST_UNREACH_NOPORT:
						if (rcvhlim >= 0 &&
						    rcvhlim <= 1)
							printf(" !");
						++got_there;
						break;
					}
					break;
				}
			}
			if (cc == 0)
				printf(" *");
			(void) fflush(stdout);
		}
		putchar('\n');
		if (got_there ||
		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
			exit(0);
		}
	}

	exit(0);
}
Beispiel #9
0
/*
 * pinger --
 * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
 * will be added on by the kernel.  The ID field is our UNIX process ID,
 * and the sequence number is an ascending integer.  The first 8 bytes
 * of the data portion are used to hold a UNIX "timeval" struct in VAX
 * byte-order, to compute the round-trip time.
 */
int pinger(void)
{
	static int oom_count;
	static int tokens;
	int i;

	/* Have we already sent enough? If we have, return an arbitrary positive value. */
	if (exiting || (npackets && ntransmitted >= npackets && !deadline))
		return 1000;

	/* Check that packets < rate*time + preload */
	if (cur_time.tv_sec == 0) {
		gettimeofday(&cur_time, NULL);
		tokens = interval*(preload-1);
	} else {
		long ntokens;
		struct timeval tv;

		gettimeofday(&tv, NULL);
		ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
			(tv.tv_usec-cur_time.tv_usec)/1000;
		if (!interval) {
			/* Case of unlimited flood is special;
			 * if we see no reply, they are limited to 100pps */
			if (ntokens < MININTERVAL && in_flight() >= preload)
				return MININTERVAL-ntokens;
		}
		ntokens += tokens;
		if (ntokens > interval*preload)
			ntokens = interval*preload;
		if (ntokens < interval)
			return interval - ntokens;

		cur_time = tv;
		tokens = ntokens - interval;
	}

	if (options & F_OUTSTANDING) {
		if (ntransmitted > 0 && !rcvd_test(ntransmitted)) {
			print_timestamp();
			printf("no answer yet for icmp_seq=%lu\n", (ntransmitted % MAX_DUP_CHK));
			fflush(stdout);
		}
	}

resend:
	i = send_probe();

	if (i == 0) {
		oom_count = 0;
		advance_ntransmitted();
		if (!(options & F_QUIET) && (options & F_FLOOD)) {
			/* Very silly, but without this output with
			 * high preload or pipe size is very confusing. */
			if ((preload < screen_width && pipesize < screen_width) ||
			    in_flight() < screen_width)
				write_stdout(".", 1);
		}
		return interval - tokens;
	}

	/* And handle various errors... */
	if (i > 0) {
		/* Apparently, it is some fatal bug. */
		abort();
	} else if (errno == ENOBUFS || errno == ENOMEM) {
		int nores_interval;

		/* Device queue overflow or OOM. Packet is not sent. */
		tokens = 0;
		/* Slowdown. This works only in adaptive mode (option -A) */
		rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
		if (options&F_ADAPTIVE)
			update_interval();
		nores_interval = SCHINT(interval/2);
		if (nores_interval > 500)
			nores_interval = 500;
		oom_count++;
		if (oom_count*nores_interval < lingertime)
			return nores_interval;
		i = 0;
		/* Fall to hard error. It is to avoid complete deadlock
		 * on stuck output device even when dealine was not requested.
		 * Expected timings are screwed up in any case, but we will
		 * exit some day. :-) */
	} else if (errno == EAGAIN) {
		/* Socket buffer is full. */
		tokens += interval;
		return MININTERVAL;
	} else {
		if ((i=receive_error_msg()) > 0) {
			/* An ICMP error arrived. */
			tokens += interval;
			return MININTERVAL;
		}
		/* Compatibility with old linuces. */
		if (i == 0 && confirm_flag && errno == EINVAL) {
			confirm_flag = 0;
			errno = 0;
		}
		if (!errno)
			goto resend;
	}

	/* Hard local error. Pretend we sent packet. */
	advance_ntransmitted();

	if (i == 0 && !(options & F_QUIET)) {
		if (options & F_FLOOD)
			write_stdout("E", 1);
		else
			perror("ping: sendmsg");
	}
	tokens = 0;
	return SCHINT(interval);
}
Beispiel #10
0
/**
 * Read a packet from the underlying radio driver. If the incoming
 * packet is a probe packet and the sender of the probe matches the
 * destination address of the queued packet (if any), the queued packet
 * is sent.
 */
static void
input_packet(void)
{
  struct lpp_hdr hdr;
  clock_time_t reception_time;

  reception_time = clock_time();

  if(!NETSTACK_FRAMER.parse()) {
    printf("lpp input_packet framer error\n");
  }

  memcpy(&hdr, packetbuf_dataptr(), sizeof(struct lpp_hdr));;
  packetbuf_hdrreduce(sizeof(struct lpp_hdr));
  /*    PRINTF("got packet type %d\n", hdr->type);*/

  if(hdr.type == TYPE_PROBE) {
    struct announcement_msg adata;
    
    /* Register the encounter with the sending node. We now know the
       neighbor's phase. */
    register_encounter(&hdr.sender, reception_time);

    /* Parse incoming announcements */
    memcpy(&adata, packetbuf_dataptr(),
           MIN(packetbuf_datalen(), sizeof(adata)));
#if 0
    PRINTF("%d.%d: probe from %d.%d with %d announcements\n",
           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
           hdr.sender.u8[0], hdr.sender.u8[1], adata->num);
    
    if(adata.num / sizeof(struct announcement_data) > sizeof(struct announcement_msg)) {
      /* Sanity check. The number of announcements is too large -
         corrupt packet has been received. */
      return 0;
    }

    for(i = 0; i < adata.num; ++i) {
      /*	  PRINTF("%d.%d: announcement %d: %d\n",
		  rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
		  adata->data[i].id,
		  adata->data[i].value);*/

      announcement_heard(&hdr.sender,
                         adata.data[i].id,
                         adata.data[i].value);
    }
#endif  /* 0 */

    /* Go through the list of packets to be sent to see if any of
       them match the sender of the probe, or if they are a
       broadcast packet that should be sent. */
    if(list_length(queued_packets_list) > 0) {
      struct queue_list_item *i;
      for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
        const rimeaddr_t *receiver;
        uint8_t sent;

        sent = 0;
 
        receiver = queuebuf_addr(i->packet, PACKETBUF_ADDR_RECEIVER);
        if(rimeaddr_cmp(receiver, &hdr.sender) ||
           rimeaddr_cmp(receiver, &rimeaddr_null)) {
          queuebuf_to_packetbuf(i->packet);

#if WITH_PENDING_BROADCAST
          if(i->broadcast_flag == BROADCAST_FLAG_NONE ||
             i->broadcast_flag == BROADCAST_FLAG_SEND) {
            i->num_transmissions = 1;
            NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
                                queuebuf_datalen(i->packet));
            sent = 1;
            PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
		   rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                   hdr.sender.u8[0], hdr.sender.u8[1],
                   receiver->u8[0], receiver->u8[1]);
	      
          } else {
            PRINTF("%d.%d: got a probe from %d.%d, did not send packet\n",
                   rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                   hdr.sender.u8[0], hdr.sender.u8[1]);
          }
#else /* WITH_PENDING_BROADCAST */
          i->num_transmissions = 1;
          NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
                               queuebuf_datalen(i->packet));
          PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
                 rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
                 hdr.sender.u8[0], hdr.sender.u8[1],
                 receiver->u8[0], receiver->u8[1]);
#endif /* WITH_PENDING_BROADCAST */

          /*          off();*/

          /* Attribute the energy spent on listening for the probe
             to this packet transmission. */
          compower_accumulate(&i->compower);
	    
          /* If the packet was not a broadcast packet, we dequeue it
             now. Broadcast packets should be transmitted to all
             neighbors, and are dequeued by the dutycycling function
             instead, after the appropriate time. */
          if(!rimeaddr_cmp(receiver, &rimeaddr_null)) {
            if(detect_ack()) {
              remove_queued_packet(i, 1);
            } else {
              remove_queued_packet(i, 0);
            }

#if WITH_PROBE_AFTER_TRANSMISSION
            /* Send a probe packet to catch any reply from the other node. */
            restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);
#endif /* WITH_PROBE_AFTER_TRANSMISSION */

#if WITH_STREAMING
            if(is_streaming) {
              ctimer_set(&stream_probe_timer, STREAM_PROBE_TIME,
                         send_stream_probe, NULL);
            }
#endif /* WITH_STREAMING */
          }

          if(sent) {
            turn_radio_off();
          }

#if WITH_ACK_OPTIMIZATION
          if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
             packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)) {
            /* We're sending a packet that needs an ACK, so we keep
               the radio on in anticipation of the ACK. */
            turn_radio_on();
          }
#endif /* WITH_ACK_OPTIMIZATION */

        }
      }
    }

  } else if(hdr.type == TYPE_DATA) {
    turn_radio_off();
    if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
      if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
        /* Not broadcast or for us */
        PRINTF("%d.%d: data not for us from %d.%d\n",
               rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
               hdr.sender.u8[0], hdr.sender.u8[1]);
        return;
      }
      packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &hdr.receiver);
    }
    packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &hdr.sender);

    PRINTF("%d.%d: got data from %d.%d\n",
           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
           hdr.sender.u8[0], hdr.sender.u8[1]);

    /* Accumulate the power consumption for the packet reception. */
    compower_accumulate(&current_packet);
    /* Convert the accumulated power consumption for the received
       packet to packet attributes so that the higher levels can
       keep track of the amount of energy spent on receiving the
       packet. */
    compower_attrconv(&current_packet);
      
    /* Clear the accumulated power consumption so that it is ready
       for the next packet. */
    compower_clear(&current_packet);

#if WITH_PENDING_BROADCAST
    if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
      /* This is a broadcast packet. Check the list of pending
         packets to see if we are currently sending a broadcast. If
         so, we refrain from sending our broadcast until one sleep
         cycle period, so that the other broadcaster will have
         finished sending. */
	
      struct queue_list_item *i;
      for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
        /* If the packet is a broadcast packet that is not yet
           ready to be sent, we do not send it. */
        if(i->broadcast_flag == BROADCAST_FLAG_PENDING) {
          PRINTF("Someone else is sending, pending -> waiting\n");
          set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
        }
      }
    }
#endif /* WITH_PENDING_BROADCAST */


#if WITH_PROBE_AFTER_RECEPTION
    /* XXX send probe after receiving a packet to facilitate data
       streaming. We must first copy the contents of the packetbuf into
       a queuebuf to avoid overwriting the data with the probe packet. */
    if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
      struct queuebuf *q;
      q = queuebuf_new_from_packetbuf();
      if(q != NULL) {
        send_probe();
        queuebuf_to_packetbuf(q);
        queuebuf_free(q);
      }
    }
#endif /* WITH_PROBE_AFTER_RECEPTION */

#if WITH_ADAPTIVE_OFF_TIME
    off_time = LOWEST_OFF_TIME;
    restart_dutycycle(off_time);
#endif /* WITH_ADAPTIVE_OFF_TIME */

    NETSTACK_MAC.input();
  }
}
Beispiel #11
0
/**
 * Duty cycle the radio and send probes. This function is called
 * repeatedly by a ctimer. The function restart_dutycycle() is used to
 * (re)start the duty cycling.
 */
static int
dutycycle(void *ptr)
{
  struct ctimer *t = ptr;
	
  PT_BEGIN(&dutycycle_pt);

  while(1) {

#if WITH_PENDING_BROADCAST
    {
	/* Before sending the probe, we mark all broadcast packets in
	   our output queue to be pending. This means that they are
	   ready to be sent, once we know that no neighbor is
	   currently broadcasting. */
      for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) {
	  if(p->broadcast_flag == BROADCAST_FLAG_WAITING) {
	    PRINTF("wait -> pending\n");
	    set_broadcast_flag(p, BROADCAST_FLAG_PENDING);
	  }
	}
      }
#endif /* WITH_PENDING_BROADCAST */
    
    /* Turn on the radio for sending a probe packet and 
       anticipating a data packet from a neighbor. */
    turn_radio_on();

    /* Send a probe packet. */
    send_probe();

    /* Set a timer so that we keep the radio on for LISTEN_TIME. */
    ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
    PT_YIELD(&dutycycle_pt);

#if WITH_PENDING_BROADCAST
    {
      struct queue_list_item *p;
      /* Go through the list of packets we are waiting to send, and
	 check if there are any pending broadcasts in the list. If
	 there are pending broadcasts, and we did not receive any
	 broadcast packets from a neighbor in response to our probe,
	 we mark the broadcasts as being ready to send. */
      for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) {
	if(p->broadcast_flag == BROADCAST_FLAG_PENDING) {
	  PRINTF("pending -> send\n");
	  set_broadcast_flag(p, BROADCAST_FLAG_SEND);
	  turn_radio_on();
	}
      }
    }
#endif /* WITH_PENDING_BROADCAST */

    /* If we have no packets to send (indicated by the list length of
       queued_packets_list being zero), we should turn the radio
       off. Othersize, we keep the radio on. */
    if(num_packets_to_send() == 0) {
      
      /* If we are not listening for announcements, we turn the radio
	 off and wait until we send the next probe. */
      if(is_listening == 0) {
        int current_off_time;
        if(!NETSTACK_RADIO.receiving_packet()) {
          turn_radio_off();
          compower_accumulate(&compower_idle_activity);
        }
        current_off_time = off_time - off_time_adjustment;
        if(current_off_time < LISTEN_TIME * 2) {
          current_off_time = LISTEN_TIME * 2;
        }
        off_time_adjustment = 0;
	ctimer_set(t, current_off_time, (void (*)(void *))dutycycle, t);
	PT_YIELD(&dutycycle_pt);

#if WITH_ADAPTIVE_OFF_TIME
	off_time += LOWEST_OFF_TIME;
	if(off_time > OFF_TIME) {
	  off_time = OFF_TIME;
	}
#endif /* WITH_ADAPTIVE_OFF_TIME */

      } else {
	/* We are listening for annonucements, so we count down the
	   listen time, and keep the radio on. */
	is_listening--;
	ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
	PT_YIELD(&dutycycle_pt);
      }
    } else {
      /* We had pending packets to send, so we do not turn the radio off. */

      ctimer_set(t, off_time, (void (*)(void *))dutycycle, t);
      PT_YIELD(&dutycycle_pt);
    }
  }

  PT_END(&dutycycle_pt);
}
Beispiel #12
0
traceroute_main(int argc, char *argv[])
#endif
{
	extern char *optarg;
	extern int optind;
	struct hostent *hp;
	struct sockaddr_in from, *to;
	int ch, i, on, probe, seq, tos, ttl;

	int options = 0;                /* socket options */
	char *source = 0;
	int nprobes = 3;

	on = 1;
	seq = tos = 0;
	to = (struct sockaddr_in *)&whereto;
	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
		switch(ch) {
		case 'd':
#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
			options |= SO_DEBUG;
#endif
			break;
		case 'm':
			max_ttl = atoi(optarg);
			if (max_ttl <= 1)
				bb_error_msg_and_die("max ttl must be >1.");
			break;
		case 'n':
			nflag++;
			break;
		case 'p':
			port = atoi(optarg);
			if (port < 1)
				bb_error_msg_and_die("port must be >0.");
			break;
		case 'q':
			nprobes = atoi(optarg);
			if (nprobes < 1)
				bb_error_msg_and_die("nprobes must be >0.");
			break;
		case 'r':
			options |= SO_DONTROUTE;
			break;
		case 's':
			/*
			 * set the ip source address of the outbound
			 * probe (e.g., on a multi-homed host).
			 */
			source = optarg;
			break;
		case 't':
			tos = atoi(optarg);
			if (tos < 0 || tos > 255)
				bb_error_msg_and_die("tos must be 0 to 255.");
			break;
		case 'v':
#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
			verbose++;
#endif
			break;
		case 'w':
			waittime = atoi(optarg);
			if (waittime <= 1)
				bb_error_msg_and_die("wait must be >1 sec.");
			break;
		default:
			bb_show_usage();
		}
	argc -= optind;
	argv += optind;

	if (argc < 1)
		bb_show_usage();

	setlinebuf (stdout);

	memset(&whereto, 0, sizeof(struct sockaddr));
	hp = xgethostbyname(*argv);
			to->sin_family = hp->h_addrtype;
	memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
			hostname = (char *)hp->h_name;
	if (*++argv)
		datalen = atoi(*argv);
	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
		bb_error_msg_and_die("packet size must be 0 <= s < %d.",
		    MAXPACKET - sizeof(struct opacket));
	datalen += sizeof(struct opacket);
	outpacket = (struct opacket *)xmalloc((unsigned)datalen);
	memset(outpacket, 0, datalen);
	outpacket->ip.ip_dst = to->sin_addr;
	outpacket->ip.ip_tos = tos;
	outpacket->ip.ip_v = IPVERSION;
	outpacket->ip.ip_id = 0;

	ident = (getpid() & 0xffff) | 0x8000;

	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
		bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);

	s = create_icmp_socket();

#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
	if (options & SO_DEBUG)
		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
#endif
	if (options & SO_DONTROUTE)
		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));
#ifdef SO_SNDBUF
	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
		       sizeof(datalen)) < 0)
		bb_perror_msg_and_die("SO_SNDBUF");
#endif
#ifdef IP_HDRINCL
	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
		       sizeof(on)) < 0)
		bb_perror_msg_and_die("IP_HDRINCL");
#endif
#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
	if (options & SO_DEBUG)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
#endif
	if (options & SO_DONTROUTE)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));

	if (source) {
		memset(&from, 0, sizeof(struct sockaddr));
		from.sin_family = AF_INET;
		from.sin_addr.s_addr = inet_addr(source);
		if (from.sin_addr.s_addr == -1)
			bb_error_msg_and_die("unknown host %s", source);
		outpacket->ip.ip_src = from.sin_addr;
#ifndef IP_HDRINCL
		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
			bb_perror_msg_and_die("bind");
#endif
	}

	fprintf(stderr, "traceroute to %s (%s)", hostname,
		inet_ntoa(to->sin_addr));
	if (source)
		fprintf(stderr, " from %s", source);
	fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);

	for (ttl = 1; ttl <= max_ttl; ++ttl) {
		u_long lastaddr = 0;
		int got_there = 0;
		int unreachable = 0;

		printf("%2d ", ttl);
		for (probe = 0; probe < nprobes; ++probe) {
			int cc, reset_timer;
			struct timeval t1, t2;
			struct timezone tz;
			struct ip *ip;

			(void) gettimeofday(&t1, &tz);
			send_probe(++seq, ttl);
			reset_timer = 1;
			while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
				(void) gettimeofday(&t2, &tz);
				if ((i = packet_ok(packet, cc, &from, seq))) {
					reset_timer = 1;
					if (from.sin_addr.s_addr != lastaddr) {
						print(packet, cc, &from);
						lastaddr = from.sin_addr.s_addr;
					}
					printf("  %g ms", deltaT(&t1, &t2));
					switch(i - 1) {
					case ICMP_UNREACH_PORT:
						ip = (struct ip *)packet;
						if (ip->ip_ttl <= 1)
							printf(" !");
						++got_there;
						break;
					case ICMP_UNREACH_NET:
						++unreachable;
						printf(" !N");
						break;
					case ICMP_UNREACH_HOST:
						++unreachable;
						printf(" !H");
						break;
					case ICMP_UNREACH_PROTOCOL:
						++got_there;
						printf(" !P");
						break;
					case ICMP_UNREACH_NEEDFRAG:
						++unreachable;
						printf(" !F");
						break;
					case ICMP_UNREACH_SRCFAIL:
						++unreachable;
						printf(" !S");
						break;
					}
					break;
				} else
					reset_timer = 0;
			}
			if (cc == 0)
				printf(" *");
			(void) fflush(stdout);
		}
		putchar('\n');
		if (got_there || unreachable >= nprobes-1)
			return 0;
	}

	return 0;
}
Beispiel #13
0
int main(int argc, char *argv[])
{
	char pa[MAXHOSTNAMELEN];
	extern char *optarg;
	extern int optind;
	struct hostent *hp;
	struct sockaddr_in6 from, *to;
	int ch, i, on, probe, seq, tos, ttl;
	int socket_errno;

	icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
	socket_errno = errno;

	if (setuid(getuid())) {
		perror("traceroute6: setuid");
		exit(-1);
	}

	on = 1;
	seq = tos = 0;
	to = (struct sockaddr_in6 *)&whereto;
	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:vi:g:V")) != EOF) {
		switch(ch) {
		case 'd':
			options |= SO_DEBUG;
			break;
		case 'm':
			max_ttl = atoi(optarg);
			if (max_ttl <= 1) {
				Fprintf(stderr,
				    "traceroute: max ttl must be >1.\n");
				exit(1);
			}
			break;
		case 'n':
			nflag++;
			break;
		case 'p':
			port = atoi(optarg);
			if (port < 1) {
				Fprintf(stderr,
				    "traceroute: port must be >0.\n");
				exit(1);
			}
			break;
		case 'q':
			nprobes = atoi(optarg);
			if (nprobes < 1) {
				Fprintf(stderr,
				    "traceroute: nprobes must be >0.\n");
				exit(1);
			}
			break;
		case 'r':
			options |= SO_DONTROUTE;
			break;
		case 's':
			/*
			 * set the ip source address of the outbound
			 * probe (e.g., on a multi-homed host).
			 */
			source = optarg;
			break;
		case 'i':
			device = optarg;
			break;
		case 'g':
			Fprintf(stderr, "Sorry, rthdr is not yet supported\n");
			break;
		case 'v':
			verbose++;
			break;
		case 'w':
			waittime = atoi(optarg);
			if (waittime <= 1) {
				Fprintf(stderr,
				    "traceroute: wait must be >1 sec.\n");
				exit(1);
			}
			break;
		case 'V':
			printf("traceroute6 utility, iputils-ss%s\n", SNAPSHOT);
			exit(0);
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 1)
		usage();

	setlinebuf (stdout);

	(void) bzero((char *)&whereto, sizeof(whereto));

	to->sin6_family = AF_INET6;
	to->sin6_port = htons(port);

	if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) {
		hostname = *argv;
	} else {
		hp = gethostbyname2(*argv, AF_INET6);
		if (hp) {
			memmove((caddr_t)&to->sin6_addr, hp->h_addr, sizeof(to->sin6_addr));
			hostname = (char *)hp->h_name;
		} else {
			(void)fprintf(stderr,
			    "traceroute: unknown host %s\n", *argv);
			exit(1);
		}
	}
	firsthop = *to;
	if (*++argv) {
		datalen = atoi(*argv);
		/* Message for rpm maintainers: have _shame_. If you want
		 * to fix something send the patch to me for sanity checking.
		 * "datalen" patch is a shit. */
		if (datalen == 0)
			datalen = sizeof(struct pkt_format);
		else if (datalen < (int)sizeof(struct pkt_format) ||
			 datalen >= MAXPACKET) {
			Fprintf(stderr,
			    "traceroute: packet size must be %d <= s < %d.\n",
				(int)sizeof(struct pkt_format), MAXPACKET);
			exit(1);
		}
	}

	ident = getpid();

	sendbuff = malloc(datalen);
	if (sendbuff == NULL) {
		fprintf(stderr, "malloc failed\n");
		exit(1);
	}

	if (icmp_sock < 0) {
		errno = socket_errno;
		perror("traceroute6: icmp socket");
		exit(1);
	}

#ifdef IPV6_RECVPKTINFO
	setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
	setsockopt(icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on));
#else
	setsockopt(icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on));
#endif

	if (options & SO_DEBUG)
		setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG,
			   (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE,
			   (char *)&on, sizeof(on));
	on = 2;
	if (setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) {
		perror("setsockopt(RAW_CHECKSUM)");
		exit(2);
	}

	if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
		perror("traceroute: UDP socket");
		exit(5);
	}
#ifdef SO_SNDBUF
	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
		       sizeof(datalen)) < 0) {
		perror("traceroute: SO_SNDBUF");
		exit(6);
	}
#endif /* SO_SNDBUF */

	if (options & SO_DEBUG)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
	if (options & SO_DONTROUTE)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));

	if (source == NULL) {
		socklen_t alen;
		int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0);

		if (probe_fd < 0) {
			perror("socket");
			exit(1);
		}
		if (device) {
			if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
				perror("WARNING: interface is ignored");
		}
		firsthop.sin6_port = htons(1025);
		if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) {
			perror("connect");
			exit(1);
		}
		alen = sizeof(saddr);
		if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
			perror("getsockname");
			exit(1);
		}
		saddr.sin6_port = 0;
		close(probe_fd);
	} else {
		(void) bzero((char *)&saddr, sizeof(saddr));
		saddr.sin6_family = AF_INET6;
		if (inet_pton(AF_INET6, source, &saddr.sin6_addr) <= 0)
		{
			Printf("traceroute: unknown addr %s\n", source);
			exit(1);
		}
	}

	if (bind(sndsock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
		perror ("traceroute: bind sending socket");
		exit (1);
	}
	if (bind(icmp_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
		perror ("traceroute: bind icmp6 socket");
		exit (1);
	}

	Fprintf(stderr, "traceroute to %s (%s)", hostname,
		inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa)));

	Fprintf(stderr, " from %s",
		inet_ntop(AF_INET6, &saddr.sin6_addr, pa, sizeof(pa)));
	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
	(void) fflush(stderr);

	for (ttl = 1; ttl <= max_ttl; ++ttl) {
		struct in6_addr lastaddr = {{{0,}}};
		int got_there = 0;
		int unreachable = 0;

		Printf("%2d ", ttl);
		for (probe = 0; probe < nprobes; ++probe) {
			int cc, reset_timer;
			struct timeval t1, t2;
			struct timezone tz;
			struct in6_addr to;

			gettimeofday(&t1, &tz);
			send_probe(++seq, ttl);
			reset_timer = 1;

			while ((cc = wait_for_reply(icmp_sock, &from, &to, reset_timer)) != 0) {
				gettimeofday(&t2, &tz);
				if ((i = packet_ok(packet, cc, &from, &to, seq, &t1))) {
					reset_timer = 1;
					if (memcmp(&from.sin6_addr, &lastaddr, sizeof(from.sin6_addr))) {
						print(packet, cc, &from);
						memcpy(&lastaddr,
						       &from.sin6_addr,
						       sizeof(lastaddr));
					}
					Printf("  %g ms", deltaT(&t1, &t2));
					switch(i - 1) {
					case ICMP6_DST_UNREACH_NOPORT:
						++got_there;
						break;

					case ICMP6_DST_UNREACH_NOROUTE:
						++unreachable;
						Printf(" !N");
						break;
					case ICMP6_DST_UNREACH_ADDR:
						++unreachable;
						Printf(" !H");
						break;

					case ICMP6_DST_UNREACH_ADMIN:
						++unreachable;
						Printf(" !S");
						break;
					}
					break;
				} else
					reset_timer = 0;
			}
			if (cc <= 0)
				Printf(" *");
			(void) fflush(stdout);
		}
		putchar('\n');
		if (got_there ||
		    (unreachable > 0 && unreachable >= nprobes-1))
			exit(0);
	}

	return 0;
}
Beispiel #14
0
void aodv(void) {
	//The queue holding all the events to be dealt with
	task *tmp_task;

	//Initalize the variables
	init_waitqueue_head(&aodv_wait);
	atomic_set(&kill_thread, 0);
	atomic_set(&aodv_is_dead, 0);


	//Name our thread
	/*lock_kernel();
	 sprintk(current->comm, "aodv-mcc");
	 //exit_mm(current); --> equivale a: current->mm = NULL;
	 //we are in a kthread? aren't we?
	 unlock_kernel();*/

	//add_wait_queue_exclusive(event_socket->sk->sleep,&(aodv_wait));
	//	add_wait_queue(&(aodv_wait),event_socket->sk->sleep);


	//why would I ever want to stop ? :)
	for (;;) {
		//should the thread exit?
		if (atomic_read(&kill_thread)) {
			goto exit;
		}
		//goto sleep until we recieve an interupt
		interruptible_sleep_on(&aodv_wait);

		//should the thread exit?
		if (atomic_read(&kill_thread)) {
			goto exit;
		}
		//While the buffer is not empty
		extern dtn_hello_ip;
		while ((tmp_task = get_task()) != NULL) {
			
			u_int32_t dst;

			//takes a different action depending on what type of event is recieved
			switch (tmp_task->type) {

			//remove following case when DTN hell test end
			case TASK_DTN_HELLO:
				//inet_aton("127.127.127.127",&dst);
				
				//extern u_int32_t dtn_hello_ip;
				gen_rreq(g_mesh_ip,dtn_hello_ip,tmp_task->tos);
#ifdef CaiDebug
				printk("-------DTN HELLO TASK---------\n");
#endif
				//insert_timer_simple(TASK_DTN_HELLO, 300*HELLO_INTERVAL, g_mesh_ip);
				//update_timer_queue();
				break;

			//RREP
			case TASK_RECV_RREP:
				recv_rrep(tmp_task);
				kfree(tmp_task->data);
				break;

				//RERR
			case TASK_RECV_RERR:
				//printk("-----------\nget RERR from %s----------\n",inet_ntoa(tmp_task->src_ip));
				recv_rerr(tmp_task);
				kfree(tmp_task->data);
				break;

			case TASK_RECV_HELLO:
				//printk("get HELLO from %s\n",inet_ntoa(tmp_task->src_ip));
				recv_hello(tmp_task);
				kfree(tmp_task->data);
				break;

           		 /****************添加接收到通路包的任务***************/
			#ifdef RECOVERYPATH
            		case TASK_RECV_RCVP:
               			//printk("Receive a RCVP\n");
               			recv_rcvp(tmp_task);
                		kfree(tmp_task->data);
                		break;
			case TASK_RECV_RRDP:
               			//printk("Receive a RRDP\n");
               			recv_rrdp(tmp_task);
                		kfree(tmp_task->data);
                		break;
			#endif

				//Cleanup  the Route Table and Flood ID queue
			case TASK_CLEANUP:
				flush_aodv_route_table();
				break;

			case TASK_HELLO:
				//printk("gen HELLO\n");
				gen_hello();
				break;

			case TASK_ST:
				gen_st_rreq();
				break;

			case TASK_GW_CLEANUP:
				update_gw_lifetimes();
				insert_timer_simple(TASK_GW_CLEANUP, ACTIVE_GWROUTE_TIMEOUT,
						g_mesh_ip);
				update_timer_queue();
				break;

			case TASK_NEIGHBOR:
			//printk("get NEIGHBOR TASH,delete neigh %s\n",inet_ntoa(tmp_task->src_ip));
			delete_aodv_neigh(tmp_task->src_ip);
				break;

			case TASK_ROUTE_CLEANUP:
				flush_aodv_route_table();
				break;

			case TASK_SEND_ETT:
				send_probe(tmp_task->dst_ip);
				break;
				//A small probe packet is received
			case TASK_RECV_S_ETT:
				recv_sprobe(tmp_task);
				kfree(tmp_task->data);
				break;
				//A large probe packet is received
			case TASK_RECV_L_ETT:
				recv_lprobe(tmp_task);
				kfree(tmp_task->data);
				break;
			case TASK_ETT_CLEANUP:
				reset_ett(find_aodv_neigh(tmp_task->src_ip));
				printk("Reseting ETT-Info from neighbour %s\n",
						inet_ntoa(tmp_task->src_ip));
				break;

			case TASK_NEIGHBOR_2H:
				delete_aodv_neigh_2h(tmp_task->src_ip);
				break;

			case TASK_RECV_RREQ:
				recv_rreq(tmp_task);
				kfree(tmp_task->data);
				break;


			case TASK_RESEND_RREQ:
				resend_rreq(tmp_task);
				break;


			case TASK_ETT_INFO:
				recv_ett_info(tmp_task);
				kfree(tmp_task->data);
				break;
			case TASK_SEND_RREP:
				gen_rrep(tmp_task->src_ip, tmp_task->dst_ip, tmp_task->tos);
				break;

			case TASK_RECV_STRREQ:
				recv_rreq_st(tmp_task);
				kfree(tmp_task->data);
				break;

			case TASK_UPDATE_LOAD:
				update_my_load();
				break;

			case TASK_GEN_RREQ:
				gen_rreq(tmp_task->src_ip, tmp_task->dst_ip, tmp_task->tos);
				break;

			default:
				break;
			}

			kfree(tmp_task);

		}

	}

	exit:
	//Set the flag that shows you are dead
	atomic_set(&aodv_is_dead, 1);

}
Beispiel #15
0
static void             /* not inline */
send_probe(int seq, int ttl)
{
	struct opacket *op = outpacket;
	struct ip *ip = &op->ip;
	struct udphdr *up = &op->udp;
	int i;
	struct timezone tz;
#if defined (DMP_TRACEROUTE_1)
	int dataSize = datalen -12; /* Minus some parameters' length in struct opacket*/
#endif
	ip->ip_off = 0;
	ip->ip_hl = sizeof(*ip) >> 2;
	ip->ip_p = IPPROTO_UDP;
#if defined (DMP_TRACEROUTE_1)
	ip->ip_len = dataSize;
#else
	ip->ip_len = datalen;
#endif	
	ip->ip_ttl = ttl;
	ip->ip_v = IPVERSION;
	ip->ip_id = htons(ident+seq);

	up->source = htons(ident);
	up->dest = htons(port+seq);
#if defined (DMP_TRACEROUTE_1)
	up->len = htons((u_short)(dataSize - sizeof(struct ip)));
#else
	up->len = htons((u_short)(datalen - sizeof(struct ip)));
#endif	
	up->check = 0;

	op->seq = seq;
	op->ttl = ttl;
	(void) gettimeofday(&op->tv, &tz);

#if defined (DMP_TRACEROUTE_1)
	i = sendto(sndsock, (char *)outpacket, dataSize, 0, &whereto,
		sizeof(struct sockaddr));
#else
	i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
		sizeof(struct sockaddr));
#endif
#if defined (DMP_TRACEROUTE_1)
	if (i < 0 || i != dataSize)  {
#else
	if (i < 0 || i != datalen)  {
#endif
		if (i<0)
			perror("sendto");
#if defined (DMP_TRACEROUTE_1)
		printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
			dataSize, i);
#else
		printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
			datalen, i);
#endif			
		(void) fflush(stdout);
	}
}


int
#ifndef CONFIG_TRACEROUTE
main(int argc, char *argv[])
#else
traceroute_main(int argc, char *argv[])
#endif
{
	extern char *optarg;
	extern int optind;
	struct hostent *hp;
	struct sockaddr_in from, *to;
	int ch, i, on, probe, seq, tos, ttl;

	int options = 0;                /* socket options */
	char *source = 0;
	int nprobes = 3;
#if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000)
	int ttl_set_flag = 0;
#endif
#if defined(AEI_VDSL_CUSTOMER_NCS)
	int failcount = 0;
#endif
#if defined(DMP_TRACEROUTE_1)
	unsigned int repTime;
	char strRepTime[16];
	TraceRouteDataMsgBody traceRouteInfo;
	memset(&traceRouteInfo, 0 , sizeof(TraceRouteDataMsgBody));
	TraceRouteDataMsgBody *pTraceRouteInfo = &traceRouteInfo;
	cmsMsg_init(EID_TRACEROUTE, &msgHandle);
#endif
	on = 1;
	seq = tos = 0;
	to = (struct sockaddr_in *)&whereto;
	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
		switch(ch) {
		case 'd':
#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
			options |= SO_DEBUG;
#endif
			break;
		case 'm':
			max_ttl = atoi(optarg);
#if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000)
			ttl_set_flag = 1;
#endif
			if (max_ttl <= 1)
				bb_error_msg_and_die("max ttl must be >1.");
			break;
		case 'n':
			nflag++;
			break;
		case 'p':
			port = atoi(optarg);
			if (port < 1)
				bb_error_msg_and_die("port must be >0.");
			break;
		case 'q':
			nprobes = atoi(optarg);
			if (nprobes < 1)
				bb_error_msg_and_die("nprobes must be >0.");
			break;
		case 'r':
			options |= SO_DONTROUTE;
			break;
		case 's':
			/*
			 * set the ip source address of the outbound
			 * probe (e.g., on a multi-homed host).
			 */
			source = optarg;
			break;
		case 't':
			tos = atoi(optarg);
			if (tos < 0 || tos > 255)
				bb_error_msg_and_die("tos must be 0 to 255.");
			break;
		case 'v':
#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
			verbose++;
#endif
			break;
		case 'w':
			waittime = atoi(optarg);
			if (waittime <= 1)
				bb_error_msg_and_die("wait must be >1 sec.");
			break;
		default:
			bb_show_usage();
		}
	argc -= optind;
	argv += optind;

	if (argc < 1)
		bb_show_usage();

	setlinebuf (stdout);

	memset(&whereto, 0, sizeof(struct sockaddr));
#if defined(DMP_TRACEROUTE_1)
	hp = gethostbyname(*argv);
	if (*++argv)
	{
		requesterId = atoi(*argv);		
	}
	if (hp == NULL)
	{
		AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_CannotResolveHostName);
		bb_herror_msg_and_die("%s", *--argv);
	}
#else
	hp = xgethostbyname(*argv);
#endif
			to->sin_family = hp->h_addrtype;
	memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
			hostname = (char *)hp->h_name;
	if (*++argv)
		datalen = atoi(*argv);
#if defined (DMP_TRACEROUTE_1)
	if (datalen == 0)
	{
		datalen = 40; /*Default data length*/
	}
#endif		
	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
		bb_error_msg_and_die("packet size must be 0 <= s < %d.",
		    MAXPACKET - sizeof(struct opacket));
	datalen += sizeof(struct opacket);
	outpacket = (struct opacket *)xmalloc((unsigned)datalen);
	memset(outpacket, 0, datalen);
	outpacket->ip.ip_dst = to->sin_addr;
	outpacket->ip.ip_tos = tos;
#if defined(DMP_TRACEROUTE_1)
	outpacket->ip.ip_tos = (outpacket->ip.ip_tos)<<2;
#endif
	outpacket->ip.ip_v = IPVERSION;
	outpacket->ip.ip_id = 0;

	ident = (getpid() & 0xffff) | 0x8000;

	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
		bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);

	s = create_icmp_socket();

#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
	if (options & SO_DEBUG)
		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
#endif
	if (options & SO_DONTROUTE)
		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));
#ifdef SO_SNDBUF
	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
		       sizeof(datalen)) < 0)
		bb_perror_msg_and_die("SO_SNDBUF");
#endif
#ifdef IP_HDRINCL
	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
		       sizeof(on)) < 0)
		bb_perror_msg_and_die("IP_HDRINCL");
#endif
#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
	if (options & SO_DEBUG)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
				  (char *)&on, sizeof(on));
#endif
	if (options & SO_DONTROUTE)
		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
				  (char *)&on, sizeof(on));

	if (source) {
		memset(&from, 0, sizeof(struct sockaddr));
		from.sin_family = AF_INET;
		from.sin_addr.s_addr = inet_addr(source);
		if (from.sin_addr.s_addr == -1)
			bb_error_msg_and_die("unknown host %s", source);
		outpacket->ip.ip_src = from.sin_addr;
#ifndef IP_HDRINCL
		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
			bb_perror_msg_and_die("bind");
#endif
	}

	fprintf(stderr, "traceroute to %s (%s)", hostname,
		inet_ntoa(to->sin_addr));
	if (source)
		fprintf(stderr, " from %s", source);
	fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);

	for (ttl = 1; ttl <= max_ttl; ++ttl) {
		u_long lastaddr = 0;
		int got_there = 0;
		int unreachable = 0;

#if defined(DMP_TRACEROUTE_1)
		pTraceRouteInfo->routeHopsNumberOfEntries++;	
#endif
		printf("%2d ", ttl);
		for (probe = 0; probe < nprobes; ++probe) {
			int cc, reset_timer;
			struct timeval t1, t2;
			struct timezone tz;
			struct ip *ip;

			(void) gettimeofday(&t1, &tz);
			send_probe(++seq, ttl);
			reset_timer = 1;
			while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
				(void) gettimeofday(&t2, &tz);
				if ((i = packet_ok(packet, cc, &from, seq))) {
					reset_timer = 1;
					if (from.sin_addr.s_addr != lastaddr) {
						print(packet, cc, &from);
						lastaddr = from.sin_addr.s_addr;
					}
					printf("  %g ms", deltaT(&t1, &t2));
#if defined(DMP_TRACEROUTE_1)
					struct icmp *hopIcp;
					int hopHlen;
					struct ip *hopIp;
					hopIp = (struct ip *) packet;
					hopHlen = hopIp->ip_hl << 2;
					hopIcp = (struct icmp *)(packet + hopHlen);
					repTime = ((int)(t2.tv_sec - t1.tv_sec) * 1000 + (int)(t2.tv_usec - t1.tv_usec) / 1000);
					sprintf(strRepTime, "%d,", repTime);
					pTraceRouteInfo->responseTime+=repTime; 
					pTraceRouteInfo->routeHops[ttl-1].hopErrorCode = hopIcp->icmp_code;
					sprintf(pTraceRouteInfo->routeHops[ttl-1].hopHost, "%s", inet_ntoa(from.sin_addr));
					sprintf(pTraceRouteInfo->routeHops[ttl-1].hopHostAddress, "%s", inet_ntoa(from.sin_addr));	
					strcat(pTraceRouteInfo->routeHops[ttl-1].hopRTTimes, strRepTime);		
#endif
					switch(i - 1) {
					case ICMP_UNREACH_PORT:
						ip = (struct ip *)packet;
						if (ip->ip_ttl <= 1)
							printf(" !");
						++got_there;
						break;
					case ICMP_UNREACH_NET:
						++unreachable;
						printf(" !N");
						break;
					case ICMP_UNREACH_HOST:
						++unreachable;
						printf(" !H");
						break;
					case ICMP_UNREACH_PROTOCOL:
						++got_there;
						printf(" !P");
						break;
					case ICMP_UNREACH_NEEDFRAG:
						++unreachable;
						printf(" !F");
						break;
					case ICMP_UNREACH_SRCFAIL:
						++unreachable;
						printf(" !S");
						break;
					}
					break;
				} else
					reset_timer = 0;
			}
			if (cc == 0)
			{
#if defined(AEI_VDSL_CUSTOMER_NCS)
				failcount++;
#endif
				printf(" *");
			}
#if defined(AEI_VDSL_CUSTOMER_NCS)
            		else
				failcount=0;
#endif
			(void) fflush(stdout);
		}
		putchar('\n');
		if (got_there || (unreachable && unreachable >= nprobes-1))
		{
#if defined(DMP_TRACEROUTE_1)		
			if (got_there)
			{
				AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Complete);
			}
			else if (unreachable && unreachable >= nprobes-1)
			{
				AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded);
			}
#endif
			return 0;
		}
#if defined(AEI_VDSL_CUSTOMER_NCS)
#if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000)
		if (failcount >= nprobes*2&&ttl_set_flag==0)
#else
		if (failcount >= nprobes*2)
#endif
		{
#if defined(DMP_TRACEROUTE_1)
			AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded);
#endif
			return 0;
		}	
#endif
	}
#if defined(DMP_TRACEROUTE_1)
	AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded);
#endif

	return 0;
}
Beispiel #16
0
static int send_probe(int ifindex, __u32 addr)
{
	struct ifreq ifr = { .ifr_ifindex = ifindex };
	struct sockaddr_in dst = {
		.sin_family = AF_INET,
		.sin_port = htons(1025),
		.sin_addr.s_addr = addr,
	};
	socklen_t len;
	unsigned char buf[256];
	struct arphdr *ah = (struct arphdr *)buf;
	unsigned char *p = (unsigned char *)(ah+1);
	struct sockaddr_ll sll = {
		.sll_family = AF_PACKET,
		.sll_ifindex = ifindex,
		.sll_protocol = htons(ETH_P_ARP),
	};

	if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
		return -1;
	if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
		return -1;
	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
		return -1;
	if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
		return -1;

	if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0)
		return -1;
	len = sizeof(dst);
	if (getsockname(udp_sock, (struct sockaddr *)&dst, &len) < 0)
		return -1;

	ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family);
	ah->ar_pro = htons(ETH_P_IP);
	ah->ar_hln = 6;
	ah->ar_pln = 4;
	ah->ar_op  = htons(ARPOP_REQUEST);

	memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln);
	p += ah->ar_hln;

	memcpy(p, &dst.sin_addr, 4);
	p += 4;

	memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
	memcpy(p, &sll.sll_addr, ah->ar_hln);
	p += ah->ar_hln;

	memcpy(p, &addr, 4);
	p += 4;

	if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0)
		return -1;
	stats.probes_sent++;
	return 0;
}

/* Be very tough on sending probes: 1 per second with burst of 3. */

static int queue_active_probe(int ifindex, __u32 addr)
{
	static struct timeval prev;
	static int buckets;
	struct timeval now;

	gettimeofday(&now, NULL);
	if (prev.tv_sec) {
		int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;

		buckets += diff;
	} else {
		buckets = broadcast_burst;
	}
	if (buckets > broadcast_burst)
		buckets = broadcast_burst;
	if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
		buckets -= broadcast_rate;
		prev = now;
		return 0;
	}
	stats.probes_suppressed++;
	return -1;
}

static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
{
	struct {
		struct nlmsghdr	n;
		struct ndmsg		ndm;
		char			buf[256];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
		.n.nlmsg_flags = NLM_F_REQUEST,
		.n.nlmsg_type = RTM_NEWNEIGH,
		.ndm.ndm_family = AF_INET,
		.ndm.ndm_state = NUD_STALE,
		.ndm.ndm_ifindex = ifindex,
		.ndm.ndm_type = RTN_UNICAST,
	};

	addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
	addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
	return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
}

static void prepare_neg_entry(__u8 *ndata, __u32 stamp)
{
	ndata[0] = 0xFF;
	ndata[1] = 0;
	ndata[2] = stamp>>24;
	ndata[3] = stamp>>16;
	ndata[4] = stamp>>8;
	ndata[5] = stamp;
}


static int do_one_request(struct nlmsghdr *n)
{
	struct ndmsg *ndm = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[NDA_MAX+1];
	struct dbkey key;
	DBT dbkey, dbdat;
	int do_acct = 0;

	if (n->nlmsg_type == NLMSG_DONE) {
		dbase->sync(dbase, 0);

		/* Now we have at least mirror of kernel db, so that
		 * may start real resolution.
		 */
		do_sysctl_adjustments();
		return 0;
	}

	if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
		return 0;

	len -= NLMSG_LENGTH(sizeof(*ndm));
	if (len < 0)
		return -1;

	if (ndm->ndm_family != AF_INET ||
	    (ifnum && !handle_if(ndm->ndm_ifindex)) ||
	    ndm->ndm_flags ||
	    ndm->ndm_type != RTN_UNICAST ||
	    !(ndm->ndm_state&~NUD_NOARP))
		return 0;

	parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);

	if (!tb[NDA_DST])
		return 0;

	key.iface = ndm->ndm_ifindex;
	memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
	dbkey.data = &key;
	dbkey.size = sizeof(key);

	if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
		dbdat.data = 0;
		dbdat.size = 0;
	}

	if (n->nlmsg_type == RTM_GETNEIGH) {
		if (!(n->nlmsg_flags&NLM_F_REQUEST))
			return 0;

		if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
			stats.app_bad++;
			return 0;
		}

		if (ndm->ndm_state&NUD_PROBE) {
			/* If we get this, kernel still has some valid
			 * address, but unicast probing failed and host
			 * is either dead or changed its mac address.
			 * Kernel is going to initiate broadcast resolution.
			 * OK, we invalidate our information as well.
			 */
			if (dbdat.data && !IS_NEG(dbdat.data))
				stats.app_neg++;

			dbase->del(dbase, &dbkey, 0);
		} else {
			/* If we get this kernel does not have any information.
			 * If we have something tell this to kernel. */
			stats.app_recv++;
			if (dbdat.data && !IS_NEG(dbdat.data)) {
				stats.app_success++;
				respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
				return 0;
			}

			/* Sheeit! We have nothing to tell. */
			/* If we have recent negative entry, be silent. */
			if (dbdat.data && NEG_VALID(dbdat.data)) {
				if (NEG_CNT(dbdat.data) >= active_probing) {
					stats.app_suppressed++;
					return 0;
				}
				do_acct = 1;
			}
		}

		if (active_probing &&
		    queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
		    do_acct) {
			NEG_CNT(dbdat.data)++;
			dbase->put(dbase, &dbkey, &dbdat, 0);
		}
	} else if (n->nlmsg_type == RTM_NEWNEIGH) {
		if (n->nlmsg_flags&NLM_F_REQUEST)
			return 0;

		if (ndm->ndm_state&NUD_FAILED) {
			/* Kernel was not able to resolve. Host is dead.
			 * Create negative entry if it is not present
			 * or renew it if it is too old. */
			if (!dbdat.data ||
			    !IS_NEG(dbdat.data) ||
			    !NEG_VALID(dbdat.data)) {
				__u8 ndata[6];

				stats.kern_neg++;
				prepare_neg_entry(ndata, time(NULL));
				dbdat.data = ndata;
				dbdat.size = sizeof(ndata);
				dbase->put(dbase, &dbkey, &dbdat, 0);
			}
		} else if (tb[NDA_LLADDR]) {
			if (dbdat.data && !IS_NEG(dbdat.data)) {
				if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
					return 0;
				stats.kern_change++;
			} else {
				stats.kern_new++;
			}
			dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
			dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
			dbase->put(dbase, &dbkey, &dbdat, 0);
		}
	}
	return 0;
}

static void load_initial_table(void)
{
	if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH) < 0) {
		perror("dump request failed");
		exit(1);
	}

}

static void get_kern_msg(void)
{
	int status;
	struct nlmsghdr *h;
	struct sockaddr_nl nladdr = {};
	struct iovec iov;
	char   buf[8192];
	struct msghdr msg = {
		(void *)&nladdr, sizeof(nladdr),
		&iov,	1,
		NULL,	0,
		0
	};

	iov.iov_base = buf;
	iov.iov_len = sizeof(buf);

	status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);

	if (status <= 0)
		return;

	if (msg.msg_namelen != sizeof(nladdr))
		return;

	if (nladdr.nl_pid)
		return;

	for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
		int len = h->nlmsg_len;
		int l = len - sizeof(*h);

		if (l < 0 || len > status)
			return;

		if (do_one_request(h) < 0)
			return;

		status -= NLMSG_ALIGN(len);
		h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
	}
}