tizen 2.3.1 release
[framework/connectivity/bluez.git] / tools / sco-tester.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2013  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdbool.h>
32
33 #include <glib.h>
34
35 #include "lib/bluetooth.h"
36 #include "lib/sco.h"
37 #include "lib/mgmt.h"
38
39 #include "monitor/bt.h"
40 #include "emulator/bthost.h"
41 #include "emulator/hciemu.h"
42
43 #include "src/shared/tester.h"
44 #include "src/shared/mgmt.h"
45
46 struct test_data {
47         const void *test_data;
48         struct mgmt *mgmt;
49         uint16_t mgmt_index;
50         struct hciemu *hciemu;
51         enum hciemu_type hciemu_type;
52         unsigned int io_id;
53         bool disable_esco;
54 };
55
56 struct sco_client_data {
57         int expect_err;
58 };
59
60 static void mgmt_debug(const char *str, void *user_data)
61 {
62         const char *prefix = user_data;
63
64         tester_print("%s%s", prefix, str);
65 }
66
67 static void read_info_callback(uint8_t status, uint16_t length,
68                                         const void *param, void *user_data)
69 {
70         struct test_data *data = tester_get_data();
71         const struct mgmt_rp_read_info *rp = param;
72         char addr[18];
73         uint16_t manufacturer;
74         uint32_t supported_settings, current_settings;
75
76         tester_print("Read Info callback");
77         tester_print("  Status: 0x%02x", status);
78
79         if (status || !param) {
80                 tester_pre_setup_failed();
81                 return;
82         }
83
84         ba2str(&rp->bdaddr, addr);
85         manufacturer = btohs(rp->manufacturer);
86         supported_settings = btohl(rp->supported_settings);
87         current_settings = btohl(rp->current_settings);
88
89         tester_print("  Address: %s", addr);
90         tester_print("  Version: 0x%02x", rp->version);
91         tester_print("  Manufacturer: 0x%04x", manufacturer);
92         tester_print("  Supported settings: 0x%08x", supported_settings);
93         tester_print("  Current settings: 0x%08x", current_settings);
94         tester_print("  Class: 0x%02x%02x%02x",
95                         rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
96         tester_print("  Name: %s", rp->name);
97         tester_print("  Short name: %s", rp->short_name);
98
99         if (strcmp(hciemu_get_address(data->hciemu), addr)) {
100                 tester_pre_setup_failed();
101                 return;
102         }
103
104         tester_pre_setup_complete();
105 }
106
107 static void index_added_callback(uint16_t index, uint16_t length,
108                                         const void *param, void *user_data)
109 {
110         struct test_data *data = tester_get_data();
111
112         tester_print("Index Added callback");
113         tester_print("  Index: 0x%04x", index);
114
115         data->mgmt_index = index;
116
117         mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
118                                         read_info_callback, NULL, NULL);
119 }
120
121 static void index_removed_callback(uint16_t index, uint16_t length,
122                                         const void *param, void *user_data)
123 {
124         struct test_data *data = tester_get_data();
125
126         tester_print("Index Removed callback");
127         tester_print("  Index: 0x%04x", index);
128
129         if (index != data->mgmt_index)
130                 return;
131
132         mgmt_unregister_index(data->mgmt, data->mgmt_index);
133
134         mgmt_unref(data->mgmt);
135         data->mgmt = NULL;
136
137         tester_post_teardown_complete();
138 }
139
140 static void read_index_list_callback(uint8_t status, uint16_t length,
141                                         const void *param, void *user_data)
142 {
143         struct test_data *data = tester_get_data();
144
145         tester_print("Read Index List callback");
146         tester_print("  Status: 0x%02x", status);
147
148         if (status || !param) {
149                 tester_pre_setup_failed();
150                 return;
151         }
152
153         mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
154                                         index_added_callback, NULL, NULL);
155
156         mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
157                                         index_removed_callback, NULL, NULL);
158
159         data->hciemu = hciemu_new(HCIEMU_TYPE_BREDRLE);
160         if (!data->hciemu) {
161                 tester_warn("Failed to setup HCI emulation");
162                 tester_pre_setup_failed();
163         }
164
165         tester_print("New hciemu instance created");
166
167         if (data->disable_esco) {
168                 uint8_t *features;
169
170                 tester_print("Disabling eSCO packet type support");
171
172                 features = hciemu_get_features(data->hciemu);
173                 if (features)
174                         features[3] &= ~0x80;
175         }
176 }
177
178 static void test_pre_setup(const void *test_data)
179 {
180         struct test_data *data = tester_get_data();
181
182         data->mgmt = mgmt_new_default();
183         if (!data->mgmt) {
184                 tester_warn("Failed to setup management interface");
185                 tester_pre_setup_failed();
186                 return;
187         }
188
189         if (tester_use_debug())
190                 mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
191
192         mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
193                                         read_index_list_callback, NULL, NULL);
194 }
195
196 static void test_post_teardown(const void *test_data)
197 {
198         struct test_data *data = tester_get_data();
199
200         hciemu_unref(data->hciemu);
201         data->hciemu = NULL;
202 }
203
204 static void test_data_free(void *test_data)
205 {
206         struct test_data *data = test_data;
207
208         if (data->io_id > 0)
209                 g_source_remove(data->io_id);
210
211         free(data);
212 }
213
214 #define test_sco_full(name, data, setup, func, _disable_esco) \
215         do { \
216                 struct test_data *user; \
217                 user = malloc(sizeof(struct test_data)); \
218                 if (!user) \
219                         break; \
220                 user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
221                 user->io_id = 0; \
222                 user->test_data = data; \
223                 user->disable_esco = _disable_esco; \
224                 tester_add_full(name, data, \
225                                 test_pre_setup, setup, func, NULL, \
226                                 test_post_teardown, 2, user, test_data_free); \
227         } while (0)
228
229 #define test_sco(name, data, setup, func) \
230         test_sco_full(name, data, setup, func, false)
231
232 #define test_sco_11(name, data, setup, func) \
233         test_sco_full(name, data, setup, func, true)
234
235 static const struct sco_client_data connect_success = {
236         .expect_err = 0
237 };
238
239 static const struct sco_client_data connect_failure = {
240         .expect_err = EOPNOTSUPP
241 };
242
243 static void client_connectable_complete(uint16_t opcode, uint8_t status,
244                                         const void *param, uint8_t len,
245                                         void *user_data)
246 {
247         if (opcode != BT_HCI_CMD_WRITE_SCAN_ENABLE)
248                 return;
249
250         tester_print("Client set connectable status 0x%02x", status);
251
252         if (status)
253                 tester_setup_failed();
254         else
255                 tester_setup_complete();
256 }
257
258 static void setup_powered_callback(uint8_t status, uint16_t length,
259                                         const void *param, void *user_data)
260 {
261         struct test_data *data = tester_get_data();
262         struct bthost *bthost;
263
264         if (status != MGMT_STATUS_SUCCESS) {
265                 tester_setup_failed();
266                 return;
267         }
268
269         tester_print("Controller powered on");
270
271         bthost = hciemu_client_get_host(data->hciemu);
272         bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
273         bthost_write_scan_enable(bthost, 0x03);
274 }
275
276 static void setup_powered(const void *test_data)
277 {
278         struct test_data *data = tester_get_data();
279         unsigned char param[] = { 0x01 };
280
281         tester_print("Powering on controller");
282
283         mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
284                                         sizeof(param), param,
285                                         NULL, NULL, NULL);
286
287         mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
288                                 sizeof(param), param, NULL, NULL, NULL);
289
290         mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
291                                 sizeof(param), param, NULL, NULL, NULL);
292
293         mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
294                                         sizeof(param), param,
295                                         setup_powered_callback, NULL, NULL);
296 }
297
298 static void test_framework(const void *test_data)
299 {
300         tester_test_passed();
301 }
302
303 static void test_socket(const void *test_data)
304 {
305         int sk;
306
307         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
308         if (sk < 0) {
309                 tester_warn("Can't create socket: %s (%d)", strerror(errno),
310                                                                         errno);
311                 tester_test_failed();
312                 return;
313         }
314
315         close(sk);
316
317         tester_test_passed();
318 }
319
320 static void test_getsockopt(const void *test_data)
321 {
322         int sk, err;
323         socklen_t len;
324         struct bt_voice voice;
325
326         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
327         if (sk < 0) {
328                 tester_warn("Can't create socket: %s (%d)", strerror(errno),
329                                                                         errno);
330                 tester_test_failed();
331                 return;
332         }
333
334         len = sizeof(voice);
335         memset(&voice, 0, len);
336
337         err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
338         if (err < 0) {
339                 tester_warn("Can't get socket option : %s (%d)",
340                                                         strerror(errno), errno);
341                 tester_test_failed();
342                 goto end;
343         }
344
345         if (voice.setting != BT_VOICE_CVSD_16BIT) {
346                 tester_warn("Invalid voice setting");
347                 tester_test_failed();
348                 goto end;
349         }
350
351         tester_test_passed();
352
353 end:
354         close(sk);
355 }
356
357 static void test_setsockopt(const void *test_data)
358 {
359         int sk, err;
360         socklen_t len;
361         struct bt_voice voice;
362
363         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
364         if (sk < 0) {
365                 tester_warn("Can't create socket: %s (%d)", strerror(errno),
366                                                                         errno);
367                 tester_test_failed();
368                 goto end;
369         }
370
371
372         len = sizeof(voice);
373         memset(&voice, 0, len);
374
375         err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
376         if (err < 0) {
377                 tester_warn("Can't get socket option : %s (%d)",
378                                                         strerror(errno), errno);
379                 tester_test_failed();
380                 goto end;
381         }
382
383         if (voice.setting != BT_VOICE_CVSD_16BIT) {
384                 tester_warn("Invalid voice setting");
385                 tester_test_failed();
386                 goto end;
387         }
388
389         memset(&voice, 0, sizeof(voice));
390         voice.setting = BT_VOICE_TRANSPARENT;
391
392         err = setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice));
393         if (err < 0) {
394                 tester_warn("Can't set socket option : %s (%d)",
395                                                         strerror(errno), errno);
396                 tester_test_failed();
397                 goto end;
398         }
399
400         len = sizeof(voice);
401         memset(&voice, 0, len);
402
403         err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
404         if (err < 0) {
405                 tester_warn("Can't get socket option : %s (%d)",
406                                                         strerror(errno), errno);
407                 tester_test_failed();
408                 goto end;
409         }
410
411         if (voice.setting != BT_VOICE_TRANSPARENT) {
412                 tester_warn("Invalid voice setting");
413                 tester_test_failed();
414                 goto end;
415         }
416
417         tester_test_passed();
418
419 end:
420         close(sk);
421 }
422
423 static int create_sco_sock(struct test_data *data)
424 {
425         const uint8_t *master_bdaddr;
426         struct sockaddr_sco addr;
427         int sk, err;
428
429         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
430                                                                 BTPROTO_SCO);
431         if (sk < 0) {
432                 err = -errno;
433                 tester_warn("Can't create socket: %s (%d)", strerror(errno),
434                                                                         errno);
435                 return err;
436         }
437
438         master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
439         if (!master_bdaddr) {
440                 tester_warn("No master bdaddr");
441                 return -ENODEV;
442         }
443
444         memset(&addr, 0, sizeof(addr));
445         addr.sco_family = AF_BLUETOOTH;
446         bacpy(&addr.sco_bdaddr, (void *) master_bdaddr);
447
448         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
449                 err = -errno;
450                 tester_warn("Can't bind socket: %s (%d)", strerror(errno),
451                                                                         errno);
452                 close(sk);
453                 return err;
454         }
455
456         return sk;
457 }
458
459 static int connect_sco_sock(struct test_data *data, int sk)
460 {
461         const uint8_t *client_bdaddr;
462         struct sockaddr_sco addr;
463         int err;
464
465         client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
466         if (!client_bdaddr) {
467                 tester_warn("No client bdaddr");
468                 return -ENODEV;
469         }
470
471         memset(&addr, 0, sizeof(addr));
472         addr.sco_family = AF_BLUETOOTH;
473         bacpy(&addr.sco_bdaddr, (void *) client_bdaddr);
474
475         err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
476         if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
477                 err = -errno;
478                 tester_warn("Can't connect socket: %s (%d)", strerror(errno),
479                                                                         errno);
480                 return err;
481         }
482
483         return 0;
484 }
485
486 static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
487                                                         gpointer user_data)
488 {
489         struct test_data *data = tester_get_data();
490         const struct sco_client_data *scodata = data->test_data;
491         int err, sk_err, sk;
492         socklen_t len = sizeof(sk_err);
493
494         data->io_id = 0;
495
496         sk = g_io_channel_unix_get_fd(io);
497
498         if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
499                 err = -errno;
500         else
501                 err = -sk_err;
502
503         if (err < 0)
504                 tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
505         else
506                 tester_print("Successfully connected");
507
508         if (-err != scodata->expect_err)
509                 tester_test_failed();
510         else
511                 tester_test_passed();
512
513         return FALSE;
514 }
515
516 static void test_connect(const void *test_data)
517 {
518         struct test_data *data = tester_get_data();
519         GIOChannel *io;
520         int sk;
521
522         sk = create_sco_sock(data);
523         if (sk < 0) {
524                 tester_test_failed();
525                 return;
526         }
527
528         if (connect_sco_sock(data, sk) < 0) {
529                 close(sk);
530                 tester_test_failed();
531                 return;
532         }
533
534         io = g_io_channel_unix_new(sk);
535         g_io_channel_set_close_on_unref(io, TRUE);
536
537         data->io_id = g_io_add_watch(io, G_IO_OUT, sco_connect_cb, NULL);
538
539         g_io_channel_unref(io);
540
541         tester_print("Connect in progress");
542 }
543
544 static void test_connect_transp(const void *test_data)
545 {
546         struct test_data *data = tester_get_data();
547         const struct sco_client_data *scodata = data->test_data;
548         int sk, err;
549         struct bt_voice voice;
550
551         sk = create_sco_sock(data);
552         if (sk < 0) {
553                 tester_test_failed();
554                 return;
555         }
556
557         memset(&voice, 0, sizeof(voice));
558         voice.setting = BT_VOICE_TRANSPARENT;
559
560         err = setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice));
561         if (err < 0) {
562                 tester_warn("Can't set socket option : %s (%d)",
563                                                         strerror(errno), errno);
564                 tester_test_failed();
565                 goto end;
566         }
567
568         err = connect_sco_sock(data, sk);
569
570         tester_warn("Connect returned %s (%d), expected %s (%d)",
571                         strerror(-err), -err,
572                         strerror(scodata->expect_err), scodata->expect_err);
573
574         if (-err != scodata->expect_err)
575                 tester_test_failed();
576         else
577                 tester_test_passed();
578
579 end:
580         close(sk);
581 }
582
583 int main(int argc, char *argv[])
584 {
585         tester_init(&argc, &argv);
586
587         test_sco("Basic Framework - Success", NULL, setup_powered,
588                                                         test_framework);
589
590         test_sco("Basic SCO Socket - Success", NULL, setup_powered,
591                                                         test_socket);
592
593         test_sco("Basic SCO Get Socket Option - Success", NULL, setup_powered,
594                                                         test_getsockopt);
595
596         test_sco("Basic SCO Set Socket Option - Success", NULL, setup_powered,
597                                                         test_setsockopt);
598
599         test_sco("eSCO CVSD - Success", &connect_success, setup_powered,
600                                                         test_connect);
601
602         test_sco("eSCO mSBC - Success", &connect_success, setup_powered,
603                                                         test_connect_transp);
604
605         test_sco_11("SCO CVSD 1.1 - Success", &connect_success, setup_powered,
606                                                         test_connect);
607
608         test_sco_11("SCO mSBC 1.1 - Failure", &connect_failure, setup_powered,
609                                                         test_connect_transp);
610
611         return tester_run();
612 }