• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@qualcomm.com>
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@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 
tv2fl(struct timeval tv)60 static float tv2fl(struct timeval tv)
61 {
62 	return (float)(tv.tv_sec*1000.0) + (float)(tv.tv_usec/1000.0);
63 }
64 
stat(int sig)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 
ping(char * svr)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 
usage(void)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 
main(int argc,char * argv[])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