Path: blob/main/usr.sbin/bluetooth/hccontrol/link_control.c
106462 views
/*-1* link_control.c2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* $Id: link_control.c,v 1.4 2003/08/18 19:19:54 max Exp $30*/3132#define L2CAP_SOCKET_CHECKED33#include <bluetooth.h>34#include <errno.h>35#include <stdio.h>36#include <string.h>37#include "hccontrol.h"3839static void hci_inquiry_response (int n, uint8_t **b);4041/* Send Inquiry command to the unit */42static int43hci_inquiry(int s, int argc, char **argv)44{45int n0, n1, n2, timo;46char b[512];47ng_hci_inquiry_cp cp;48ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;4950/* set defaults */51cp.lap[2] = 0x9e;52cp.lap[1] = 0x8b;53cp.lap[0] = 0x33;54cp.inquiry_length = 5;55cp.num_responses = 8;5657/* parse command parameters */58switch (argc) {59case 3:60/* number of responses, range 0x00 - 0xff */61if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 0xff)62return (USAGE);6364cp.num_responses = (n0 & 0xff);6566case 2:67/* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */68if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30)69return (USAGE);7071cp.inquiry_length = (n0 & 0xff);7273case 1:74/* LAP */75if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)76return (USAGE);7778cp.lap[0] = (n0 & 0xff);79cp.lap[1] = (n1 & 0xff);80cp.lap[2] = (n2 & 0xff);8182case 0:83/* use defaults */84break;8586default:87return (USAGE);88}8990/* send request and expect status back */91n0 = sizeof(b);92if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,93NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp),94b, &n0) == ERROR)95return (ERROR);9697if (*b != 0x00)98return (FAILED);99100timo = timeout;101timeout = cp.inquiry_length * 1.28 + 1;102103wait_for_more:104/* wait for inquiry events */105n0 = sizeof(b);106if (hci_recv(s, b, &n0) == ERROR) {107timeout = timo;108return (ERROR);109}110111if (n0 < sizeof(*e)) {112timeout = timo;113errno = EIO;114return (ERROR);115}116117switch (e->event) {118case NG_HCI_EVENT_INQUIRY_RESULT: {119ng_hci_inquiry_result_ep *ir =120(ng_hci_inquiry_result_ep *)(e + 1);121uint8_t *r = (uint8_t *)(ir + 1);122123fprintf(stdout, "Inquiry result, num_responses=%d\n",124ir->num_responses);125126for (n0 = 0; n0 < ir->num_responses; n0++)127hci_inquiry_response(n0, &r);128129goto wait_for_more;130}131132case NG_HCI_EVENT_INQUIRY_COMPL:133fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n",134hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e)));135break;136137default:138goto wait_for_more;139}140141timeout = timo;142143return (OK);144} /* hci_inquiry */145146/* Print Inquiry_Result event */147static void148hci_inquiry_response(int n, uint8_t **b)149{150ng_hci_inquiry_response *ir = (ng_hci_inquiry_response *)(*b);151152fprintf(stdout, "Inquiry result #%d\n", n);153fprintf(stdout, "\tBD_ADDR: %s\n", hci_bdaddr2str(&ir->bdaddr));154fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n",155ir->page_scan_rep_mode);156fprintf(stdout, "\tPage Scan Period Mode: %#02x\n",157ir->page_scan_period_mode);158fprintf(stdout, "\tPage Scan Mode: %#02x\n",159ir->page_scan_mode);160fprintf(stdout, "\tClass: %02x:%02x:%02x\n",161ir->uclass[2], ir->uclass[1], ir->uclass[0]);162fprintf(stdout, "\tClock offset: %#04x\n",163le16toh(ir->clock_offset));164165*b += sizeof(*ir);166} /* hci_inquiry_response */167168/* Send Create_Connection command to the unit */169static int170hci_create_connection(int s, int argc, char **argv)171{172int n0;173char b[512];174ng_hci_create_con_cp cp;175ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;176177/* Set defaults */178memset(&cp, 0, sizeof(cp));179cp.pkt_type = htole16( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |180NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |181NG_HCI_PKT_DM5);182cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;183cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;184cp.clock_offset = 0;185cp.accept_role_switch = 1;186187/* parse command parameters */188switch (argc) {189case 6:190/* accept role switch */191if (sscanf(argv[5], "%d", &n0) != 1)192return (USAGE);193194cp.accept_role_switch = n0 ? 1 : 0;195196case 5:197/* clock offset */198if (sscanf(argv[4], "%d", &n0) != 1)199return (USAGE);200201cp.clock_offset = (n0 & 0xffff);202cp.clock_offset = htole16(cp.clock_offset);203204case 4:205/* page scan mode */206if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3)207return (USAGE);208209cp.page_scan_mode = (n0 & 0xff);210211case 3:212/* page scan rep mode */213if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)214return (USAGE);215216cp.page_scan_rep_mode = (n0 & 0xff);217218case 2:219/* packet type */220if (sscanf(argv[1], "%x", &n0) != 1)221return (USAGE);222223n0 &= ( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |224NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |225NG_HCI_PKT_DM5);226if (n0 == 0)227return (USAGE);228229cp.pkt_type = (n0 & 0xffff);230cp.pkt_type = htole16(cp.pkt_type);231232case 1:233/* BD_ADDR */234if (!bt_aton(argv[0], &cp.bdaddr)) {235struct hostent *he = NULL;236237if ((he = bt_gethostbyname(argv[0])) == NULL)238return (USAGE);239240memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));241}242break;243244default:245return (USAGE);246}247248/* send request and expect status response */249n0 = sizeof(b);250if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,251NG_HCI_OCF_CREATE_CON),252(char const *) &cp, sizeof(cp), b, &n0) == ERROR)253return (ERROR);254255if (*b != 0x00)256return (FAILED);257258/* wait for event */259again:260n0 = sizeof(b);261if (hci_recv(s, b, &n0) == ERROR)262return (ERROR);263if (n0 < sizeof(*e)) {264errno = EIO;265return (ERROR);266}267268if (e->event == NG_HCI_EVENT_CON_COMPL) {269ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1);270271if (ep->status != 0x00) {272fprintf(stdout, "Status: %s [%#02x]\n",273hci_status2str(ep->status), ep->status);274return (FAILED);275}276277fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));278fprintf(stdout, "Connection handle: %d\n",279le16toh(ep->con_handle));280fprintf(stdout, "Encryption mode: %s [%d]\n",281hci_encrypt2str(ep->encryption_mode, 0),282ep->encryption_mode);283} else284goto again;285286return (OK);287} /* hci_create_connection */288289/* Send Disconnect command to the unit */290static int291hci_disconnect(int s, int argc, char **argv)292{293int n;294char b[512];295ng_hci_discon_cp cp;296ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;297298/* Set defaults */299memset(&cp, 0, sizeof(cp));300cp.reason = 0x13;301302/* parse command parameters */303switch (argc) {304case 2:305/* reason */306if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff)307return (USAGE);308309cp.reason = (uint8_t) (n & 0xff);310311case 1:312/* connection handle */313if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)314return (USAGE);315316cp.con_handle = (uint16_t) (n & 0x0fff);317cp.con_handle = htole16(cp.con_handle);318break;319320default:321return (USAGE);322}323324/* send request and expect status response */325n = sizeof(b);326if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,327NG_HCI_OCF_DISCON),328(char const *) &cp, sizeof(cp), b, &n) == ERROR)329return (ERROR);330331if (*b != 0x00)332return (FAILED);333334/* wait for event */335again:336n = sizeof(b);337if (hci_recv(s, b, &n) == ERROR)338return (ERROR);339if (n < sizeof(*e)) {340errno = EIO;341return (ERROR);342}343344if (e->event == NG_HCI_EVENT_DISCON_COMPL) {345ng_hci_discon_compl_ep *ep = (ng_hci_discon_compl_ep *)(e + 1);346347if (ep->status != 0x00) {348fprintf(stdout, "Status: %s [%#02x]\n",349hci_status2str(ep->status), ep->status);350return (FAILED);351}352353fprintf(stdout, "Connection handle: %d\n",354le16toh(ep->con_handle));355fprintf(stdout, "Reason: %s [%#02x]\n",356hci_status2str(ep->reason), ep->reason);357} else358goto again;359360return (OK);361} /* hci_disconnect */362363/* Send Add_SCO_Connection command to the unit */364static int365hci_add_sco_connection(int s, int argc, char **argv)366{367int n;368char b[512];369ng_hci_add_sco_con_cp cp;370ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;371372/* Set defaults */373memset(&cp, 0, sizeof(cp));374cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);375376/* parse command parameters */377switch (argc) {378case 2:379/* packet type */380if (sscanf(argv[1], "%x", &n) != 1)381return (USAGE);382383n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);384if (n == 0)385return (USAGE);386387cp.pkt_type = (uint16_t) (n & 0x0fff);388cp.pkt_type = htole16(cp.pkt_type);389390case 1:391/* acl connection handle */392if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)393return (USAGE);394395cp.con_handle = (uint16_t) (n & 0x0fff);396cp.con_handle = htole16(cp.con_handle);397break;398399default:400return (USAGE);401}402403/* send request and expect status response */404n = sizeof(b);405if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,406NG_HCI_OCF_ADD_SCO_CON),407(char const *) &cp, sizeof(cp), b, &n) == ERROR)408return (ERROR);409410if (*b != 0x00)411return (FAILED);412413/* wait for event */414again:415n = sizeof(b);416if (hci_recv(s, b, &n) == ERROR)417return (ERROR);418if (n < sizeof(*e)) {419errno = EIO;420return (ERROR);421}422423if (e->event == NG_HCI_EVENT_CON_COMPL) {424ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1);425426if (ep->status != 0x00) {427fprintf(stdout, "Status: %s [%#02x]\n",428hci_status2str(ep->status), ep->status);429return (FAILED);430}431432fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));433fprintf(stdout, "Connection handle: %d\n",434le16toh(ep->con_handle));435fprintf(stdout, "Encryption mode: %s [%d]\n",436hci_encrypt2str(ep->encryption_mode, 0),437ep->encryption_mode);438} else439goto again;440441return (OK);442} /* Add_SCO_Connection */443444/* Send Change_Connection_Packet_Type command to the unit */445static int446hci_change_connection_packet_type(int s, int argc, char **argv)447{448int n;449char b[512];450ng_hci_change_con_pkt_type_cp cp;451ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;452453switch (argc) {454case 2:455/* connection handle */456if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)457return (USAGE);458459cp.con_handle = (uint16_t) (n & 0x0fff);460cp.con_handle = htole16(cp.con_handle);461462/* packet type */463if (sscanf(argv[1], "%x", &n) != 1)464return (USAGE);465466cp.pkt_type = (uint16_t) (n & 0xffff);467cp.pkt_type = htole16(cp.pkt_type);468break;469470default:471return (USAGE);472}473474/* send request and expect status response */475n = sizeof(b);476if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,477NG_HCI_OCF_CHANGE_CON_PKT_TYPE),478(char const *) &cp, sizeof(cp), b, &n) == ERROR)479return (ERROR);480481if (*b != 0x00)482return (FAILED);483484/* wait for event */485again:486n = sizeof(b);487if (hci_recv(s, b, &n) == ERROR)488return (ERROR);489if (n < sizeof(*e)) {490errno = EIO;491return (ERROR);492}493494if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) {495ng_hci_con_pkt_type_changed_ep *ep =496(ng_hci_con_pkt_type_changed_ep *)(e + 1);497498if (ep->status != 0x00) {499fprintf(stdout, "Status: %s [%#02x]\n",500hci_status2str(ep->status), ep->status);501return (FAILED);502}503504fprintf(stdout, "Connection handle: %d\n",505le16toh(ep->con_handle));506fprintf(stdout, "Packet type: %#04x\n",507le16toh(ep->pkt_type));508} else509goto again;510511return (OK);512} /* hci_change_connection_packet_type */513514/* Send Remote_Name_Request command to the unit */515static int516hci_remote_name_request(int s, int argc, char **argv)517{518int n0;519char b[512];520ng_hci_remote_name_req_cp cp;521ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;522523memset(&cp, 0, sizeof(cp));524cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;525cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;526527/* parse command parameters */528switch (argc) {529case 4:530/* clock_offset */531if (sscanf(argv[3], "%x", &n0) != 1)532return (USAGE);533534cp.clock_offset = (n0 & 0xffff);535cp.clock_offset = htole16(cp.clock_offset);536537case 3:538/* page_scan_mode */539if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)540return (USAGE);541542cp.page_scan_mode = (n0 & 0xff);543544case 2:545/* page_scan_rep_mode */546if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)547return (USAGE);548549cp.page_scan_rep_mode = (n0 & 0xff);550551case 1:552/* BD_ADDR */553if (!bt_aton(argv[0], &cp.bdaddr)) {554struct hostent *he = NULL;555556if ((he = bt_gethostbyname(argv[0])) == NULL)557return (USAGE);558559memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));560}561break;562563default:564return (USAGE);565}566567/* send request and expect status response */568n0 = sizeof(b);569if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,570NG_HCI_OCF_REMOTE_NAME_REQ),571(char const *) &cp, sizeof(cp), b, &n0) == ERROR)572return (ERROR);573574if (*b != 0x00)575return (FAILED);576577/* wait for event */578again:579n0 = sizeof(b);580if (hci_recv(s, b, &n0) == ERROR)581return (ERROR);582if (n0 < sizeof(*e)) {583errno = EIO;584return (ERROR);585}586587if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) {588ng_hci_remote_name_req_compl_ep *ep =589(ng_hci_remote_name_req_compl_ep *)(e + 1);590591if (ep->status != 0x00) {592fprintf(stdout, "Status: %s [%#02x]\n",593hci_status2str(ep->status), ep->status);594return (FAILED);595}596597fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));598fprintf(stdout, "Name: %s\n", ep->name);599} else600goto again;601602return (OK);603} /* hci_remote_name_request */604605/* Send Read_Remote_Supported_Features command to the unit */606static int607hci_read_remote_supported_features(int s, int argc, char **argv)608{609int n;610char b[512];611ng_hci_read_remote_features_cp cp;612ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;613char buffer[2048];614615/* parse command parameters */616switch (argc) {617case 1:618/* connecton handle */619if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)620return (USAGE);621622cp.con_handle = (n & 0x0fff);623cp.con_handle = htole16(cp.con_handle);624break;625626default:627return (USAGE);628}629630/* send request and expect status response */631n = sizeof(b);632if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,633NG_HCI_OCF_READ_REMOTE_FEATURES),634(char const *) &cp, sizeof(cp), b, &n) == ERROR)635return (ERROR);636637if (*b != 0x00)638return (FAILED);639640/* wait for event */641again:642n = sizeof(b);643if (hci_recv(s, b, &n) == ERROR)644return (ERROR);645646if (n < sizeof(*e)) {647errno = EIO;648return (ERROR);649}650651if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) {652ng_hci_read_remote_features_compl_ep *ep =653(ng_hci_read_remote_features_compl_ep *)(e + 1);654655if (ep->status != 0x00) {656fprintf(stdout, "Status: %s [%#02x]\n",657hci_status2str(ep->status), ep->status);658return (FAILED);659}660661fprintf(stdout, "Connection handle: %d\n",662le16toh(ep->con_handle));663fprintf(stdout, "Features: ");664for (n = 0; n < sizeof(ep->features); n++)665fprintf(stdout, "%#02x ", ep->features[n]);666fprintf(stdout, "\n%s\n", hci_features2str(ep->features,667buffer, sizeof(buffer)));668} else669goto again;670671return (OK);672} /* hci_read_remote_supported_features */673674/* Send Read_Remote_Version_Information command to the unit */675static int676hci_read_remote_version_information(int s, int argc, char **argv)677{678int n;679char b[512];680ng_hci_read_remote_ver_info_cp cp;681ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;682683/* parse command parameters */684switch (argc) {685case 1:686/* connecton handle */687if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)688return (USAGE);689690cp.con_handle = (n & 0x0fff);691cp.con_handle = htole16(cp.con_handle);692break;693694default:695return (USAGE);696}697698/* send request and expect status response */699n = sizeof(b);700if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,701NG_HCI_OCF_READ_REMOTE_VER_INFO),702(char const *) &cp, sizeof(cp), b, &n) == ERROR)703return (ERROR);704705if (*b != 0x00)706return (FAILED);707708/* wait for event */709again:710n = sizeof(b);711if (hci_recv(s, b, &n) == ERROR)712return (ERROR);713714if (n < sizeof(*e)) {715errno = EIO;716return (ERROR);717}718719if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) {720ng_hci_read_remote_ver_info_compl_ep *ep =721(ng_hci_read_remote_ver_info_compl_ep *)(e + 1);722723if (ep->status != 0x00) {724fprintf(stdout, "Status: %s [%#02x]\n",725hci_status2str(ep->status), ep->status);726return (FAILED);727}728729ep->manufacturer = le16toh(ep->manufacturer);730731fprintf(stdout, "Connection handle: %d\n",732le16toh(ep->con_handle));733fprintf(stdout, "LMP version: %s [%#02x]\n",734hci_lmpver2str(ep->lmp_version), ep->lmp_version);735fprintf(stdout, "LMP sub-version: %#04x\n",736le16toh(ep->lmp_subversion));737fprintf(stdout, "Manufacturer: %s [%#04x]\n",738hci_manufacturer2str(ep->manufacturer),739ep->manufacturer);740} else741goto again;742743return (OK);744} /* hci_read_remote_version_information */745746/* Send Read_Clock_Offset command to the unit */747static int748hci_read_clock_offset(int s, int argc, char **argv)749{750int n;751char b[512];752ng_hci_read_clock_offset_cp cp;753ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;754755/* parse command parameters */756switch (argc) {757case 1:758/* connecton handle */759if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)760return (USAGE);761762cp.con_handle = (n & 0x0fff);763cp.con_handle = htole16(cp.con_handle);764break;765766default:767return (USAGE);768}769770/* send request and expect status response */771n = sizeof(b);772if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,773NG_HCI_OCF_READ_CLOCK_OFFSET),774(char const *) &cp, sizeof(cp), b, &n) == ERROR)775return (ERROR);776777if (*b != 0x00)778return (FAILED);779780/* wait for event */781again:782n = sizeof(b);783if (hci_recv(s, b, &n) == ERROR)784return (ERROR);785786if (n < sizeof(*e)) {787errno = EIO;788return (ERROR);789}790791if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) {792ng_hci_read_clock_offset_compl_ep *ep =793(ng_hci_read_clock_offset_compl_ep *)(e + 1);794795if (ep->status != 0x00) {796fprintf(stdout, "Status: %s [%#02x]\n",797hci_status2str(ep->status), ep->status);798return (FAILED);799}800801fprintf(stdout, "Connection handle: %d\n",802le16toh(ep->con_handle));803fprintf(stdout, "Clock offset: %#04x\n",804le16toh(ep->clock_offset));805} else806goto again;807808return (OK);809} /* hci_read_clock_offset */810811struct hci_command link_control_commands[] = {812{813"inquiry <LAP> <inquiry_length> <num_reponses>",814"\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \815"Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \816"input parameter contains the LAP from which the inquiry access code shall\n" \817"be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\818"specifies the total duration of the Inquiry Mode and, when this time\n" \819"expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \820"number of responses that can be received before the Inquiry is halted.\n\n" \821"\t<LAP> - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \822"\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \823"\t<num_responses> - dd",824&hci_inquiry825},826{827"create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>",828"" \829"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n\n" \830"\t<pkt> - xxxx; packet type\n" \831"" \832"\t\tACL packets\n" \833"\t\t-----------\n" \834"\t\t0x0008 DM1\n" \835"\t\t0x0010 DH1\n" \836"\t\t0x0400 DM3\n" \837"\t\t0x0800 DH3\n" \838"\t\t0x4000 DM5\n" \839"\t\t0x8000 DH5\n\n" \840"" \841"\trep_mode - d; page scan repetition mode\n" \842"" \843"\t\tPage scan repetition modes\n" \844"\t\t--------------------------\n" \845"\t\t0 Page scan repetition mode 0\n" \846"\t\t1 Page scan repetition mode 1\n" \847"\t\t2 Page scan repetition mode 2\n" \848"\n" \849"\tps_mode - d; Page scan mode\n" \850"" \851"\t\tPage scan modes\n" \852"\t\t---------------\n" \853"\t\t0 Mandatory page scan mode\n" \854"\t\t1 Optional page scan mode1\n" \855"\t\t2 Optional page scan mode2\n" \856"\t\t3 Optional page scan mode3\n" \857"\n" \858"\tclck_off - dddd; clock offset. Use 0 if unknown\n\n" \859"\trole_sw - d; allow (1) or deny role switch\n",860&hci_create_connection861},862{863"disconnect <connection_handle> <reason>",864"\nThe Disconnection command is used to terminate an existing connection.\n" \865"The connection handle command parameter indicates which connection is to\n" \866"be disconnected. The Reason command parameter indicates the reason for\n" \867"ending the connection.\n\n" \868"\t<connection_handle> - dddd; connection handle\n" \869"\t<reason> - dd; reason; usually 19 (0x13) - user ended;\n" \870"\t also 0x05, 0x13-0x15, 0x1A, 0x29",871&hci_disconnect872},873{874"add_sco_connection <acl connection handle> <packet type>",875"This command will cause the link manager to create a SCO connection using\n" \876"the ACL connection specified by the connection handle command parameter.\n" \877"The Link Manager will determine how the new connection is established. This\n"\878"connection is determined by the current state of the device, its piconet,\n" \879"and the state of the device to be connected. The packet type command parameter\n" \880"specifies which packet types the Link Manager should use for the connection.\n"\881"The Link Manager must only use the packet type(s) specified by the packet\n" \882"type command parameter for sending HCI SCO data packets. Multiple packet\n" \883"types may be specified for the packet type command parameter by performing\n" \884"a bitwise OR operation of the different packet types. Note: An SCO connection\n" \885"can only be created when an ACL connection already exists and when it is\n" \886"not put in park mode.\n\n" \887"\t<connection_handle> - dddd; ACL connection handle\n" \888"\t<packet_type> - xxxx; packet type\n" \889"" \890"\t\tSCO packets\n" \891"\t\t-----------\n" \892"\t\t0x0020 HV1\n" \893"\t\t0x0040 HV2\n" \894"\t\t0x0080 HV3\n",895&hci_add_sco_connection896},897{898"change_connection_packet_type <connection_hande> <packet_type>",899"The Change_Connection_Packet_Type command is used to change which packet\n" \900"types can be used for a connection that is currently established. This\n" \901"allows current connections to be dynamically modified to support different\n" \902"types of user data. The Packet_Type command parameter specifies which\n" \903"packet types the Link Manager can use for the connection. Multiple packet\n" \904"types may be specified for the Packet_Type command parameter by bitwise OR\n" \905"operation of the different packet types.\n\n" \906"\t<connection_handle> - dddd; connection handle\n" \907"\t<packet_type> - xxxx; packet type mask\n" \908"" \909"\t\tACL packets\n" \910"\t\t-----------\n" \911"\t\t0x0008 DM1\n" \912"\t\t0x0010 DH1\n" \913"\t\t0x0400 DM3\n" \914"\t\t0x0800 DH3\n" \915"\t\t0x4000 DM5\n" \916"\t\t0x8000 DH5\n\n" \917"" \918"\t\tSCO packets\n" \919"\t\t-----------\n" \920"\t\t0x0020 HV1\n" \921"\t\t0x0040 HV2\n" \922"\t\t0x0080 HV3\n" \923"",924&hci_change_connection_packet_type925},926{927"remote_name_request <BD_ADDR> <ps_rep_mode> <ps_mode> <clock_offset>",928"\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \929"name of another Bluetooth unit.\n\n" \930"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \931"\t<ps_rep_mode> - dd; page scan repetition mode [0-2]\n" \932"\t<ps_mode> - dd; page scan mode [0-3]\n" \933"\t<clock_offset> - xxxx; clock offset [0 - 0xffff]",934&hci_remote_name_request935},936{937"read_remote_supported_features <connection_handle>",938"\nThis command requests a list of the supported features for the remote\n" \939"unit identified by the connection handle parameter. The connection handle\n" \940"must be a connection handle for an ACL connection.\n\n" \941"\t<connection_handle> - dddd; connection handle",942&hci_read_remote_supported_features943},944{945"read_remote_version_information <connection_handle>",946"\nThis command will obtain the values for the version information for the\n" \947"remote Bluetooth unit identified by the connection handle parameter. The\n" \948"connection handle must be a connection handle for an ACL connection.\n\n" \949"\t<connection_handle> - dddd; connection handle",950&hci_read_remote_version_information951},952{953"read_clock_offset <connection_handle>",954"\nThis command allows the Host to read the clock offset from the remote unit.\n" \955"\t<connection_handle> - dddd; connection handle",956&hci_read_clock_offset957},958{959NULL,960}};961962963964