3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
37 #include <linux/sockios.h>
41 #include "lib/bluetooth.h"
42 #include "lib/l2cap.h"
47 #include "src/shared/util.h"
48 #include "btio/btio.h"
52 #define CON_SETUP_RETRIES 3
53 #define CON_SETUP_TO 9
57 #ifdef __TIZEN_PATCH__
58 /* Compatibility with old ioctls */
59 #define OLD_BNEPCONADD 1
60 #define OLD_BNEPCONDEL 2
61 #define OLD_BNEPGETCONLIST 3
62 #define OLD_BNEPGETCONINFO 4
64 static unsigned long bnepconnadd;
65 static unsigned long bnepconndel;
66 static unsigned long bnepgetconnlist;
67 static unsigned long bnepgetconninfo;
71 const char *name; /* Friendly name */
72 const char *uuid128; /* UUID 128 */
73 uint16_t id; /* Service class identifier */
75 { "panu", PANU_UUID, BNEP_SVC_PANU },
76 { "gn", GN_UUID, BNEP_SVC_GN },
77 { "nap", NAP_UUID, BNEP_SVC_NAP },
84 } __attribute__ ((packed));
95 bnep_connect_cb conn_cb;
97 bnep_disconnect_cb disconn_cb;
101 const char *bnep_uuid(uint16_t id)
105 for (i = 0; __svc[i].uuid128; i++)
106 if (__svc[i].id == id)
107 return __svc[i].uuid128;
111 const char *bnep_name(uint16_t id)
115 for (i = 0; __svc[i].name; i++)
116 if (__svc[i].id == id)
117 return __svc[i].name;
123 ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
127 if (err == -EPROTONOSUPPORT)
128 warn("kernel lacks bnep-protocol support");
130 error("bnep: Failed to open control socket: %s (%d)",
131 strerror(-err), -err);
135 #ifdef __TIZEN_PATCH__
136 /* Temporary ioctl compatibility hack */
138 struct bnep_connlist_req req;
139 struct bnep_conninfo ci[1];
144 if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
146 bnepconnadd = BNEPCONNADD;
147 bnepconndel = BNEPCONNDEL;
148 bnepgetconnlist = BNEPGETCONNLIST;
149 bnepgetconninfo = BNEPGETCONNINFO;
152 bnepconnadd = OLD_BNEPCONADD;
153 bnepconndel = OLD_BNEPCONDEL;
154 bnepgetconnlist = OLD_BNEPGETCONLIST;
155 bnepgetconninfo = OLD_BNEPGETCONINFO;
162 int bnep_cleanup(void)
168 static int bnep_conndel(const bdaddr_t *dst)
170 struct bnep_conndel_req req;
172 memset(&req, 0, sizeof(req));
173 baswap((bdaddr_t *)&req.dst, dst);
175 if (ioctl(ctl, BNEPCONNDEL, &req) < 0) {
177 error("bnep: Failed to kill connection: %s (%d)",
178 strerror(-err), -err);
184 static int bnep_connadd(int sk, uint16_t role, char *dev)
186 struct bnep_connadd_req req;
188 memset(&req, 0, sizeof(req));
189 strncpy(req.device, dev, 16);
190 req.device[15] = '\0';
194 if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
196 error("bnep: Failed to add device %s: %s(%d)",
197 dev, strerror(-err), -err);
201 strncpy(dev, req.device, 16);
205 static int bnep_if_up(const char *devname)
210 sk = socket(AF_INET, SOCK_DGRAM, 0);
212 memset(&ifr, 0, sizeof(ifr));
213 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
215 ifr.ifr_flags |= IFF_UP;
216 ifr.ifr_flags |= IFF_MULTICAST;
218 if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
220 error("bnep: Could not bring up %s: %s(%d)",
221 devname, strerror(-err), -err);
229 static int bnep_if_down(const char *devname)
234 sk = socket(AF_INET, SOCK_DGRAM, 0);
236 #ifdef __TIZEN_PATCH__
241 memset(&ifr, 0, sizeof(ifr));
242 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
244 ifr.ifr_flags &= ~IFF_UP;
246 /* Bring down the interface */
247 if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
249 error("bnep: Could not bring down %s: %s(%d)",
250 devname, strerror(-err), -err);
258 static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
261 struct bnep *session = data;
263 if (session->disconn_cb)
264 session->disconn_cb(session->disconn_data);
269 static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
272 struct bnep *session = data;
273 struct bnep_control_rsp *rsp;
274 struct timeval timeo;
279 if (cond & G_IO_NVAL)
282 if (session->setup_to > 0) {
283 g_source_remove(session->setup_to);
284 session->setup_to = 0;
287 if (cond & (G_IO_HUP | G_IO_ERR)) {
288 error("bnep: Hangup or error on l2cap server socket");
292 sk = g_io_channel_unix_get_fd(chan);
293 memset(pkt, 0, BNEP_MTU);
294 r = read(sk, pkt, sizeof(pkt) - 1);
296 error("bnep: IO Channel read error");
301 error("bnep: No packet received on l2cap socket");
307 if ((size_t) r < sizeof(*rsp)) {
308 error("bnep: Packet received is not bnep type");
313 if (rsp->type != BNEP_CONTROL) {
314 error("bnep: Packet received is not bnep type");
318 if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
321 r = ntohs(rsp->resp);
322 if (r != BNEP_SUCCESS) {
323 error("bnep: failed");
327 memset(&timeo, 0, sizeof(timeo));
329 setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
331 sk = g_io_channel_unix_get_fd(session->io);
332 if (bnep_connadd(sk, session->src, session->iface) < 0)
335 if (bnep_if_up(session->iface) < 0) {
336 bnep_conndel(&session->dst_addr);
340 session->watch = g_io_add_watch(session->io,
341 G_IO_ERR | G_IO_HUP | G_IO_NVAL,
342 (GIOFunc) bnep_watchdog_cb, session);
343 g_io_channel_unref(session->io);
346 session->conn_cb(session->iface, 0, session->conn_data);
351 session->conn_cb(NULL, -EIO, session->conn_data);
356 static int bnep_setup_conn_req(struct bnep *session)
358 struct bnep_setup_conn_req *req;
359 struct __service_16 *s;
360 unsigned char pkt[BNEP_MTU];
365 req->type = BNEP_CONTROL;
366 req->ctrl = BNEP_SETUP_CONN_REQ;
367 req->uuid_size = 2; /* 16bit UUID */
368 s = (void *) req->service;
369 s->src = htons(session->src);
370 s->dst = htons(session->dst);
372 fd = g_io_channel_unix_get_fd(session->io);
373 if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
374 error("bnep: connection req send failed: %s", strerror(errno));
383 static gboolean bnep_conn_req_to(gpointer user_data)
385 struct bnep *session = user_data;
387 if (session->attempts == CON_SETUP_RETRIES) {
388 error("bnep: Too many bnep connection attempts");
390 error("bnep: connection setup TO, retrying...");
391 if (bnep_setup_conn_req(session) == 0)
395 session->conn_cb(NULL, -ETIMEDOUT, session->conn_data);
400 struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
403 struct bnep *session;
410 session = g_new0(struct bnep, 1);
411 session->io = g_io_channel_unix_new(dup_fd);
412 session->src = local_role;
413 session->dst = remote_role;
414 strncpy(session->iface, iface, 16);
415 session->iface[15] = '\0';
417 g_io_channel_set_close_on_unref(session->io, TRUE);
418 session->watch = g_io_add_watch(session->io,
419 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
420 (GIOFunc) bnep_setup_cb, session);
425 void bnep_free(struct bnep *session)
431 g_io_channel_shutdown(session->io, FALSE, NULL);
432 g_io_channel_unref(session->io);
436 if (session->watch > 0) {
437 g_source_remove(session->watch);
444 int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb, void *data)
449 if (!session || !conn_cb)
452 session->attempts = 0;
453 session->conn_cb = conn_cb;
454 session->conn_data = data;
456 bt_io_get(session->io, &gerr, BT_IO_OPT_DEST_BDADDR, &session->dst_addr,
459 error("bnep: connect failed: %s", gerr->message);
464 err = bnep_setup_conn_req(session);
468 session->setup_to = g_timeout_add_seconds(CON_SETUP_TO,
469 bnep_conn_req_to, session);
473 void bnep_disconnect(struct bnep *session)
478 #ifndef __TIZEN_PATCH__
479 if (session->watch > 0) {
480 g_source_remove(session->watch);
485 g_io_channel_unref(session->io);
489 bnep_if_down(session->iface);
490 bnep_conndel(&session->dst_addr);
493 void bnep_set_disconnect(struct bnep *session, bnep_disconnect_cb disconn_cb,
496 if (!session || !disconn_cb)
499 if (!session->disconn_cb && !session->disconn_data) {
500 session->disconn_cb = disconn_cb;
501 session->disconn_data = data;
505 #ifndef __TIZEN_PATCH__
506 static int bnep_add_to_bridge(const char *devname, const char *bridge)
512 if (!devname || !bridge)
515 ifindex = if_nametoindex(devname);
517 sk = socket(AF_INET, SOCK_STREAM, 0);
520 #ifdef __TIZEN_PATCH__
521 err = ioctl(sk, SIOCBRADDBR, bridge);
524 info("bridge create err: %d", err);
529 memset(&ifr, 0, sizeof(ifr));
530 strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
531 ifr.ifr_ifindex = ifindex;
533 if (ioctl(sk, SIOCBRADDIF, &ifr) < 0) {
535 error("bnep: Can't add %s to the bridge %s: %s(%d)",
536 devname, bridge, strerror(-err), -err);
538 info("bnep: bridge %s: interface %s added", bridge, devname);
547 static int bnep_del_from_bridge(const char *devname, const char *bridge)
553 if (!devname || !bridge)
556 ifindex = if_nametoindex(devname);
558 sk = socket(AF_INET, SOCK_STREAM, 0);
562 memset(&ifr, 0, sizeof(ifr));
563 strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
564 ifr.ifr_ifindex = ifindex;
566 if (ioctl(sk, SIOCBRDELIF, &ifr) < 0) {
568 error("bnep: Can't delete %s from the bridge %s: %s(%d)",
569 devname, bridge, strerror(-err), -err);
571 info("bnep: bridge %s: interface %s removed", bridge, devname);
579 int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
580 const bdaddr_t *addr)
584 if (!bridge || !iface || !addr)
587 err = bnep_connadd(sk, dst, iface);
591 #ifndef __TIZEN_PATCH__
592 err = bnep_add_to_bridge(iface, bridge);
599 return bnep_if_up(iface);
602 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
604 if (!bridge || !iface || !addr)
607 bnep_del_from_bridge(iface, bridge);
612 ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp)
614 struct bnep_control_rsp rsp;
618 rsp.resp = htons(resp);
620 return send(sk, &rsp, sizeof(rsp), 0);
623 uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
626 const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
627 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
628 uint8_t *dest, *source;
632 source = req->service + req->uuid_size;
634 switch (req->uuid_size) {
636 *dst = get_be16(dest);
637 *src = get_be16(source);
639 case 16: /* UUID128 */
640 /* Check that the bytes in the UUID, except the service ID
641 * itself, are correct. The service ID is checked in
642 * bnep_setup_chk(). */
643 if (memcmp(&dest[4], bt_base, sizeof(bt_base)) != 0)
644 return BNEP_CONN_INVALID_DST;
645 if (memcmp(&source[4], bt_base, sizeof(bt_base)) != 0)
646 return BNEP_CONN_INVALID_SRC;
648 /* Intentional no-break */
651 val = get_be32(dest);
653 return BNEP_CONN_INVALID_DST;
657 val = get_be32(source);
659 return BNEP_CONN_INVALID_SRC;
664 return BNEP_CONN_INVALID_SVC;
667 /* Allowed PAN Profile scenarios */
671 if (*src == BNEP_SVC_PANU)
673 return BNEP_CONN_INVALID_SRC;
675 if (*src == BNEP_SVC_PANU || *src == BNEP_SVC_GN ||
676 *src == BNEP_SVC_NAP)
679 return BNEP_CONN_INVALID_SRC;
682 return BNEP_CONN_INVALID_DST;
685 #ifdef __TIZEN_PATCH__
686 int bnep_if_down_wrapper(const char *devname)
688 bnep_if_down(devname);
692 int bnep_conndel_wrapper(const bdaddr_t *dst)