Home | History | Annotate | Download | only in tools
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2000-2001  Qualcomm Incorporated
      6  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk (at) qualcomm.com>
      7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel (at) holtmann.org>
      8  *
      9  *
     10  *  This program is free software; you can redistribute it and/or modify
     11  *  it under the terms of the GNU General Public License as published by
     12  *  the Free Software Foundation; either version 2 of the License, or
     13  *  (at your option) any later version.
     14  *
     15  *  This program is distributed in the hope that it will be useful,
     16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  *  GNU General Public License for more details.
     19  *
     20  *  You should have received a copy of the GNU General Public License
     21  *  along with this program; if not, write to the Free Software
     22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     23  *
     24  */
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include <config.h>
     28 #endif
     29 
     30 #include <stdio.h>
     31 #include <errno.h>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <getopt.h>
     36 #include <signal.h>
     37 #include <sys/time.h>
     38 #include <sys/poll.h>
     39 #include <sys/socket.h>
     40 
     41 #include <bluetooth/bluetooth.h>
     42 #include <bluetooth/hci.h>
     43 #include <bluetooth/hci_lib.h>
     44 #include <bluetooth/l2cap.h>
     45 
     46 /* Defaults */
     47 static bdaddr_t bdaddr;
     48 static int size    = 44;
     49 static int ident   = 200;
     50 static int delay   = 1;
     51 static int count   = -1;
     52 static int timeout = 10;
     53 static int reverse = 0;
     54 static int verify = 0;
     55 
     56 /* Stats */
     57 static int sent_pkt = 0;
     58 static int recv_pkt = 0;
     59 
     60 static float tv2fl(struct timeval tv)
     61 {
     62 	return (float)(tv.tv_sec*1000.0) + (float)(tv.tv_usec/1000.0);
     63 }
     64 
     65 static void stat(int sig)
     66 {
     67 	int loss = sent_pkt ? (float)((sent_pkt-recv_pkt)/(sent_pkt/100.0)) : 0;
     68 	printf("%d sent, %d received, %d%% loss\n", sent_pkt, recv_pkt, loss);
     69 	exit(0);
     70 }
     71 
     72 static void ping(char *svr)
     73 {
     74 	struct sigaction sa;
     75 	struct sockaddr_l2 addr;
     76 	socklen_t optlen;
     77 	unsigned char *send_buf;
     78 	unsigned char *recv_buf;
     79 	char str[18];
     80 	int i, sk, lost;
     81 	uint8_t id;
     82 
     83 	memset(&sa, 0, sizeof(sa));
     84 	sa.sa_handler = stat;
     85 	sigaction(SIGINT, &sa, NULL);
     86 
     87 	send_buf = malloc(L2CAP_CMD_HDR_SIZE + size);
     88 	recv_buf = malloc(L2CAP_CMD_HDR_SIZE + size);
     89 	if (!send_buf || !recv_buf) {
     90 		perror("Can't allocate buffer");
     91 		exit(1);
     92 	}
     93 
     94 	/* Create socket */
     95 	sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
     96 	if (sk < 0) {
     97 		perror("Can't create socket");
     98 		goto error;
     99 	}
    100 
    101 	/* Bind to local address */
    102 	memset(&addr, 0, sizeof(addr));
    103 	addr.l2_family = AF_BLUETOOTH;
    104 	bacpy(&addr.l2_bdaddr, &bdaddr);
    105 
    106 	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    107 		perror("Can't bind socket");
    108 		goto error;
    109 	}
    110 
    111 	/* Connect to remote device */
    112 	memset(&addr, 0, sizeof(addr));
    113 	addr.l2_family = AF_BLUETOOTH;
    114 	str2ba(svr, &addr.l2_bdaddr);
    115 
    116 	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    117 		perror("Can't connect");
    118 		goto error;
    119 	}
    120 
    121 	/* Get local address */
    122 	memset(&addr, 0, sizeof(addr));
    123 	optlen = sizeof(addr);
    124 
    125 	if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
    126 		perror("Can't get local address");
    127 		goto error;
    128 	}
    129 
    130 	ba2str(&addr.l2_bdaddr, str);
    131 	printf("Ping: %s from %s (data size %d) ...\n", svr, str, size);
    132 
    133 	/* Initialize send buffer */
    134 	for (i = 0; i < size; i++)
    135 		send_buf[L2CAP_CMD_HDR_SIZE + i] = (i % 40) + 'A';
    136 
    137 	id = ident;
    138 
    139 	while (count == -1 || count-- > 0) {
    140 		struct timeval tv_send, tv_recv, tv_diff;
    141 		l2cap_cmd_hdr *send_cmd = (l2cap_cmd_hdr *) send_buf;
    142 		l2cap_cmd_hdr *recv_cmd = (l2cap_cmd_hdr *) recv_buf;
    143 
    144 		/* Build command header */
    145 		send_cmd->ident = id;
    146 		send_cmd->len   = htobs(size);
    147 
    148 		if (reverse)
    149 			send_cmd->code = L2CAP_ECHO_RSP;
    150 		else
    151 			send_cmd->code = L2CAP_ECHO_REQ;
    152 
    153 		gettimeofday(&tv_send, NULL);
    154 
    155 		/* Send Echo Command */
    156 		if (send(sk, send_buf, L2CAP_CMD_HDR_SIZE + size, 0) <= 0) {
    157 			perror("Send failed");
    158 			goto error;
    159 		}
    160 
    161 		/* Wait for Echo Response */
    162 		lost = 0;
    163 		while (1) {
    164 			struct pollfd pf[1];
    165 			int err;
    166 
    167 			pf[0].fd = sk;
    168 			pf[0].events = POLLIN;
    169 
    170 			if ((err = poll(pf, 1, timeout * 1000)) < 0) {
    171 				perror("Poll failed");
    172 				goto error;
    173 			}
    174 
    175 			if (!err) {
    176 				lost = 1;
    177 				break;
    178 			}
    179 
    180 			if ((err = recv(sk, recv_buf, L2CAP_CMD_HDR_SIZE + size, 0)) < 0) {
    181 				perror("Recv failed");
    182 				goto error;
    183 			}
    184 
    185 			if (!err){
    186 				printf("Disconnected\n");
    187 				goto error;
    188 			}
    189 
    190 			recv_cmd->len = btohs(recv_cmd->len);
    191 
    192 			/* Check for our id */
    193 			if (recv_cmd->ident != id)
    194 				continue;
    195 
    196 			/* Check type */
    197 			if (!reverse && recv_cmd->code == L2CAP_ECHO_RSP)
    198 				break;
    199 
    200 			if (recv_cmd->code == L2CAP_COMMAND_REJ) {
    201 				printf("Peer doesn't support Echo packets\n");
    202 				goto error;
    203 			}
    204 
    205 		}
    206 		sent_pkt++;
    207 
    208 		if (!lost) {
    209 			recv_pkt++;
    210 
    211 			gettimeofday(&tv_recv, NULL);
    212 			timersub(&tv_recv, &tv_send, &tv_diff);
    213 
    214 			if (verify) {
    215 				/* Check payload length */
    216 				if (recv_cmd->len != size) {
    217 					fprintf(stderr, "Received %d bytes, expected %d\n",
    218 						   recv_cmd->len, size);
    219 					goto error;
    220 				}
    221 
    222 				/* Check payload */
    223 				if (memcmp(&send_buf[L2CAP_CMD_HDR_SIZE],
    224 						   &recv_buf[L2CAP_CMD_HDR_SIZE], size)) {
    225 					fprintf(stderr, "Response payload different.\n");
    226 					goto error;
    227 				}
    228 			}
    229 
    230 			printf("%d bytes from %s id %d time %.2fms\n", recv_cmd->len, svr,
    231 				   id - ident, tv2fl(tv_diff));
    232 
    233 			if (delay)
    234 				sleep(delay);
    235 		} else {
    236 			printf("no response from %s: id %d\n", svr, id - ident);
    237 		}
    238 
    239 		if (++id > 254)
    240 			id = ident;
    241 	}
    242 	stat(0);
    243 	free(send_buf);
    244 	free(recv_buf);
    245 	return;
    246 
    247 error:
    248 	close(sk);
    249 	free(send_buf);
    250 	free(recv_buf);
    251 	exit(1);
    252 }
    253 
    254 static void usage(void)
    255 {
    256 	printf("l2ping - L2CAP ping\n");
    257 	printf("Usage:\n");
    258 	printf("\tl2ping [-i device] [-s size] [-c count] [-t timeout] [-d delay] [-f] [-r] [-v] <bdaddr>\n");
    259 	printf("\t-f  Flood ping (delay = 0)\n");
    260 	printf("\t-r  Reverse ping\n");
    261 	printf("\t-v  Verify request and response payload\n");
    262 }
    263 
    264 int main(int argc, char *argv[])
    265 {
    266 	int opt;
    267 
    268 	/* Default options */
    269 	bacpy(&bdaddr, BDADDR_ANY);
    270 
    271 	while ((opt=getopt(argc,argv,"i:d:s:c:t:frv")) != EOF) {
    272 		switch(opt) {
    273 		case 'i':
    274 			if (!strncasecmp(optarg, "hci", 3))
    275 				hci_devba(atoi(optarg + 3), &bdaddr);
    276 			else
    277 				str2ba(optarg, &bdaddr);
    278 			break;
    279 
    280 		case 'd':
    281 			delay = atoi(optarg);
    282 			break;
    283 
    284 		case 'f':
    285 			/* Kinda flood ping */
    286 			delay = 0;
    287 			break;
    288 
    289 		case 'r':
    290 			/* Use responses instead of requests */
    291 			reverse = 1;
    292 			break;
    293 
    294 		case 'v':
    295 			verify = 1;
    296 			break;
    297 
    298 		case 'c':
    299 			count = atoi(optarg);
    300 			break;
    301 
    302 		case 't':
    303 			timeout = atoi(optarg);
    304 			break;
    305 
    306 		case 's':
    307 			size = atoi(optarg);
    308 			break;
    309 
    310 		default:
    311 			usage();
    312 			exit(1);
    313 		}
    314 	}
    315 
    316 	if (!(argc - optind)) {
    317 		usage();
    318 		exit(1);
    319 	}
    320 
    321 	ping(argv[optind]);
    322 
    323 	return 0;
    324 }
    325