OSDN Git Service

4229de7547aa8b6aaf4791635e96ad4fc0791c21
[android-x86/external-bluetooth-bluez.git] / utils / 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-2008  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
55 /* Stats */
56 static int sent_pkt = 0;
57 static int recv_pkt = 0;
58
59 static float tv2fl(struct timeval tv)
60 {
61         return (float)(tv.tv_sec*1000.0) + (float)(tv.tv_usec/1000.0);
62 }
63
64 static void stat(int sig)
65 {
66         int loss = sent_pkt ? (float)((sent_pkt-recv_pkt)/(sent_pkt/100.0)) : 0;
67         printf("%d sent, %d received, %d%% loss\n", sent_pkt, recv_pkt, loss);
68         exit(0);
69 }
70
71 static void ping(char *svr)
72 {
73         struct sigaction sa;
74         struct sockaddr_l2 addr;
75         socklen_t optlen;
76         unsigned char *buf;
77         char str[18];
78         int i, sk, lost;
79         uint8_t id;
80
81         memset(&sa, 0, sizeof(sa));
82         sa.sa_handler = stat;
83         sigaction(SIGINT, &sa, NULL);
84
85         buf = malloc(L2CAP_CMD_HDR_SIZE + size);
86         if (!buf) {
87                 perror("Can't allocate buffer");
88                 exit(1);
89         }
90
91         /* Create socket */
92         sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
93         if (sk < 0) {
94                 perror("Can't create socket");
95                 free(buf);
96                 exit(1);
97         }
98
99         /* Bind to local address */
100         memset(&addr, 0, sizeof(addr));
101         addr.l2_family = AF_BLUETOOTH;
102         bacpy(&addr.l2_bdaddr, &bdaddr);
103
104         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
105                 perror("Can't bind socket");
106                 close(sk);
107                 free(buf);
108                 exit(1);
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                 close(sk);
119                 free(buf);
120                 exit(1);
121         }
122
123         /* Get local address */
124         memset(&addr, 0, sizeof(addr));
125         optlen = sizeof(addr);
126
127         if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
128                 perror("Can't get local address");
129                 close(sk);
130                 free(buf);
131                 exit(1);
132         }
133
134         ba2str(&addr.l2_bdaddr, str);
135         printf("Ping: %s from %s (data size %d) ...\n", svr, str, size);
136
137         /* Initialize buffer */
138         for (i = 0; i < size; i++)
139                 buf[L2CAP_CMD_HDR_SIZE + i] = (i % 40) + 'A';
140
141         id = ident;
142
143         while (count == -1 || count-- > 0) {
144                 struct timeval tv_send, tv_recv, tv_diff;
145                 l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
146
147                 /* Build command header */
148                 cmd->ident = id;
149                 cmd->len   = htobs(size);
150
151                 if (reverse)
152                         cmd->code = L2CAP_ECHO_RSP;
153                 else
154                         cmd->code = L2CAP_ECHO_REQ;
155
156                 gettimeofday(&tv_send, NULL);
157
158                 /* Send Echo Command */
159                 if (send(sk, buf, L2CAP_CMD_HDR_SIZE + size, 0) <= 0) {
160                         perror("Send failed");
161                         exit(1);
162                 }
163
164                 /* Wait for Echo Response */
165                 lost = 0;
166                 while (1) {
167                         struct pollfd pf[1];
168                         int err;
169
170                         pf[0].fd = sk;
171                         pf[0].events = POLLIN;
172
173                         if ((err = poll(pf, 1, timeout * 1000)) < 0) {
174                                 perror("Poll failed");
175                                 exit(1);
176                         }
177
178                         if (!err) {
179                                 lost = 1;
180                                 break;
181                         }
182
183                         if ((err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + size, 0)) < 0) {
184                                 perror("Recv failed");
185                                 exit(1);
186                         }
187
188                         if (!err){
189                                 printf("Disconnected\n");
190                                 exit(1);
191                         }
192
193                         cmd->len = btohs(cmd->len);
194
195                         /* Check for our id */
196                         if (cmd->ident != id)
197                                 continue;
198
199                         /* Check type */
200                         if (!reverse && cmd->code == L2CAP_ECHO_RSP)
201                                 break;
202
203                         if (cmd->code == L2CAP_COMMAND_REJ) {
204                                 printf("Peer doesn't support Echo packets\n");
205                                 exit(1);
206                         }
207
208                 }
209                 sent_pkt++;
210
211                 if (!lost) {
212                         recv_pkt++;
213
214                         gettimeofday(&tv_recv, NULL);
215                         timersub(&tv_recv, &tv_send, &tv_diff);
216
217                         printf("%d bytes from %s id %d time %.2fms\n", cmd->len, svr, id - ident, tv2fl(tv_diff));
218
219                         if (delay)
220                                 sleep(delay);
221                 } else {
222                         printf("no response from %s: id %d\n", svr, id - ident);
223                 }
224
225                 if (++id > 254)
226                         id = ident;
227         }
228         stat(0);
229 }
230
231 static void usage(void)
232 {
233         printf("l2ping - L2CAP ping\n");
234         printf("Usage:\n");
235         printf("\tl2ping [-i device] [-s size] [-c count] [-t timeout] [-d delay] [-f] [-r] <bdaddr>\n");
236 }
237
238 int main(int argc, char *argv[])
239 {
240         int opt;
241
242         /* Default options */
243         bacpy(&bdaddr, BDADDR_ANY);
244
245         while ((opt=getopt(argc,argv,"i:d:s:c:t:fr")) != EOF) {
246                 switch(opt) {
247                 case 'i':
248                         if (!strncasecmp(optarg, "hci", 3))
249                                 hci_devba(atoi(optarg + 3), &bdaddr);
250                         else
251                                 str2ba(optarg, &bdaddr);
252                         break;
253
254                 case 'd':
255                         delay = atoi(optarg);
256                         break;
257
258                 case 'f':
259                         /* Kinda flood ping */
260                         delay = 0;
261                         break;
262
263                 case 'r':
264                         /* Use responses instead of requests */
265                         reverse = 1;
266                         break;
267
268                 case 'c':
269                         count = atoi(optarg);
270                         break;
271
272                 case 't':
273                         timeout = atoi(optarg);
274                         break;
275
276                 case 's':
277                         size = atoi(optarg);
278                         break;
279
280                 default:
281                         usage();
282                         exit(1);
283                 }
284         }
285
286         if (!(argc - optind)) {
287                 usage();
288                 exit(1);
289         }
290
291         ping(argv[optind]);
292
293         return 0;
294 }