Example #1
0
int translate(char *mesh_iface, int argc, char **argv)
{
	struct ether_addr *dst_mac = NULL;
	struct bat_host *bat_host;
	int ret = EXIT_FAILURE;
	char *dst_string, *mac_string;

	if (argc <= 1) {
		fprintf(stderr, "Error - destination not specified\n");
		translate_usage();
		return EXIT_FAILURE;
	}

	dst_string = argv[1];
	bat_hosts_init(0);
	bat_host = bat_hosts_find_by_name(dst_string);

	if (bat_host)
		dst_mac = &bat_host->mac_addr;

	if (!dst_mac) {
		dst_mac = resolve_mac(dst_string);

		if (!dst_mac) {
			fprintf(stderr, "Error - mac address of the ping destination could not be resolved and is not a bat-host name: %s\n", dst_string);
			goto out;
		}
	}

	dst_mac = translate_mac(mesh_iface, dst_mac);
	if (dst_mac) {
		mac_string = ether_ntoa_long(dst_mac);
		printf("%s\n", mac_string);
		ret = EXIT_SUCCESS;
	} else {
		ret = EXIT_NOSUCCESS;
	}

out:
	bat_hosts_free();
	return ret;
}
Example #2
0
int ping(char *mesh_iface, int argc, char **argv)
{
	struct icmp_packet_rr icmp_packet_out, icmp_packet_in;
	struct timeval tv;
	struct ether_addr *dst_mac = NULL, *rr_mac = NULL;
	struct bat_host *bat_host, *rr_host;
	ssize_t read_len;
	fd_set read_socket;
	int ret = EXIT_FAILURE, ping_fd = 0, res, optchar, found_args = 1;
	int loop_count = -1, loop_interval = 0, timeout = 1, rr = 0, i;
	unsigned int seq_counter = 0, packets_out = 0, packets_in = 0, packets_loss;
	char *dst_string, *mac_string, *rr_string;
	double time_delta;
	float min = 0.0, max = 0.0, avg = 0.0, mdev = 0.0;
	uint8_t last_rr_cur = 0, last_rr[BAT_RR_LEN][ETH_ALEN];
	size_t packet_len;
	char *debugfs_mnt;
	char icmp_socket[MAX_PATH+1];

	while ((optchar = getopt(argc, argv, "hc:i:t:R")) != -1) {
		switch (optchar) {
		case 'c':
			loop_count = strtol(optarg, NULL , 10);
			if (loop_count < 1)
				loop_count = -1;
			found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2);
			break;
		case 'h':
			ping_usage();
			return EXIT_SUCCESS;
		case 'i':
			loop_interval = strtol(optarg, NULL , 10);
			if (loop_interval < 1)
				loop_interval = 1;
			found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2);
			break;
		case 't':
			timeout = strtol(optarg, NULL , 10);
			if (timeout < 1)
				timeout = 1;
			found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2);
			break;
		case 'R':
			rr = 1;
			found_args++;
			break;
		default:
			ping_usage();
			return EXIT_FAILURE;
		}
	}

	if (argc <= found_args) {
		printf("Error - target mac address or bat-host name not specified\n");
		ping_usage();
		return EXIT_FAILURE;
	}

	dst_string = argv[found_args];
	bat_hosts_init(0);
	bat_host = bat_hosts_find_by_name(dst_string);

	if (bat_host)
		dst_mac = &bat_host->mac_addr;

	if (!dst_mac) {
		dst_mac = ether_aton(dst_string);

		if (!dst_mac) {
			printf("Error - the ping destination is not a mac address or bat-host name: %s\n", dst_string);
			goto out;
		}
	}

	mac_string = ether_ntoa_long(dst_mac);
	signal(SIGINT, sig_handler);
	signal(SIGTERM, sig_handler);

	debugfs_mnt = debugfs_mount(NULL);
	if (!debugfs_mnt) {
		printf("Error - can't mount or find debugfs\n");
		goto out;
	}

	debugfs_make_path(SOCKET_PATH_FMT, mesh_iface, icmp_socket, sizeof(icmp_socket));

	ping_fd = open(icmp_socket, O_RDWR);

	if (ping_fd < 0) {
		printf("Error - can't open a connection to the batman adv kernel module via the socket '%s': %s\n",
				icmp_socket, strerror(errno));
		printf("Check whether the module is loaded and active.\n");
		goto out;
	}

	packet_len = sizeof(struct icmp_packet);

	memcpy(&icmp_packet_out.dst, dst_mac, ETH_ALEN);
	icmp_packet_out.packet_type = BAT_ICMP;
	icmp_packet_out.version = COMPAT_VERSION;
	icmp_packet_out.msg_type = ECHO_REQUEST;
	icmp_packet_out.ttl = 50;
	icmp_packet_out.seqno = 0;

	if (rr) {
		packet_len = sizeof(struct icmp_packet_rr);
		icmp_packet_out.rr_cur = 1;
		memset(&icmp_packet_out.rr, 0, BAT_RR_LEN * ETH_ALEN);
		memset(last_rr, 0, BAT_RR_LEN * ETH_ALEN);
	}

	printf("PING %s (%s) %zu(%zu) bytes of data\n", dst_string, mac_string,
		packet_len, packet_len + 28);

	while (!is_aborted) {
		tv.tv_sec = timeout;
		tv.tv_usec = 0;

		if (loop_count == 0)
			break;

		if (loop_count > 0)
			loop_count--;

		icmp_packet_out.seqno = htons(++seq_counter);

		if (write(ping_fd, (char *)&icmp_packet_out, packet_len) < 0) {
			printf("Error - can't write to batman adv kernel file '%s': %s\n", icmp_socket, strerror(errno));
			goto sleep;
		}

		start_timer();

		FD_ZERO(&read_socket);
		FD_SET(ping_fd, &read_socket);

		res = select(ping_fd + 1, &read_socket, NULL, NULL, &tv);

		if (is_aborted)
			break;

		packets_out++;

		if (res == 0) {
			printf("Reply from host %s timed out\n", dst_string);
			goto sleep;
		}

		if (res < 0)
			goto sleep;

		read_len = read(ping_fd, (char *)&icmp_packet_in, packet_len);

		if (read_len < 0) {
			printf("Error - can't read from batman adv kernel file '%s': %s\n", icmp_socket, strerror(errno));
			goto sleep;
		}

		if ((size_t)read_len < packet_len) {
			printf("Warning - dropping received packet as it is smaller than expected (%zu): %zd\n",
				packet_len, read_len);
			goto sleep;
		}

		switch (icmp_packet_in.msg_type) {
		case ECHO_REPLY:
			time_delta = end_timer();
			printf("%zd bytes from %s icmp_seq=%hu ttl=%d time=%.2f ms",
					read_len, dst_string, ntohs(icmp_packet_in.seqno),
					icmp_packet_in.ttl, time_delta);

			if (read_len == sizeof(struct icmp_packet_rr)) {
				if (last_rr_cur == icmp_packet_in.rr_cur
					&& !memcmp(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN)) {

					printf("\t(same route)");

				} else {
					printf("\nRR: ");

					for (i = 0; i < BAT_RR_LEN
						&& i < icmp_packet_in.rr_cur; i++) {

						rr_mac = (struct ether_addr *)&icmp_packet_in.rr[i];
						rr_host = bat_hosts_find_by_mac((char *)rr_mac);
						if (rr_host)
							rr_string = rr_host->name;
						else
							rr_string = ether_ntoa_long(rr_mac);
						printf("\t%s\n", rr_string);

						if (memcmp(rr_mac, dst_mac, ETH_ALEN) == 0)
							printf("\t%s\n", rr_string);
					}

					last_rr_cur = icmp_packet_in.rr_cur;
					memcpy(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN);
				}
			}

			printf("\n");

			if ((time_delta < min) || (min == 0.0))
				min = time_delta;
			if (time_delta > max)
				max = time_delta;
			avg += time_delta;
			mdev += time_delta * time_delta;
			packets_in++;
			break;
		case DESTINATION_UNREACHABLE:
			printf("From %s: Destination Host Unreachable (icmp_seq %hu)\n", dst_string, ntohs(icmp_packet_in.seqno));
			break;
		case TTL_EXCEEDED:
			printf("From %s: Time to live exceeded (icmp_seq %hu)\n", dst_string, ntohs(icmp_packet_in.seqno));
			break;
		case PARAMETER_PROBLEM:
			printf("Error - the batman adv kernel module version (%d) differs from ours (%d)\n",
					icmp_packet_in.ttl, COMPAT_VERSION);
			printf("Please make sure to compatible versions!\n");
			goto out;
		default:
			printf("Unknown message type %d len %zd received\n", icmp_packet_in.msg_type, read_len);
			break;
		}

sleep:
		if (loop_interval > 0)
			sleep(loop_interval);
		else if ((tv.tv_sec != 0) || (tv.tv_usec != 0))
			select(0, NULL, NULL, NULL, &tv);
	}

	if (packets_out == 0)
		packets_loss = 0;
	else
		packets_loss = ((packets_out - packets_in) * 100) / packets_out;

	if (packets_in) {
		avg /= packets_in;
		mdev /= packets_in;
		mdev = mdev - avg * avg;
		if (mdev > 0.0)
			mdev = sqrt(mdev);
		else
			mdev = 0.0;
	} else {
		avg = 0.0;
		mdev = 0.0;
	}

	printf("--- %s ping statistics ---\n", dst_string);
	printf("%u packets transmitted, %u received, %u%% packet loss\n",
		packets_out, packets_in, packets_loss);
	printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f ms\n",
		min, avg, max, mdev);

	ret = EXIT_SUCCESS;

