1bcff2d91STakanori Watanabe /* 2bcff2d91STakanori Watanabe * le.c 3bcff2d91STakanori Watanabe * 4bcff2d91STakanori Watanabe * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org> 5bcff2d91STakanori Watanabe * All rights reserved. 6bcff2d91STakanori Watanabe * 7bcff2d91STakanori Watanabe * Redistribution and use in source and binary forms, with or without 8bcff2d91STakanori Watanabe * modification, are permitted provided that the following conditions 9bcff2d91STakanori Watanabe * are met: 10bcff2d91STakanori Watanabe * 1. Redistributions of source code must retain the above copyright 11bcff2d91STakanori Watanabe * notice, this list of conditions and the following disclaimer. 12bcff2d91STakanori Watanabe * 2. Redistributions in binary form must reproduce the above copyright 13bcff2d91STakanori Watanabe * notice, this list of conditions and the following disclaimer in the 14bcff2d91STakanori Watanabe * documentation and/or other materials provided with the distribution. 15bcff2d91STakanori Watanabe * 16bcff2d91STakanori Watanabe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17bcff2d91STakanori Watanabe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bcff2d91STakanori Watanabe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19bcff2d91STakanori Watanabe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20bcff2d91STakanori Watanabe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21bcff2d91STakanori Watanabe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22bcff2d91STakanori Watanabe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23bcff2d91STakanori Watanabe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24bcff2d91STakanori Watanabe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25bcff2d91STakanori Watanabe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bcff2d91STakanori Watanabe * SUCH DAMAGE. 27bcff2d91STakanori Watanabe * 28bcff2d91STakanori Watanabe * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $ 29bcff2d91STakanori Watanabe * $FreeBSD$ 30bcff2d91STakanori Watanabe */ 31bcff2d91STakanori Watanabe 32bcff2d91STakanori Watanabe #include <sys/types.h> 33bcff2d91STakanori Watanabe #include <sys/ioctl.h> 34bcff2d91STakanori Watanabe #include <sys/sysctl.h> 35bcff2d91STakanori Watanabe #include <sys/select.h> 36bcff2d91STakanori Watanabe #include <assert.h> 378907f744SAlan Somers #include <bitstring.h> 38bcff2d91STakanori Watanabe #include <err.h> 39bcff2d91STakanori Watanabe #include <errno.h> 40bcff2d91STakanori Watanabe #include <netgraph/ng_message.h> 41bcff2d91STakanori Watanabe #include <errno.h> 42bcff2d91STakanori Watanabe #include <stdio.h> 43bcff2d91STakanori Watanabe #include <stdlib.h> 44bcff2d91STakanori Watanabe #include <string.h> 45bcff2d91STakanori Watanabe #include <unistd.h> 464cae2db2STakanori Watanabe #include <stdint.h> 47bcff2d91STakanori Watanabe #define L2CAP_SOCKET_CHECKED 48bcff2d91STakanori Watanabe #include <bluetooth.h> 49bcff2d91STakanori Watanabe #include "hccontrol.h" 509c3471faSMarcelo Araujo 51bcff2d91STakanori Watanabe static int le_set_scan_param(int s, int argc, char *argv[]); 52bcff2d91STakanori Watanabe static int le_set_scan_enable(int s, int argc, char *argv[]); 53bcff2d91STakanori Watanabe static int parse_param(int argc, char *argv[], char *buf, int *len); 54bcff2d91STakanori Watanabe static int le_set_scan_response(int s, int argc, char *argv[]); 5521eefd31SHans Petter Selasky static int le_read_supported_states(int s, int argc, char *argv[]); 56bcff2d91STakanori Watanabe static int le_read_local_supported_features(int s, int argc ,char *argv[]); 57bcff2d91STakanori Watanabe static int set_le_event_mask(int s, uint64_t mask); 58bcff2d91STakanori Watanabe static int set_event_mask(int s, uint64_t mask); 59bcff2d91STakanori Watanabe static int le_enable(int s, int argc, char *argv[]); 60c3f60abcSHans Petter Selasky static int le_set_advertising_enable(int s, int argc, char *argv[]); 61c3f60abcSHans Petter Selasky static int le_set_advertising_param(int s, int argc, char *argv[]); 62c3f60abcSHans Petter Selasky static int le_read_advertising_channel_tx_power(int s, int argc, char *argv[]); 63bcff2d91STakanori Watanabe 649c3471faSMarcelo Araujo static int 659c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[]) 66bcff2d91STakanori Watanabe { 67bcff2d91STakanori Watanabe int type; 68bcff2d91STakanori Watanabe int interval; 69bcff2d91STakanori Watanabe int window; 70bcff2d91STakanori Watanabe int adrtype; 71bcff2d91STakanori Watanabe int policy; 72eb2aebeaSTakanori Watanabe int n; 73bcff2d91STakanori Watanabe 74bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_cp cp; 75bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_rp rp; 76bcff2d91STakanori Watanabe 779c3471faSMarcelo Araujo if (argc != 5) 78eb2aebeaSTakanori Watanabe return (USAGE); 79bcff2d91STakanori Watanabe 809c3471faSMarcelo Araujo if (strcmp(argv[0], "active") == 0) 81bcff2d91STakanori Watanabe type = 1; 829c3471faSMarcelo Araujo else if (strcmp(argv[0], "passive") == 0) 83bcff2d91STakanori Watanabe type = 0; 849c3471faSMarcelo Araujo else 85eb2aebeaSTakanori Watanabe return (USAGE); 86bcff2d91STakanori Watanabe 87bcff2d91STakanori Watanabe interval = (int)(atof(argv[1])/0.625); 88bcff2d91STakanori Watanabe interval = (interval < 4)? 4: interval; 89bcff2d91STakanori Watanabe window = (int)(atof(argv[2])/0.625); 90bcff2d91STakanori Watanabe window = (window < 4) ? 4 : interval; 91bcff2d91STakanori Watanabe 929c3471faSMarcelo Araujo if (strcmp(argv[3], "public") == 0) 93bcff2d91STakanori Watanabe adrtype = 0; 9405e526fbSTakanori Watanabe else if (strcmp(argv[3], "random") == 0) 95bcff2d91STakanori Watanabe adrtype = 1; 969c3471faSMarcelo Araujo else 97eb2aebeaSTakanori Watanabe return (USAGE); 98bcff2d91STakanori Watanabe 999c3471faSMarcelo Araujo if (strcmp(argv[4], "all") == 0) 100bcff2d91STakanori Watanabe policy = 0; 1019c3471faSMarcelo Araujo else if (strcmp(argv[4], "whitelist") == 0) 102bcff2d91STakanori Watanabe policy = 1; 1039c3471faSMarcelo Araujo else 104eb2aebeaSTakanori Watanabe return (USAGE); 105bcff2d91STakanori Watanabe 106bcff2d91STakanori Watanabe cp.le_scan_type = type; 107bcff2d91STakanori Watanabe cp.le_scan_interval = interval; 108bcff2d91STakanori Watanabe cp.own_address_type = adrtype; 109bcff2d91STakanori Watanabe cp.le_scan_window = window; 110bcff2d91STakanori Watanabe cp.scanning_filter_policy = policy; 111bcff2d91STakanori Watanabe n = sizeof(rp); 112bcff2d91STakanori Watanabe 113eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 114eb2aebeaSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 115eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 116eb2aebeaSTakanori Watanabe return (ERROR); 117eb2aebeaSTakanori Watanabe 118eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 119eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 120eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 121eb2aebeaSTakanori Watanabe return (FAILED); 122eb2aebeaSTakanori Watanabe } 123eb2aebeaSTakanori Watanabe 124eb2aebeaSTakanori Watanabe return (OK); 125bcff2d91STakanori Watanabe } 126bcff2d91STakanori Watanabe 1279c3471faSMarcelo Araujo static int 1289c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 129bcff2d91STakanori Watanabe { 130bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 131bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 132eb2aebeaSTakanori Watanabe int n, enable = 0; 133bcff2d91STakanori Watanabe 134bcff2d91STakanori Watanabe if (argc != 1) 135eb2aebeaSTakanori Watanabe return (USAGE); 136bcff2d91STakanori Watanabe 1379c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 138bcff2d91STakanori Watanabe enable = 1; 1399c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 140eb2aebeaSTakanori Watanabe return (USAGE); 1419c3471faSMarcelo Araujo 142bcff2d91STakanori Watanabe n = sizeof(rp); 143bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 144bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 145eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 146bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 147eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 148eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 149eb2aebeaSTakanori Watanabe return (ERROR); 150bcff2d91STakanori Watanabe 151eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 152eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 153eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 154eb2aebeaSTakanori Watanabe return (FAILED); 155eb2aebeaSTakanori Watanabe } 156bcff2d91STakanori Watanabe 157eb2aebeaSTakanori Watanabe fprintf(stdout, "LE Scan: %s\n", 158eb2aebeaSTakanori Watanabe enable? "Enabled" : "Disabled"); 159eb2aebeaSTakanori Watanabe 160eb2aebeaSTakanori Watanabe return (OK); 161bcff2d91STakanori Watanabe } 1629c3471faSMarcelo Araujo 1639c3471faSMarcelo Araujo static int 1649c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 165bcff2d91STakanori Watanabe { 166bcff2d91STakanori Watanabe char *buflast = buf + (*len); 167bcff2d91STakanori Watanabe char *curbuf = buf; 168bcff2d91STakanori Watanabe char *token,*lenpos; 169bcff2d91STakanori Watanabe int ch; 170bcff2d91STakanori Watanabe int datalen; 171bcff2d91STakanori Watanabe uint16_t value; 172bcff2d91STakanori Watanabe optreset = 1; 173bcff2d91STakanori Watanabe optind = 0; 174bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 175bcff2d91STakanori Watanabe switch(ch){ 176bcff2d91STakanori Watanabe case 'n': 177bcff2d91STakanori Watanabe datalen = strlen(optarg); 1789c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 179bcff2d91STakanori Watanabe goto done; 180bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 181bcff2d91STakanori Watanabe curbuf[1] = 8; 182bcff2d91STakanori Watanabe curbuf += 2; 183bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 184bcff2d91STakanori Watanabe curbuf += datalen; 185bcff2d91STakanori Watanabe break; 186bcff2d91STakanori Watanabe case 'f': 1879c3471faSMarcelo Araujo if (curbuf+3 > buflast) 188bcff2d91STakanori Watanabe goto done; 189bcff2d91STakanori Watanabe curbuf[0] = 2; 190bcff2d91STakanori Watanabe curbuf[1] = 1; 19132f32669SHans Petter Selasky curbuf[2] = (uint8_t)strtol(optarg, NULL, 16); 192bcff2d91STakanori Watanabe curbuf += 3; 193bcff2d91STakanori Watanabe break; 194bcff2d91STakanori Watanabe case 'u': 195bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 196bcff2d91STakanori Watanabe goto done; 19732f32669SHans Petter Selasky lenpos = curbuf; 198bcff2d91STakanori Watanabe curbuf[1] = 2; 199bcff2d91STakanori Watanabe *lenpos = 1; 200bcff2d91STakanori Watanabe curbuf += 2; 201bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 202bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 203bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 204bcff2d91STakanori Watanabe break; 205bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 206bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 207bcff2d91STakanori Watanabe curbuf += 2; 20832f32669SHans Petter Selasky *lenpos += 2; 209bcff2d91STakanori Watanabe } 210bcff2d91STakanori Watanabe 211bcff2d91STakanori Watanabe } 212bcff2d91STakanori Watanabe } 213bcff2d91STakanori Watanabe done: 214bcff2d91STakanori Watanabe *len = curbuf - buf; 215bcff2d91STakanori Watanabe 216eb2aebeaSTakanori Watanabe return (OK); 217bcff2d91STakanori Watanabe } 218bcff2d91STakanori Watanabe 2199c3471faSMarcelo Araujo static int 2209c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 221bcff2d91STakanori Watanabe { 222bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 223bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 224bcff2d91STakanori Watanabe int n; 225bcff2d91STakanori Watanabe int len; 226bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2279c3471faSMarcelo Araujo 228bcff2d91STakanori Watanabe len = sizeof(buf); 229bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 230bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 231bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 232bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 233bcff2d91STakanori Watanabe n = sizeof(rp); 234eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 235bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 236eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 237eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 238eb2aebeaSTakanori Watanabe return (ERROR); 239bcff2d91STakanori Watanabe 240eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 241eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 242eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 243eb2aebeaSTakanori Watanabe return (FAILED); 244eb2aebeaSTakanori Watanabe } 245bcff2d91STakanori Watanabe 246eb2aebeaSTakanori Watanabe return (OK); 247bcff2d91STakanori Watanabe } 248bcff2d91STakanori Watanabe 2499c3471faSMarcelo Araujo static int 2509c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 251bcff2d91STakanori Watanabe { 252bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 253bcff2d91STakanori Watanabe int n = sizeof(rp); 2549c3471faSMarcelo Araujo 255ea011491SHans Petter Selasky union { 256ea011491SHans Petter Selasky uint64_t raw; 257ea011491SHans Petter Selasky uint8_t octets[8]; 258ea011491SHans Petter Selasky } le_features; 259ea011491SHans Petter Selasky 260ea011491SHans Petter Selasky char buffer[2048]; 261ea011491SHans Petter Selasky 262ea011491SHans Petter Selasky if (hci_simple_request(s, 263bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 264bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 265ea011491SHans Petter Selasky (void *)&rp, &n) == ERROR) 266ea011491SHans Petter Selasky return (ERROR); 2679c3471faSMarcelo Araujo 268ea011491SHans Petter Selasky if (rp.status != 0x00) { 269ea011491SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 270ea011491SHans Petter Selasky hci_status2str(rp.status), rp.status); 271ea011491SHans Petter Selasky return (FAILED); 272ea011491SHans Petter Selasky } 273bcff2d91STakanori Watanabe 274ea011491SHans Petter Selasky le_features.raw = rp.le_features; 275ea011491SHans Petter Selasky 276ea011491SHans Petter Selasky fprintf(stdout, "LE Features: "); 277ea011491SHans Petter Selasky for(int i = 0; i < 8; i++) 278ea011491SHans Petter Selasky fprintf(stdout, " %#02x", le_features.octets[i]); 279ea011491SHans Petter Selasky fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets, 280ea011491SHans Petter Selasky buffer, sizeof(buffer))); 281ea011491SHans Petter Selasky fprintf(stdout, "\n"); 282ea011491SHans Petter Selasky 283eb2aebeaSTakanori Watanabe return (OK); 284bcff2d91STakanori Watanabe } 2859c3471faSMarcelo Araujo 2869c3471faSMarcelo Araujo static int 28721eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[]) 288bcff2d91STakanori Watanabe { 28921eefd31SHans Petter Selasky ng_hci_le_read_supported_states_rp rp; 290bcff2d91STakanori Watanabe int n = sizeof(rp); 2919c3471faSMarcelo Araujo 29221eefd31SHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE( 2939c3471faSMarcelo Araujo NG_HCI_OGF_LE, 29421eefd31SHans Petter Selasky NG_HCI_OCF_LE_READ_SUPPORTED_STATES), 29521eefd31SHans Petter Selasky (void *)&rp, &n) == ERROR) 29621eefd31SHans Petter Selasky return (ERROR); 2979c3471faSMarcelo Araujo 29821eefd31SHans Petter Selasky if (rp.status != 0x00) { 29921eefd31SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 30021eefd31SHans Petter Selasky hci_status2str(rp.status), rp.status); 30121eefd31SHans Petter Selasky return (FAILED); 30221eefd31SHans Petter Selasky } 303bcff2d91STakanori Watanabe 30421eefd31SHans Petter Selasky fprintf(stdout, "LE States: %jx\n", rp.le_states); 30521eefd31SHans Petter Selasky 30621eefd31SHans Petter Selasky return (OK); 307bcff2d91STakanori Watanabe } 308bcff2d91STakanori Watanabe 3099c3471faSMarcelo Araujo static int 3109c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 311bcff2d91STakanori Watanabe { 312bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 313bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 314eb2aebeaSTakanori Watanabe int i, n; 315bcff2d91STakanori Watanabe 316bcff2d91STakanori Watanabe n = sizeof(rp); 317bcff2d91STakanori Watanabe 318bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 319bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 320bcff2d91STakanori Watanabe mask >>= 8; 321bcff2d91STakanori Watanabe } 322eb2aebeaSTakanori Watanabe if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3239c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 324eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 325eb2aebeaSTakanori Watanabe return (ERROR); 326bcff2d91STakanori Watanabe 327eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 328eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 329eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 330eb2aebeaSTakanori Watanabe return (FAILED); 331eb2aebeaSTakanori Watanabe } 332eb2aebeaSTakanori Watanabe 333eb2aebeaSTakanori Watanabe return (OK); 334bcff2d91STakanori Watanabe } 335bcff2d91STakanori Watanabe 3369c3471faSMarcelo Araujo static int 3379c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 338bcff2d91STakanori Watanabe { 339bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 340bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 341eb2aebeaSTakanori Watanabe int i, n; 342bcff2d91STakanori Watanabe 343bcff2d91STakanori Watanabe n = sizeof(rp); 344bcff2d91STakanori Watanabe 345bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 346bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 347bcff2d91STakanori Watanabe mask >>= 8; 348bcff2d91STakanori Watanabe } 349eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3509c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 351eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 352eb2aebeaSTakanori Watanabe return (ERROR); 353bcff2d91STakanori Watanabe 354eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 355eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 356eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 357eb2aebeaSTakanori Watanabe return (FAILED); 358eb2aebeaSTakanori Watanabe } 359eb2aebeaSTakanori Watanabe 360eb2aebeaSTakanori Watanabe return (OK); 361bcff2d91STakanori Watanabe } 362bcff2d91STakanori Watanabe 3639c3471faSMarcelo Araujo static 3649c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 365bcff2d91STakanori Watanabe { 366eb2aebeaSTakanori Watanabe int result; 367eb2aebeaSTakanori Watanabe 3689c3471faSMarcelo Araujo if (argc != 1) 369eb2aebeaSTakanori Watanabe return (USAGE); 370bcff2d91STakanori Watanabe 371bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 372eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 373bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 374eb2aebeaSTakanori Watanabe if (result != OK) 375eb2aebeaSTakanori Watanabe return result; 376eb2aebeaSTakanori Watanabe result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 377eb2aebeaSTakanori Watanabe if (result == OK) { 378eb2aebeaSTakanori Watanabe fprintf(stdout, "LE enabled\n"); 379eb2aebeaSTakanori Watanabe return (OK); 380eb2aebeaSTakanori Watanabe } else 381eb2aebeaSTakanori Watanabe return result; 382eb2aebeaSTakanori Watanabe } else if (strcasecmp(argv[0], "disable") == 0) { 383eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 384eb2aebeaSTakanori Watanabe if (result == OK) { 385eb2aebeaSTakanori Watanabe fprintf(stdout, "LE disabled\n"); 386eb2aebeaSTakanori Watanabe return (OK); 387eb2aebeaSTakanori Watanabe } else 388eb2aebeaSTakanori Watanabe return result; 389eb2aebeaSTakanori Watanabe } else 390eb2aebeaSTakanori Watanabe return (USAGE); 391bcff2d91STakanori Watanabe } 392bcff2d91STakanori Watanabe 393c3f60abcSHans Petter Selasky static int 394c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[]) 395c3f60abcSHans Petter Selasky { 396c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_cp cp; 397c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_rp rp; 398c3f60abcSHans Petter Selasky int n, enable = 0; 399c3f60abcSHans Petter Selasky 400c3f60abcSHans Petter Selasky if (argc != 1) 401c3f60abcSHans Petter Selasky return USAGE; 402c3f60abcSHans Petter Selasky 403c3f60abcSHans Petter Selasky if (strcmp(argv[0], "enable") == 0) 404c3f60abcSHans Petter Selasky enable = 1; 405c3f60abcSHans Petter Selasky else if (strcmp(argv[0], "disable") != 0) 406c3f60abcSHans Petter Selasky return USAGE; 407c3f60abcSHans Petter Selasky 408c3f60abcSHans Petter Selasky n = sizeof(rp); 409c3f60abcSHans Petter Selasky cp.advertising_enable = enable; 410c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 411c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE), 412c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 413c3f60abcSHans Petter Selasky return (ERROR); 414c3f60abcSHans Petter Selasky 415c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 416c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 417c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 418c3f60abcSHans Petter Selasky return (FAILED); 419c3f60abcSHans Petter Selasky } 420c3f60abcSHans Petter Selasky fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled")); 421c3f60abcSHans Petter Selasky 422c3f60abcSHans Petter Selasky return (OK); 423c3f60abcSHans Petter Selasky } 424c3f60abcSHans Petter Selasky 425c3f60abcSHans Petter Selasky static int 426c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[]) 427c3f60abcSHans Petter Selasky { 428c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_cp cp; 429c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_rp rp; 430c3f60abcSHans Petter Selasky 431c3f60abcSHans Petter Selasky int n, ch; 432c3f60abcSHans Petter Selasky 433c3f60abcSHans Petter Selasky cp.advertising_interval_min = 0x800; 434c3f60abcSHans Petter Selasky cp.advertising_interval_max = 0x800; 435c3f60abcSHans Petter Selasky cp.advertising_type = 0; 436c3f60abcSHans Petter Selasky cp.own_address_type = 0; 437c3f60abcSHans Petter Selasky cp.direct_address_type = 0; 438c3f60abcSHans Petter Selasky 439c3f60abcSHans Petter Selasky cp.advertising_channel_map = 7; 440c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 0; 441c3f60abcSHans Petter Selasky 442c3f60abcSHans Petter Selasky optreset = 1; 443c3f60abcSHans Petter Selasky optind = 0; 444c3f60abcSHans Petter Selasky while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) { 445c3f60abcSHans Petter Selasky switch(ch) { 446c3f60abcSHans Petter Selasky case 'm': 447c3f60abcSHans Petter Selasky cp.advertising_interval_min = 448c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 449c3f60abcSHans Petter Selasky break; 450c3f60abcSHans Petter Selasky case 'M': 451c3f60abcSHans Petter Selasky cp.advertising_interval_max = 452c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 453c3f60abcSHans Petter Selasky break; 454c3f60abcSHans Petter Selasky case 't': 455c3f60abcSHans Petter Selasky cp.advertising_type = 456c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 457c3f60abcSHans Petter Selasky break; 458c3f60abcSHans Petter Selasky case 'o': 459c3f60abcSHans Petter Selasky cp.own_address_type = 460c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 461c3f60abcSHans Petter Selasky break; 462c3f60abcSHans Petter Selasky case 'p': 463c3f60abcSHans Petter Selasky cp.direct_address_type = 464c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 465c3f60abcSHans Petter Selasky break; 466c3f60abcSHans Petter Selasky case 'a': 467c3f60abcSHans Petter Selasky if (!bt_aton(optarg, &cp.direct_address)) { 468c3f60abcSHans Petter Selasky struct hostent *he = NULL; 469c3f60abcSHans Petter Selasky 470c3f60abcSHans Petter Selasky if ((he = bt_gethostbyname(optarg)) == NULL) 471c3f60abcSHans Petter Selasky return (USAGE); 472c3f60abcSHans Petter Selasky 473c3f60abcSHans Petter Selasky memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address)); 474c3f60abcSHans Petter Selasky } 475c3f60abcSHans Petter Selasky break; 476c3f60abcSHans Petter Selasky case 'c': 477c3f60abcSHans Petter Selasky cp.advertising_channel_map = 478c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 479c3f60abcSHans Petter Selasky break; 480c3f60abcSHans Petter Selasky case 'f': 481c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 482c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 483c3f60abcSHans Petter Selasky break; 484c3f60abcSHans Petter Selasky } 485c3f60abcSHans Petter Selasky } 486c3f60abcSHans Petter Selasky 487c3f60abcSHans Petter Selasky n = sizeof(rp); 488c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 489c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS), 490c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 491c3f60abcSHans Petter Selasky return (ERROR); 492c3f60abcSHans Petter Selasky 493c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 494c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 495c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 496c3f60abcSHans Petter Selasky return (FAILED); 497c3f60abcSHans Petter Selasky } 498c3f60abcSHans Petter Selasky 499c3f60abcSHans Petter Selasky return (OK); 500c3f60abcSHans Petter Selasky } 501c3f60abcSHans Petter Selasky 502c3f60abcSHans Petter Selasky static int 503c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[]) 504c3f60abcSHans Petter Selasky { 505c3f60abcSHans Petter Selasky ng_hci_le_read_advertising_channel_tx_power_rp rp; 506c3f60abcSHans Petter Selasky int n; 507c3f60abcSHans Petter Selasky 508c3f60abcSHans Petter Selasky n = sizeof(rp); 509c3f60abcSHans Petter Selasky 510c3f60abcSHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 511c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER), 512c3f60abcSHans Petter Selasky (void *)&rp, &n) == ERROR) 513c3f60abcSHans Petter Selasky return (ERROR); 514c3f60abcSHans Petter Selasky 515c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 516c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 517c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 518c3f60abcSHans Petter Selasky return (FAILED); 519c3f60abcSHans Petter Selasky } 520c3f60abcSHans Petter Selasky 521c3f60abcSHans Petter Selasky fprintf(stdout, "Advertising transmit power level: %d dBm\n", 522c3f60abcSHans Petter Selasky (int8_t)rp.transmit_power_level); 523c3f60abcSHans Petter Selasky 524c3f60abcSHans Petter Selasky return (OK); 525c3f60abcSHans Petter Selasky } 526c3f60abcSHans Petter Selasky 527c3f60abcSHans Petter Selasky static int 528c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[]) 529c3f60abcSHans Petter Selasky { 530c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_cp cp; 531c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_rp rp; 532c3f60abcSHans Petter Selasky int n, len; 533c3f60abcSHans Petter Selasky 534c3f60abcSHans Petter Selasky n = sizeof(rp); 535c3f60abcSHans Petter Selasky 536c3f60abcSHans Petter Selasky char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 537c3f60abcSHans Petter Selasky 538c3f60abcSHans Petter Selasky len = sizeof(buf); 539c3f60abcSHans Petter Selasky parse_param(argc, argv, buf, &len); 540c3f60abcSHans Petter Selasky memset(cp.advertising_data, 0, sizeof(cp.advertising_data)); 541c3f60abcSHans Petter Selasky cp.advertising_data_length = len; 5427b2f84dbSHans Petter Selasky memcpy(cp.advertising_data, buf, len); 543c3f60abcSHans Petter Selasky 544c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 545c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_DATA), 546c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 547c3f60abcSHans Petter Selasky return (ERROR); 548c3f60abcSHans Petter Selasky 549c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 550c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 551c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 552c3f60abcSHans Petter Selasky return (FAILED); 553c3f60abcSHans Petter Selasky } 554c3f60abcSHans Petter Selasky 555c3f60abcSHans Petter Selasky return (OK); 556c3f60abcSHans Petter Selasky } 557*1f5d883dSTakanori Watanabe static int 558*1f5d883dSTakanori Watanabe le_read_buffer_size(int s, int argc, char *argv[]) 559*1f5d883dSTakanori Watanabe { 560*1f5d883dSTakanori Watanabe union { 561*1f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp v1; 562*1f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp_v2 v2; 563*1f5d883dSTakanori Watanabe } rp; 564*1f5d883dSTakanori Watanabe 565*1f5d883dSTakanori Watanabe int n, ch; 566*1f5d883dSTakanori Watanabe uint8_t v; 567*1f5d883dSTakanori Watanabe uint16_t cmd; 568*1f5d883dSTakanori Watanabe 569*1f5d883dSTakanori Watanabe optreset = 1; 570*1f5d883dSTakanori Watanabe optind = 0; 571*1f5d883dSTakanori Watanabe 572*1f5d883dSTakanori Watanabe /* Default to version 1*/ 573*1f5d883dSTakanori Watanabe v = 1; 574*1f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE; 575*1f5d883dSTakanori Watanabe 576*1f5d883dSTakanori Watanabe while ((ch = getopt(argc, argv , "v:")) != -1) { 577*1f5d883dSTakanori Watanabe switch(ch) { 578*1f5d883dSTakanori Watanabe case 'v': 579*1f5d883dSTakanori Watanabe v = (uint8_t)strtol(optarg, NULL, 16); 580*1f5d883dSTakanori Watanabe if (v == 2) 581*1f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2; 582*1f5d883dSTakanori Watanabe else if (v > 2) 583*1f5d883dSTakanori Watanabe return (USAGE); 584*1f5d883dSTakanori Watanabe break; 585*1f5d883dSTakanori Watanabe default: 586*1f5d883dSTakanori Watanabe v = 1; 587*1f5d883dSTakanori Watanabe } 588*1f5d883dSTakanori Watanabe } 589*1f5d883dSTakanori Watanabe 590*1f5d883dSTakanori Watanabe n = sizeof(rp); 591*1f5d883dSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd), 592*1f5d883dSTakanori Watanabe (void *)&rp, &n) == ERROR) 593*1f5d883dSTakanori Watanabe return (ERROR); 594*1f5d883dSTakanori Watanabe 595*1f5d883dSTakanori Watanabe if (rp.v1.status != 0x00) { 596*1f5d883dSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 597*1f5d883dSTakanori Watanabe hci_status2str(rp.v1.status), rp.v1.status); 598*1f5d883dSTakanori Watanabe return (FAILED); 599*1f5d883dSTakanori Watanabe } 600*1f5d883dSTakanori Watanabe 601*1f5d883dSTakanori Watanabe fprintf(stdout, "ACL data packet length: %d\n", 602*1f5d883dSTakanori Watanabe rp.v1.hc_le_data_packet_length); 603*1f5d883dSTakanori Watanabe fprintf(stdout, "Number of ACL data packets: %d\n", 604*1f5d883dSTakanori Watanabe rp.v1.hc_total_num_le_data_packets); 605*1f5d883dSTakanori Watanabe 606*1f5d883dSTakanori Watanabe if (v == 2) { 607*1f5d883dSTakanori Watanabe fprintf(stdout, "ISO data packet length: %d\n", 608*1f5d883dSTakanori Watanabe rp.v2.hc_iso_data_packet_length); 609*1f5d883dSTakanori Watanabe fprintf(stdout, "Number of ISO data packets: %d\n", 610*1f5d883dSTakanori Watanabe rp.v2.hc_total_num_iso_data_packets); 611*1f5d883dSTakanori Watanabe } 612*1f5d883dSTakanori Watanabe 613*1f5d883dSTakanori Watanabe return (OK); 614*1f5d883dSTakanori Watanabe } 615c3f60abcSHans Petter Selasky 616bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 617bcff2d91STakanori Watanabe { 618bcff2d91STakanori Watanabe "le_enable", 619bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 620bcff2d91STakanori Watanabe "Enable LE event ", 621bcff2d91STakanori Watanabe &le_enable, 622bcff2d91STakanori Watanabe }, 623bcff2d91STakanori Watanabe { 624bcff2d91STakanori Watanabe "le_read_local_supported_features", 625bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 626bcff2d91STakanori Watanabe "read local supported features mask", 627bcff2d91STakanori Watanabe &le_read_local_supported_features, 628bcff2d91STakanori Watanabe }, 629bcff2d91STakanori Watanabe { 63021eefd31SHans Petter Selasky "le_read_supported_states", 63121eefd31SHans Petter Selasky "le_read_supported_states\n" 632bcff2d91STakanori Watanabe "read supported status" 633bcff2d91STakanori Watanabe , 63421eefd31SHans Petter Selasky &le_read_supported_states, 635bcff2d91STakanori Watanabe }, 636bcff2d91STakanori Watanabe { 637bcff2d91STakanori Watanabe "le_set_scan_response", 638bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 639bcff2d91STakanori Watanabe "set LE scan response data" 640bcff2d91STakanori Watanabe , 641bcff2d91STakanori Watanabe &le_set_scan_response, 642bcff2d91STakanori Watanabe }, 643bcff2d91STakanori Watanabe { 644bcff2d91STakanori Watanabe "le_set_scan_enable", 645bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 646bcff2d91STakanori Watanabe "enable or disable LE device scan", 647bcff2d91STakanori Watanabe &le_set_scan_enable 648bcff2d91STakanori Watanabe }, 649bcff2d91STakanori Watanabe { 650bcff2d91STakanori Watanabe "le_set_scan_param", 651bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 652bcff2d91STakanori Watanabe "set LE device scan parameter", 653bcff2d91STakanori Watanabe &le_set_scan_param 654bcff2d91STakanori Watanabe }, 655c3f60abcSHans Petter Selasky { 656c3f60abcSHans Petter Selasky "le_set_advertising_enable", 657c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 658c3f60abcSHans Petter Selasky "start or stop advertising", 659c3f60abcSHans Petter Selasky &le_set_advertising_enable 660c3f60abcSHans Petter Selasky }, 661c3f60abcSHans Petter Selasky { 662c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 663c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 664c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 665c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 666c3f60abcSHans Petter Selasky }, 667c3f60abcSHans Petter Selasky { 668c3f60abcSHans Petter Selasky "le_set_advertising_param", 669c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 670c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 671c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 672c3f60abcSHans Petter Selasky "[-a peer_address]\n" 673c3f60abcSHans Petter Selasky "set LE device advertising parameters", 674c3f60abcSHans Petter Selasky &le_set_advertising_param 675c3f60abcSHans Petter Selasky }, 676c3f60abcSHans Petter Selasky { 677c3f60abcSHans Petter Selasky "le_set_advertising_data", 678c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 679c3f60abcSHans Petter Selasky "set LE device advertising packed data", 680c3f60abcSHans Petter Selasky &le_set_advertising_data 681c3f60abcSHans Petter Selasky }, 682*1f5d883dSTakanori Watanabe { 683*1f5d883dSTakanori Watanabe "le_read_buffer_size", 684*1f5d883dSTakanori Watanabe "le_read_buffer_size [-v 1|2]\n" 685*1f5d883dSTakanori Watanabe "Read the maximum size of ACL and ISO data packets", 686*1f5d883dSTakanori Watanabe &le_read_buffer_size 687*1f5d883dSTakanori Watanabe }, 688bcff2d91STakanori Watanabe }; 689