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; 729c3471faSMarcelo Araujo int e, 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) 78bcff2d91STakanori 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 85bcff2d91STakanori 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 97bcff2d91STakanori 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 104bcff2d91STakanori 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 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 113bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 114bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 115bcff2d91STakanori Watanabe 116bcff2d91STakanori Watanabe return 0; 117bcff2d91STakanori Watanabe } 118bcff2d91STakanori Watanabe 1199c3471faSMarcelo Araujo static int 1209c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 121bcff2d91STakanori Watanabe { 122bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 123bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 124bcff2d91STakanori Watanabe int e, n, enable = 0; 125bcff2d91STakanori Watanabe 126bcff2d91STakanori Watanabe if (argc != 1) 127bcff2d91STakanori Watanabe return USAGE; 128bcff2d91STakanori Watanabe 1299c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 130bcff2d91STakanori Watanabe enable = 1; 1319c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 132bcff2d91STakanori Watanabe return USAGE; 1339c3471faSMarcelo Araujo 134bcff2d91STakanori Watanabe n = sizeof(rp); 135bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 136bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 137bcff2d91STakanori Watanabe e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 138bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 139bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 140bcff2d91STakanori Watanabe 1419c3471faSMarcelo Araujo if (e != 0 || rp.status != 0) 142bcff2d91STakanori Watanabe return ERROR; 143bcff2d91STakanori Watanabe 1449c3471faSMarcelo Araujo return OK; 145bcff2d91STakanori Watanabe } 1469c3471faSMarcelo Araujo 1479c3471faSMarcelo Araujo static int 1489c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 149bcff2d91STakanori Watanabe { 150bcff2d91STakanori Watanabe char *buflast = buf + (*len); 151bcff2d91STakanori Watanabe char *curbuf = buf; 152bcff2d91STakanori Watanabe char *token,*lenpos; 153bcff2d91STakanori Watanabe int ch; 154bcff2d91STakanori Watanabe int datalen; 155bcff2d91STakanori Watanabe uint16_t value; 156bcff2d91STakanori Watanabe optreset = 1; 157bcff2d91STakanori Watanabe optind = 0; 158bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 159bcff2d91STakanori Watanabe switch(ch){ 160bcff2d91STakanori Watanabe case 'n': 161bcff2d91STakanori Watanabe datalen = strlen(optarg); 1629c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 163bcff2d91STakanori Watanabe goto done; 164bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 165bcff2d91STakanori Watanabe curbuf[1] = 8; 166bcff2d91STakanori Watanabe curbuf += 2; 167bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 168bcff2d91STakanori Watanabe curbuf += datalen; 169bcff2d91STakanori Watanabe break; 170bcff2d91STakanori Watanabe case 'f': 1719c3471faSMarcelo Araujo if (curbuf+3 > buflast) 172bcff2d91STakanori Watanabe goto done; 173bcff2d91STakanori Watanabe curbuf[0] = 2; 174bcff2d91STakanori Watanabe curbuf[1] = 1; 175bcff2d91STakanori Watanabe curbuf[2] = atoi(optarg); 176bcff2d91STakanori Watanabe curbuf += 3; 177bcff2d91STakanori Watanabe break; 178bcff2d91STakanori Watanabe case 'u': 179bcff2d91STakanori Watanabe lenpos = buf; 180bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 181bcff2d91STakanori Watanabe goto done; 182bcff2d91STakanori Watanabe curbuf[1] = 2; 183bcff2d91STakanori Watanabe *lenpos = 1; 184bcff2d91STakanori Watanabe curbuf += 2; 185bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 186bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 187bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 188bcff2d91STakanori Watanabe break; 189bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 190bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 191bcff2d91STakanori Watanabe curbuf += 2; 192bcff2d91STakanori Watanabe } 193bcff2d91STakanori Watanabe 194bcff2d91STakanori Watanabe } 195bcff2d91STakanori Watanabe } 196bcff2d91STakanori Watanabe done: 197bcff2d91STakanori Watanabe *len = curbuf - buf; 198bcff2d91STakanori Watanabe 199bcff2d91STakanori Watanabe return OK; 200bcff2d91STakanori Watanabe } 201bcff2d91STakanori Watanabe 2029c3471faSMarcelo Araujo static int 2039c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 204bcff2d91STakanori Watanabe { 205bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 206bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 207bcff2d91STakanori Watanabe int n; 208bcff2d91STakanori Watanabe int e; 209bcff2d91STakanori Watanabe int len; 210bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2119c3471faSMarcelo Araujo 212bcff2d91STakanori Watanabe len = sizeof(buf); 213bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 214bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 215bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 216bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 217bcff2d91STakanori Watanabe n = sizeof(rp); 218bcff2d91STakanori Watanabe e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 219bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 220bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 221bcff2d91STakanori Watanabe 2229c3471faSMarcelo Araujo printf("SET SCAN RESPONSE %d %d %d\n", e, rp.status, n); 223bcff2d91STakanori Watanabe 224bcff2d91STakanori Watanabe return OK; 225bcff2d91STakanori Watanabe } 226bcff2d91STakanori Watanabe 2279c3471faSMarcelo Araujo static int 2289c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 229bcff2d91STakanori Watanabe { 230bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 231bcff2d91STakanori Watanabe int n = sizeof(rp); 2329c3471faSMarcelo Araujo 233ea011491SHans Petter Selasky union { 234ea011491SHans Petter Selasky uint64_t raw; 235ea011491SHans Petter Selasky uint8_t octets[8]; 236ea011491SHans Petter Selasky } le_features; 237ea011491SHans Petter Selasky 238ea011491SHans Petter Selasky char buffer[2048]; 239ea011491SHans Petter Selasky 240ea011491SHans Petter Selasky if (hci_simple_request(s, 241bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 242bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 243ea011491SHans Petter Selasky (void *)&rp, &n) == ERROR) 244ea011491SHans Petter Selasky return (ERROR); 2459c3471faSMarcelo Araujo 246ea011491SHans Petter Selasky if (rp.status != 0x00) { 247ea011491SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 248ea011491SHans Petter Selasky hci_status2str(rp.status), rp.status); 249ea011491SHans Petter Selasky return (FAILED); 250ea011491SHans Petter Selasky } 251bcff2d91STakanori Watanabe 252ea011491SHans Petter Selasky le_features.raw = rp.le_features; 253ea011491SHans Petter Selasky 254ea011491SHans Petter Selasky fprintf(stdout, "LE Features: "); 255ea011491SHans Petter Selasky for(int i = 0; i < 8; i++) 256ea011491SHans Petter Selasky fprintf(stdout, " %#02x", le_features.octets[i]); 257ea011491SHans Petter Selasky fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets, 258ea011491SHans Petter Selasky buffer, sizeof(buffer))); 259ea011491SHans Petter Selasky fprintf(stdout, "\n"); 260ea011491SHans Petter Selasky 261ea011491SHans Petter Selasky return OK; 262bcff2d91STakanori Watanabe } 2639c3471faSMarcelo Araujo 2649c3471faSMarcelo Araujo static int 26521eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[]) 266bcff2d91STakanori Watanabe { 26721eefd31SHans Petter Selasky ng_hci_le_read_supported_states_rp rp; 268bcff2d91STakanori Watanabe int n = sizeof(rp); 2699c3471faSMarcelo Araujo 27021eefd31SHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE( 2719c3471faSMarcelo Araujo NG_HCI_OGF_LE, 27221eefd31SHans Petter Selasky NG_HCI_OCF_LE_READ_SUPPORTED_STATES), 27321eefd31SHans Petter Selasky (void *)&rp, &n) == ERROR) 27421eefd31SHans Petter Selasky return (ERROR); 2759c3471faSMarcelo Araujo 27621eefd31SHans Petter Selasky if (rp.status != 0x00) { 27721eefd31SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 27821eefd31SHans Petter Selasky hci_status2str(rp.status), rp.status); 27921eefd31SHans Petter Selasky return (FAILED); 28021eefd31SHans Petter Selasky } 281bcff2d91STakanori Watanabe 28221eefd31SHans Petter Selasky fprintf(stdout, "LE States: %jx\n", rp.le_states); 28321eefd31SHans Petter Selasky 28421eefd31SHans Petter Selasky return (OK); 285bcff2d91STakanori Watanabe } 286bcff2d91STakanori Watanabe 2879c3471faSMarcelo Araujo static int 2889c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 289bcff2d91STakanori Watanabe { 290bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 291bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 292bcff2d91STakanori Watanabe int i, n ,e; 293bcff2d91STakanori Watanabe 294bcff2d91STakanori Watanabe n = sizeof(rp); 295bcff2d91STakanori Watanabe 296bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 297bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 298bcff2d91STakanori Watanabe mask >>= 8; 299bcff2d91STakanori Watanabe } 3009c3471faSMarcelo Araujo e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3019c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 3029c3471faSMarcelo Araujo (void *)&semc, sizeof(semc), (void *)&rp, &n); 303bcff2d91STakanori Watanabe 304bcff2d91STakanori Watanabe return 0; 305bcff2d91STakanori Watanabe } 306bcff2d91STakanori Watanabe 3079c3471faSMarcelo Araujo static int 3089c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 309bcff2d91STakanori Watanabe { 310bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 311bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 312bcff2d91STakanori Watanabe int i, n, e; 313bcff2d91STakanori Watanabe 314bcff2d91STakanori Watanabe n = sizeof(rp); 315bcff2d91STakanori Watanabe 316bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 317bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 318bcff2d91STakanori Watanabe mask >>= 8; 319bcff2d91STakanori Watanabe } 3209c3471faSMarcelo Araujo e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3219c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 3229c3471faSMarcelo Araujo (void *)&semc, sizeof(semc), (void *)&rp, &n); 323bcff2d91STakanori Watanabe 324bcff2d91STakanori Watanabe return 0; 325bcff2d91STakanori Watanabe } 326bcff2d91STakanori Watanabe 3279c3471faSMarcelo Araujo static 3289c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 329bcff2d91STakanori Watanabe { 3309c3471faSMarcelo Araujo if (argc != 1) 331bcff2d91STakanori Watanabe return USAGE; 332bcff2d91STakanori Watanabe 333bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 334bcff2d91STakanori Watanabe set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 335bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 336bcff2d91STakanori Watanabe set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 337b4b880cbSEd Maste } else if (strcasecmp(argv[0], "disable") == 0) 338bcff2d91STakanori Watanabe set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 3399c3471faSMarcelo Araujo else 340bcff2d91STakanori Watanabe return USAGE; 341bcff2d91STakanori Watanabe 342bcff2d91STakanori Watanabe return OK; 343bcff2d91STakanori Watanabe } 344bcff2d91STakanori Watanabe 345c3f60abcSHans Petter Selasky static int 346c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[]) 347c3f60abcSHans Petter Selasky { 348c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_cp cp; 349c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_rp rp; 350c3f60abcSHans Petter Selasky int n, enable = 0; 351c3f60abcSHans Petter Selasky 352c3f60abcSHans Petter Selasky if (argc != 1) 353c3f60abcSHans Petter Selasky return USAGE; 354c3f60abcSHans Petter Selasky 355c3f60abcSHans Petter Selasky if (strcmp(argv[0], "enable") == 0) 356c3f60abcSHans Petter Selasky enable = 1; 357c3f60abcSHans Petter Selasky else if (strcmp(argv[0], "disable") != 0) 358c3f60abcSHans Petter Selasky return USAGE; 359c3f60abcSHans Petter Selasky 360c3f60abcSHans Petter Selasky n = sizeof(rp); 361c3f60abcSHans Petter Selasky cp.advertising_enable = enable; 362c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 363c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE), 364c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 365c3f60abcSHans Petter Selasky return (ERROR); 366c3f60abcSHans Petter Selasky 367c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 368c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 369c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 370c3f60abcSHans Petter Selasky return (FAILED); 371c3f60abcSHans Petter Selasky } 372c3f60abcSHans Petter Selasky fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled")); 373c3f60abcSHans Petter Selasky 374c3f60abcSHans Petter Selasky return (OK); 375c3f60abcSHans Petter Selasky } 376c3f60abcSHans Petter Selasky 377c3f60abcSHans Petter Selasky static int 378c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[]) 379c3f60abcSHans Petter Selasky { 380c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_cp cp; 381c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_rp rp; 382c3f60abcSHans Petter Selasky 383c3f60abcSHans Petter Selasky int n, ch; 384c3f60abcSHans Petter Selasky 385c3f60abcSHans Petter Selasky cp.advertising_interval_min = 0x800; 386c3f60abcSHans Petter Selasky cp.advertising_interval_max = 0x800; 387c3f60abcSHans Petter Selasky cp.advertising_type = 0; 388c3f60abcSHans Petter Selasky cp.own_address_type = 0; 389c3f60abcSHans Petter Selasky cp.direct_address_type = 0; 390c3f60abcSHans Petter Selasky 391c3f60abcSHans Petter Selasky cp.advertising_channel_map = 7; 392c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 0; 393c3f60abcSHans Petter Selasky 394c3f60abcSHans Petter Selasky optreset = 1; 395c3f60abcSHans Petter Selasky optind = 0; 396c3f60abcSHans Petter Selasky while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) { 397c3f60abcSHans Petter Selasky switch(ch) { 398c3f60abcSHans Petter Selasky case 'm': 399c3f60abcSHans Petter Selasky cp.advertising_interval_min = 400c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 401c3f60abcSHans Petter Selasky break; 402c3f60abcSHans Petter Selasky case 'M': 403c3f60abcSHans Petter Selasky cp.advertising_interval_max = 404c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 405c3f60abcSHans Petter Selasky break; 406c3f60abcSHans Petter Selasky case 't': 407c3f60abcSHans Petter Selasky cp.advertising_type = 408c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 409c3f60abcSHans Petter Selasky break; 410c3f60abcSHans Petter Selasky case 'o': 411c3f60abcSHans Petter Selasky cp.own_address_type = 412c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 413c3f60abcSHans Petter Selasky break; 414c3f60abcSHans Petter Selasky case 'p': 415c3f60abcSHans Petter Selasky cp.direct_address_type = 416c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 417c3f60abcSHans Petter Selasky break; 418c3f60abcSHans Petter Selasky case 'a': 419c3f60abcSHans Petter Selasky if (!bt_aton(optarg, &cp.direct_address)) { 420c3f60abcSHans Petter Selasky struct hostent *he = NULL; 421c3f60abcSHans Petter Selasky 422c3f60abcSHans Petter Selasky if ((he = bt_gethostbyname(optarg)) == NULL) 423c3f60abcSHans Petter Selasky return (USAGE); 424c3f60abcSHans Petter Selasky 425c3f60abcSHans Petter Selasky memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address)); 426c3f60abcSHans Petter Selasky } 427c3f60abcSHans Petter Selasky break; 428c3f60abcSHans Petter Selasky case 'c': 429c3f60abcSHans Petter Selasky cp.advertising_channel_map = 430c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 431c3f60abcSHans Petter Selasky break; 432c3f60abcSHans Petter Selasky case 'f': 433c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 434c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 435c3f60abcSHans Petter Selasky break; 436c3f60abcSHans Petter Selasky } 437c3f60abcSHans Petter Selasky } 438c3f60abcSHans Petter Selasky 439c3f60abcSHans Petter Selasky n = sizeof(rp); 440c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 441c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS), 442c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 443c3f60abcSHans Petter Selasky return (ERROR); 444c3f60abcSHans Petter Selasky 445c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 446c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 447c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 448c3f60abcSHans Petter Selasky return (FAILED); 449c3f60abcSHans Petter Selasky } 450c3f60abcSHans Petter Selasky 451c3f60abcSHans Petter Selasky return (OK); 452c3f60abcSHans Petter Selasky } 453c3f60abcSHans Petter Selasky 454c3f60abcSHans Petter Selasky static int 455c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[]) 456c3f60abcSHans Petter Selasky { 457c3f60abcSHans Petter Selasky ng_hci_le_read_advertising_channel_tx_power_rp rp; 458c3f60abcSHans Petter Selasky int n; 459c3f60abcSHans Petter Selasky 460c3f60abcSHans Petter Selasky n = sizeof(rp); 461c3f60abcSHans Petter Selasky 462c3f60abcSHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 463c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER), 464c3f60abcSHans Petter Selasky (void *)&rp, &n) == ERROR) 465c3f60abcSHans Petter Selasky return (ERROR); 466c3f60abcSHans Petter Selasky 467c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 468c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 469c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 470c3f60abcSHans Petter Selasky return (FAILED); 471c3f60abcSHans Petter Selasky } 472c3f60abcSHans Petter Selasky 473c3f60abcSHans Petter Selasky fprintf(stdout, "Advertising transmit power level: %d dBm\n", 474c3f60abcSHans Petter Selasky (int8_t)rp.transmit_power_level); 475c3f60abcSHans Petter Selasky 476c3f60abcSHans Petter Selasky return (OK); 477c3f60abcSHans Petter Selasky } 478c3f60abcSHans Petter Selasky 479c3f60abcSHans Petter Selasky static int 480c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[]) 481c3f60abcSHans Petter Selasky { 482c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_cp cp; 483c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_rp rp; 484c3f60abcSHans Petter Selasky int n, len; 485c3f60abcSHans Petter Selasky 486c3f60abcSHans Petter Selasky n = sizeof(rp); 487c3f60abcSHans Petter Selasky 488c3f60abcSHans Petter Selasky char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 489c3f60abcSHans Petter Selasky 490c3f60abcSHans Petter Selasky len = sizeof(buf); 491c3f60abcSHans Petter Selasky parse_param(argc, argv, buf, &len); 492c3f60abcSHans Petter Selasky memset(cp.advertising_data, 0, sizeof(cp.advertising_data)); 493c3f60abcSHans Petter Selasky cp.advertising_data_length = len; 494*7b2f84dbSHans Petter Selasky memcpy(cp.advertising_data, buf, len); 495c3f60abcSHans Petter Selasky 496c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 497c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_DATA), 498c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 499c3f60abcSHans Petter Selasky return (ERROR); 500c3f60abcSHans Petter Selasky 501c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 502c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 503c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 504c3f60abcSHans Petter Selasky return (FAILED); 505c3f60abcSHans Petter Selasky } 506c3f60abcSHans Petter Selasky 507c3f60abcSHans Petter Selasky return (OK); 508c3f60abcSHans Petter Selasky } 509c3f60abcSHans Petter Selasky 510bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 511bcff2d91STakanori Watanabe { 512bcff2d91STakanori Watanabe "le_enable", 513bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 514bcff2d91STakanori Watanabe "Enable LE event ", 515bcff2d91STakanori Watanabe &le_enable, 516bcff2d91STakanori Watanabe }, 517bcff2d91STakanori Watanabe { 518bcff2d91STakanori Watanabe "le_read_local_supported_features", 519bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 520bcff2d91STakanori Watanabe "read local supported features mask", 521bcff2d91STakanori Watanabe &le_read_local_supported_features, 522bcff2d91STakanori Watanabe }, 523bcff2d91STakanori Watanabe { 52421eefd31SHans Petter Selasky "le_read_supported_states", 52521eefd31SHans Petter Selasky "le_read_supported_states\n" 526bcff2d91STakanori Watanabe "read supported status" 527bcff2d91STakanori Watanabe , 52821eefd31SHans Petter Selasky &le_read_supported_states, 529bcff2d91STakanori Watanabe }, 530bcff2d91STakanori Watanabe { 531bcff2d91STakanori Watanabe "le_set_scan_response", 532bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 533bcff2d91STakanori Watanabe "set LE scan response data" 534bcff2d91STakanori Watanabe , 535bcff2d91STakanori Watanabe &le_set_scan_response, 536bcff2d91STakanori Watanabe }, 537bcff2d91STakanori Watanabe { 538bcff2d91STakanori Watanabe "le_set_scan_enable", 539bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 540bcff2d91STakanori Watanabe "enable or disable LE device scan", 541bcff2d91STakanori Watanabe &le_set_scan_enable 542bcff2d91STakanori Watanabe }, 543bcff2d91STakanori Watanabe { 544bcff2d91STakanori Watanabe "le_set_scan_param", 545bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 546bcff2d91STakanori Watanabe "set LE device scan parameter", 547bcff2d91STakanori Watanabe &le_set_scan_param 548bcff2d91STakanori Watanabe }, 549c3f60abcSHans Petter Selasky { 550c3f60abcSHans Petter Selasky "le_set_advertising_enable", 551c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 552c3f60abcSHans Petter Selasky "start or stop advertising", 553c3f60abcSHans Petter Selasky &le_set_advertising_enable 554c3f60abcSHans Petter Selasky }, 555c3f60abcSHans Petter Selasky { 556c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 557c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 558c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 559c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 560c3f60abcSHans Petter Selasky }, 561c3f60abcSHans Petter Selasky { 562c3f60abcSHans Petter Selasky "le_set_advertising_param", 563c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 564c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 565c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 566c3f60abcSHans Petter Selasky "[-a peer_address]\n" 567c3f60abcSHans Petter Selasky "set LE device advertising parameters", 568c3f60abcSHans Petter Selasky &le_set_advertising_param 569c3f60abcSHans Petter Selasky }, 570c3f60abcSHans Petter Selasky { 571c3f60abcSHans Petter Selasky "le_set_advertising_data", 572c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 573c3f60abcSHans Petter Selasky "set LE device advertising packed data", 574c3f60abcSHans Petter Selasky &le_set_advertising_data 575c3f60abcSHans Petter Selasky }, 576bcff2d91STakanori Watanabe }; 577