OSDN Git Service

tools/btattach: Add command line switch for specifying the baudrate
[android-x86/external-bluetooth-bluez.git] / tools / l2ping.c
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 <poll.h>
39 #include <sys/socket.h>
40
41 #include "lib/bluetooth.h"
42 #include "lib/hci.h"
43 #include "lib/hci_lib.h"
44 #include "lib/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 }