mgmtops.c revision 3c8ab480f9020f49d51f4b8eb17746b70d16b989
1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/* 2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * BlueZ - Bluetooth protocol stack for Linux 4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Copyright (C) 2010 Nokia Corporation 6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org> 7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * This program is free software; you can redistribute it and/or modify 9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * it under the terms of the GNU General Public License as published by 10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * the Free Software Foundation; either version 2 of the License, or 11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * (at your option) any later version. 12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * This program is distributed in the hope that it will be useful, 14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * but WITHOUT ANY WARRANTY; without even the implied warranty of 15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * GNU General Public License for more details. 17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * You should have received a copy of the GNU General Public License 19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * along with this program; if not, write to the Free Software 20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */ 23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#ifdef HAVE_CONFIG_H 25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <config.h> 26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif 27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <stdio.h> 29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <errno.h> 30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <unistd.h> 31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <stdlib.h> 32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/types.h> 33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/ioctl.h> 34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/wait.h> 35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <glib.h> 37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/bluetooth.h> 39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/hci.h> 40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/sdp.h> 41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/sdp_lib.h> 42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/mgmt.h> 43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "plugin.h" 45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "log.h" 46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "adapter.h" 47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "manager.h" 48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "device.h" 49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "event.h" 50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define MGMT_BUF_SIZE 1024 52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int max_index = -1; 54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic struct controller_info { 55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean valid; 56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean notified; 57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t type; 58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru bdaddr_t bdaddr; 59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t features[8]; 60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t dev_class[3]; 61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t manufacturer; 62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t hci_ver; 63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t hci_rev; 64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean enabled; 65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean connectable; 66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean discoverable; 67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean pairable; 68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t sec_mode; 69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru GSList *connections; 70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} *controllers = NULL; 71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_sock = -1; 73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic guint mgmt_watch = 0; 74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint8_t mgmt_version = 0; 76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint16_t mgmt_revision = 0; 77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void read_version_complete(int sk, void *buf, size_t len) 79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_hdr hdr; 81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_rp_read_version *rp = buf; 82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (len < sizeof(*rp)) { 84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Too small read version complete event"); 85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_revision = btohs(bt_get_unaligned(&rp->revision)); 89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_version = rp->version; 90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("version %u revision %u", mgmt_version, mgmt_revision); 92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(&hdr, 0, sizeof(hdr)); 94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr.opcode = htobs(MGMT_OP_READ_INDEX_LIST); 95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (write(sk, &hdr, sizeof(hdr)) < 0) 96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Unable to read controller index list: %s (%d)", 97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru strerror(errno), errno); 98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void add_controller(uint16_t index) 101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (index > max_index) { 103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru size_t size = sizeof(struct controller_info) * (index + 1); 104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru max_index = index; 105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru controllers = g_realloc(controllers, size); 106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(&controllers[index], 0, sizeof(struct controller_info)); 109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru controllers[index].valid = TRUE; 111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("Added controller %u", index); 113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void read_info(int sk, uint16_t index) 116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)]; 118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_hdr *hdr = (void *) buf; 119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)]; 120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(buf, 0, sizeof(buf)); 122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->opcode = htobs(MGMT_OP_READ_INFO); 123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->len = htobs(sizeof(*cp)); 124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru cp->index = htobs(index); 126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (write(sk, buf, sizeof(buf)) < 0) 128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Unable to send read_info command: %s (%d)", 129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru strerror(errno), errno); 130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void get_connections(int sk, uint16_t index) 133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_get_connections)]; 135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_hdr *hdr = (void *) buf; 136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_cp_get_connections *cp = (void *) &buf[sizeof(*hdr)]; 137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(buf, 0, sizeof(buf)); 139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->opcode = htobs(MGMT_OP_GET_CONNECTIONS); 140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->len = htobs(sizeof(*cp)); 141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru cp->index = htobs(index); 143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (write(sk, buf, sizeof(buf)) < 0) 145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Unable to send get_connections command: %s (%d)", 146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru strerror(errno), errno); 147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_index_added(int sk, void *buf, size_t len) 150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_ev_index_added *ev = buf; 152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t index; 153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (len < sizeof(*ev)) { 155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Too small index added event"); 156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru index = btohs(bt_get_unaligned(&ev->index)); 160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru add_controller(index); 162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru read_info(sk, index); 163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void remove_controller(uint16_t index) 166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (index > max_index) 168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (!controllers[index].valid) 171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru btd_manager_unregister_adapter(index); 174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(&controllers[index], 0, sizeof(struct controller_info)); 176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("Removed controller %u", index); 178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_index_removed(int sk, void *buf, size_t len) 181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_ev_index_removed *ev = buf; 183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t index; 184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (len < sizeof(*ev)) { 186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Too small index removed event"); 187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru index = btohs(bt_get_unaligned(&ev->index)); 191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru remove_controller(index); 193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_mode(int index, uint16_t opcode, uint8_t val) 196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)]; 198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_hdr *hdr = (void *) buf; 199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)]; 200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru memset(buf, 0, sizeof(buf)); 202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->opcode = htobs(opcode); 203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru hdr->len = htobs(sizeof(*cp)); 204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru cp->index = htobs(index); 206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru cp->val = val; 207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (write(mgmt_sock, buf, sizeof(buf)) < 0) 209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return -errno; 210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return 0; 212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_connectable(int index, gboolean connectable) 215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("index %d connectable %d", index, connectable); 217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return mgmt_set_mode(index, MGMT_OP_SET_CONNECTABLE, connectable); 218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_discoverable(int index, gboolean discoverable) 221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("index %d discoverable %d", index, discoverable); 223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return mgmt_set_mode(index, MGMT_OP_SET_DISCOVERABLE, discoverable); 224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_pairable(int index, gboolean pairable) 227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("index %d pairable %d", index, pairable); 229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable); 230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_update_powered(int index, uint8_t powered) 233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct controller_info *info; 235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct btd_adapter *adapter; 236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru gboolean pairable, discoverable; 237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t on_mode; 238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (index > max_index) { 240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Unexpected index %u", index); 241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return -ENODEV; 242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info = &controllers[index]; 245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info->enabled = powered; 247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru adapter = manager_find_adapter(&info->bdaddr); 249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (adapter == NULL) { 250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("Adapter not found"); 251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return -ENODEV; 252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (!powered) { 255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info->connectable = FALSE; 256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info->pairable = FALSE; 257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info->discoverable = FALSE; 258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru btd_adapter_stop(adapter); 260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return 0; 261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru btd_adapter_start(adapter); 264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable); 266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru discoverable = (on_mode == MODE_DISCOVERABLE); 268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (on_mode == MODE_DISCOVERABLE && !info->discoverable) 270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_set_discoverable(index, TRUE); 271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru else if (on_mode == MODE_CONNECTABLE && !info->connectable) 272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_set_connectable(index, TRUE); 273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru else { 274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t mode = 0; 275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (info->connectable) 277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mode |= SCAN_PAGE; 278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (info->discoverable) 279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mode |= SCAN_INQUIRY; 280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru adapter_mode_changed(adapter, mode); 282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (info->pairable != pairable) 285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_set_pairable(index, pairable); 286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return 0; 288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_powered(int sk, void *buf, size_t len) 291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_mode *ev = buf; 293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t index; 294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (len < sizeof(*ev)) { 296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Too small powered event"); 297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru index = btohs(bt_get_unaligned(&ev->index)); 301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("Controller %u powered %u", index, ev->val); 303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mgmt_update_powered(index, ev->val); 305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_discoverable(int sk, void *buf, size_t len) 308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_mode *ev = buf; 310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct controller_info *info; 311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct btd_adapter *adapter; 312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t index; 313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint8_t mode; 314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (len < sizeof(*ev)) { 316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Too small discoverable event"); 317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru index = btohs(bt_get_unaligned(&ev->index)); 321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru DBG("Controller %u discoverable %u", index, ev->val); 323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (index > max_index) { 325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru error("Unexpected index %u in discoverable event", index); 326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info = &controllers[index]; 330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru info->discoverable = ev->val ? TRUE : FALSE; 332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru adapter = manager_find_adapter(&info->bdaddr); 334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (!adapter) 335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return; 336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (info->connectable) 338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mode = SCAN_PAGE; 339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru else 340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mode = 0; 341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (info->discoverable) 343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru mode |= SCAN_INQUIRY; 344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru adapter_mode_changed(adapter, mode); 346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_connectable(int sk, void *buf, size_t len) 349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct mgmt_mode *ev = buf; 351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct controller_info *info; 352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru struct btd_adapter *adapter; 353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uint16_t index; 354 uint8_t mode; 355 356 if (len < sizeof(*ev)) { 357 error("Too small connectable event"); 358 return; 359 } 360 361 index = btohs(bt_get_unaligned(&ev->index)); 362 363 DBG("Controller %u connectable %u", index, ev->val); 364 365 if (index > max_index) { 366 error("Unexpected index %u in connectable event", index); 367 return; 368 } 369 370 info = &controllers[index]; 371 372 info->connectable = ev->val ? TRUE : FALSE; 373 374 adapter = manager_find_adapter(&info->bdaddr); 375 if (!adapter) 376 return; 377 378 if (info->discoverable) 379 mode = SCAN_INQUIRY; 380 else 381 mode = 0; 382 383 if (info->connectable) 384 mode |= SCAN_PAGE; 385 386 adapter_mode_changed(adapter, mode); 387} 388 389static void mgmt_pairable(int sk, void *buf, size_t len) 390{ 391 struct mgmt_mode *ev = buf; 392 struct controller_info *info; 393 struct btd_adapter *adapter; 394 uint16_t index; 395 396 if (len < sizeof(*ev)) { 397 error("Too small pairable event"); 398 return; 399 } 400 401 index = btohs(bt_get_unaligned(&ev->index)); 402 403 DBG("Controller %u pairable %u", index, ev->val); 404 405 if (index > max_index) { 406 error("Unexpected index %u in pairable event", index); 407 return; 408 } 409 410 info = &controllers[index]; 411 412 info->pairable = ev->val ? TRUE : FALSE; 413 414 adapter = manager_find_adapter(&info->bdaddr); 415 if (!adapter) 416 return; 417 418 btd_adapter_pairable_changed(adapter, info->pairable); 419} 420 421static void mgmt_new_key(int sk, void *buf, size_t len) 422{ 423 struct mgmt_ev_new_key *ev = buf; 424 struct controller_info *info; 425 uint16_t index; 426 427 if (len != sizeof(*ev)) { 428 error("new_key event size mismatch (%zu != %zu)", 429 len, sizeof(*ev)); 430 return; 431 } 432 433 index = btohs(bt_get_unaligned(&ev->index)); 434 435 DBG("Controller %u new key of type %u pin_len %u", index, 436 ev->key.type, ev->key.pin_len); 437 438 if (index > max_index) { 439 error("Unexpected index %u in new_key event", index); 440 return; 441 } 442 443 if (ev->key.pin_len > 16) { 444 error("Invalid PIN length (%u) in new_key event", 445 ev->key.pin_len); 446 return; 447 } 448 449 info = &controllers[index]; 450 451 btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr, 452 ev->key.val, ev->key.type, 453 ev->key.pin_len, ev->old_key_type); 454} 455 456static void mgmt_device_connected(int sk, void *buf, size_t len) 457{ 458 struct mgmt_ev_device_connected *ev = buf; 459 struct controller_info *info; 460 uint16_t index; 461 char addr[18]; 462 463 if (len < sizeof(*ev)) { 464 error("Too small device_connected event"); 465 return; 466 } 467 468 index = btohs(bt_get_unaligned(&ev->index)); 469 ba2str(&ev->bdaddr, addr); 470 471 DBG("hci%u device %s connected", index, addr); 472 473 if (index > max_index) { 474 error("Unexpected index %u in device_connected event", index); 475 return; 476 } 477 478 info = &controllers[index]; 479 480 btd_event_conn_complete(&info->bdaddr, 0, &ev->bdaddr); 481} 482 483static void mgmt_device_disconnected(int sk, void *buf, size_t len) 484{ 485 struct mgmt_ev_device_disconnected *ev = buf; 486 struct controller_info *info; 487 uint16_t index; 488 char addr[18]; 489 490 if (len < sizeof(*ev)) { 491 error("Too small device_disconnected event"); 492 return; 493 } 494 495 index = btohs(bt_get_unaligned(&ev->index)); 496 ba2str(&ev->bdaddr, addr); 497 498 DBG("hci%u device %s disconnected", index, addr); 499 500 if (index > max_index) { 501 error("Unexpected index %u in device_disconnected event", index); 502 return; 503 } 504 505 info = &controllers[index]; 506 507 btd_event_disconn_complete(&info->bdaddr, &ev->bdaddr); 508} 509 510static void mgmt_connect_failed(int sk, void *buf, size_t len) 511{ 512 struct mgmt_ev_connect_failed *ev = buf; 513 struct controller_info *info; 514 uint16_t index; 515 char addr[18]; 516 517 if (len < sizeof(*ev)) { 518 error("Too small connect_failed event"); 519 return; 520 } 521 522 index = btohs(bt_get_unaligned(&ev->index)); 523 ba2str(&ev->bdaddr, addr); 524 525 DBG("hci%u %s status %u", index, addr, ev->status); 526 527 if (index > max_index) { 528 error("Unexpected index %u in connect_failed event", index); 529 return; 530 } 531 532 info = &controllers[index]; 533 534 btd_event_conn_complete(&info->bdaddr, ev->status, &ev->bdaddr); 535} 536 537static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin) 538{ 539 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_pin_code_reply)]; 540 struct mgmt_hdr *hdr = (void *) buf; 541 size_t buf_len; 542 char addr[18]; 543 544 ba2str(bdaddr, addr); 545 DBG("index %d addr %s pin %s", index, addr, pin ? pin : "<none>"); 546 547 memset(buf, 0, sizeof(buf)); 548 549 if (pin == NULL) { 550 struct mgmt_cp_pin_code_neg_reply *cp; 551 552 hdr->opcode = htobs(MGMT_OP_PIN_CODE_NEG_REPLY); 553 hdr->len = htobs(sizeof(*cp)); 554 555 cp = (void *) &buf[sizeof(*hdr)]; 556 cp->index = htobs(index); 557 bacpy(&cp->bdaddr, bdaddr); 558 559 buf_len = sizeof(*hdr) + sizeof(*cp); 560 } else { 561 struct mgmt_cp_pin_code_reply *cp; 562 size_t pin_len; 563 564 pin_len = strlen(pin); 565 if (pin_len > 16) 566 return -EINVAL; 567 568 hdr->opcode = htobs(MGMT_OP_PIN_CODE_REPLY); 569 hdr->len = htobs(sizeof(*cp)); 570 571 cp = (void *) &buf[sizeof(*hdr)]; 572 cp->index = htobs(index); 573 bacpy(&cp->bdaddr, bdaddr); 574 cp->pin_len = pin_len; 575 memcpy(cp->pin_code, pin, pin_len); 576 577 buf_len = sizeof(*hdr) + sizeof(*cp); 578 } 579 580 if (write(mgmt_sock, buf, buf_len) < 0) 581 return -errno; 582 583 return 0; 584} 585 586static void mgmt_pin_code_request(int sk, void *buf, size_t len) 587{ 588 struct mgmt_ev_pin_code_request *ev = buf; 589 struct controller_info *info; 590 uint16_t index; 591 char addr[18]; 592 int err; 593 594 if (len < sizeof(*ev)) { 595 error("Too small pin_code_request event"); 596 return; 597 } 598 599 index = btohs(bt_get_unaligned(&ev->index)); 600 ba2str(&ev->bdaddr, addr); 601 602 DBG("hci%u %s", index, addr); 603 604 if (index > max_index) { 605 error("Unexpected index %u in pin_code_request event", index); 606 return; 607 } 608 609 info = &controllers[index]; 610 611 err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr); 612 if (err < 0) { 613 error("btd_event_request_pin: %s", strerror(-err)); 614 mgmt_pincode_reply(index, &ev->bdaddr, NULL); 615 } 616} 617 618static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) 619{ 620 if (uuid->type == SDP_UUID16) 621 sdp_uuid16_to_uuid128(uuid128, uuid); 622 else if (uuid->type == SDP_UUID32) 623 sdp_uuid32_to_uuid128(uuid128, uuid); 624 else 625 memcpy(uuid128, uuid, sizeof(*uuid)); 626} 627 628static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint) 629{ 630 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_uuid)]; 631 struct mgmt_hdr *hdr = (void *) buf; 632 struct mgmt_cp_add_uuid *cp = (void *) &buf[sizeof(*hdr)]; 633 uuid_t uuid128; 634 635 DBG("index %d", index); 636 637 uuid_to_uuid128(&uuid128, uuid); 638 639 memset(buf, 0, sizeof(buf)); 640 hdr->opcode = htobs(MGMT_OP_ADD_UUID); 641 hdr->len = htobs(sizeof(*cp)); 642 643 cp->index = htobs(index); 644 memcpy(cp->uuid, uuid128.value.uuid128.data, 16); 645 cp->svc_hint = svc_hint; 646 647 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 648 return -errno; 649 650 return 0; 651} 652 653static int mgmt_remove_uuid(int index, uuid_t *uuid) 654{ 655 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_uuid)]; 656 struct mgmt_hdr *hdr = (void *) buf; 657 struct mgmt_cp_remove_uuid *cp = (void *) &buf[sizeof(*hdr)]; 658 uuid_t uuid128; 659 660 DBG("index %d", index); 661 662 uuid_to_uuid128(&uuid128, uuid); 663 664 memset(buf, 0, sizeof(buf)); 665 hdr->opcode = htobs(MGMT_OP_REMOVE_UUID); 666 hdr->len = htobs(sizeof(*cp)); 667 668 cp->index = htobs(index); 669 memcpy(cp->uuid, uuid128.value.uuid128.data, 16); 670 671 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 672 return -errno; 673 674 return 0; 675} 676 677static int clear_uuids(int index) 678{ 679 uuid_t uuid_any; 680 681 memset(&uuid_any, 0, sizeof(uuid_any)); 682 uuid_any.type = SDP_UUID128; 683 684 return mgmt_remove_uuid(index, &uuid_any); 685} 686 687static void read_index_list_complete(int sk, void *buf, size_t len) 688{ 689 struct mgmt_rp_read_index_list *rp = buf; 690 uint16_t num; 691 int i; 692 693 if (len < sizeof(*rp)) { 694 error("Too small read index list complete event"); 695 return; 696 } 697 698 num = btohs(bt_get_unaligned(&rp->num_controllers)); 699 700 if (num * sizeof(uint16_t) + sizeof(*rp) != len) { 701 error("Incorrect packet size for index list event"); 702 return; 703 } 704 705 for (i = 0; i < num; i++) { 706 uint16_t index; 707 708 index = btohs(bt_get_unaligned(&rp->index[i])); 709 710 add_controller(index); 711 get_connections(sk, index); 712 clear_uuids(index); 713 } 714} 715 716static int mgmt_set_powered(int index, gboolean powered) 717{ 718 DBG("index %d powered %d", index, powered); 719 return mgmt_set_mode(index, MGMT_OP_SET_POWERED, powered); 720} 721 722static void read_info_complete(int sk, void *buf, size_t len) 723{ 724 struct mgmt_rp_read_info *rp = buf; 725 struct controller_info *info; 726 struct btd_adapter *adapter; 727 uint8_t mode; 728 uint16_t index; 729 char addr[18]; 730 731 if (len < sizeof(*rp)) { 732 error("Too small read info complete event"); 733 return; 734 } 735 736 index = btohs(bt_get_unaligned(&rp->index)); 737 if (index > max_index) { 738 error("Unexpected index %u in read info complete", index); 739 return; 740 } 741 742 mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 1); 743 744 info = &controllers[index]; 745 info->type = rp->type; 746 info->enabled = rp->powered; 747 info->connectable = rp->connectable; 748 info->discoverable = rp->discoverable; 749 info->pairable = rp->pairable; 750 info->sec_mode = rp->sec_mode; 751 bacpy(&info->bdaddr, &rp->bdaddr); 752 memcpy(info->dev_class, rp->dev_class, 3); 753 memcpy(info->features, rp->features, 8); 754 info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer)); 755 info->hci_ver = rp->hci_ver; 756 info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev)); 757 758 ba2str(&info->bdaddr, addr); 759 DBG("hci%u type %u addr %s", index, info->type, addr); 760 DBG("hci%u class 0x%02x%02x%02x", index, 761 info->dev_class[2], info->dev_class[1], info->dev_class[0]); 762 DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer, 763 info->hci_ver, info->hci_rev); 764 DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index, 765 info->enabled, info->discoverable, 766 info->pairable, info->sec_mode); 767 768 adapter = btd_manager_register_adapter(index); 769 if (adapter == NULL) { 770 error("mgmtops: unable to register adapter"); 771 return; 772 } 773 774 btd_adapter_get_mode(adapter, &mode, NULL, NULL); 775 if (mode == MODE_OFF) { 776 mgmt_set_powered(index, FALSE); 777 return; 778 } 779 780 if (info->enabled) 781 mgmt_update_powered(index, TRUE); 782 else 783 mgmt_set_powered(index, TRUE); 784 785 btd_adapter_unref(adapter); 786} 787 788static void set_powered_complete(int sk, void *buf, size_t len) 789{ 790 struct mgmt_mode *rp = buf; 791 uint16_t index; 792 793 if (len < sizeof(*rp)) { 794 error("Too small set powered complete event"); 795 return; 796 } 797 798 index = btohs(bt_get_unaligned(&rp->index)); 799 800 DBG("hci%d powered %u", index, rp->val); 801 802 mgmt_update_powered(index, rp->val); 803} 804 805static void set_discoverable_complete(int sk, void *buf, size_t len) 806{ 807 struct mgmt_mode *rp = buf; 808 struct controller_info *info; 809 struct btd_adapter *adapter; 810 uint16_t index; 811 uint8_t mode; 812 813 if (len < sizeof(*rp)) { 814 error("Too small set discoverable complete event"); 815 return; 816 } 817 818 index = btohs(bt_get_unaligned(&rp->index)); 819 820 DBG("hci%d discoverable %u", index, rp->val); 821 822 if (index > max_index) { 823 error("Unexpected index %u in discoverable complete", index); 824 return; 825 } 826 827 info = &controllers[index]; 828 829 info->discoverable = rp->val ? TRUE : FALSE; 830 831 adapter = manager_find_adapter(&info->bdaddr); 832 if (!adapter) 833 return; 834 835 /* set_discoverable will always also change page scanning */ 836 mode = SCAN_PAGE; 837 838 if (info->discoverable) 839 mode |= SCAN_INQUIRY; 840 841 adapter_mode_changed(adapter, mode); 842} 843 844static void set_connectable_complete(int sk, void *buf, size_t len) 845{ 846 struct mgmt_mode *rp = buf; 847 struct controller_info *info; 848 struct btd_adapter *adapter; 849 uint16_t index; 850 851 if (len < sizeof(*rp)) { 852 error("Too small set connectable complete event"); 853 return; 854 } 855 856 index = btohs(bt_get_unaligned(&rp->index)); 857 858 DBG("hci%d connectable %u", index, rp->val); 859 860 if (index > max_index) { 861 error("Unexpected index %u in connectable complete", index); 862 return; 863 } 864 865 info = &controllers[index]; 866 867 info->connectable = rp->val ? TRUE : FALSE; 868 869 adapter = manager_find_adapter(&info->bdaddr); 870 if (adapter) 871 adapter_mode_changed(adapter, rp->val ? SCAN_PAGE : 0); 872} 873 874static void set_pairable_complete(int sk, void *buf, size_t len) 875{ 876 struct mgmt_mode *rp = buf; 877 struct controller_info *info; 878 struct btd_adapter *adapter; 879 uint16_t index; 880 881 if (len < sizeof(*rp)) { 882 error("Too small set pairable complete event"); 883 return; 884 } 885 886 index = btohs(bt_get_unaligned(&rp->index)); 887 888 DBG("hci%d pairable %u", index, rp->val); 889 890 if (index > max_index) { 891 error("Unexpected index %u in pairable complete", index); 892 return; 893 } 894 895 info = &controllers[index]; 896 897 info->pairable = rp->val ? TRUE : FALSE; 898 899 adapter = manager_find_adapter(&info->bdaddr); 900 if (!adapter) 901 return; 902 903 btd_adapter_pairable_changed(adapter, info->pairable); 904} 905 906static void disconnect_complete(int sk, void *buf, size_t len) 907{ 908 struct mgmt_rp_disconnect *rp = buf; 909 struct controller_info *info; 910 uint16_t index; 911 char addr[18]; 912 913 if (len < sizeof(*rp)) { 914 error("Too small disconnect complete event"); 915 return; 916 } 917 918 index = btohs(bt_get_unaligned(&rp->index)); 919 920 ba2str(&rp->bdaddr, addr); 921 922 DBG("hci%d %s disconnected", index, addr); 923 924 if (index > max_index) { 925 error("Unexpected index %u in disconnect complete", index); 926 return; 927 } 928 929 info = &controllers[index]; 930 931 btd_event_disconn_complete(&info->bdaddr, &rp->bdaddr); 932} 933 934static void get_connections_complete(int sk, void *buf, size_t len) 935{ 936 struct mgmt_rp_get_connections *rp = buf; 937 struct controller_info *info; 938 uint16_t index; 939 int i; 940 941 if (len < sizeof(*rp)) { 942 error("Too small get_connections complete event"); 943 return; 944 } 945 946 if (len < (sizeof(*rp) + (rp->conn_count * sizeof(bdaddr_t)))) { 947 error("Too small get_connections complete event"); 948 return; 949 } 950 951 index = btohs(bt_get_unaligned(&rp->index)); 952 953 if (index > max_index) { 954 error("Unexpected index %u in get_connections complete", 955 index); 956 return; 957 } 958 959 info = &controllers[index]; 960 961 for (i = 0; i < rp->conn_count; i++) { 962 bdaddr_t *bdaddr = g_memdup(&rp->conn[i], sizeof(bdaddr_t)); 963 info->connections = g_slist_append(info->connections, bdaddr); 964 } 965 966 read_info(sk, index); 967} 968 969static void mgmt_cmd_complete(int sk, void *buf, size_t len) 970{ 971 struct mgmt_ev_cmd_complete *ev = buf; 972 uint16_t opcode; 973 974 DBG(""); 975 976 if (len < sizeof(*ev)) { 977 error("Too small management command complete event packet"); 978 return; 979 } 980 981 opcode = btohs(bt_get_unaligned(&ev->opcode)); 982 983 switch (opcode) { 984 case MGMT_OP_READ_VERSION: 985 read_version_complete(sk, ev->data, len - sizeof(*ev)); 986 break; 987 case MGMT_OP_READ_INDEX_LIST: 988 read_index_list_complete(sk, ev->data, len - sizeof(*ev)); 989 break; 990 case MGMT_OP_READ_INFO: 991 read_info_complete(sk, ev->data, len - sizeof(*ev)); 992 break; 993 case MGMT_OP_SET_POWERED: 994 set_powered_complete(sk, ev->data, len - sizeof(*ev)); 995 break; 996 case MGMT_OP_SET_DISCOVERABLE: 997 set_discoverable_complete(sk, ev->data, len - sizeof(*ev)); 998 break; 999 case MGMT_OP_SET_CONNECTABLE: 1000 set_connectable_complete(sk, ev->data, len - sizeof(*ev)); 1001 break; 1002 case MGMT_OP_SET_PAIRABLE: 1003 set_pairable_complete(sk, ev->data, len - sizeof(*ev)); 1004 break; 1005 case MGMT_OP_ADD_UUID: 1006 DBG("add_uuid complete"); 1007 break; 1008 case MGMT_OP_REMOVE_UUID: 1009 DBG("remove_uuid complete"); 1010 break; 1011 case MGMT_OP_SET_DEV_CLASS: 1012 DBG("set_dev_class complete"); 1013 break; 1014 case MGMT_OP_SET_SERVICE_CACHE: 1015 DBG("set_service_cache complete"); 1016 break; 1017 case MGMT_OP_LOAD_KEYS: 1018 DBG("load_keys complete"); 1019 break; 1020 case MGMT_OP_REMOVE_KEY: 1021 DBG("remove_key complete"); 1022 break; 1023 case MGMT_OP_DISCONNECT: 1024 DBG("disconnect complete"); 1025 disconnect_complete(sk, ev->data, len - sizeof(*ev)); 1026 break; 1027 case MGMT_OP_GET_CONNECTIONS: 1028 get_connections_complete(sk, ev->data, len - sizeof(*ev)); 1029 break; 1030 case MGMT_OP_PIN_CODE_REPLY: 1031 DBG("pin_code_reply complete"); 1032 break; 1033 case MGMT_OP_PIN_CODE_NEG_REPLY: 1034 DBG("pin_code_neg_reply complete"); 1035 break; 1036 default: 1037 error("Unknown command complete for opcode %u", opcode); 1038 break; 1039 } 1040} 1041 1042static void mgmt_cmd_status(int sk, void *buf, size_t len) 1043{ 1044 struct mgmt_ev_cmd_status *ev = buf; 1045 uint16_t opcode; 1046 1047 if (len < sizeof(*ev)) { 1048 error("Too small management command status event packet"); 1049 return; 1050 } 1051 1052 opcode = btohs(bt_get_unaligned(&ev->opcode)); 1053 1054 DBG("status %u opcode %u", ev->status, opcode); 1055} 1056 1057static void mgmt_controller_error(int sk, void *buf, size_t len) 1058{ 1059 struct mgmt_ev_controller_error *ev = buf; 1060 uint16_t index; 1061 1062 if (len < sizeof(*ev)) { 1063 error("Too small management controller error event packet"); 1064 return; 1065 } 1066 1067 index = btohs(bt_get_unaligned(&ev->index)); 1068 1069 DBG("index %u error_code %u", index, ev->error_code); 1070} 1071 1072static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) 1073{ 1074 char buf[MGMT_BUF_SIZE]; 1075 struct mgmt_hdr *hdr = (void *) buf; 1076 int sk; 1077 ssize_t ret; 1078 uint16_t len, opcode; 1079 1080 DBG("cond %d", cond); 1081 1082 if (cond & G_IO_NVAL) 1083 return FALSE; 1084 1085 sk = g_io_channel_unix_get_fd(io); 1086 1087 if (cond & (G_IO_ERR | G_IO_HUP)) { 1088 error("Error on management socket"); 1089 return FALSE; 1090 } 1091 1092 ret = read(sk, buf, sizeof(buf)); 1093 if (ret < 0) { 1094 error("Unable to read from management socket: %s (%d)", 1095 strerror(errno), errno); 1096 return TRUE; 1097 } 1098 1099 DBG("Received %zd bytes from management socket", ret); 1100 1101 if (ret < MGMT_HDR_SIZE) { 1102 error("Too small Management packet"); 1103 return TRUE; 1104 } 1105 1106 opcode = btohs(bt_get_unaligned(&hdr->opcode)); 1107 len = btohs(bt_get_unaligned(&hdr->len)); 1108 1109 if (ret != MGMT_HDR_SIZE + len) { 1110 error("Packet length mismatch. ret %zd len %u", ret, len); 1111 return TRUE; 1112 } 1113 1114 switch (opcode) { 1115 case MGMT_EV_CMD_COMPLETE: 1116 mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len); 1117 break; 1118 case MGMT_EV_CMD_STATUS: 1119 mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len); 1120 break; 1121 case MGMT_EV_CONTROLLER_ERROR: 1122 mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len); 1123 break; 1124 case MGMT_EV_INDEX_ADDED: 1125 mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len); 1126 break; 1127 case MGMT_EV_INDEX_REMOVED: 1128 mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len); 1129 break; 1130 case MGMT_EV_POWERED: 1131 mgmt_powered(sk, buf + MGMT_HDR_SIZE, len); 1132 break; 1133 case MGMT_EV_DISCOVERABLE: 1134 mgmt_discoverable(sk, buf + MGMT_HDR_SIZE, len); 1135 break; 1136 case MGMT_EV_CONNECTABLE: 1137 mgmt_connectable(sk, buf + MGMT_HDR_SIZE, len); 1138 break; 1139 case MGMT_EV_PAIRABLE: 1140 mgmt_pairable(sk, buf + MGMT_HDR_SIZE, len); 1141 break; 1142 case MGMT_EV_NEW_KEY: 1143 mgmt_new_key(sk, buf + MGMT_HDR_SIZE, len); 1144 break; 1145 case MGMT_EV_DEVICE_CONNECTED: 1146 mgmt_device_connected(sk, buf + MGMT_HDR_SIZE, len); 1147 break; 1148 case MGMT_EV_DEVICE_DISCONNECTED: 1149 mgmt_device_disconnected(sk, buf + MGMT_HDR_SIZE, len); 1150 break; 1151 case MGMT_EV_CONNECT_FAILED: 1152 mgmt_connect_failed(sk, buf + MGMT_HDR_SIZE, len); 1153 break; 1154 case MGMT_EV_PIN_CODE_REQUEST: 1155 mgmt_pin_code_request(sk, buf + MGMT_HDR_SIZE, len); 1156 break; 1157 default: 1158 error("Unknown Management opcode %u", opcode); 1159 break; 1160 } 1161 1162 return TRUE; 1163} 1164 1165static int mgmt_setup(void) 1166{ 1167 struct mgmt_hdr hdr; 1168 struct sockaddr_hci addr; 1169 GIOChannel *io; 1170 GIOCondition condition; 1171 int dd, err; 1172 1173 dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 1174 if (dd < 0) 1175 return -errno; 1176 1177 memset(&addr, 0, sizeof(addr)); 1178 addr.hci_family = AF_BLUETOOTH; 1179 addr.hci_dev = HCI_DEV_NONE; 1180 addr.hci_channel = HCI_CHANNEL_CONTROL; 1181 1182 if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1183 err = -errno; 1184 goto fail; 1185 } 1186 1187 memset(&hdr, 0, sizeof(hdr)); 1188 hdr.opcode = htobs(MGMT_OP_READ_VERSION); 1189 if (write(dd, &hdr, sizeof(hdr)) < 0) { 1190 err = -errno; 1191 goto fail; 1192 } 1193 1194 io = g_io_channel_unix_new(dd); 1195 condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; 1196 mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL); 1197 g_io_channel_unref(io); 1198 1199 mgmt_sock = dd; 1200 1201 info("Bluetooth Management interface initialized"); 1202 1203 return 0; 1204 1205fail: 1206 close(dd); 1207 return err; 1208} 1209 1210static void mgmt_cleanup(void) 1211{ 1212 g_free(controllers); 1213 controllers = NULL; 1214 max_index = -1; 1215 1216 if (mgmt_sock >= 0) { 1217 close(mgmt_sock); 1218 mgmt_sock = -1; 1219 } 1220 1221 if (mgmt_watch > 0) { 1222 g_source_remove(mgmt_watch); 1223 mgmt_watch = 0; 1224 } 1225} 1226 1227static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor) 1228{ 1229 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)]; 1230 struct mgmt_hdr *hdr = (void *) buf; 1231 struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)]; 1232 1233 DBG("index %d major %u minor %u", index, major, minor); 1234 1235 memset(buf, 0, sizeof(buf)); 1236 hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS); 1237 hdr->len = htobs(sizeof(*cp)); 1238 1239 cp->index = htobs(index); 1240 cp->major = major; 1241 cp->minor = minor; 1242 1243 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 1244 return -errno; 1245 1246 return 0; 1247} 1248 1249static int mgmt_set_limited_discoverable(int index, gboolean limited) 1250{ 1251 DBG("index %d limited %d", index, limited); 1252 return -ENOSYS; 1253} 1254 1255static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic) 1256{ 1257 DBG("index %d length %u periodic %d", index, length, periodic); 1258 return -ENOSYS; 1259} 1260 1261static int mgmt_stop_inquiry(int index) 1262{ 1263 DBG("index %d", index); 1264 return -ENOSYS; 1265} 1266 1267static int mgmt_start_scanning(int index) 1268{ 1269 DBG("index %d", index); 1270 return -ENOSYS; 1271} 1272 1273static int mgmt_stop_scanning(int index) 1274{ 1275 DBG("index %d", index); 1276 return -ENOSYS; 1277} 1278 1279static int mgmt_resolve_name(int index, bdaddr_t *bdaddr) 1280{ 1281 char addr[18]; 1282 1283 ba2str(bdaddr, addr); 1284 DBG("index %d addr %s", index, addr); 1285 1286 return -ENOSYS; 1287} 1288 1289static int mgmt_set_name(int index, const char *name) 1290{ 1291 DBG("index %d, name %s", index, name); 1292 return -ENOSYS; 1293} 1294 1295static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr) 1296{ 1297 char addr[18]; 1298 1299 ba2str(bdaddr, addr); 1300 DBG("index %d addr %s", index, addr); 1301 1302 return -ENOSYS; 1303} 1304 1305static int mgmt_fast_connectable(int index, gboolean enable) 1306{ 1307 DBG("index %d enable %d", index, enable); 1308 return -ENOSYS; 1309} 1310 1311static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout, 1312 uint32_t *clock, uint16_t *accuracy) 1313{ 1314 char addr[18]; 1315 1316 ba2str(bdaddr, addr); 1317 DBG("index %d addr %s which %d timeout %d", index, addr, which, 1318 timeout); 1319 1320 return -ENOSYS; 1321} 1322 1323static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr) 1324{ 1325 char addr[18]; 1326 struct controller_info *info = &controllers[index]; 1327 1328 ba2str(&info->bdaddr, addr); 1329 DBG("index %d addr %s", index, addr); 1330 1331 if (!info->valid) 1332 return -ENODEV; 1333 1334 bacpy(bdaddr, &info->bdaddr); 1335 1336 return 0; 1337} 1338 1339static int mgmt_block_device(int index, bdaddr_t *bdaddr) 1340{ 1341 char addr[18]; 1342 1343 ba2str(bdaddr, addr); 1344 DBG("index %d addr %s", index, addr); 1345 1346 return -ENOSYS; 1347} 1348 1349static int mgmt_unblock_device(int index, bdaddr_t *bdaddr) 1350{ 1351 char addr[18]; 1352 1353 ba2str(bdaddr, addr); 1354 DBG("index %d addr %s", index, addr); 1355 1356 return -ENOSYS; 1357} 1358 1359static int mgmt_get_conn_list(int index, GSList **conns) 1360{ 1361 struct controller_info *info = &controllers[index]; 1362 1363 DBG("index %d", index); 1364 1365 *conns = info->connections; 1366 info->connections = NULL; 1367 1368 return 0; 1369} 1370 1371static int mgmt_read_local_version(int index, struct hci_version *ver) 1372{ 1373 struct controller_info *info = &controllers[index]; 1374 1375 DBG("index %d", index); 1376 1377 if (!info->valid) 1378 return -ENODEV; 1379 1380 memset(ver, 0, sizeof(*ver)); 1381 ver->manufacturer = info->manufacturer; 1382 ver->hci_ver = info->hci_ver; 1383 ver->hci_rev = info->hci_rev; 1384 1385 return 0; 1386} 1387 1388static int mgmt_read_local_features(int index, uint8_t *features) 1389{ 1390 struct controller_info *info = &controllers[index]; 1391 1392 DBG("index %d", index); 1393 1394 if (!info->valid) 1395 return -ENODEV; 1396 1397 memcpy(features, info->features, 8); 1398 1399 return 0; 1400} 1401 1402static int mgmt_disconnect(int index, bdaddr_t *bdaddr) 1403{ 1404 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_disconnect)]; 1405 struct mgmt_hdr *hdr = (void *) buf; 1406 struct mgmt_cp_disconnect *cp = (void *) &buf[sizeof(*hdr)]; 1407 char addr[18]; 1408 1409 ba2str(bdaddr, addr); 1410 DBG("index %d %s", index, addr); 1411 1412 memset(buf, 0, sizeof(buf)); 1413 hdr->opcode = htobs(MGMT_OP_DISCONNECT); 1414 hdr->len = htobs(sizeof(*cp)); 1415 1416 cp->index = htobs(index); 1417 bacpy(&cp->bdaddr, bdaddr); 1418 1419 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 1420 error("write: %s (%d)", strerror(errno), errno); 1421 1422 return 0; 1423} 1424 1425static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr) 1426{ 1427 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_key)]; 1428 struct mgmt_hdr *hdr = (void *) buf; 1429 struct mgmt_cp_remove_key *cp = (void *) &buf[sizeof(*hdr)]; 1430 char addr[18]; 1431 1432 ba2str(bdaddr, addr); 1433 DBG("index %d addr %s", index, addr); 1434 1435 memset(buf, 0, sizeof(buf)); 1436 hdr->opcode = htobs(MGMT_OP_REMOVE_KEY); 1437 hdr->len = htobs(sizeof(*cp)); 1438 1439 cp->index = htobs(index); 1440 bacpy(&cp->bdaddr, bdaddr); 1441 cp->disconnect = 1; 1442 1443 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 1444 return -errno; 1445 1446 return 0; 1447} 1448 1449static int mgmt_request_authentication(int index, bdaddr_t *bdaddr) 1450{ 1451 char addr[18]; 1452 1453 ba2str(bdaddr, addr); 1454 DBG("index %d %s", index, addr); 1455 1456 return -ENOSYS; 1457} 1458 1459static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success) 1460{ 1461 char addr[18]; 1462 1463 ba2str(bdaddr, addr); 1464 DBG("index %d addr %s success %d", index, addr, success); 1465 1466 return -ENOSYS; 1467} 1468 1469static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey) 1470{ 1471 char addr[18]; 1472 1473 ba2str(bdaddr, addr); 1474 DBG("index %d addr %s passkey %06u", index, addr, passkey); 1475 1476 return -ENOSYS; 1477} 1478 1479static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth) 1480{ 1481 char addr[18]; 1482 1483 ba2str(bdaddr, addr); 1484 DBG("index %d addr %s", index, addr); 1485 1486 return -ENOSYS; 1487} 1488 1489static int mgmt_read_scan_enable(int index) 1490{ 1491 DBG("index %d", index); 1492 return -ENOSYS; 1493} 1494 1495static int mgmt_enable_le(int index) 1496{ 1497 DBG("index %d", index); 1498 return -ENOSYS; 1499} 1500 1501static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb, 1502 gpointer user_data) 1503{ 1504 char addr[18]; 1505 1506 ba2str(dst, addr); 1507 DBG("index %d addr %s", index, addr); 1508 1509 return -ENOSYS; 1510} 1511 1512static int mgmt_set_did(int index, uint16_t vendor, uint16_t product, 1513 uint16_t version) 1514{ 1515 DBG("index %d vendor %u product %u version %u", 1516 index, vendor, product, version); 1517 return -ENOSYS; 1518} 1519 1520static int mgmt_disable_cod_cache(int index) 1521{ 1522 DBG("index %d", index); 1523 return mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 0); 1524} 1525 1526static int mgmt_restore_powered(int index) 1527{ 1528 DBG("index %d", index); 1529 return -ENOSYS; 1530} 1531 1532static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys) 1533{ 1534 char *buf; 1535 struct mgmt_hdr *hdr; 1536 struct mgmt_cp_load_keys *cp; 1537 struct mgmt_key_info *key; 1538 size_t key_count, cp_size; 1539 GSList *l; 1540 int err; 1541 1542 key_count = g_slist_length(keys); 1543 1544 DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys); 1545 1546 cp_size = sizeof(*cp) + (key_count * sizeof(*key)); 1547 1548 buf = g_try_malloc0(sizeof(*hdr) + cp_size); 1549 if (buf == NULL) 1550 return -ENOMEM; 1551 1552 memset(buf, 0, sizeof(buf)); 1553 1554 hdr = (void *) buf; 1555 hdr->opcode = htobs(MGMT_OP_LOAD_KEYS); 1556 hdr->len = htobs(cp_size); 1557 1558 cp = (void *) (buf + sizeof(*hdr)); 1559 cp->index = htobs(index); 1560 cp->debug_keys = debug_keys; 1561 cp->key_count = htobs(key_count); 1562 1563 for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) { 1564 struct link_key_info *info = l->data; 1565 1566 bacpy(&key->bdaddr, &info->bdaddr); 1567 key->type = info->type; 1568 memcpy(key->val, info->key, 16); 1569 key->pin_len = info->pin_len; 1570 } 1571 1572 if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0) 1573 err = -errno; 1574 else 1575 err = 0; 1576 1577 g_free(buf); 1578 1579 return err; 1580} 1581 1582static struct btd_adapter_ops mgmt_ops = { 1583 .setup = mgmt_setup, 1584 .cleanup = mgmt_cleanup, 1585 .set_powered = mgmt_set_powered, 1586 .set_discoverable = mgmt_set_discoverable, 1587 .set_pairable = mgmt_set_pairable, 1588 .set_limited_discoverable = mgmt_set_limited_discoverable, 1589 .start_inquiry = mgmt_start_inquiry, 1590 .stop_inquiry = mgmt_stop_inquiry, 1591 .start_scanning = mgmt_start_scanning, 1592 .stop_scanning = mgmt_stop_scanning, 1593 .resolve_name = mgmt_resolve_name, 1594 .cancel_resolve_name = mgmt_cancel_resolve_name, 1595 .set_name = mgmt_set_name, 1596 .set_dev_class = mgmt_set_dev_class, 1597 .set_fast_connectable = mgmt_fast_connectable, 1598 .read_clock = mgmt_read_clock, 1599 .read_bdaddr = mgmt_read_bdaddr, 1600 .block_device = mgmt_block_device, 1601 .unblock_device = mgmt_unblock_device, 1602 .get_conn_list = mgmt_get_conn_list, 1603 .read_local_version = mgmt_read_local_version, 1604 .read_local_features = mgmt_read_local_features, 1605 .disconnect = mgmt_disconnect, 1606 .remove_bonding = mgmt_remove_bonding, 1607 .request_authentication = mgmt_request_authentication, 1608 .pincode_reply = mgmt_pincode_reply, 1609 .confirm_reply = mgmt_confirm_reply, 1610 .passkey_reply = mgmt_passkey_reply, 1611 .get_auth_info = mgmt_get_auth_info, 1612 .read_scan_enable = mgmt_read_scan_enable, 1613 .enable_le = mgmt_enable_le, 1614 .encrypt_link = mgmt_encrypt_link, 1615 .set_did = mgmt_set_did, 1616 .add_uuid = mgmt_add_uuid, 1617 .remove_uuid = mgmt_remove_uuid, 1618 .disable_cod_cache = mgmt_disable_cod_cache, 1619 .restore_powered = mgmt_restore_powered, 1620 .load_keys = mgmt_load_keys, 1621}; 1622 1623static int mgmt_init(void) 1624{ 1625 return btd_register_adapter_ops(&mgmt_ops, TRUE); 1626} 1627 1628static void mgmt_exit(void) 1629{ 1630 btd_adapter_cleanup_ops(&mgmt_ops); 1631} 1632 1633BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION, 1634 BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit) 1635