diff --git a/android/pan.c b/android/pan.c
index 6c9815b..0bb576e 100644
--- a/android/pan.c
+++ b/android/pan.c
sk = g_io_channel_unix_get_fd(chan);
- /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
- n = read(sk, packet, sizeof(packet));
+ /*
+ * BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
+ * of kernel setup connection msg handling.
+ */
+ n = recv(sk, packet, sizeof(packet), MSG_PEEK);
if (n < 0) {
error("read(): %s(%d)", strerror(errno), errno);
goto failed;
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index e325b72..59599e4 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
req.sock = sk;
req.role = role;
+ req.flags = (1 << BNEP_SETUP_RESPONSE);
if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
int err = -errno;
error("bnep: Failed to add device %s: %s(%d)",
return 0;
}
+static uint32_t bnep_getsuppfeat(void)
+{
+ uint32_t feat;
+
+ if (ioctl(ctl, BNEPGETSUPPFEAT, &feat) < 0)
+ feat = 0;
+
+ DBG("supported features: 0x%x", feat);
+
+ return feat;
+}
+
static int bnep_if_up(const char *devname)
{
struct ifreq ifr;
uint8_t *dest, *source;
uint32_t val;
- if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
+ if (((req->type != BNEP_CONTROL) &&
+ (req->type != (BNEP_CONTROL | BNEP_EXT_HEADER))) ||
+ req->ctrl != BNEP_SETUP_CONN_REQ)
return BNEP_CONN_NOT_ALLOWED;
dest = req->service;
return BNEP_CONN_INVALID_DST;
}
+static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
+ char *iface, const bdaddr_t *addr,
+ uint8_t *setup_data, int len)
+{
+ int err, n;
+ uint16_t rsp;
+
+ n = read(sk, setup_data, len);
+ if (n != len) {
+ err = -EIO;
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ err = bnep_connadd(sk, dst, iface);
+ if (err < 0) {
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ err = bnep_add_to_bridge(iface, bridge);
+ if (err < 0) {
+ bnep_conndel(addr);
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ err = bnep_if_up(iface);
+ if (err < 0) {
+ bnep_del_from_bridge(iface, bridge);
+ bnep_conndel(addr);
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ }
+
+reply:
+ if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
+ err = -errno;
+ error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
+ -err);
+ }
+
+ return err;
+}
+
int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
uint8_t *setup_data, int len)
{
int err;
+ uint32_t feat;
uint16_t rsp, dst;
struct bnep_setup_conn_req *req = (void *) setup_data;
err = -rsp;
error("bnep: error while decoding setup connection request: %d",
rsp);
- goto reply;
+ goto failed;
}
+ feat = bnep_getsuppfeat();
+
+ /*
+ * Take out setup data if kernel doesn't support handling it, especially
+ * setup request. If kernel would have set session flags, they should
+ * be checked and handled respectively.
+ */
+ if (!feat || !(feat & (1 << BNEP_SETUP_RESPONSE)))
+ return bnep_server_add_legacy(sk, dst, bridge, iface, addr,
+ setup_data, len);
+
err = bnep_connadd(sk, dst, iface);
if (err < 0) {
rsp = BNEP_CONN_NOT_ALLOWED;
- goto reply;
+ goto failed;
}
err = bnep_add_to_bridge(iface, bridge);
- if (err < 0) {
- bnep_conndel(addr);
- rsp = BNEP_CONN_NOT_ALLOWED;
- goto reply;
- }
+ if (err < 0)
+ goto failed_conn;
err = bnep_if_up(iface);
if (err < 0)
- rsp = BNEP_CONN_NOT_ALLOWED;
+ goto failed_bridge;
-reply:
+ return 0;
+
+failed_bridge:
+ bnep_del_from_bridge(iface, bridge);
+
+failed_conn:
+ bnep_conndel(addr);
+
+ return err;
+
+failed:
if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
err = -errno;
- error("bnep: send ctrl rsp error: %s (%d)", strerror(errno),
- errno);
+ error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
+ -err);
}
return err;
diff --git a/profiles/network/server.c b/profiles/network/server.c
index 32aafc3..1bff9f8 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
sk = g_io_channel_unix_get_fd(chan);
- /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
- n = read(sk, packet, sizeof(packet));
+ /*
+ * BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
+ * of kernel setup connection msg handling.
+ */
+ n = recv(sk, packet, sizeof(packet), MSG_PEEK);
if (n < 0) {
error("read(): %s(%d)", strerror(errno), errno);
return FALSE;
diff --git a/tools/bneptest.c b/tools/bneptest.c
index 98ee9b1..a7d5815 100644
--- a/tools/bneptest.c
+++ b/tools/bneptest.c
sk = g_io_channel_unix_get_fd(chan);
/* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
- n = read(sk, packet, sizeof(packet));
+ n = recv(sk, packet, sizeof(packet), MSG_PEEK);
if (n < 0) {
error("read(): %s(%d)", strerror(errno), errno);
return FALSE;