1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include <config.h> 27#endif 28 29#include <stdio.h> 30#include <errno.h> 31#include <unistd.h> 32#include <stdlib.h> 33#include <sys/socket.h> 34#include <sys/ioctl.h> 35 36#include <bluetooth/bluetooth.h> 37#include <bluetooth/bnep.h> 38 39#include <netinet/in.h> 40 41#include "pand.h" 42 43static int ctl; 44 45/* Compatibility with old ioctls */ 46#define OLD_BNEPCONADD 1 47#define OLD_BNEPCONDEL 2 48#define OLD_BNEPGETCONLIST 3 49#define OLD_BNEPGETCONINFO 4 50 51static unsigned long bnepconnadd; 52static unsigned long bnepconndel; 53static unsigned long bnepgetconnlist; 54static unsigned long bnepgetconninfo; 55 56static struct { 57 char *str; 58 uint16_t uuid; 59} __svc[] = { 60 { "PANU", BNEP_SVC_PANU }, 61 { "NAP", BNEP_SVC_NAP }, 62 { "GN", BNEP_SVC_GN }, 63 { NULL } 64}; 65 66int bnep_str2svc(char *svc, uint16_t *uuid) 67{ 68 int i; 69 for (i = 0; __svc[i].str; i++) 70 if (!strcasecmp(svc, __svc[i].str)) { 71 *uuid = __svc[i].uuid; 72 return 0; 73 } 74 return -1; 75} 76 77char *bnep_svc2str(uint16_t uuid) 78{ 79 int i; 80 for (i = 0; __svc[i].str; i++) 81 if (__svc[i].uuid == uuid) 82 return __svc[i].str; 83 return NULL; 84} 85 86int bnep_init(void) 87{ 88 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP); 89 if (ctl < 0) { 90 perror("Failed to open control socket"); 91 return 1; 92 } 93 94 /* Temporary ioctl compatibility hack */ 95 { 96 struct bnep_connlist_req req; 97 struct bnep_conninfo ci[1]; 98 99 req.cnum = 1; 100 req.ci = ci; 101 102 if (!ioctl(ctl, BNEPGETCONNLIST, &req)) { 103 /* New ioctls */ 104 bnepconnadd = BNEPCONNADD; 105 bnepconndel = BNEPCONNDEL; 106 bnepgetconnlist = BNEPGETCONNLIST; 107 bnepgetconninfo = BNEPGETCONNINFO; 108 } else { 109 /* Old ioctls */ 110 bnepconnadd = OLD_BNEPCONADD; 111 bnepconndel = OLD_BNEPCONDEL; 112 bnepgetconnlist = OLD_BNEPGETCONLIST; 113 bnepgetconninfo = OLD_BNEPGETCONINFO; 114 } 115 } 116 117 return 0; 118} 119 120int bnep_cleanup(void) 121{ 122 close(ctl); 123 return 0; 124} 125 126int bnep_show_connections(void) 127{ 128 struct bnep_connlist_req req; 129 struct bnep_conninfo ci[48]; 130 unsigned int i; 131 132 req.cnum = 48; 133 req.ci = ci; 134 if (ioctl(ctl, bnepgetconnlist, &req)) { 135 perror("Failed to get connection list"); 136 return -1; 137 } 138 139 for (i = 0; i < req.cnum; i++) { 140 char addr[18]; 141 ba2str((bdaddr_t *) ci[i].dst, addr); 142 printf("%s %s %s\n", ci[i].device, 143 addr, bnep_svc2str(ci[i].role)); 144 } 145 return 0; 146} 147 148int bnep_kill_connection(uint8_t *dst) 149{ 150 struct bnep_conndel_req req; 151 152 memcpy(req.dst, dst, ETH_ALEN); 153 req.flags = 0; 154 if (ioctl(ctl, bnepconndel, &req)) { 155 perror("Failed to kill connection"); 156 return -1; 157 } 158 return 0; 159} 160 161int bnep_kill_all_connections(void) 162{ 163 struct bnep_connlist_req req; 164 struct bnep_conninfo ci[48]; 165 unsigned int i; 166 167 req.cnum = 48; 168 req.ci = ci; 169 if (ioctl(ctl, bnepgetconnlist, &req)) { 170 perror("Failed to get connection list"); 171 return -1; 172 } 173 174 for (i = 0; i < req.cnum; i++) { 175 struct bnep_conndel_req req; 176 memcpy(req.dst, ci[i].dst, ETH_ALEN); 177 req.flags = 0; 178 ioctl(ctl, bnepconndel, &req); 179 } 180 return 0; 181} 182 183static int bnep_connadd(int sk, uint16_t role, char *dev) 184{ 185 struct bnep_connadd_req req; 186 187 strncpy(req.device, dev, 16); 188 req.device[15] = '\0'; 189 req.sock = sk; 190 req.role = role; 191 if (ioctl(ctl, bnepconnadd, &req)) 192 return -1; 193 strncpy(dev, req.device, 16); 194 return 0; 195} 196 197struct __service_16 { 198 uint16_t dst; 199 uint16_t src; 200} __attribute__ ((packed)); 201 202struct __service_32 { 203 uint16_t unused1; 204 uint16_t dst; 205 uint16_t unused2; 206 uint16_t src; 207} __attribute__ ((packed)); 208 209struct __service_128 { 210 uint16_t unused1; 211 uint16_t dst; 212 uint16_t unused2[8]; 213 uint16_t src; 214 uint16_t unused3[7]; 215} __attribute__ ((packed)); 216 217int bnep_accept_connection(int sk, uint16_t role, char *dev) 218{ 219 struct bnep_setup_conn_req *req; 220 struct bnep_control_rsp *rsp; 221 unsigned char pkt[BNEP_MTU]; 222 ssize_t r; 223 224 r = recv(sk, pkt, BNEP_MTU, 0); 225 if (r <= 0) 226 return -1; 227 228 errno = EPROTO; 229 230 if ((size_t) r < sizeof(*req)) 231 return -1; 232 233 req = (void *) pkt; 234 235 /* Highest known Control command ID 236 * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */ 237 if (req->type == BNEP_CONTROL && 238 req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) { 239 uint8_t pkt[3]; 240 241 pkt[0] = BNEP_CONTROL; 242 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; 243 pkt[2] = req->ctrl; 244 245 send(sk, pkt, sizeof(pkt), 0); 246 247 return -1; 248 } 249 250 if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) 251 return -1; 252 253 /* FIXME: Check role UUIDs */ 254 255 rsp = (void *) pkt; 256 rsp->type = BNEP_CONTROL; 257 rsp->ctrl = BNEP_SETUP_CONN_RSP; 258 rsp->resp = htons(BNEP_SUCCESS); 259 if (send(sk, rsp, sizeof(*rsp), 0) < 0) 260 return -1; 261 262 return bnep_connadd(sk, role, dev); 263} 264 265/* Create BNEP connection 266 * sk - Connect L2CAP socket 267 * role - Local role 268 * service - Remote service 269 * dev - Network device (contains actual dev name on return) 270 */ 271int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev) 272{ 273 struct bnep_setup_conn_req *req; 274 struct bnep_control_rsp *rsp; 275 struct __service_16 *s; 276 struct timeval timeo; 277 unsigned char pkt[BNEP_MTU]; 278 ssize_t r; 279 280 /* Send request */ 281 req = (void *) pkt; 282 req->type = BNEP_CONTROL; 283 req->ctrl = BNEP_SETUP_CONN_REQ; 284 req->uuid_size = 2; /* 16bit UUID */ 285 286 s = (void *) req->service; 287 s->dst = htons(svc); 288 s->src = htons(role); 289 290 memset(&timeo, 0, sizeof(timeo)); 291 timeo.tv_sec = 30; 292 293 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); 294 295 if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0) 296 return -1; 297 298receive: 299 /* Get response */ 300 r = recv(sk, pkt, BNEP_MTU, 0); 301 if (r <= 0) 302 return -1; 303 304 memset(&timeo, 0, sizeof(timeo)); 305 timeo.tv_sec = 0; 306 307 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); 308 309 errno = EPROTO; 310 311 if ((size_t) r < sizeof(*rsp)) 312 return -1; 313 314 rsp = (void *) pkt; 315 if (rsp->type != BNEP_CONTROL) 316 return -1; 317 318 if (rsp->ctrl != BNEP_SETUP_CONN_RSP) 319 goto receive; 320 321 r = ntohs(rsp->resp); 322 323 switch (r) { 324 case BNEP_SUCCESS: 325 break; 326 327 case BNEP_CONN_INVALID_DST: 328 case BNEP_CONN_INVALID_SRC: 329 case BNEP_CONN_INVALID_SVC: 330 errno = EPROTO; 331 return -1; 332 333 case BNEP_CONN_NOT_ALLOWED: 334 errno = EACCES; 335 return -1; 336 } 337 338 return bnep_connadd(sk, role, dev); 339} 340