1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk (at) qualcomm.com> 6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel (at) 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/l2cap.h> 38 #include <bluetooth/bnep.h> 39 40 #include <netinet/in.h> 41 42 #include "pand.h" 43 44 static int ctl; 45 46 /* Compatibility with old ioctls */ 47 #define OLD_BNEPCONADD 1 48 #define OLD_BNEPCONDEL 2 49 #define OLD_BNEPGETCONLIST 3 50 #define OLD_BNEPGETCONINFO 4 51 52 static unsigned long bnepconnadd; 53 static unsigned long bnepconndel; 54 static unsigned long bnepgetconnlist; 55 static unsigned long bnepgetconninfo; 56 57 static struct { 58 char *str; 59 uint16_t uuid; 60 } __svc[] = { 61 { "PANU", BNEP_SVC_PANU }, 62 { "NAP", BNEP_SVC_NAP }, 63 { "GN", BNEP_SVC_GN }, 64 { NULL } 65 }; 66 67 int bnep_str2svc(char *svc, uint16_t *uuid) 68 { 69 int i; 70 for (i = 0; __svc[i].str; i++) 71 if (!strcasecmp(svc, __svc[i].str)) { 72 *uuid = __svc[i].uuid; 73 return 0; 74 } 75 return -1; 76 } 77 78 char *bnep_svc2str(uint16_t uuid) 79 { 80 int i; 81 for (i = 0; __svc[i].str; i++) 82 if (__svc[i].uuid == uuid) 83 return __svc[i].str; 84 return NULL; 85 } 86 87 int bnep_init(void) 88 { 89 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP); 90 if (ctl < 0) { 91 perror("Failed to open control socket"); 92 return 1; 93 } 94 95 /* Temporary ioctl compatibility hack */ 96 { 97 struct bnep_connlist_req req; 98 struct bnep_conninfo ci[1]; 99 100 req.cnum = 1; 101 req.ci = ci; 102 103 if (!ioctl(ctl, BNEPGETCONNLIST, &req)) { 104 /* New ioctls */ 105 bnepconnadd = BNEPCONNADD; 106 bnepconndel = BNEPCONNDEL; 107 bnepgetconnlist = BNEPGETCONNLIST; 108 bnepgetconninfo = BNEPGETCONNINFO; 109 } else { 110 /* Old ioctls */ 111 bnepconnadd = OLD_BNEPCONADD; 112 bnepconndel = OLD_BNEPCONDEL; 113 bnepgetconnlist = OLD_BNEPGETCONLIST; 114 bnepgetconninfo = OLD_BNEPGETCONINFO; 115 } 116 } 117 118 return 0; 119 } 120 121 int bnep_cleanup(void) 122 { 123 close(ctl); 124 return 0; 125 } 126 127 int bnep_show_connections(void) 128 { 129 struct bnep_connlist_req req; 130 struct bnep_conninfo ci[48]; 131 unsigned int i; 132 133 req.cnum = 48; 134 req.ci = ci; 135 if (ioctl(ctl, bnepgetconnlist, &req)) { 136 perror("Failed to get connection list"); 137 return -1; 138 } 139 140 for (i = 0; i < req.cnum; i++) { 141 printf("%s %s %s\n", ci[i].device, 142 batostr((bdaddr_t *) ci[i].dst), 143 bnep_svc2str(ci[i].role)); 144 } 145 return 0; 146 } 147 148 int 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 161 int 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 183 static 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 197 struct __service_16 { 198 uint16_t dst; 199 uint16_t src; 200 } __attribute__ ((packed)); 201 202 struct __service_32 { 203 uint16_t unused1; 204 uint16_t dst; 205 uint16_t unused2; 206 uint16_t src; 207 } __attribute__ ((packed)); 208 209 struct __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 217 int 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 if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) 235 return -1; 236 237 /* FIXME: Check role UUIDs */ 238 239 rsp = (void *) pkt; 240 rsp->type = BNEP_CONTROL; 241 rsp->ctrl = BNEP_SETUP_CONN_RSP; 242 rsp->resp = htons(BNEP_SUCCESS); 243 if (send(sk, rsp, sizeof(*rsp), 0) < 0) 244 return -1; 245 246 return bnep_connadd(sk, role, dev); 247 } 248 249 /* Create BNEP connection 250 * sk - Connect L2CAP socket 251 * role - Local role 252 * service - Remote service 253 * dev - Network device (contains actual dev name on return) 254 */ 255 int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev) 256 { 257 struct bnep_setup_conn_req *req; 258 struct bnep_control_rsp *rsp; 259 struct __service_16 *s; 260 struct timeval timeo; 261 unsigned char pkt[BNEP_MTU]; 262 ssize_t r; 263 264 /* Send request */ 265 req = (void *) pkt; 266 req->type = BNEP_CONTROL; 267 req->ctrl = BNEP_SETUP_CONN_REQ; 268 req->uuid_size = 2; /* 16bit UUID */ 269 270 s = (void *) req->service; 271 s->dst = htons(svc); 272 s->src = htons(role); 273 274 memset(&timeo, 0, sizeof(timeo)); 275 timeo.tv_sec = 30; 276 277 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); 278 279 if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0) 280 return -1; 281 282 receive: 283 /* Get response */ 284 r = recv(sk, pkt, BNEP_MTU, 0); 285 if (r <= 0) 286 return -1; 287 288 memset(&timeo, 0, sizeof(timeo)); 289 timeo.tv_sec = 0; 290 291 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); 292 293 errno = EPROTO; 294 295 if ((size_t) r < sizeof(*rsp)) 296 return -1; 297 298 rsp = (void *) pkt; 299 if (rsp->type != BNEP_CONTROL) 300 return -1; 301 302 if (rsp->ctrl != BNEP_SETUP_CONN_RSP) 303 goto receive; 304 305 r = ntohs(rsp->resp); 306 307 switch (r) { 308 case BNEP_SUCCESS: 309 break; 310 311 case BNEP_CONN_INVALID_DST: 312 case BNEP_CONN_INVALID_SRC: 313 case BNEP_CONN_INVALID_SVC: 314 errno = EPROTO; 315 return -1; 316 317 case BNEP_CONN_NOT_ALLOWED: 318 errno = EACCES; 319 return -1; 320 } 321 322 return bnep_connadd(sk, role, dev); 323 } 324