xref: /freebsd/usr.sbin/bluetooth/hccontrol/node.c (revision 4b2eaea43fec8e8792be611dea204071a10b655a)
1 /*
2  * node.c
3  *
4  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $Id: node.c,v 1.8 2002/11/12 22:33:17 max Exp $
29  * $FreeBSD$
30  */
31 
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <bitstring.h>
36 #include <errno.h>
37 #include <ng_hci.h>
38 #include <ng_l2cap.h>
39 #include <ng_btsocket.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "hccontrol.h"
44 
45 /* Send Read_Node_State command to the node */
46 static int
47 hci_read_node_state(int s, int argc, char **argv)
48 {
49 	struct ng_btsocket_hci_raw_node_state	r;
50 
51 	memset(&r, 0, sizeof(r));
52 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
53 		return (ERROR);
54 
55 	fprintf(stdout, "Node: %s\nState: %#x\n", r.hci_node, r.state);
56 
57 	return (OK);
58 } /* hci_read_node_state */
59 
60 /* Send Intitialize command to the node */
61 static int
62 hci_node_initialize(int s, int argc, char **argv)
63 {
64 	struct ng_btsocket_hci_raw_node_init	r;
65 
66 	memset(&r, 0, sizeof(r));
67 	if (ioctl(s, SIOC_HCI_RAW_NODE_INIT, &r, sizeof(r)) < 0)
68 		return (ERROR);
69 
70 	return (OK);
71 } /* hci_node_initialize */
72 
73 /* Send Read_Debug_Level command to the node */
74 static int
75 hci_read_debug_level(int s, int argc, char **argv)
76 {
77 	struct ng_btsocket_hci_raw_node_debug	r;
78 
79 	memset(&r, 0, sizeof(r));
80 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
81 		return (ERROR);
82 
83 	fprintf(stdout, "Node: %s\nDebug level: %d\n", r.hci_node, r.debug);
84 
85 	return (OK);
86 } /* hci_read_debug_level */
87 
88 /* Send Write_Debug_Level command to the node */
89 static int
90 hci_write_debug_level(int s, int argc, char **argv)
91 {
92 	struct ng_btsocket_hci_raw_node_debug	r;
93 
94 	memset(&r, 0, sizeof(r));
95 	switch (argc) {
96 	case 1:
97 		r.debug = atoi(argv[0]);
98 		break;
99 
100 	default:
101 		return (USAGE);
102 	}
103 
104 	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
105 		return (ERROR);
106 
107 	return (OK);
108 } /* hci_write_debug_level */
109 
110 /* Send Read_Node_Buffer_Size command to the node */
111 static int
112 hci_read_node_buffer_size(int s, int argc, char **argv)
113 {
114 	struct ng_btsocket_hci_raw_node_buffer	r;
115 
116 	memset(&r, 0, sizeof(r));
117 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
118 		return (ERROR);
119 
120 	fprintf(stdout, "Node: %s\n",
121 		r.hci_node);
122 	fprintf(stdout, "Number of free command buffers: %d\n",
123 		r.buffer.cmd_free);
124 	fprintf(stdout, "Max. ACL packet size: %d\n",
125 		r.buffer.acl_size);
126 	fprintf(stdout, "Numbef of free ACL buffers: %d\n",
127 		r.buffer.acl_free);
128 	fprintf(stdout, "Total number of ACL buffers: %d\n",
129 		r.buffer.acl_pkts);
130 	fprintf(stdout, "Max. SCO packet size: %d\n",
131 		r.buffer.sco_size);
132 	fprintf(stdout, "Numbef of free SCO buffers: %d\n",
133 		r.buffer.sco_free);
134 	fprintf(stdout, "Total number of SCO buffers: %d\n",
135 		r.buffer.sco_pkts);
136 
137 	return (OK);
138 } /* hci_read_node_buffer_size */
139 
140 /* Send Read_Node_BD_ADDR command to the node */
141 static int
142 hci_read_node_bd_addr(int s, int argc, char **argv)
143 {
144 	struct ng_btsocket_hci_raw_node_bdaddr	r;
145 
146 	memset(&r, 0, sizeof(r));
147 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
148 		return (ERROR);
149 
150 	fprintf(stdout, "Node: %s\n", r.hci_node);
151 	fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
152 		r.bdaddr.b[5], r.bdaddr.b[4], r.bdaddr.b[3],
153 		r.bdaddr.b[2], r.bdaddr.b[1], r.bdaddr.b[0]);
154 
155 	return (OK);
156 } /* hci_read_node_bd_addr */
157 
158 /* Send Read_Node_Features command to the node */
159 static int
160 hci_read_node_features(int s, int argc, char **argv)
161 {
162 	struct ng_btsocket_hci_raw_node_features	r;
163 	int						n;
164 	char						buffer[1024];
165 
166 	memset(&r, 0, sizeof(r));
167 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
168 		return (ERROR);
169 
170 	fprintf(stdout, "Node: %s\nFeatures: ", r.hci_node);
171 	for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
172 		fprintf(stdout, "%#02x ", r.features[n]);
173 	fprintf(stdout, "\n%s\n", hci_features2str(r.features,
174 		buffer, sizeof(buffer)));
175 
176 	return (OK);
177 } /* hci_read_node_features */
178 
179 /* Send Read_Node_Stat command to the node */
180 static int
181 hci_read_node_stat(int s, int argc, char **argv)
182 {
183 	struct ng_btsocket_hci_raw_node_stat	r;
184 
185 	memset(&r, 0, sizeof(r));
186 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
187 		return (ERROR);
188 
189 	fprintf(stdout, "Node: %s\n", r.hci_node);
190 	fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
191 	fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
192 	fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
193 	fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
194 	fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
195 	fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
196 	fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
197 	fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
198 
199 	return (OK);
200 } /* hci_read_node_stat */
201 
202 /* Send Reset_Node_Stat command to the node */
203 static int
204 hci_reset_node_stat(int s, int argc, char **argv)
205 {
206 	struct ng_btsocket_hci_raw_node_reset_stat	r;
207 
208 	memset(&r, 0, sizeof(r));
209 	if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT, &r, sizeof(r)) < 0)
210 		return (ERROR);
211 
212 	return (OK);
213 } /* hci_reset_node_stat */
214 
215 /* Send Flush_Neighbor_Cache command to the node */
216 static int
217 hci_flush_neighbor_cache(int s, int argc, char **argv)
218 {
219 	struct ng_btsocket_hci_raw_node_flush_neighbor_cache	r;
220 
221 	memset(&r, 0, sizeof(r));
222 	if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE,
223 			&r, sizeof(r)) < 0)
224 		return (ERROR);
225 
226 	return (OK);
227 } /* hci_flush_neighbor_cache */
228 
229 /* Send Read_Neighbor_Cache command to the node */
230 static int
231 hci_read_neighbor_cache(int s, int argc, char **argv)
232 {
233 	struct ng_btsocket_hci_raw_node_neighbor_cache	r;
234 	int						n, error = OK;
235 
236 	memset(&r, 0, sizeof(r));
237 	r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
238 	r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
239 				sizeof(ng_hci_node_neighbor_cache_entry_ep));
240 	if (r.entries == NULL) {
241 		errno = ENOMEM;
242 		return (ERROR);
243 	}
244 
245 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
246 			sizeof(r)) < 0) {
247 		error = ERROR;
248 		goto out;
249 	}
250 
251 	fprintf(stdout, "Neighbor cache for the node: %s\n", r.hci_node);
252 	fprintf(stdout,
253 "BD_ADDR           " \
254 "Features                " \
255 "Clock offset " \
256 "Page scan " \
257 "Rep. scan\n");
258 
259 	for (n = 0; n < r.num_entries; n++) {
260 		fprintf(stdout,
261 "%02x:%02x:%02x:%02x:%02x:%02x " \
262 "%02x %02x %02x %02x %02x %02x %02x %02x " \
263 "%#12x " \
264 "%#9x " \
265 "%#9x\n",
266 			r.entries[n].bdaddr.b[5], r.entries[n].bdaddr.b[4],
267 			r.entries[n].bdaddr.b[3], r.entries[n].bdaddr.b[2],
268 			r.entries[n].bdaddr.b[1], r.entries[n].bdaddr.b[0],
269 			r.entries[n].features[0], r.entries[n].features[1],
270 			r.entries[n].features[2], r.entries[n].features[3],
271 			r.entries[n].features[4], r.entries[n].features[5],
272 			r.entries[n].features[6], r.entries[n].features[7],
273 			r.entries[n].clock_offset, r.entries[n].page_scan_mode,
274 			r.entries[n].page_scan_rep_mode);
275 	}
276 out:
277 	free(r.entries);
278 
279 	return (error);
280 } /* hci_read_neightbor_cache */
281 
282 /* Send Read_Connection_List command to the node */
283 static int
284 hci_read_connection_list(int s, int argc, char **argv)
285 {
286 	struct ng_btsocket_hci_raw_con_list	r;
287 	int					n, error = OK;
288 
289 	memset(&r, 0, sizeof(r));
290 	r.num_connections = NG_HCI_MAX_CON_NUM;
291 	r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
292 	if (r.connections == NULL) {
293 		errno = ENOMEM;
294 		return (ERROR);
295 	}
296 
297 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
298 		error = ERROR;
299 		goto out;
300 	}
301 
302 	fprintf(stdout, "Connections list for the node: %s\n", r.hci_node);
303 	fprintf(stdout,
304 "Remote BD_ADDR    " \
305 "Handle " \
306 "Type " \
307 "Mode " \
308 "Role " \
309 "Encrypt " \
310 "Pending " \
311 "Queue " \
312 "State\n");
313 
314 	for (n = 0; n < r.num_connections; n++) {
315 		fprintf(stdout,
316 "%02x:%02x:%02x:%02x:%02x:%02x " \
317 "%6d " \
318 "%4.4s " \
319 "%4d " \
320 "%4.4s " \
321 "%7.7s " \
322 "%7d " \
323 "%5d " \
324 "%s\n",
325 			r.connections[n].bdaddr.b[5],
326 			r.connections[n].bdaddr.b[4],
327 			r.connections[n].bdaddr.b[3],
328 			r.connections[n].bdaddr.b[2],
329 			r.connections[n].bdaddr.b[1],
330 			r.connections[n].bdaddr.b[0],
331 			r.connections[n].con_handle,
332 			(r.connections[n].link_type == NG_HCI_LINK_ACL)?
333 				"ACL" : "SCO",
334 			r.connections[n].mode,
335 			(r.connections[n].role == NG_HCI_ROLE_MASTER)?
336 				"MAST" : "SLAV",
337 			hci_encrypt2str(r.connections[n].encryption_mode, 1),
338 			r.connections[n].pending,
339 			r.connections[n].queue_len,
340 			hci_con_state2str(r.connections[n].state));
341 	}
342 out:
343 	free(r.connections);
344 
345 	return (error);
346 } /* hci_read_connection_list */
347 
348 /* Send Read_Link_Policy_Settings_Mask command to the node */
349 int
350 hci_read_link_policy_settings_mask(int s, int argc, char **argv)
351 {
352 	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
353 
354 	memset(&r, 0, sizeof(r));
355 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
356 		return (ERROR);
357 
358 	fprintf(stdout, "Node: %s\nLink Policy Settings mask: %#04x\n",
359 			r.hci_node, r.policy_mask);
360 
361 	return (OK);
362 } /* hci_read_link_policy_settings_mask */
363 
364 /* Send Write_Link_Policy_Settings_Mask command to the node */
365 int
366 hci_write_link_policy_settings_mask(int s, int argc, char **argv)
367 {
368 	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
369 	int							m;
370 
371 	memset(&r, 0, sizeof(r));
372 
373 	switch (argc) {
374 	case 1:
375 		if (sscanf(argv[0], "%x", &m) != 1)
376 			return (USAGE);
377 
378 		r.policy_mask = (m & 0xffff);
379 		break;
380 
381 	default:
382 		return (USAGE);
383 	}
384 
385 	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
386 		return (ERROR);
387 
388 	return (OK);
389 } /* hci_write_link_policy_settings_mask */
390 
391 /* Send Read_Packet_Mask command to the node */
392 int
393 hci_read_packet_mask(int s, int argc, char **argv)
394 {
395 	struct ng_btsocket_hci_raw_node_packet_mask	r;
396 
397 	memset(&r, 0, sizeof(r));
398 	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
399 		return (ERROR);
400 
401 	fprintf(stdout, "Node: %s\nPacket mask: %#04x\n",
402 			r.hci_node, r.packet_mask);
403 
404 	return (OK);
405 } /* hci_read_packet_mask */
406 
407 /* Send Write_Packet_Mask command to the node */
408 int
409 hci_write_packet_mask(int s, int argc, char **argv)
410 {
411 	struct ng_btsocket_hci_raw_node_packet_mask	r;
412 	int						m;
413 
414 	memset(&r, 0, sizeof(r));
415 
416 	switch (argc) {
417 	case 1:
418 		if (sscanf(argv[0], "%x", &m) != 1)
419 			return (USAGE);
420 
421 		r.packet_mask = (m & 0xffff);
422 		break;
423 
424 	default:
425 		return (USAGE);
426 	}
427 
428 	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
429 		return (ERROR);
430 
431 	return (OK);
432 } /* hci_write_packet_mask */
433 
434 struct hci_command	node_commands[] = {
435 {
436 "read_node_state",
437 "Get HCI node state",
438 &hci_read_node_state
439 },
440 {
441 "initialize",
442 "Initialize HCI node",
443 &hci_node_initialize
444 },
445 {
446 "read_debug_level",
447 "Read HCI node debug level",
448 &hci_read_debug_level
449 },
450 {
451 "write_debug_level <level>",
452 "Write HCI node debug level",
453 &hci_write_debug_level
454 },
455 {
456 "read_node_buffer_size",
457 "Read HCI node buffer information",
458 &hci_read_node_buffer_size
459 },
460 {
461 "read_node_bd_addr",
462 "Read HCI node BD_ADDR",
463 &hci_read_node_bd_addr
464 },
465 {
466 "read_node_features",
467 "Read HCI node features",
468 &hci_read_node_features
469 },
470 {
471 "read_node_stat",
472 "Read HCI node statistic information",
473 &hci_read_node_stat
474 },
475 {
476 "reset_node_stat",
477 "Reset HCI node statistic information",
478 &hci_reset_node_stat
479 },
480 {
481 "flush_neighbor_cache",
482 "Flush HCI node neighbor cache",
483 &hci_flush_neighbor_cache
484 },
485 {
486 "read_neighbor_cache",
487 "Read HCI node neighbor cache",
488 &hci_read_neighbor_cache
489 },
490 {
491 "read_connection_list",
492 "Read connection list",
493 &hci_read_connection_list
494 },
495 {
496 "read_node_link_policy_settings_mask",
497 "Read Link Policy Settinngs mask for the node",
498 &hci_read_link_policy_settings_mask
499 },
500 {
501 "write_node_link_policy_settings_mask <policy_mask>",
502 "Write Link Policy Settinngs mask for the node. Policy mask - xxxx",
503 &hci_write_link_policy_settings_mask
504 },
505 {
506 "read_node_packet_mask",
507 "Read Packet mask for the node",
508 &hci_read_packet_mask
509 },
510 {
511 "write_node_packet_mask <packet_mask>",
512 "Write Packet mask for the node. Packet mask - xxxx",
513 &hci_write_packet_mask
514 },
515 {
516 NULL,
517 }};
518 
519