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> 429287f06dSTakanori Watanabe #include <stdbool.h> 43bcff2d91STakanori Watanabe #include <stdio.h> 44bcff2d91STakanori Watanabe #include <stdlib.h> 45bcff2d91STakanori Watanabe #include <string.h> 46bcff2d91STakanori Watanabe #include <unistd.h> 474cae2db2STakanori Watanabe #include <stdint.h> 48bcff2d91STakanori Watanabe #define L2CAP_SOCKET_CHECKED 49bcff2d91STakanori Watanabe #include <bluetooth.h> 50bcff2d91STakanori Watanabe #include "hccontrol.h" 519c3471faSMarcelo Araujo 52bcff2d91STakanori Watanabe static int le_set_scan_param(int s, int argc, char *argv[]); 53bcff2d91STakanori Watanabe static int le_set_scan_enable(int s, int argc, char *argv[]); 54bcff2d91STakanori Watanabe static int parse_param(int argc, char *argv[], char *buf, int *len); 55bcff2d91STakanori Watanabe static int le_set_scan_response(int s, int argc, char *argv[]); 5621eefd31SHans Petter Selasky static int le_read_supported_states(int s, int argc, char *argv[]); 57bcff2d91STakanori Watanabe static int le_read_local_supported_features(int s, int argc ,char *argv[]); 58bcff2d91STakanori Watanabe static int set_le_event_mask(int s, uint64_t mask); 59bcff2d91STakanori Watanabe static int set_event_mask(int s, uint64_t mask); 60bcff2d91STakanori Watanabe static int le_enable(int s, int argc, char *argv[]); 61c3f60abcSHans Petter Selasky static int le_set_advertising_enable(int s, int argc, char *argv[]); 62c3f60abcSHans Petter Selasky static int le_set_advertising_param(int s, int argc, char *argv[]); 63c3f60abcSHans Petter Selasky static int le_read_advertising_channel_tx_power(int s, int argc, char *argv[]); 649287f06dSTakanori Watanabe static int le_scan(int s, int argc, char *argv[]); 659287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose); 66*11fb4bdbSTakanori Watanabe static int le_read_white_list_size(int s, int argc, char *argv[]); 67*11fb4bdbSTakanori Watanabe static int le_clear_white_list(int s, int argc, char *argv[]); 68*11fb4bdbSTakanori Watanabe static int le_add_device_to_white_list(int s, int argc, char *argv[]); 69*11fb4bdbSTakanori Watanabe static int le_remove_device_from_white_list(int s, int argc, char *argv[]); 70bcff2d91STakanori Watanabe 719c3471faSMarcelo Araujo static int 729c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[]) 73bcff2d91STakanori Watanabe { 74bcff2d91STakanori Watanabe int type; 75bcff2d91STakanori Watanabe int interval; 76bcff2d91STakanori Watanabe int window; 77bcff2d91STakanori Watanabe int adrtype; 78bcff2d91STakanori Watanabe int policy; 79eb2aebeaSTakanori Watanabe int n; 80bcff2d91STakanori Watanabe 81bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_cp cp; 82bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_rp rp; 83bcff2d91STakanori Watanabe 849c3471faSMarcelo Araujo if (argc != 5) 85eb2aebeaSTakanori Watanabe return (USAGE); 86bcff2d91STakanori Watanabe 879c3471faSMarcelo Araujo if (strcmp(argv[0], "active") == 0) 88bcff2d91STakanori Watanabe type = 1; 899c3471faSMarcelo Araujo else if (strcmp(argv[0], "passive") == 0) 90bcff2d91STakanori Watanabe type = 0; 919c3471faSMarcelo Araujo else 92eb2aebeaSTakanori Watanabe return (USAGE); 93bcff2d91STakanori Watanabe 94bcff2d91STakanori Watanabe interval = (int)(atof(argv[1])/0.625); 95bcff2d91STakanori Watanabe interval = (interval < 4)? 4: interval; 96bcff2d91STakanori Watanabe window = (int)(atof(argv[2])/0.625); 97bcff2d91STakanori Watanabe window = (window < 4) ? 4 : interval; 98bcff2d91STakanori Watanabe 999c3471faSMarcelo Araujo if (strcmp(argv[3], "public") == 0) 100bcff2d91STakanori Watanabe adrtype = 0; 10105e526fbSTakanori Watanabe else if (strcmp(argv[3], "random") == 0) 102bcff2d91STakanori Watanabe adrtype = 1; 1039c3471faSMarcelo Araujo else 104eb2aebeaSTakanori Watanabe return (USAGE); 105bcff2d91STakanori Watanabe 1069c3471faSMarcelo Araujo if (strcmp(argv[4], "all") == 0) 107bcff2d91STakanori Watanabe policy = 0; 1089c3471faSMarcelo Araujo else if (strcmp(argv[4], "whitelist") == 0) 109bcff2d91STakanori Watanabe policy = 1; 1109c3471faSMarcelo Araujo else 111eb2aebeaSTakanori Watanabe return (USAGE); 112bcff2d91STakanori Watanabe 113bcff2d91STakanori Watanabe cp.le_scan_type = type; 114bcff2d91STakanori Watanabe cp.le_scan_interval = interval; 115bcff2d91STakanori Watanabe cp.own_address_type = adrtype; 116bcff2d91STakanori Watanabe cp.le_scan_window = window; 117bcff2d91STakanori Watanabe cp.scanning_filter_policy = policy; 118bcff2d91STakanori Watanabe n = sizeof(rp); 119bcff2d91STakanori Watanabe 120eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 121eb2aebeaSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 122eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 123eb2aebeaSTakanori Watanabe return (ERROR); 124eb2aebeaSTakanori Watanabe 125eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 126eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 127eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 128eb2aebeaSTakanori Watanabe return (FAILED); 129eb2aebeaSTakanori Watanabe } 130eb2aebeaSTakanori Watanabe 131eb2aebeaSTakanori Watanabe return (OK); 132bcff2d91STakanori Watanabe } 133bcff2d91STakanori Watanabe 1349c3471faSMarcelo Araujo static int 1359c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 136bcff2d91STakanori Watanabe { 137bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 138bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 139eb2aebeaSTakanori Watanabe int n, enable = 0; 140bcff2d91STakanori Watanabe 141bcff2d91STakanori Watanabe if (argc != 1) 142eb2aebeaSTakanori Watanabe return (USAGE); 143bcff2d91STakanori Watanabe 1449c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 145bcff2d91STakanori Watanabe enable = 1; 1469c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 147eb2aebeaSTakanori Watanabe return (USAGE); 1489c3471faSMarcelo Araujo 149bcff2d91STakanori Watanabe n = sizeof(rp); 150bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 151bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 152eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 153bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 154eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 155eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 156eb2aebeaSTakanori Watanabe return (ERROR); 157bcff2d91STakanori Watanabe 158eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 159eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 160eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 161eb2aebeaSTakanori Watanabe return (FAILED); 162eb2aebeaSTakanori Watanabe } 163bcff2d91STakanori Watanabe 164eb2aebeaSTakanori Watanabe fprintf(stdout, "LE Scan: %s\n", 165eb2aebeaSTakanori Watanabe enable? "Enabled" : "Disabled"); 166eb2aebeaSTakanori Watanabe 167eb2aebeaSTakanori Watanabe return (OK); 168bcff2d91STakanori Watanabe } 1699c3471faSMarcelo Araujo 1709c3471faSMarcelo Araujo static int 1719c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 172bcff2d91STakanori Watanabe { 173bcff2d91STakanori Watanabe char *buflast = buf + (*len); 174bcff2d91STakanori Watanabe char *curbuf = buf; 175bcff2d91STakanori Watanabe char *token,*lenpos; 176bcff2d91STakanori Watanabe int ch; 177bcff2d91STakanori Watanabe int datalen; 178bcff2d91STakanori Watanabe uint16_t value; 179bcff2d91STakanori Watanabe optreset = 1; 180bcff2d91STakanori Watanabe optind = 0; 181bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 182bcff2d91STakanori Watanabe switch(ch){ 183bcff2d91STakanori Watanabe case 'n': 184bcff2d91STakanori Watanabe datalen = strlen(optarg); 1859c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 186bcff2d91STakanori Watanabe goto done; 187bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 188bcff2d91STakanori Watanabe curbuf[1] = 8; 189bcff2d91STakanori Watanabe curbuf += 2; 190bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 191bcff2d91STakanori Watanabe curbuf += datalen; 192bcff2d91STakanori Watanabe break; 193bcff2d91STakanori Watanabe case 'f': 1949c3471faSMarcelo Araujo if (curbuf+3 > buflast) 195bcff2d91STakanori Watanabe goto done; 196bcff2d91STakanori Watanabe curbuf[0] = 2; 197bcff2d91STakanori Watanabe curbuf[1] = 1; 19832f32669SHans Petter Selasky curbuf[2] = (uint8_t)strtol(optarg, NULL, 16); 199bcff2d91STakanori Watanabe curbuf += 3; 200bcff2d91STakanori Watanabe break; 201bcff2d91STakanori Watanabe case 'u': 202bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 203bcff2d91STakanori Watanabe goto done; 20432f32669SHans Petter Selasky lenpos = curbuf; 205bcff2d91STakanori Watanabe curbuf[1] = 2; 206bcff2d91STakanori Watanabe *lenpos = 1; 207bcff2d91STakanori Watanabe curbuf += 2; 208bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 209bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 210bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 211bcff2d91STakanori Watanabe break; 212bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 213bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 214bcff2d91STakanori Watanabe curbuf += 2; 21532f32669SHans Petter Selasky *lenpos += 2; 216bcff2d91STakanori Watanabe } 217bcff2d91STakanori Watanabe 218bcff2d91STakanori Watanabe } 219bcff2d91STakanori Watanabe } 220bcff2d91STakanori Watanabe done: 221bcff2d91STakanori Watanabe *len = curbuf - buf; 222bcff2d91STakanori Watanabe 223eb2aebeaSTakanori Watanabe return (OK); 224bcff2d91STakanori Watanabe } 225bcff2d91STakanori Watanabe 2269c3471faSMarcelo Araujo static int 2279c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 228bcff2d91STakanori Watanabe { 229bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 230bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 231bcff2d91STakanori Watanabe int n; 232bcff2d91STakanori Watanabe int len; 233bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2349c3471faSMarcelo Araujo 235bcff2d91STakanori Watanabe len = sizeof(buf); 236bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 237bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 238bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 239bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 240bcff2d91STakanori Watanabe n = sizeof(rp); 241eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 242bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 243eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 244eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 245eb2aebeaSTakanori Watanabe return (ERROR); 246bcff2d91STakanori Watanabe 247eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 248eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 249eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 250eb2aebeaSTakanori Watanabe return (FAILED); 251eb2aebeaSTakanori Watanabe } 252bcff2d91STakanori Watanabe 253eb2aebeaSTakanori Watanabe return (OK); 254bcff2d91STakanori Watanabe } 255bcff2d91STakanori Watanabe 2569c3471faSMarcelo Araujo static int 2579c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 258bcff2d91STakanori Watanabe { 259bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 260bcff2d91STakanori Watanabe int n = sizeof(rp); 2619c3471faSMarcelo Araujo 262ea011491SHans Petter Selasky union { 263ea011491SHans Petter Selasky uint64_t raw; 264ea011491SHans Petter Selasky uint8_t octets[8]; 265ea011491SHans Petter Selasky } le_features; 266ea011491SHans Petter Selasky 267ea011491SHans Petter Selasky char buffer[2048]; 268ea011491SHans Petter Selasky 269ea011491SHans Petter Selasky if (hci_simple_request(s, 270bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 271bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 272ea011491SHans Petter Selasky (void *)&rp, &n) == ERROR) 273ea011491SHans Petter Selasky return (ERROR); 2749c3471faSMarcelo Araujo 275ea011491SHans Petter Selasky if (rp.status != 0x00) { 276ea011491SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 277ea011491SHans Petter Selasky hci_status2str(rp.status), rp.status); 278ea011491SHans Petter Selasky return (FAILED); 279ea011491SHans Petter Selasky } 280bcff2d91STakanori Watanabe 281ea011491SHans Petter Selasky le_features.raw = rp.le_features; 282ea011491SHans Petter Selasky 283ea011491SHans Petter Selasky fprintf(stdout, "LE Features: "); 284ea011491SHans Petter Selasky for(int i = 0; i < 8; i++) 285ea011491SHans Petter Selasky fprintf(stdout, " %#02x", le_features.octets[i]); 286ea011491SHans Petter Selasky fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets, 287ea011491SHans Petter Selasky buffer, sizeof(buffer))); 288ea011491SHans Petter Selasky fprintf(stdout, "\n"); 289ea011491SHans Petter Selasky 290eb2aebeaSTakanori Watanabe return (OK); 291bcff2d91STakanori Watanabe } 2929c3471faSMarcelo Araujo 2939c3471faSMarcelo Araujo static int 29421eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[]) 295bcff2d91STakanori Watanabe { 29621eefd31SHans Petter Selasky ng_hci_le_read_supported_states_rp rp; 297bcff2d91STakanori Watanabe int n = sizeof(rp); 2989c3471faSMarcelo Araujo 29921eefd31SHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE( 3009c3471faSMarcelo Araujo NG_HCI_OGF_LE, 30121eefd31SHans Petter Selasky NG_HCI_OCF_LE_READ_SUPPORTED_STATES), 30221eefd31SHans Petter Selasky (void *)&rp, &n) == ERROR) 30321eefd31SHans Petter Selasky return (ERROR); 3049c3471faSMarcelo Araujo 30521eefd31SHans Petter Selasky if (rp.status != 0x00) { 30621eefd31SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 30721eefd31SHans Petter Selasky hci_status2str(rp.status), rp.status); 30821eefd31SHans Petter Selasky return (FAILED); 30921eefd31SHans Petter Selasky } 310bcff2d91STakanori Watanabe 31121eefd31SHans Petter Selasky fprintf(stdout, "LE States: %jx\n", rp.le_states); 31221eefd31SHans Petter Selasky 31321eefd31SHans Petter Selasky return (OK); 314bcff2d91STakanori Watanabe } 315bcff2d91STakanori Watanabe 3169c3471faSMarcelo Araujo static int 3179c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 318bcff2d91STakanori Watanabe { 319bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 320bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 321eb2aebeaSTakanori Watanabe int i, n; 322bcff2d91STakanori Watanabe 323bcff2d91STakanori Watanabe n = sizeof(rp); 324bcff2d91STakanori Watanabe 325bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 326bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 327bcff2d91STakanori Watanabe mask >>= 8; 328bcff2d91STakanori Watanabe } 329eb2aebeaSTakanori Watanabe if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3309c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 331eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 332eb2aebeaSTakanori Watanabe return (ERROR); 333bcff2d91STakanori Watanabe 334eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 335eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 336eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 337eb2aebeaSTakanori Watanabe return (FAILED); 338eb2aebeaSTakanori Watanabe } 339eb2aebeaSTakanori Watanabe 340eb2aebeaSTakanori Watanabe return (OK); 341bcff2d91STakanori Watanabe } 342bcff2d91STakanori Watanabe 3439c3471faSMarcelo Araujo static int 3449c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 345bcff2d91STakanori Watanabe { 346bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 347bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 348eb2aebeaSTakanori Watanabe int i, n; 349bcff2d91STakanori Watanabe 350bcff2d91STakanori Watanabe n = sizeof(rp); 351bcff2d91STakanori Watanabe 352bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 353bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 354bcff2d91STakanori Watanabe mask >>= 8; 355bcff2d91STakanori Watanabe } 356eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3579c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 358eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 359eb2aebeaSTakanori Watanabe return (ERROR); 360bcff2d91STakanori Watanabe 361eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 362eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 363eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 364eb2aebeaSTakanori Watanabe return (FAILED); 365eb2aebeaSTakanori Watanabe } 366eb2aebeaSTakanori Watanabe 367eb2aebeaSTakanori Watanabe return (OK); 368bcff2d91STakanori Watanabe } 369bcff2d91STakanori Watanabe 3709c3471faSMarcelo Araujo static 3719c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 372bcff2d91STakanori Watanabe { 373eb2aebeaSTakanori Watanabe int result; 374eb2aebeaSTakanori Watanabe 3759c3471faSMarcelo Araujo if (argc != 1) 376eb2aebeaSTakanori Watanabe return (USAGE); 377bcff2d91STakanori Watanabe 378bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 379eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 380bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 381eb2aebeaSTakanori Watanabe if (result != OK) 382eb2aebeaSTakanori Watanabe return result; 383eb2aebeaSTakanori Watanabe result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 384eb2aebeaSTakanori Watanabe if (result == OK) { 385eb2aebeaSTakanori Watanabe fprintf(stdout, "LE enabled\n"); 386eb2aebeaSTakanori Watanabe return (OK); 387eb2aebeaSTakanori Watanabe } else 388eb2aebeaSTakanori Watanabe return result; 389eb2aebeaSTakanori Watanabe } else if (strcasecmp(argv[0], "disable") == 0) { 390eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 391eb2aebeaSTakanori Watanabe if (result == OK) { 392eb2aebeaSTakanori Watanabe fprintf(stdout, "LE disabled\n"); 393eb2aebeaSTakanori Watanabe return (OK); 394eb2aebeaSTakanori Watanabe } else 395eb2aebeaSTakanori Watanabe return result; 396eb2aebeaSTakanori Watanabe } else 397eb2aebeaSTakanori Watanabe return (USAGE); 398bcff2d91STakanori Watanabe } 399bcff2d91STakanori Watanabe 400c3f60abcSHans Petter Selasky static int 401c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[]) 402c3f60abcSHans Petter Selasky { 403c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_cp cp; 404c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_rp rp; 405c3f60abcSHans Petter Selasky int n, enable = 0; 406c3f60abcSHans Petter Selasky 407c3f60abcSHans Petter Selasky if (argc != 1) 408c3f60abcSHans Petter Selasky return USAGE; 409c3f60abcSHans Petter Selasky 410c3f60abcSHans Petter Selasky if (strcmp(argv[0], "enable") == 0) 411c3f60abcSHans Petter Selasky enable = 1; 412c3f60abcSHans Petter Selasky else if (strcmp(argv[0], "disable") != 0) 413c3f60abcSHans Petter Selasky return USAGE; 414c3f60abcSHans Petter Selasky 415c3f60abcSHans Petter Selasky n = sizeof(rp); 416c3f60abcSHans Petter Selasky cp.advertising_enable = enable; 417c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 418c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE), 419c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 420c3f60abcSHans Petter Selasky return (ERROR); 421c3f60abcSHans Petter Selasky 422c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 423c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 424c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 425c3f60abcSHans Petter Selasky return (FAILED); 426c3f60abcSHans Petter Selasky } 427c3f60abcSHans Petter Selasky fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled")); 428c3f60abcSHans Petter Selasky 429c3f60abcSHans Petter Selasky return (OK); 430c3f60abcSHans Petter Selasky } 431c3f60abcSHans Petter Selasky 432c3f60abcSHans Petter Selasky static int 433c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[]) 434c3f60abcSHans Petter Selasky { 435c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_cp cp; 436c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_rp rp; 437c3f60abcSHans Petter Selasky 438c3f60abcSHans Petter Selasky int n, ch; 439c3f60abcSHans Petter Selasky 440c3f60abcSHans Petter Selasky cp.advertising_interval_min = 0x800; 441c3f60abcSHans Petter Selasky cp.advertising_interval_max = 0x800; 442c3f60abcSHans Petter Selasky cp.advertising_type = 0; 443c3f60abcSHans Petter Selasky cp.own_address_type = 0; 444c3f60abcSHans Petter Selasky cp.direct_address_type = 0; 445c3f60abcSHans Petter Selasky 446c3f60abcSHans Petter Selasky cp.advertising_channel_map = 7; 447c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 0; 448c3f60abcSHans Petter Selasky 449c3f60abcSHans Petter Selasky optreset = 1; 450c3f60abcSHans Petter Selasky optind = 0; 451c3f60abcSHans Petter Selasky while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) { 452c3f60abcSHans Petter Selasky switch(ch) { 453c3f60abcSHans Petter Selasky case 'm': 454c3f60abcSHans Petter Selasky cp.advertising_interval_min = 455c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 456c3f60abcSHans Petter Selasky break; 457c3f60abcSHans Petter Selasky case 'M': 458c3f60abcSHans Petter Selasky cp.advertising_interval_max = 459c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 460c3f60abcSHans Petter Selasky break; 461c3f60abcSHans Petter Selasky case 't': 462c3f60abcSHans Petter Selasky cp.advertising_type = 463c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 464c3f60abcSHans Petter Selasky break; 465c3f60abcSHans Petter Selasky case 'o': 466c3f60abcSHans Petter Selasky cp.own_address_type = 467c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 468c3f60abcSHans Petter Selasky break; 469c3f60abcSHans Petter Selasky case 'p': 470c3f60abcSHans Petter Selasky cp.direct_address_type = 471c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 472c3f60abcSHans Petter Selasky break; 473c3f60abcSHans Petter Selasky case 'a': 474c3f60abcSHans Petter Selasky if (!bt_aton(optarg, &cp.direct_address)) { 475c3f60abcSHans Petter Selasky struct hostent *he = NULL; 476c3f60abcSHans Petter Selasky 477c3f60abcSHans Petter Selasky if ((he = bt_gethostbyname(optarg)) == NULL) 478c3f60abcSHans Petter Selasky return (USAGE); 479c3f60abcSHans Petter Selasky 480c3f60abcSHans Petter Selasky memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address)); 481c3f60abcSHans Petter Selasky } 482c3f60abcSHans Petter Selasky break; 483c3f60abcSHans Petter Selasky case 'c': 484c3f60abcSHans Petter Selasky cp.advertising_channel_map = 485c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 486c3f60abcSHans Petter Selasky break; 487c3f60abcSHans Petter Selasky case 'f': 488c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 489c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 490c3f60abcSHans Petter Selasky break; 491c3f60abcSHans Petter Selasky } 492c3f60abcSHans Petter Selasky } 493c3f60abcSHans Petter Selasky 494c3f60abcSHans Petter Selasky n = sizeof(rp); 495c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 496c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS), 497c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 498c3f60abcSHans Petter Selasky return (ERROR); 499c3f60abcSHans Petter Selasky 500c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 501c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 502c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 503c3f60abcSHans Petter Selasky return (FAILED); 504c3f60abcSHans Petter Selasky } 505c3f60abcSHans Petter Selasky 506c3f60abcSHans Petter Selasky return (OK); 507c3f60abcSHans Petter Selasky } 508c3f60abcSHans Petter Selasky 509c3f60abcSHans Petter Selasky static int 510c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[]) 511c3f60abcSHans Petter Selasky { 512c3f60abcSHans Petter Selasky ng_hci_le_read_advertising_channel_tx_power_rp rp; 513c3f60abcSHans Petter Selasky int n; 514c3f60abcSHans Petter Selasky 515c3f60abcSHans Petter Selasky n = sizeof(rp); 516c3f60abcSHans Petter Selasky 517c3f60abcSHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 518c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER), 519c3f60abcSHans Petter Selasky (void *)&rp, &n) == ERROR) 520c3f60abcSHans Petter Selasky return (ERROR); 521c3f60abcSHans Petter Selasky 522c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 523c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 524c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 525c3f60abcSHans Petter Selasky return (FAILED); 526c3f60abcSHans Petter Selasky } 527c3f60abcSHans Petter Selasky 528c3f60abcSHans Petter Selasky fprintf(stdout, "Advertising transmit power level: %d dBm\n", 529c3f60abcSHans Petter Selasky (int8_t)rp.transmit_power_level); 530c3f60abcSHans Petter Selasky 531c3f60abcSHans Petter Selasky return (OK); 532c3f60abcSHans Petter Selasky } 533c3f60abcSHans Petter Selasky 534c3f60abcSHans Petter Selasky static int 535c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[]) 536c3f60abcSHans Petter Selasky { 537c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_cp cp; 538c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_rp rp; 539c3f60abcSHans Petter Selasky int n, len; 540c3f60abcSHans Petter Selasky 541c3f60abcSHans Petter Selasky n = sizeof(rp); 542c3f60abcSHans Petter Selasky 543c3f60abcSHans Petter Selasky char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 544c3f60abcSHans Petter Selasky 545c3f60abcSHans Petter Selasky len = sizeof(buf); 546c3f60abcSHans Petter Selasky parse_param(argc, argv, buf, &len); 547c3f60abcSHans Petter Selasky memset(cp.advertising_data, 0, sizeof(cp.advertising_data)); 548c3f60abcSHans Petter Selasky cp.advertising_data_length = len; 5497b2f84dbSHans Petter Selasky memcpy(cp.advertising_data, buf, len); 550c3f60abcSHans Petter Selasky 551c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 552c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_DATA), 553c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 554c3f60abcSHans Petter Selasky return (ERROR); 555c3f60abcSHans Petter Selasky 556c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 557c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 558c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 559c3f60abcSHans Petter Selasky return (FAILED); 560c3f60abcSHans Petter Selasky } 561c3f60abcSHans Petter Selasky 562c3f60abcSHans Petter Selasky return (OK); 563c3f60abcSHans Petter Selasky } 5641f5d883dSTakanori Watanabe static int 5651f5d883dSTakanori Watanabe le_read_buffer_size(int s, int argc, char *argv[]) 5661f5d883dSTakanori Watanabe { 5671f5d883dSTakanori Watanabe union { 5681f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp v1; 5691f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp_v2 v2; 5701f5d883dSTakanori Watanabe } rp; 5711f5d883dSTakanori Watanabe 5721f5d883dSTakanori Watanabe int n, ch; 5731f5d883dSTakanori Watanabe uint8_t v; 5741f5d883dSTakanori Watanabe uint16_t cmd; 5751f5d883dSTakanori Watanabe 5761f5d883dSTakanori Watanabe optreset = 1; 5771f5d883dSTakanori Watanabe optind = 0; 5781f5d883dSTakanori Watanabe 5791f5d883dSTakanori Watanabe /* Default to version 1*/ 5801f5d883dSTakanori Watanabe v = 1; 5811f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE; 5821f5d883dSTakanori Watanabe 5831f5d883dSTakanori Watanabe while ((ch = getopt(argc, argv , "v:")) != -1) { 5841f5d883dSTakanori Watanabe switch(ch) { 5851f5d883dSTakanori Watanabe case 'v': 5861f5d883dSTakanori Watanabe v = (uint8_t)strtol(optarg, NULL, 16); 5871f5d883dSTakanori Watanabe if (v == 2) 5881f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2; 5891f5d883dSTakanori Watanabe else if (v > 2) 5901f5d883dSTakanori Watanabe return (USAGE); 5911f5d883dSTakanori Watanabe break; 5921f5d883dSTakanori Watanabe default: 5931f5d883dSTakanori Watanabe v = 1; 5941f5d883dSTakanori Watanabe } 5951f5d883dSTakanori Watanabe } 5961f5d883dSTakanori Watanabe 5971f5d883dSTakanori Watanabe n = sizeof(rp); 5981f5d883dSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd), 5991f5d883dSTakanori Watanabe (void *)&rp, &n) == ERROR) 6001f5d883dSTakanori Watanabe return (ERROR); 6011f5d883dSTakanori Watanabe 6021f5d883dSTakanori Watanabe if (rp.v1.status != 0x00) { 6031f5d883dSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 6041f5d883dSTakanori Watanabe hci_status2str(rp.v1.status), rp.v1.status); 6051f5d883dSTakanori Watanabe return (FAILED); 6061f5d883dSTakanori Watanabe } 6071f5d883dSTakanori Watanabe 6081f5d883dSTakanori Watanabe fprintf(stdout, "ACL data packet length: %d\n", 6091f5d883dSTakanori Watanabe rp.v1.hc_le_data_packet_length); 6101f5d883dSTakanori Watanabe fprintf(stdout, "Number of ACL data packets: %d\n", 6111f5d883dSTakanori Watanabe rp.v1.hc_total_num_le_data_packets); 6121f5d883dSTakanori Watanabe 6131f5d883dSTakanori Watanabe if (v == 2) { 6141f5d883dSTakanori Watanabe fprintf(stdout, "ISO data packet length: %d\n", 6151f5d883dSTakanori Watanabe rp.v2.hc_iso_data_packet_length); 6161f5d883dSTakanori Watanabe fprintf(stdout, "Number of ISO data packets: %d\n", 6171f5d883dSTakanori Watanabe rp.v2.hc_total_num_iso_data_packets); 6181f5d883dSTakanori Watanabe } 6191f5d883dSTakanori Watanabe 6201f5d883dSTakanori Watanabe return (OK); 6211f5d883dSTakanori Watanabe } 622c3f60abcSHans Petter Selasky 6239287f06dSTakanori Watanabe static int 6249287f06dSTakanori Watanabe le_scan(int s, int argc, char *argv[]) 6259287f06dSTakanori Watanabe { 6269287f06dSTakanori Watanabe int n, bufsize, scancount, numscans; 6279287f06dSTakanori Watanabe bool verbose; 6289287f06dSTakanori Watanabe uint8_t active = 0; 6299287f06dSTakanori Watanabe char ch; 6309287f06dSTakanori Watanabe 6319287f06dSTakanori Watanabe char b[512]; 6329287f06dSTakanori Watanabe ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 6339287f06dSTakanori Watanabe 6349287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_cp scan_param_cp; 6359287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_rp scan_param_rp; 6369287f06dSTakanori Watanabe 6379287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_cp scan_enable_cp; 6389287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_rp scan_enable_rp; 6399287f06dSTakanori Watanabe 6409287f06dSTakanori Watanabe optreset = 1; 6419287f06dSTakanori Watanabe optind = 0; 6429287f06dSTakanori Watanabe verbose = false; 6439287f06dSTakanori Watanabe numscans = 1; 6449287f06dSTakanori Watanabe 6459287f06dSTakanori Watanabe while ((ch = getopt(argc, argv , "an:v")) != -1) { 6469287f06dSTakanori Watanabe switch(ch) { 6479287f06dSTakanori Watanabe case 'a': 6489287f06dSTakanori Watanabe active = 1; 6499287f06dSTakanori Watanabe break; 6509287f06dSTakanori Watanabe case 'n': 6519287f06dSTakanori Watanabe numscans = (uint8_t)strtol(optarg, NULL, 10); 6529287f06dSTakanori Watanabe break; 6539287f06dSTakanori Watanabe case 'v': 6549287f06dSTakanori Watanabe verbose = true; 6559287f06dSTakanori Watanabe break; 6569287f06dSTakanori Watanabe } 6579287f06dSTakanori Watanabe } 6589287f06dSTakanori Watanabe 6599287f06dSTakanori Watanabe scan_param_cp.le_scan_type = active; 6609287f06dSTakanori Watanabe scan_param_cp.le_scan_interval = (uint16_t)(100/0.625); 6619287f06dSTakanori Watanabe scan_param_cp.le_scan_window = (uint16_t)(50/0.625); 6629287f06dSTakanori Watanabe /* Address type public */ 6639287f06dSTakanori Watanabe scan_param_cp.own_address_type = 0; 6649287f06dSTakanori Watanabe /* 'All' filter policy */ 6659287f06dSTakanori Watanabe scan_param_cp.scanning_filter_policy = 0; 6669287f06dSTakanori Watanabe n = sizeof(scan_param_rp); 6679287f06dSTakanori Watanabe 6689287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 6699287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 6709287f06dSTakanori Watanabe (void *)&scan_param_cp, sizeof(scan_param_cp), 6719287f06dSTakanori Watanabe (void *)&scan_param_rp, &n) == ERROR) 6729287f06dSTakanori Watanabe return (ERROR); 6739287f06dSTakanori Watanabe 6749287f06dSTakanori Watanabe if (scan_param_rp.status != 0x00) { 6759287f06dSTakanori Watanabe fprintf(stdout, "LE_Set_Scan_Parameters failed. Status: %s [%#02x]\n", 6769287f06dSTakanori Watanabe hci_status2str(scan_param_rp.status), 6779287f06dSTakanori Watanabe scan_param_rp.status); 6789287f06dSTakanori Watanabe return (FAILED); 6799287f06dSTakanori Watanabe } 6809287f06dSTakanori Watanabe 6819287f06dSTakanori Watanabe /* Enable scanning */ 6829287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 6839287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 1; 6849287f06dSTakanori Watanabe scan_enable_cp.filter_duplicates = 1; 6859287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 6869287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 6879287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 6889287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 6899287f06dSTakanori Watanabe return (ERROR); 6909287f06dSTakanori Watanabe 6919287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 6929287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable enable failed. Status: %s [%#02x]\n", 6939287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 6949287f06dSTakanori Watanabe scan_enable_rp.status); 6959287f06dSTakanori Watanabe return (FAILED); 6969287f06dSTakanori Watanabe } 6979287f06dSTakanori Watanabe 6989287f06dSTakanori Watanabe scancount = 0; 6999287f06dSTakanori Watanabe while (scancount < numscans) { 7009287f06dSTakanori Watanabe /* wait for scan events */ 7019287f06dSTakanori Watanabe bufsize = sizeof(b); 7029287f06dSTakanori Watanabe if (hci_recv(s, b, &bufsize) == ERROR) { 7039287f06dSTakanori Watanabe return (ERROR); 7049287f06dSTakanori Watanabe } 7059287f06dSTakanori Watanabe 7069287f06dSTakanori Watanabe if (bufsize < sizeof(*e)) { 7079287f06dSTakanori Watanabe errno = EIO; 7089287f06dSTakanori Watanabe return (ERROR); 7099287f06dSTakanori Watanabe } 7109287f06dSTakanori Watanabe scancount++; 7119287f06dSTakanori Watanabe if (e->event == NG_HCI_EVENT_LE) { 7129287f06dSTakanori Watanabe fprintf(stdout, "Scan %d\n", scancount); 7139287f06dSTakanori Watanabe handle_le_event(e, verbose); 7149287f06dSTakanori Watanabe } 7159287f06dSTakanori Watanabe } 7169287f06dSTakanori Watanabe 7179287f06dSTakanori Watanabe fprintf(stdout, "Scan complete\n"); 7189287f06dSTakanori Watanabe 7199287f06dSTakanori Watanabe /* Disable scanning */ 7209287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 7219287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 0; 7229287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 7239287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 7249287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 7259287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 7269287f06dSTakanori Watanabe return (ERROR); 7279287f06dSTakanori Watanabe 7289287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 7299287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable disable failed. Status: %s [%#02x]\n", 7309287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 7319287f06dSTakanori Watanabe scan_enable_rp.status); 7329287f06dSTakanori Watanabe return (FAILED); 7339287f06dSTakanori Watanabe } 7349287f06dSTakanori Watanabe 7359287f06dSTakanori Watanabe return (OK); 7369287f06dSTakanori Watanabe } 7379287f06dSTakanori Watanabe 7389287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose) 7399287f06dSTakanori Watanabe { 7409287f06dSTakanori Watanabe int rc; 7419287f06dSTakanori Watanabe ng_hci_le_ep *leer = 7429287f06dSTakanori Watanabe (ng_hci_le_ep *)(e + 1); 7439287f06dSTakanori Watanabe ng_hci_le_advertising_report_ep *advrep = 7449287f06dSTakanori Watanabe (ng_hci_le_advertising_report_ep *)(leer + 1); 7459287f06dSTakanori Watanabe ng_hci_le_advreport *reports = 7469287f06dSTakanori Watanabe (ng_hci_le_advreport *)(advrep + 1); 7479287f06dSTakanori Watanabe 7489287f06dSTakanori Watanabe if (leer->subevent_code == NG_HCI_LEEV_ADVREP) { 7499287f06dSTakanori Watanabe fprintf(stdout, "Scan result, num_reports: %d\n", 7509287f06dSTakanori Watanabe advrep->num_reports); 7519287f06dSTakanori Watanabe for(rc = 0; rc < advrep->num_reports; rc++) { 7529287f06dSTakanori Watanabe uint8_t length = (uint8_t)reports[rc].length_data; 7539287f06dSTakanori Watanabe fprintf(stdout, "\tBD_ADDR %s \n", 7549287f06dSTakanori Watanabe hci_bdaddr2str(&reports[rc].bdaddr)); 7559287f06dSTakanori Watanabe fprintf(stdout, "\tAddress type: %s\n", 7569287f06dSTakanori Watanabe hci_addrtype2str(reports[rc].addr_type)); 7579287f06dSTakanori Watanabe if (length > 0 && verbose) { 7589287f06dSTakanori Watanabe dump_adv_data(length, reports[rc].data); 7599287f06dSTakanori Watanabe print_adv_data(length, reports[rc].data); 7609287f06dSTakanori Watanabe fprintf(stdout, 7619287f06dSTakanori Watanabe "\tRSSI: %d dBm\n", 7629287f06dSTakanori Watanabe (int8_t)reports[rc].data[length]); 7639287f06dSTakanori Watanabe fprintf(stdout, "\n"); 7649287f06dSTakanori Watanabe } 7659287f06dSTakanori Watanabe } 7669287f06dSTakanori Watanabe } 7679287f06dSTakanori Watanabe } 7689287f06dSTakanori Watanabe 769*11fb4bdbSTakanori Watanabe static int 770*11fb4bdbSTakanori Watanabe le_read_white_list_size(int s, int argc, char *argv[]) 771*11fb4bdbSTakanori Watanabe { 772*11fb4bdbSTakanori Watanabe ng_hci_le_read_white_list_size_rp rp; 773*11fb4bdbSTakanori Watanabe int n; 774*11fb4bdbSTakanori Watanabe 775*11fb4bdbSTakanori Watanabe n = sizeof(rp); 776*11fb4bdbSTakanori Watanabe 777*11fb4bdbSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 778*11fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE), 779*11fb4bdbSTakanori Watanabe (void *)&rp, &n) == ERROR) 780*11fb4bdbSTakanori Watanabe return (ERROR); 781*11fb4bdbSTakanori Watanabe 782*11fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 783*11fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 784*11fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 785*11fb4bdbSTakanori Watanabe return (FAILED); 786*11fb4bdbSTakanori Watanabe } 787*11fb4bdbSTakanori Watanabe 788*11fb4bdbSTakanori Watanabe fprintf(stdout, "White list size: %d\n", 789*11fb4bdbSTakanori Watanabe (uint8_t)rp.white_list_size); 790*11fb4bdbSTakanori Watanabe 791*11fb4bdbSTakanori Watanabe return (OK); 792*11fb4bdbSTakanori Watanabe } 793*11fb4bdbSTakanori Watanabe 794*11fb4bdbSTakanori Watanabe static int 795*11fb4bdbSTakanori Watanabe le_clear_white_list(int s, int argc, char *argv[]) 796*11fb4bdbSTakanori Watanabe { 797*11fb4bdbSTakanori Watanabe ng_hci_le_clear_white_list_rp rp; 798*11fb4bdbSTakanori Watanabe int n; 799*11fb4bdbSTakanori Watanabe 800*11fb4bdbSTakanori Watanabe n = sizeof(rp); 801*11fb4bdbSTakanori Watanabe 802*11fb4bdbSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 803*11fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_CLEAR_WHITE_LIST), 804*11fb4bdbSTakanori Watanabe (void *)&rp, &n) == ERROR) 805*11fb4bdbSTakanori Watanabe return (ERROR); 806*11fb4bdbSTakanori Watanabe 807*11fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 808*11fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 809*11fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 810*11fb4bdbSTakanori Watanabe return (FAILED); 811*11fb4bdbSTakanori Watanabe } 812*11fb4bdbSTakanori Watanabe 813*11fb4bdbSTakanori Watanabe fprintf(stdout, "White list cleared\n"); 814*11fb4bdbSTakanori Watanabe 815*11fb4bdbSTakanori Watanabe return (OK); 816*11fb4bdbSTakanori Watanabe } 817*11fb4bdbSTakanori Watanabe 818*11fb4bdbSTakanori Watanabe static int 819*11fb4bdbSTakanori Watanabe le_add_device_to_white_list(int s, int argc, char *argv[]) 820*11fb4bdbSTakanori Watanabe { 821*11fb4bdbSTakanori Watanabe ng_hci_le_add_device_to_white_list_cp cp; 822*11fb4bdbSTakanori Watanabe ng_hci_le_add_device_to_white_list_rp rp; 823*11fb4bdbSTakanori Watanabe int n; 824*11fb4bdbSTakanori Watanabe char ch; 825*11fb4bdbSTakanori Watanabe optreset = 1; 826*11fb4bdbSTakanori Watanabe optind = 0; 827*11fb4bdbSTakanori Watanabe bool addr_set = false; 828*11fb4bdbSTakanori Watanabe 829*11fb4bdbSTakanori Watanabe n = sizeof(rp); 830*11fb4bdbSTakanori Watanabe 831*11fb4bdbSTakanori Watanabe cp.address_type = 0x00; 832*11fb4bdbSTakanori Watanabe 833*11fb4bdbSTakanori Watanabe while ((ch = getopt(argc, argv , "t:a:")) != -1) { 834*11fb4bdbSTakanori Watanabe switch(ch) { 835*11fb4bdbSTakanori Watanabe case 't': 836*11fb4bdbSTakanori Watanabe if (strcmp(optarg, "public") == 0) 837*11fb4bdbSTakanori Watanabe cp.address_type = 0x00; 838*11fb4bdbSTakanori Watanabe else if (strcmp(optarg, "random") == 0) 839*11fb4bdbSTakanori Watanabe cp.address_type = 0x01; 840*11fb4bdbSTakanori Watanabe else 841*11fb4bdbSTakanori Watanabe return (USAGE); 842*11fb4bdbSTakanori Watanabe break; 843*11fb4bdbSTakanori Watanabe case 'a': 844*11fb4bdbSTakanori Watanabe addr_set = true; 845*11fb4bdbSTakanori Watanabe if (!bt_aton(optarg, &cp.address)) { 846*11fb4bdbSTakanori Watanabe struct hostent *he = NULL; 847*11fb4bdbSTakanori Watanabe 848*11fb4bdbSTakanori Watanabe if ((he = bt_gethostbyname(optarg)) == NULL) 849*11fb4bdbSTakanori Watanabe return (USAGE); 850*11fb4bdbSTakanori Watanabe 851*11fb4bdbSTakanori Watanabe memcpy(&cp.address, he->h_addr, 852*11fb4bdbSTakanori Watanabe sizeof(cp.address)); 853*11fb4bdbSTakanori Watanabe } 854*11fb4bdbSTakanori Watanabe break; 855*11fb4bdbSTakanori Watanabe } 856*11fb4bdbSTakanori Watanabe } 857*11fb4bdbSTakanori Watanabe 858*11fb4bdbSTakanori Watanabe if (addr_set == false) 859*11fb4bdbSTakanori Watanabe return (USAGE); 860*11fb4bdbSTakanori Watanabe 861*11fb4bdbSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 862*11fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST), 863*11fb4bdbSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 864*11fb4bdbSTakanori Watanabe return (ERROR); 865*11fb4bdbSTakanori Watanabe 866*11fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 867*11fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 868*11fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 869*11fb4bdbSTakanori Watanabe return (FAILED); 870*11fb4bdbSTakanori Watanabe } 871*11fb4bdbSTakanori Watanabe 872*11fb4bdbSTakanori Watanabe fprintf(stdout, "Address added to white list\n"); 873*11fb4bdbSTakanori Watanabe 874*11fb4bdbSTakanori Watanabe return (OK); 875*11fb4bdbSTakanori Watanabe } 876*11fb4bdbSTakanori Watanabe 877*11fb4bdbSTakanori Watanabe static int 878*11fb4bdbSTakanori Watanabe le_remove_device_from_white_list(int s, int argc, char *argv[]) 879*11fb4bdbSTakanori Watanabe { 880*11fb4bdbSTakanori Watanabe ng_hci_le_remove_device_from_white_list_cp cp; 881*11fb4bdbSTakanori Watanabe ng_hci_le_remove_device_from_white_list_rp rp; 882*11fb4bdbSTakanori Watanabe int n; 883*11fb4bdbSTakanori Watanabe char ch; 884*11fb4bdbSTakanori Watanabe optreset = 1; 885*11fb4bdbSTakanori Watanabe optind = 0; 886*11fb4bdbSTakanori Watanabe bool addr_set = false; 887*11fb4bdbSTakanori Watanabe 888*11fb4bdbSTakanori Watanabe n = sizeof(rp); 889*11fb4bdbSTakanori Watanabe 890*11fb4bdbSTakanori Watanabe cp.address_type = 0x00; 891*11fb4bdbSTakanori Watanabe 892*11fb4bdbSTakanori Watanabe while ((ch = getopt(argc, argv , "t:a:")) != -1) { 893*11fb4bdbSTakanori Watanabe switch(ch) { 894*11fb4bdbSTakanori Watanabe case 't': 895*11fb4bdbSTakanori Watanabe if (strcmp(optarg, "public") == 0) 896*11fb4bdbSTakanori Watanabe cp.address_type = 0x00; 897*11fb4bdbSTakanori Watanabe else if (strcmp(optarg, "random") == 0) 898*11fb4bdbSTakanori Watanabe cp.address_type = 0x01; 899*11fb4bdbSTakanori Watanabe else 900*11fb4bdbSTakanori Watanabe return (USAGE); 901*11fb4bdbSTakanori Watanabe break; 902*11fb4bdbSTakanori Watanabe case 'a': 903*11fb4bdbSTakanori Watanabe addr_set = true; 904*11fb4bdbSTakanori Watanabe if (!bt_aton(optarg, &cp.address)) { 905*11fb4bdbSTakanori Watanabe struct hostent *he = NULL; 906*11fb4bdbSTakanori Watanabe 907*11fb4bdbSTakanori Watanabe if ((he = bt_gethostbyname(optarg)) == NULL) 908*11fb4bdbSTakanori Watanabe return (USAGE); 909*11fb4bdbSTakanori Watanabe 910*11fb4bdbSTakanori Watanabe memcpy(&cp.address, he->h_addr, 911*11fb4bdbSTakanori Watanabe sizeof(cp.address)); 912*11fb4bdbSTakanori Watanabe } 913*11fb4bdbSTakanori Watanabe break; 914*11fb4bdbSTakanori Watanabe } 915*11fb4bdbSTakanori Watanabe } 916*11fb4bdbSTakanori Watanabe 917*11fb4bdbSTakanori Watanabe if (addr_set == false) 918*11fb4bdbSTakanori Watanabe return (USAGE); 919*11fb4bdbSTakanori Watanabe 920*11fb4bdbSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 921*11fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST), 922*11fb4bdbSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 923*11fb4bdbSTakanori Watanabe return (ERROR); 924*11fb4bdbSTakanori Watanabe 925*11fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 926*11fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 927*11fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 928*11fb4bdbSTakanori Watanabe return (FAILED); 929*11fb4bdbSTakanori Watanabe } 930*11fb4bdbSTakanori Watanabe 931*11fb4bdbSTakanori Watanabe fprintf(stdout, "Address removed from white list\n"); 932*11fb4bdbSTakanori Watanabe 933*11fb4bdbSTakanori Watanabe return (OK); 934*11fb4bdbSTakanori Watanabe } 935*11fb4bdbSTakanori Watanabe 936bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 937bcff2d91STakanori Watanabe { 938bcff2d91STakanori Watanabe "le_enable", 939bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 940bcff2d91STakanori Watanabe "Enable LE event ", 941bcff2d91STakanori Watanabe &le_enable, 942bcff2d91STakanori Watanabe }, 943bcff2d91STakanori Watanabe { 944bcff2d91STakanori Watanabe "le_read_local_supported_features", 945bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 946bcff2d91STakanori Watanabe "read local supported features mask", 947bcff2d91STakanori Watanabe &le_read_local_supported_features, 948bcff2d91STakanori Watanabe }, 949bcff2d91STakanori Watanabe { 95021eefd31SHans Petter Selasky "le_read_supported_states", 95121eefd31SHans Petter Selasky "le_read_supported_states\n" 952bcff2d91STakanori Watanabe "read supported status" 953bcff2d91STakanori Watanabe , 95421eefd31SHans Petter Selasky &le_read_supported_states, 955bcff2d91STakanori Watanabe }, 956bcff2d91STakanori Watanabe { 957bcff2d91STakanori Watanabe "le_set_scan_response", 958bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 959bcff2d91STakanori Watanabe "set LE scan response data" 960bcff2d91STakanori Watanabe , 961bcff2d91STakanori Watanabe &le_set_scan_response, 962bcff2d91STakanori Watanabe }, 963bcff2d91STakanori Watanabe { 964bcff2d91STakanori Watanabe "le_set_scan_enable", 965bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 966bcff2d91STakanori Watanabe "enable or disable LE device scan", 967bcff2d91STakanori Watanabe &le_set_scan_enable 968bcff2d91STakanori Watanabe }, 969bcff2d91STakanori Watanabe { 970bcff2d91STakanori Watanabe "le_set_scan_param", 971bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 972bcff2d91STakanori Watanabe "set LE device scan parameter", 973bcff2d91STakanori Watanabe &le_set_scan_param 974bcff2d91STakanori Watanabe }, 975c3f60abcSHans Petter Selasky { 976c3f60abcSHans Petter Selasky "le_set_advertising_enable", 977c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 978c3f60abcSHans Petter Selasky "start or stop advertising", 979c3f60abcSHans Petter Selasky &le_set_advertising_enable 980c3f60abcSHans Petter Selasky }, 981c3f60abcSHans Petter Selasky { 982c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 983c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 984c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 985c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 986c3f60abcSHans Petter Selasky }, 987c3f60abcSHans Petter Selasky { 988c3f60abcSHans Petter Selasky "le_set_advertising_param", 989c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 990c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 991c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 992c3f60abcSHans Petter Selasky "[-a peer_address]\n" 993c3f60abcSHans Petter Selasky "set LE device advertising parameters", 994c3f60abcSHans Petter Selasky &le_set_advertising_param 995c3f60abcSHans Petter Selasky }, 996c3f60abcSHans Petter Selasky { 997c3f60abcSHans Petter Selasky "le_set_advertising_data", 998c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 999c3f60abcSHans Petter Selasky "set LE device advertising packed data", 1000c3f60abcSHans Petter Selasky &le_set_advertising_data 1001c3f60abcSHans Petter Selasky }, 10021f5d883dSTakanori Watanabe { 10031f5d883dSTakanori Watanabe "le_read_buffer_size", 10041f5d883dSTakanori Watanabe "le_read_buffer_size [-v 1|2]\n" 10051f5d883dSTakanori Watanabe "Read the maximum size of ACL and ISO data packets", 10061f5d883dSTakanori Watanabe &le_read_buffer_size 10071f5d883dSTakanori Watanabe }, 10089287f06dSTakanori Watanabe { 10099287f06dSTakanori Watanabe "le_scan", 10109287f06dSTakanori Watanabe "le_scan [-a] [-v] [-n number_of_scans]\n" 10119287f06dSTakanori Watanabe "Do an LE scan", 10129287f06dSTakanori Watanabe &le_scan 10139287f06dSTakanori Watanabe }, 1014*11fb4bdbSTakanori Watanabe { 1015*11fb4bdbSTakanori Watanabe "le_read_white_list_size", 1016*11fb4bdbSTakanori Watanabe "le_read_white_list_size\n" 1017*11fb4bdbSTakanori Watanabe "Read total number of white list entries that can be stored", 1018*11fb4bdbSTakanori Watanabe &le_read_white_list_size 1019*11fb4bdbSTakanori Watanabe }, 1020*11fb4bdbSTakanori Watanabe { 1021*11fb4bdbSTakanori Watanabe "le_clear_white_list", 1022*11fb4bdbSTakanori Watanabe "le_clear_white_list\n" 1023*11fb4bdbSTakanori Watanabe "Clear the white list in the controller", 1024*11fb4bdbSTakanori Watanabe &le_clear_white_list 1025*11fb4bdbSTakanori Watanabe }, 1026*11fb4bdbSTakanori Watanabe { 1027*11fb4bdbSTakanori Watanabe "le_add_device_to_white_list", 1028*11fb4bdbSTakanori Watanabe "le_add_device_to_white_list\n" 1029*11fb4bdbSTakanori Watanabe "[-t public|random] -a address\n" 1030*11fb4bdbSTakanori Watanabe "Add device to the white list", 1031*11fb4bdbSTakanori Watanabe &le_add_device_to_white_list 1032*11fb4bdbSTakanori Watanabe }, 1033*11fb4bdbSTakanori Watanabe { 1034*11fb4bdbSTakanori Watanabe "le_remove_device_from_white_list", 1035*11fb4bdbSTakanori Watanabe "le_remove_device_from_white_list\n" 1036*11fb4bdbSTakanori Watanabe "[-t public|random] -a address\n" 1037*11fb4bdbSTakanori Watanabe "Remove device from the white list", 1038*11fb4bdbSTakanori Watanabe &le_remove_device_from_white_list 1039*11fb4bdbSTakanori Watanabe }, 1040bcff2d91STakanori Watanabe }; 1041