1d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi/*
2d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
3d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  BlueZ - Bluetooth protocol stack for Linux
4d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
58307634aa6d9dd96c12cec8b8acf1059b54e0ae6Vinicius Costa Gomes *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
68307634aa6d9dd96c12cec8b8acf1059b54e0ae6Vinicius Costa Gomes *
7d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
8d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  This program is free software; you can redistribute it and/or modify
9d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  it under the terms of the GNU General Public License as published by
10d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  the Free Software Foundation; either version 2 of the License, or
11d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  (at your option) any later version.
12d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
13d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  This program is distributed in the hope that it will be useful,
14d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  GNU General Public License for more details.
17d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
18d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  You should have received a copy of the GNU General Public License
19d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  along with this program; if not, write to the Free Software
20d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi *
22d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi */
23d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi
24612d0207646064f309edd564a69d30b42de9e26fClaudio Takahasi#ifdef HAVE_CONFIG_H
25d2657982a8a7f4caace5b6bd8d701c5c8f8ba644Claudio Takahasi#include <config.h>
26e04efbaddf3d6a178dbbab9e5355dfecaa4da3adBruna Moreira#endif
275399423bd667efa5d15d8dec895250fe5a3bbec2Claudio Takahasi
28a278db781a26c639267b1d88d5fbe08f99af6c61Elvis Pfützenreuter#include <stdio.h>
295399423bd667efa5d15d8dec895250fe5a3bbec2Claudio Takahasi#include <errno.h>
302448a8ba038009ab5a89d6e141ee4e1b0c71aa53Claudio Takahasi#include <unistd.h>
312448a8ba038009ab5a89d6e141ee4e1b0c71aa53Claudio Takahasi#include <stdlib.h>
32922c5feb93adfb9773a854d8e89eb2c5604e632bSheldon Demario#include <sys/param.h>
33922c5feb93adfb9773a854d8e89eb2c5604e632bSheldon Demario#include <sys/ioctl.h>
34262323b597306be0758efcfbc068df73931ba2a4Anderson Lizardo#include <sys/socket.h>
35adc7ca1ece5e579998e5f3b0cca9af7bf8ac8ca1Sheldon Demario#include <sys/wait.h>
36adc7ca1ece5e579998e5f3b0cca9af7bf8ac8ca1Sheldon Demario#include <net/if.h>
37c4fe3b3a0b3da660d3ec59bfc392bd05c9a29e5aVinicius Costa Gomes#include <linux/sockios.h>
380a70694d3afd91470a83567c18d20a29ad1996e6Anderson Lizardo
390a70694d3afd91470a83567c18d20a29ad1996e6Anderson Lizardo#include <bluetooth/bluetooth.h>
400a70694d3afd91470a83567c18d20a29ad1996e6Anderson Lizardo#include <bluetooth/l2cap.h>
41c4fe3b3a0b3da660d3ec59bfc392bd05c9a29e5aVinicius Costa Gomes#include <bluetooth/bnep.h>
42c4fe3b3a0b3da660d3ec59bfc392bd05c9a29e5aVinicius Costa Gomes
43b1514662a0f04b11172ca97adfe4cac3c39536b2Bruna Moreira#include <glib.h>
44b1514662a0f04b11172ca97adfe4cac3c39536b2Bruna Moreira
45b1514662a0f04b11172ca97adfe4cac3c39536b2Bruna Moreira#include "log.h"
46ad0e7f2c5ab9270369301f81eb5da1954eaab82fSheldon Demario#include "common.h"
47ad0e7f2c5ab9270369301f81eb5da1954eaab82fSheldon Demario
48a278db781a26c639267b1d88d5fbe08f99af6c61Elvis Pfützenreuterstatic int ctl;
49ad0e7f2c5ab9270369301f81eb5da1954eaab82fSheldon Demario
501b07befa15ec80b00be4881c9ed8a253c54e15fcBruna Moreirastatic struct {
511b07befa15ec80b00be4881c9ed8a253c54e15fcBruna Moreira	const char	*name;		/* Friendly name */
521b07befa15ec80b00be4881c9ed8a253c54e15fcBruna Moreira	const char	*uuid128;	/* UUID 128 */
53612d0207646064f309edd564a69d30b42de9e26fClaudio Takahasi	uint16_t	id;		/* Service class identifier */
54612d0207646064f309edd564a69d30b42de9e26fClaudio Takahasi} __svc[] = {
55612d0207646064f309edd564a69d30b42de9e26fClaudio Takahasi	{ "panu",	PANU_UUID,	BNEP_SVC_PANU	},
56612d0207646064f309edd564a69d30b42de9e26fClaudio Takahasi	{ "gn",		GN_UUID,	BNEP_SVC_GN	},
57	{ "nap",	NAP_UUID,	BNEP_SVC_NAP	},
58	{ NULL }
59};
60
61uint16_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
86const 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
96const 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
106int 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
120int bnep_cleanup(void)
121{
122	close(ctl);
123	return 0;
124}
125
126int 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
142int 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
170int 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
190int 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
215int 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
240int 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