diff options
Diffstat (limited to 'tools/l2ping.c')
| -rw-r--r-- | tools/l2ping.c | 251 | 
1 files changed, 251 insertions, 0 deletions
| diff --git a/tools/l2ping.c b/tools/l2ping.c new file mode 100644 index 00000000..9bb8a4d6 --- /dev/null +++ b/tools/l2ping.c @@ -0,0 +1,251 @@ +/*  +	BlueZ - Bluetooth protocol stack for Linux +	Copyright (C) 2000-2001 Qualcomm Incorporated + +	Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License version 2 as +	published by the Free Software Foundation; + +	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +	IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, +	OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +	RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +	USE OR PERFORMANCE OF THIS SOFTWARE. + +	ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, +	TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <unistd.h> +#include <syslog.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <netdb.h> + +#include <asm/types.h> +#include <asm/byteorder.h> + +#include "bluetooth.h" +#include "l2cap.h" + +/* Defaults */ +bdaddr_t bdaddr; +int size  = 20; +int ident = 200; +int delay = 1; +int count = -1; + +/* Stats */ +int sent_pkt = 0, recv_pkt = 0; + +static float tv2fl(struct timeval tv) +{ +	return (float)(tv.tv_sec*1000.0) + (float)(tv.tv_usec/1000.0); +} + +static void stat(int sig) +{ +	int loss = sent_pkt ? (float)((sent_pkt-recv_pkt)/(sent_pkt/100.0)) : 0; +	printf("%d sent, %d received, %d%% loss\n", sent_pkt, recv_pkt, loss); +	exit(0); +} + +static void ping(char *svr) +{ +	struct sockaddr_l2 addr; +	struct sigaction sa; +	char buf[2048]; +	int s, i, opt, lost; +	uint8_t id; + +	memset(&sa, 0, sizeof(sa)); +	sa.sa_handler = stat; +	sigaction(SIGINT, &sa, NULL); + +	if ((s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) { +		perror("Can't create socket."); +		exit(1); +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.l2_family = AF_BLUETOOTH; +	addr.l2_bdaddr = bdaddr; +        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("Can't bind socket."); +		exit(1); +        } + +	baswap(&addr.l2_bdaddr, strtoba(svr)); +	if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +		perror("Can't connect."); +		exit(1); +	} + +	/* Get local address */ +	opt = sizeof(addr); +	if( getsockname(s, (struct sockaddr *)&addr, &opt) < 0 ) { +		perror("Can't get local address."); +		exit(1); +	} +	baswap(&bdaddr, &addr.l2_bdaddr); + +	printf("Ping: %s from %s (data size %d) ...\n", svr, batostr(&bdaddr), size); + +	/* Initialize buffer */ +	for(i = L2CAP_CMD_HDR_SIZE; i < sizeof(buf); i++) +		buf[i]=(i%40)+'A'; + +	id = ident; + +	while( count == -1 || count-- > 0 ){ +		struct timeval tv_send, tv_recv, tv_diff; +		l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; + +		/* Build command header */ +		cmd->code  = L2CAP_ECHO_REQ; +		cmd->ident = id; +		cmd->len   = __cpu_to_le16(size); + +		gettimeofday(&tv_send, NULL); + +		/* Send Echo Request */ +		if( send(s, buf, size + L2CAP_CMD_HDR_SIZE, 0) <= 0 ){ +			perror("Send failed"); +			exit(1); +		} + +		/* Wait for Echo Response */ +		lost = 0; +		while( 1 ) { +			struct pollfd pf[1]; +			register int err; + +			pf[0].fd = s; pf[0].events = POLLIN; +			if( (err = poll(pf, 1, 10*1000)) < 0 ) { +				perror("Poll failed"); +				exit(1); +			} + +			if( !err ){ +				lost = 1; +				break; +			} + +			if( (err = recv(s, buf, sizeof(buf), 0)) < 0 ) { +				perror("Recv failed"); +				exit(1); +			} + +			if( !err ){ +				printf("Disconnected\n"); +				exit(1); +			} + +			cmd->len = __le16_to_cpu(cmd->len); + +			/* Check for our id */ +			if( cmd->ident != id ) +				continue; + +			/* Check type */ +			if( cmd->code == L2CAP_ECHO_RSP ) +				break; +			if( cmd->code == L2CAP_COMMAND_REJ ){ +				printf("Peer doesn't support Echo packets\n"); +				exit(1); +			} + +		} +		sent_pkt++; + +		if( !lost ){ +			recv_pkt++; + +			gettimeofday(&tv_recv, NULL); +			timersub(&tv_recv, &tv_send, &tv_diff); + +			printf("%d bytes from %s id %d time %.2fms\n", cmd->len, svr, id, tv2fl(tv_diff)); + +			if( delay ) sleep(delay); +		} else { +			printf("no response from %s: id %d\n", svr, id); +		} + +		if( ++id > 254 ) id = ident; +	} +	stat(0); +} + +static void usage(void) +{ +	printf("l2ping - L2CAP ping\n"); +	printf("Usage:\n"); +	printf("\tl2ping [-S source addr] [-s size] [-c count] [-f] <bd_addr>\n"); +} + +extern int optind,opterr,optopt; +extern char *optarg; + +int main(int argc, char *argv[]) +{ +	register int opt; + +	/* Default options */ +	bacpy(&bdaddr, BDADDR_ANY); + +	while ((opt=getopt(argc,argv,"s:c:fS:")) != EOF) { +		switch(opt) { +		case 'f': +			/* Kinda flood ping */ +			delay = 0; +			break; + +		case 'c': +			count = atoi(optarg); +			break; + +		case 's': +			size = atoi(optarg); +			break; + +		case 'S': +			baswap(&bdaddr, strtoba(optarg)); +			break; + +		default: +			usage(); +			exit(1); +		} +	} + +	if (!(argc - optind)) { +		usage(); +		exit(1); +	} + +	ping(argv[optind]); + +	return 0; +} | 
