diff options
author | Max Krasnyansky <maxk@qualcomm.com> | 2002-03-08 21:12:35 +0000 |
---|---|---|
committer | Max Krasnyansky <maxk@qualcomm.com> | 2002-03-08 21:12:35 +0000 |
commit | c98b2f82a4e532ca61592b08e3ad60749eb9f8d7 (patch) | |
tree | 19a3df72d2cd6a8d64b7d98473261c7e07e306a0 /tools/l2ping.c |
Initial revision
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; +} |