out:
	bat_hosts_free();
	if (ping_fd)
		close(ping_fd);
	return ret;
}
Example #3
0
static void parse_hosts_file(struct hashtable_t **hash, const char path[], int read_opt)
{
	FILE *fd;
	char *line_ptr = NULL;
	char name[HOST_NAME_MAX_LEN], mac_str[18];
	struct ether_addr *mac_addr;
	struct bat_host *bat_host;
	struct hashtable_t *swaphash;
	size_t len = 0;

	name[0] = mac_str[0] = '\0';

	fd = fopen(path, "r");
	if (!fd)
		return;

	while (getline(&line_ptr, &len, fd) != -1) {
		/* ignore empty lines and comments */
		if ((line_ptr[0] == '\n') || (line_ptr[0] == '#'))
			continue;

		if (sscanf(line_ptr, "%17[^ \t]%49s\n", mac_str, name) != 2) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - unrecognized bat-host definition: %s", line_ptr);
			continue;
		}

		mac_addr = ether_aton(mac_str);
		if (!mac_addr) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - invalid mac address in '%s' detected: %s\n", path, mac_str);
			continue;
		}

		bat_host = bat_hosts_find_by_mac((char *)mac_addr);

		/* mac entry already exists - we found a new name for it */
		if (bat_host) {
			/* if the mac addresses and the names are the same we can safely ignore the entry */
			if (strcmp(bat_host->name, name) == 0)
				continue;

			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - mac already known (changing name from '%s' to '%s'): %s\n",
					bat_host->name, name, mac_str);
			strncpy(bat_host->name, name, HOST_NAME_MAX_LEN - 1);
			continue;
		}

		bat_host = bat_hosts_find_by_name(name);

		/* name entry already exists - we found a new mac address for it */
		if (bat_host) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - name already known (changing mac from '%s' to '%s'): %s\n",
					ether_ntoa(&bat_host->mac_addr), mac_str, name);
			hash_remove(*hash, bat_host);
			free(bat_host);
		}

		bat_host = malloc(sizeof(struct bat_host));

		if (!bat_host) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Error - could not allocate memory: %s\n", strerror(errno));
			goto out;
		}

		memcpy(&bat_host->mac_addr, mac_addr, sizeof(struct ether_addr));
		strncpy(bat_host->name, name, HOST_NAME_MAX_LEN - 1);

		hash_add(*hash, bat_host);

		if ((*hash)->elements * 4 > (*hash)->size) {
			swaphash = hash_resize((*hash), (*hash)->size * 2);

			if (swaphash)
				*hash = swaphash;
			else if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - couldn't resize bat hosts hash table\n");
		}
	}

out:
	if (fd)
		fclose(fd);
	if (line_ptr)
		free(line_ptr);
	return;
}