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; 72*eb2aebeaSTakanori 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) 78*eb2aebeaSTakanori 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 85*eb2aebeaSTakanori 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 97*eb2aebeaSTakanori 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 104*eb2aebeaSTakanori 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 113*eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 114*eb2aebeaSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 115*eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 116*eb2aebeaSTakanori Watanabe return (ERROR); 117*eb2aebeaSTakanori Watanabe 118*eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 119*eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 120*eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 121*eb2aebeaSTakanori Watanabe return (FAILED); 122*eb2aebeaSTakanori Watanabe } 123*eb2aebeaSTakanori Watanabe 124*eb2aebeaSTakanori 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; 132*eb2aebeaSTakanori Watanabe int n, enable = 0; 133bcff2d91STakanori Watanabe 134bcff2d91STakanori Watanabe if (argc != 1) 135*eb2aebeaSTakanori 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) 140*eb2aebeaSTakanori Watanabe return (USAGE); 1419c3471faSMarcelo Araujo 142bcff2d91STakanori Watanabe n = sizeof(rp); 143bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 144bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 145*eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 146bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 147*eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 148*eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 149*eb2aebeaSTakanori Watanabe return (ERROR); 150bcff2d91STakanori Watanabe 151*eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 152*eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 153*eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 154*eb2aebeaSTakanori Watanabe return (FAILED); 155*eb2aebeaSTakanori Watanabe } 156bcff2d91STakanori Watanabe 157*eb2aebeaSTakanori Watanabe fprintf(stdout, "LE Scan: %s\n", 158*eb2aebeaSTakanori Watanabe enable? "Enabled" : "Disabled"); 159*eb2aebeaSTakanori Watanabe 160*eb2aebeaSTakanori 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 216*eb2aebeaSTakanori 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); 234*eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 235bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 236*eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 237*eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 238*eb2aebeaSTakanori Watanabe return (ERROR); 239bcff2d91STakanori Watanabe 240*eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 241*eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 242*eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 243*eb2aebeaSTakanori Watanabe return (FAILED); 244*eb2aebeaSTakanori Watanabe } 245bcff2d91STakanori Watanabe 246*eb2aebeaSTakanori 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 283*eb2aebeaSTakanori 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; 314*eb2aebeaSTakanori 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 } 322*eb2aebeaSTakanori Watanabe if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3239c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 324*eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 325*eb2aebeaSTakanori Watanabe return (ERROR); 326bcff2d91STakanori Watanabe 327*eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 328*eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 329*eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 330*eb2aebeaSTakanori Watanabe return (FAILED); 331*eb2aebeaSTakanori Watanabe } 332*eb2aebeaSTakanori Watanabe 333*eb2aebeaSTakanori 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; 341*eb2aebeaSTakanori 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 } 349*eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3509c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 351*eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 352*eb2aebeaSTakanori Watanabe return (ERROR); 353bcff2d91STakanori Watanabe 354*eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 355*eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 356*eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 357*eb2aebeaSTakanori Watanabe return (FAILED); 358*eb2aebeaSTakanori Watanabe } 359*eb2aebeaSTakanori Watanabe 360*eb2aebeaSTakanori Watanabe return (OK); 361bcff2d91STakanori Watanabe } 362bcff2d91STakanori Watanabe 3639c3471faSMarcelo Araujo static 3649c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 365bcff2d91STakanori Watanabe { 366*eb2aebeaSTakanori Watanabe int result; 367*eb2aebeaSTakanori Watanabe 3689c3471faSMarcelo Araujo if (argc != 1) 369*eb2aebeaSTakanori Watanabe return (USAGE); 370bcff2d91STakanori Watanabe 371bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 372*eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 373bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 374*eb2aebeaSTakanori Watanabe if (result != OK) 375*eb2aebeaSTakanori Watanabe return result; 376*eb2aebeaSTakanori Watanabe result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 377*eb2aebeaSTakanori Watanabe if (result == OK) { 378*eb2aebeaSTakanori Watanabe fprintf(stdout, "LE enabled\n"); 379*eb2aebeaSTakanori Watanabe return (OK); 380*eb2aebeaSTakanori Watanabe } else 381*eb2aebeaSTakanori Watanabe return result; 382*eb2aebeaSTakanori Watanabe } else if (strcasecmp(argv[0], "disable") == 0) { 383*eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 384*eb2aebeaSTakanori Watanabe if (result == OK) { 385*eb2aebeaSTakanori Watanabe fprintf(stdout, "LE disabled\n"); 386*eb2aebeaSTakanori Watanabe return (OK); 387*eb2aebeaSTakanori Watanabe } else 388*eb2aebeaSTakanori Watanabe return result; 389*eb2aebeaSTakanori Watanabe } else 390*eb2aebeaSTakanori 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 } 557c3f60abcSHans Petter Selasky 558bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 559bcff2d91STakanori Watanabe { 560bcff2d91STakanori Watanabe "le_enable", 561bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 562bcff2d91STakanori Watanabe "Enable LE event ", 563bcff2d91STakanori Watanabe &le_enable, 564bcff2d91STakanori Watanabe }, 565bcff2d91STakanori Watanabe { 566bcff2d91STakanori Watanabe "le_read_local_supported_features", 567bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 568bcff2d91STakanori Watanabe "read local supported features mask", 569bcff2d91STakanori Watanabe &le_read_local_supported_features, 570bcff2d91STakanori Watanabe }, 571bcff2d91STakanori Watanabe { 57221eefd31SHans Petter Selasky "le_read_supported_states", 57321eefd31SHans Petter Selasky "le_read_supported_states\n" 574bcff2d91STakanori Watanabe "read supported status" 575bcff2d91STakanori Watanabe , 57621eefd31SHans Petter Selasky &le_read_supported_states, 577bcff2d91STakanori Watanabe }, 578bcff2d91STakanori Watanabe { 579bcff2d91STakanori Watanabe "le_set_scan_response", 580bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 581bcff2d91STakanori Watanabe "set LE scan response data" 582bcff2d91STakanori Watanabe , 583bcff2d91STakanori Watanabe &le_set_scan_response, 584bcff2d91STakanori Watanabe }, 585bcff2d91STakanori Watanabe { 586bcff2d91STakanori Watanabe "le_set_scan_enable", 587bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 588bcff2d91STakanori Watanabe "enable or disable LE device scan", 589bcff2d91STakanori Watanabe &le_set_scan_enable 590bcff2d91STakanori Watanabe }, 591bcff2d91STakanori Watanabe { 592bcff2d91STakanori Watanabe "le_set_scan_param", 593bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 594bcff2d91STakanori Watanabe "set LE device scan parameter", 595bcff2d91STakanori Watanabe &le_set_scan_param 596bcff2d91STakanori Watanabe }, 597c3f60abcSHans Petter Selasky { 598c3f60abcSHans Petter Selasky "le_set_advertising_enable", 599c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 600c3f60abcSHans Petter Selasky "start or stop advertising", 601c3f60abcSHans Petter Selasky &le_set_advertising_enable 602c3f60abcSHans Petter Selasky }, 603c3f60abcSHans Petter Selasky { 604c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 605c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 606c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 607c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 608c3f60abcSHans Petter Selasky }, 609c3f60abcSHans Petter Selasky { 610c3f60abcSHans Petter Selasky "le_set_advertising_param", 611c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 612c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 613c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 614c3f60abcSHans Petter Selasky "[-a peer_address]\n" 615c3f60abcSHans Petter Selasky "set LE device advertising parameters", 616c3f60abcSHans Petter Selasky &le_set_advertising_param 617c3f60abcSHans Petter Selasky }, 618c3f60abcSHans Petter Selasky { 619c3f60abcSHans Petter Selasky "le_set_advertising_data", 620c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 621c3f60abcSHans Petter Selasky "set LE device advertising packed data", 622c3f60abcSHans Petter Selasky &le_set_advertising_data 623c3f60abcSHans Petter Selasky }, 624bcff2d91STakanori Watanabe }; 625