Home | History | Annotate | Download | only in network
      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