1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <sys/param.h> 33 #include <sys/ioctl.h> 34 #include <sys/socket.h> 35 #include <sys/wait.h> 36 #include <net/if.h> 37 #include <linux/sockios.h> 38 39 #include <bluetooth/bluetooth.h> 40 #include <bluetooth/l2cap.h> 41 #include <bluetooth/bnep.h> 42 43 #include <glib.h> 44 45 #include "log.h" 46 #include "common.h" 47 48 static int ctl; 49 50 static struct { 51 const char *name; /* Friendly name */ 52 const char *uuid128; /* UUID 128 */ 53 uint16_t id; /* Service class identifier */ 54 } __svc[] = { 55 { "panu", PANU_UUID, BNEP_SVC_PANU }, 56 { "gn", GN_UUID, BNEP_SVC_GN }, 57 { "nap", NAP_UUID, BNEP_SVC_NAP }, 58 { NULL } 59 }; 60 61 uint16_t bnep_service_id(const char *svc) 62 { 63 int i; 64 uint16_t id; 65 66 /* Friendly service name */ 67 for (i = 0; __svc[i].name; i++) 68 if (!strcasecmp(svc, __svc[i].name)) { 69 return __svc[i].id; 70 } 71 72 /* UUID 128 string */ 73 for (i = 0; __svc[i].uuid128; i++) 74 if (!strcasecmp(svc, __svc[i].uuid128)) { 75 return __svc[i].id; 76 } 77 78 /* Try convert to HEX */ 79 id = strtol(svc, NULL, 16); 80 if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN)) 81 return 0; 82 83 return id; 84 } 85 86 const char *bnep_uuid(uint16_t id) 87 { 88 int i; 89 90 for (i = 0; __svc[i].uuid128; i++) 91 if (__svc[i].id == id) 92 return __svc[i].uuid128; 93 return NULL; 94 } 95 96 const char *bnep_name(uint16_t id) 97 { 98 int i; 99 100 for (i = 0; __svc[i].name; i++) 101 if (__svc[i].id == id) 102 return __svc[i].name; 103 return NULL; 104 } 105 106 int bnep_init(void) 107 { 108 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP); 109 110 if (ctl < 0) { 111 int err = errno; 112 error("Failed to open control socket: %s (%d)", 113 strerror(err), err); 114 return -err; 115 } 116 117 return 0; 118 } 119 120 int bnep_cleanup(void) 121 { 122 close(ctl); 123 return 0; 124 } 125 126 int bnep_kill_connection(bdaddr_t *dst) 127 { 128 struct bnep_conndel_req req; 129 130 memset(&req, 0, sizeof(req)); 131 baswap((bdaddr_t *)&req.dst, dst); 132 req.flags = 0; 133 if (ioctl(ctl, BNEPCONNDEL, &req)) { 134 int err = errno; 135 error("Failed to kill connection: %s (%d)", 136 strerror(err), err); 137 return -err; 138 } 139 return 0; 140 } 141 142 int bnep_kill_all_connections(void) 143 { 144 struct bnep_connlist_req req; 145 struct bnep_conninfo ci[7]; 146 unsigned int i; 147 int err; 148 149 memset(&req, 0, sizeof(req)); 150 req.cnum = 7; 151 req.ci = ci; 152 if (ioctl(ctl, BNEPGETCONNLIST, &req)) { 153 err = errno; 154 error("Failed to get connection list: %s (%d)", 155 strerror(err), err); 156 return -err; 157 } 158 159 for (i = 0; i < req.cnum; i++) { 160 struct bnep_conndel_req del; 161 162 memset(&del, 0, sizeof(del)); 163 memcpy(del.dst, ci[i].dst, ETH_ALEN); 164 del.flags = 0; 165 ioctl(ctl, BNEPCONNDEL, &del); 166 } 167 return 0; 168 } 169 170 int bnep_connadd(int sk, uint16_t role, char *dev) 171 { 172 struct bnep_connadd_req req; 173 174 memset(&req, 0, sizeof(req)); 175 strncpy(req.device, dev, 16); 176 req.device[15] = '\0'; 177 req.sock = sk; 178 req.role = role; 179 if (ioctl(ctl, BNEPCONNADD, &req) < 0) { 180 int err = errno; 181 error("Failed to add device %s: %s(%d)", 182 dev, strerror(err), err); 183 return -err; 184 } 185 186 strncpy(dev, req.device, 16); 187 return 0; 188 } 189 190 int bnep_if_up(const char *devname) 191 { 192 struct ifreq ifr; 193 int sk, err; 194 195 sk = socket(AF_INET, SOCK_DGRAM, 0); 196 197 memset(&ifr, 0, sizeof(ifr)); 198 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1); 199 200 ifr.ifr_flags |= IFF_UP; 201 ifr.ifr_flags |= IFF_MULTICAST; 202 203 err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr); 204 205 close(sk); 206 207 if (err < 0) { 208 error("Could not bring up %s", devname); 209 return err; 210 } 211 212 return 0; 213 } 214 215 int bnep_if_down(const char *devname) 216 { 217 struct ifreq ifr; 218 int sk, err; 219 220 sk = socket(AF_INET, SOCK_DGRAM, 0); 221 222 memset(&ifr, 0, sizeof(ifr)); 223 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1); 224 225 ifr.ifr_flags &= ~IFF_UP; 226 227 /* Bring down the interface */ 228 err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr); 229 230 close(sk); 231 232 if (err < 0) { 233 error("Could not bring down %s", devname); 234 return err; 235 } 236 237 return 0; 238 } 239 240 int bnep_add_to_bridge(const char *devname, const char *bridge) 241 { 242 int ifindex = if_nametoindex(devname); 243 struct ifreq ifr; 244 int sk, err; 245 246 if (!devname || !bridge) 247 return -EINVAL; 248 249 sk = socket(AF_INET, SOCK_STREAM, 0); 250 if (sk < 0) 251 return -1; 252 253 memset(&ifr, 0, sizeof(ifr)); 254 strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1); 255 ifr.ifr_ifindex = ifindex; 256 257 err = ioctl(sk, SIOCBRADDIF, &ifr); 258 259 close(sk); 260 261 if (err < 0) 262 return err; 263 264 info("bridge %s: interface %s added", bridge, devname); 265 266 return 0; 267 } 268