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