Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/hccontrol/node.c
103095 views
1
/*-
2
* node.c
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*
30
* $Id: node.c,v 1.6 2003/07/22 21:14:02 max Exp $
31
*/
32
33
#include <sys/ioctl.h>
34
#include <sys/param.h>
35
#define L2CAP_SOCKET_CHECKED
36
#include <bluetooth.h>
37
#include <errno.h>
38
#include <netgraph/ng_message.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <uuid.h>
44
#include "hccontrol.h"
45
46
/* Send Read_Node_State command to the node */
47
static int
48
hci_read_node_state(int s, int argc, char **argv)
49
{
50
struct ng_btsocket_hci_raw_node_state r;
51
52
memset(&r, 0, sizeof(r));
53
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
54
return (ERROR);
55
56
fprintf(stdout, "State: %#x\n", r.state);
57
58
return (OK);
59
} /* hci_read_node_state */
60
61
/* Send Intitialize command to the node */
62
static int
63
hci_node_initialize(int s, int argc, char **argv)
64
{
65
if (ioctl(s, SIOC_HCI_RAW_NODE_INIT) < 0)
66
return (ERROR);
67
68
return (OK);
69
} /* hci_node_initialize */
70
71
/* Send Read_Debug_Level command to the node */
72
static int
73
hci_read_debug_level(int s, int argc, char **argv)
74
{
75
struct ng_btsocket_hci_raw_node_debug r;
76
77
memset(&r, 0, sizeof(r));
78
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
79
return (ERROR);
80
81
fprintf(stdout, "Debug level: %d\n", r.debug);
82
83
return (OK);
84
} /* hci_read_debug_level */
85
86
/* Send Write_Debug_Level command to the node */
87
static int
88
hci_write_debug_level(int s, int argc, char **argv)
89
{
90
struct ng_btsocket_hci_raw_node_debug r;
91
92
memset(&r, 0, sizeof(r));
93
switch (argc) {
94
case 1:
95
r.debug = atoi(argv[0]);
96
break;
97
98
default:
99
return (USAGE);
100
}
101
102
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
103
return (ERROR);
104
105
return (OK);
106
} /* hci_write_debug_level */
107
108
/* Send Read_Node_Buffer_Size command to the node */
109
static int
110
hci_read_node_buffer_size(int s, int argc, char **argv)
111
{
112
struct ng_btsocket_hci_raw_node_buffer r;
113
114
memset(&r, 0, sizeof(r));
115
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
116
return (ERROR);
117
118
fprintf(stdout, "Number of free command buffers: %d\n",
119
r.buffer.cmd_free);
120
fprintf(stdout, "Max. ACL packet size: %d\n",
121
r.buffer.acl_size);
122
fprintf(stdout, "Numbef of free ACL buffers: %d\n",
123
r.buffer.acl_free);
124
fprintf(stdout, "Total number of ACL buffers: %d\n",
125
r.buffer.acl_pkts);
126
fprintf(stdout, "Max. SCO packet size: %d\n",
127
r.buffer.sco_size);
128
fprintf(stdout, "Numbef of free SCO buffers: %d\n",
129
r.buffer.sco_free);
130
fprintf(stdout, "Total number of SCO buffers: %d\n",
131
r.buffer.sco_pkts);
132
133
return (OK);
134
} /* hci_read_node_buffer_size */
135
136
/* Send Read_Node_BD_ADDR command to the node */
137
static int
138
hci_read_node_bd_addr(int s, int argc, char **argv)
139
{
140
struct ng_btsocket_hci_raw_node_bdaddr r;
141
142
memset(&r, 0, sizeof(r));
143
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
144
return (ERROR);
145
146
fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&r.bdaddr, NULL));
147
148
return (OK);
149
} /* hci_read_node_bd_addr */
150
151
/* Send Read_Node_Features command to the node */
152
static int
153
hci_read_node_features(int s, int argc, char **argv)
154
{
155
struct ng_btsocket_hci_raw_node_features r;
156
int n;
157
char buffer[2048];
158
159
memset(&r, 0, sizeof(r));
160
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
161
return (ERROR);
162
163
fprintf(stdout, "Features: ");
164
for (n = 0; n < nitems(r.features); n++)
165
fprintf(stdout, "%#02x ", r.features[n]);
166
fprintf(stdout, "\n%s\n", hci_features2str(r.features,
167
buffer, sizeof(buffer)));
168
169
return (OK);
170
} /* hci_read_node_features */
171
172
/* Send Read_Node_Stat command to the node */
173
static int
174
hci_read_node_stat(int s, int argc, char **argv)
175
{
176
struct ng_btsocket_hci_raw_node_stat r;
177
178
memset(&r, 0, sizeof(r));
179
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
180
return (ERROR);
181
182
fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
183
fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
184
fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
185
fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
186
fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
187
fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
188
fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
189
fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
190
191
return (OK);
192
} /* hci_read_node_stat */
193
194
/* Send Reset_Node_Stat command to the node */
195
static int
196
hci_reset_node_stat(int s, int argc, char **argv)
197
{
198
if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT) < 0)
199
return (ERROR);
200
201
return (OK);
202
} /* hci_reset_node_stat */
203
204
/* Send Flush_Neighbor_Cache command to the node */
205
static int
206
hci_flush_neighbor_cache(int s, int argc, char **argv)
207
{
208
if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE) < 0)
209
return (ERROR);
210
211
return (OK);
212
} /* hci_flush_neighbor_cache */
213
214
/* Send Read_Neighbor_Cache command to the node */
215
static int
216
hci_read_neighbor_cache(int s, int argc, char **argv)
217
{
218
struct ng_btsocket_hci_raw_node_neighbor_cache r;
219
int n, error = OK;
220
const char *addrtype2str[] = {"B", "P", "R", "E"};
221
222
memset(&r, 0, sizeof(r));
223
r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
224
r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
225
sizeof(ng_hci_node_neighbor_cache_entry_ep));
226
if (r.entries == NULL) {
227
errno = ENOMEM;
228
return (ERROR);
229
}
230
231
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
232
sizeof(r)) < 0) {
233
error = ERROR;
234
goto out;
235
}
236
237
fprintf(stdout,
238
"T " \
239
"BD_ADDR " \
240
"Features " \
241
"Clock offset " \
242
"Page scan " \
243
"Rep. scan\n");
244
245
for (n = 0; n < r.num_entries; n++) {
246
uint8_t addrtype = r.entries[n].addrtype;
247
if(addrtype >= nitems(addrtype2str))
248
addrtype = nitems(addrtype2str) - 1;
249
fprintf(stdout,
250
"%1s %-17.17s " \
251
"%02x %02x %02x %02x %02x %02x %02x %02x " \
252
"%#12x " \
253
"%#9x " \
254
"%#9x\n",
255
addrtype2str[addrtype],
256
hci_bdaddr2str(&r.entries[n].bdaddr),
257
r.entries[n].features[0], r.entries[n].features[1],
258
r.entries[n].features[2], r.entries[n].features[3],
259
r.entries[n].features[4], r.entries[n].features[5],
260
r.entries[n].features[6], r.entries[n].features[7],
261
r.entries[n].clock_offset, r.entries[n].page_scan_mode,
262
r.entries[n].page_scan_rep_mode);
263
print_adv_data(r.entries[n].extinq_size,
264
r.entries[n].extinq_data);
265
fprintf(stdout,"\n");
266
}
267
out:
268
free(r.entries);
269
270
return (error);
271
} /* hci_read_neightbor_cache */
272
273
/* Send Read_Connection_List command to the node */
274
static int
275
hci_read_connection_list(int s, int argc, char **argv)
276
{
277
struct ng_btsocket_hci_raw_con_list r;
278
int n, error = OK;
279
280
memset(&r, 0, sizeof(r));
281
r.num_connections = NG_HCI_MAX_CON_NUM;
282
r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
283
if (r.connections == NULL) {
284
errno = ENOMEM;
285
return (ERROR);
286
}
287
288
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
289
error = ERROR;
290
goto out;
291
}
292
293
fprintf(stdout,
294
"Remote BD_ADDR " \
295
"Handle " \
296
"Type " \
297
"Mode " \
298
"Role " \
299
"Encrypt " \
300
"Pending " \
301
"Queue " \
302
"State\n");
303
304
for (n = 0; n < r.num_connections; n++) {
305
fprintf(stdout,
306
"%-17.17s " \
307
"%6d " \
308
"%4.4s " \
309
"%4d " \
310
"%4.4s " \
311
"%7.7s " \
312
"%7d " \
313
"%5d " \
314
"%s\n",
315
hci_bdaddr2str(&r.connections[n].bdaddr),
316
r.connections[n].con_handle,
317
(r.connections[n].link_type == NG_HCI_LINK_ACL)?
318
"ACL" : "SCO",
319
r.connections[n].mode,
320
(r.connections[n].role == NG_HCI_ROLE_MASTER)?
321
"MAST" : "SLAV",
322
hci_encrypt2str(r.connections[n].encryption_mode, 1),
323
r.connections[n].pending,
324
r.connections[n].queue_len,
325
hci_con_state2str(r.connections[n].state));
326
}
327
out:
328
free(r.connections);
329
330
return (error);
331
} /* hci_read_connection_list */
332
333
/* Send Read_Node_Link_Policy_Settings_Mask command to the node */
334
int
335
hci_read_node_link_policy_settings_mask(int s, int argc, char **argv)
336
{
337
struct ng_btsocket_hci_raw_node_link_policy_mask r;
338
339
memset(&r, 0, sizeof(r));
340
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
341
return (ERROR);
342
343
fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask);
344
345
return (OK);
346
} /* hci_read_node_link_policy_settings_mask */
347
348
/* Send Write_Node_Link_Policy_Settings_Mask command to the node */
349
int
350
hci_write_node_link_policy_settings_mask(int s, int argc, char **argv)
351
{
352
struct ng_btsocket_hci_raw_node_link_policy_mask r;
353
int m;
354
355
memset(&r, 0, sizeof(r));
356
357
switch (argc) {
358
case 1:
359
if (sscanf(argv[0], "%x", &m) != 1)
360
return (USAGE);
361
362
r.policy_mask = (m & 0xffff);
363
break;
364
365
default:
366
return (USAGE);
367
}
368
369
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
370
return (ERROR);
371
372
return (OK);
373
} /* hci_write_node_link_policy_settings_mask */
374
375
/* Send Read_Node_Packet_Mask command to the node */
376
int
377
hci_read_node_packet_mask(int s, int argc, char **argv)
378
{
379
struct ng_btsocket_hci_raw_node_packet_mask r;
380
381
memset(&r, 0, sizeof(r));
382
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
383
return (ERROR);
384
385
fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask);
386
387
return (OK);
388
} /* hci_read_node_packet_mask */
389
390
/* Send Write_Node_Packet_Mask command to the node */
391
int
392
hci_write_node_packet_mask(int s, int argc, char **argv)
393
{
394
struct ng_btsocket_hci_raw_node_packet_mask r;
395
int m;
396
397
memset(&r, 0, sizeof(r));
398
399
switch (argc) {
400
case 1:
401
if (sscanf(argv[0], "%x", &m) != 1)
402
return (USAGE);
403
404
r.packet_mask = (m & 0xffff);
405
break;
406
407
default:
408
return (USAGE);
409
}
410
411
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
412
return (ERROR);
413
414
return (OK);
415
} /* hci_write_node_packet_mask */
416
417
/* Send Read_Node_Role_Switch command to the node */
418
int
419
hci_read_node_role_switch(int s, int argc, char **argv)
420
{
421
struct ng_btsocket_hci_raw_node_role_switch r;
422
423
memset(&r, 0, sizeof(r));
424
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0)
425
return (ERROR);
426
427
fprintf(stdout, "Role switch: %d\n", r.role_switch);
428
429
return (OK);
430
} /* hci_read_node_role_switch */
431
432
/* Send Write_Node_Role_Switch command to the node */
433
int
434
hci_write_node_role_switch(int s, int argc, char **argv)
435
{
436
struct ng_btsocket_hci_raw_node_role_switch r;
437
int m;
438
439
memset(&r, 0, sizeof(r));
440
441
switch (argc) {
442
case 1:
443
if (sscanf(argv[0], "%d", &m) != 1)
444
return (USAGE);
445
446
r.role_switch = m? 1 : 0;
447
break;
448
449
default:
450
return (USAGE);
451
}
452
453
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0)
454
return (ERROR);
455
456
return (OK);
457
} /* hci_write_node_role_switch */
458
459
/* Send Read_Node_List command to the node */
460
int
461
hci_read_node_list(int s, int argc, char **argv)
462
{
463
struct ng_btsocket_hci_raw_node_list_names r;
464
int i;
465
466
r.num_names = MAX_NODE_NUM;
467
r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));
468
if (r.names == NULL)
469
return (ERROR);
470
471
if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) {
472
free(r.names);
473
return (ERROR);
474
}
475
476
fprintf(stdout, "Name ID Num hooks\n");
477
for (i = 0; i < r.num_names; ++i)
478
fprintf(stdout, "%-15s %08x %9d\n",
479
r.names[i].name, r.names[i].id, r.names[i].hooks);
480
481
free(r.names);
482
483
return (OK);
484
} /* hci_read_node_list */
485
486
struct hci_command node_commands[] = {
487
{
488
"read_node_state",
489
"Get the HCI node state",
490
&hci_read_node_state
491
},
492
{
493
"initialize",
494
"Initialize the HCI node",
495
&hci_node_initialize
496
},
497
{
498
"read_debug_level",
499
"Read the HCI node debug level",
500
&hci_read_debug_level
501
},
502
{
503
"write_debug_level <level>",
504
"Write the HCI node debug level",
505
&hci_write_debug_level
506
},
507
{
508
"read_node_buffer_size",
509
"Read the HCI node buffer information. This will return current state of the\n"\
510
"HCI buffer for the HCI node",
511
&hci_read_node_buffer_size
512
},
513
{
514
"read_node_bd_addr",
515
"Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node",
516
&hci_read_node_bd_addr
517
},
518
{
519
"read_node_features",
520
"Read the HCI node features. This will return list of supported features as\n" \
521
"cached by the HCI node",
522
&hci_read_node_features
523
},
524
{
525
"read_node_stat",
526
"Read packets and bytes counters for the HCI node",
527
&hci_read_node_stat
528
},
529
{
530
"reset_node_stat",
531
"Reset packets and bytes counters for the HCI node",
532
&hci_reset_node_stat
533
},
534
{
535
"flush_neighbor_cache",
536
"Flush content of the HCI node neighbor cache",
537
&hci_flush_neighbor_cache
538
},
539
{
540
"read_neighbor_cache",
541
"Read content of the HCI node neighbor cache",
542
&hci_read_neighbor_cache
543
},
544
{
545
"read_connection_list",
546
"Read the baseband connection descriptors list for the HCI node",
547
&hci_read_connection_list
548
},
549
{
550
"read_node_link_policy_settings_mask",
551
"Read the value of the Link Policy Settinngs mask for the HCI node",
552
&hci_read_node_link_policy_settings_mask
553
},
554
{
555
"write_node_link_policy_settings_mask <policy_mask>",
556
"Write the value of the Link Policy Settings mask for the HCI node. By default\n" \
557
"all supported Link Policy modes (as reported by the local device features) are\n"\
558
"enabled. The particular Link Policy mode is enabled if local device supports\n"\
559
"it and correspinding bit in the mask was set\n\n" \
560
"\t<policy_mask> - xxxx; Link Policy mask\n" \
561
"\t\t0x0000 - Disable All LM Modes\n" \
562
"\t\t0x0001 - Enable Master Slave Switch\n" \
563
"\t\t0x0002 - Enable Hold Mode\n" \
564
"\t\t0x0004 - Enable Sniff Mode\n" \
565
"\t\t0x0008 - Enable Park Mode\n",
566
&hci_write_node_link_policy_settings_mask
567
},
568
{
569
"read_node_packet_mask",
570
"Read the value of the Packet mask for the HCI node",
571
&hci_read_node_packet_mask
572
},
573
{
574
"write_node_packet_mask <packet_mask>",
575
"Write the value of the Packet mask for the HCI node. By default all supported\n" \
576
"packet types (as reported by the local device features) are enabled. The\n" \
577
"particular packet type is enabled if local device supports it and corresponding\n" \
578
"bit in the mask was set\n\n" \
579
"\t<packet_mask> - xxxx; packet type mask\n" \
580
"" \
581
"\t\tACL packets\n" \
582
"\t\t-----------\n" \
583
"\t\t0x0008 DM1\n" \
584
"\t\t0x0010 DH1\n" \
585
"\t\t0x0400 DM3\n" \
586
"\t\t0x0800 DH3\n" \
587
"\t\t0x4000 DM5\n" \
588
"\t\t0x8000 DH5\n" \
589
"\n" \
590
"\t\tSCO packets\n" \
591
"\t\t-----------\n" \
592
"\t\t0x0020 HV1\n" \
593
"\t\t0x0040 HV2\n" \
594
"\t\t0x0080 HV3\n",
595
&hci_write_node_packet_mask
596
},
597
{
598
"read_node_role_switch",
599
"Read the value of the Role Switch parameter for the HCI node",
600
&hci_read_node_role_switch
601
},
602
{
603
"write_node_role_switch {0|1}",
604
"Write the value of the Role Switch parameter for the HCI node. By default,\n" \
605
"if Role Switch is supported, local device will try to perform Role Switch\n" \
606
"and become Master on incoming connection. Some devices do not support Role\n" \
607
"Switch and thus incoming connections from such devices will fail. Setting\n" \
608
"this parameter to zero will prevent Role Switch and thus accepting device\n" \
609
"will remain Slave",
610
&hci_write_node_role_switch
611
},
612
{
613
"read_node_list",
614
"Get a list of HCI nodes, their Netgraph IDs and connected hooks.",
615
&hci_read_node_list
616
},
617
{
618
NULL,
619
}};
620
621
622