Bug 823803 - Add L2CAP/EL2CAP Socket support, r=qdot, r=gyeh

This version of BlueZ from Code Aurora has added GOEP_PSM to Object
Push Profile service record, which means that remote devices may
connect with us via both L2CAP and RFCOMM. This patch completes
L2CAP/EL2CAP socket implementation.
This commit is contained in:
Eric Chou 2013-04-12 18:45:37 +08:00
parent 10e35f2d67
commit 6e7344ce22
4 changed files with 90 additions and 15 deletions

View File

@ -59,8 +59,9 @@ BEGIN_BLUETOOTH_NAMESPACE
enum BluetoothSocketType {
RFCOMM = 1,
SCO = 2,
L2CAP = 3
SCO = 2,
L2CAP = 3,
EL2CAP = 4
};
class BluetoothSignal;

View File

@ -28,9 +28,9 @@
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/sco.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
#include "BluetoothUnixSocketConnector.h"
#include "nsThreadUtils.h"
@ -38,7 +38,10 @@
using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
static const int L2CAP_SO_SNDBUF = 400 * 1024; // 400 KB send buffer
static const int L2CAP_SO_RCVBUF = 400 * 1024; // 400 KB receive buffer
static const int L2CAP_MAX_MTU = 65000;
static
int get_bdaddr(const char *str, bdaddr_t *ba)
@ -74,7 +77,8 @@ bool
BluetoothUnixSocketConnector::SetUp(int aFd)
{
int lm = 0;
int sndbuf;
int sndbuf, rcvbuf;
/* kernel does not yet support LM for SCO */
switch (mType) {
case BluetoothSocketType::RFCOMM:
@ -82,6 +86,7 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
lm |= mEncrypt ? RFCOMM_LM_ENCRYPT : 0;
break;
case BluetoothSocketType::L2CAP:
case BluetoothSocketType::EL2CAP:
lm |= mAuth ? L2CAP_LM_AUTH : 0;
lm |= mEncrypt ? L2CAP_LM_ENCRYPT : 0;
break;
@ -92,9 +97,17 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
}
if (lm) {
if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
return false;
if (mType == BluetoothSocketType::RFCOMM) {
if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
return false;
}
} else if (mType == BluetoothSocketType::L2CAP ||
mType == BluetoothSocketType::EL2CAP) {
if (setsockopt(aFd, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm))) {
NS_WARNING("setsockopt(L2CAP_LM) failed, throwing");
return false;
}
}
}
@ -106,6 +119,44 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
}
}
/* Setting L2CAP socket options */
if (mType == BluetoothSocketType::L2CAP ||
mType == BluetoothSocketType::EL2CAP) {
struct l2cap_options opts;
int optlen = sizeof(opts), err;
err = getsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
if (!err) {
/* setting MTU for [E]L2CAP */
opts.omtu = opts.imtu = L2CAP_MAX_MTU;
/* Enable ERTM for [E]L2CAP */
if (mType == BluetoothSocketType::EL2CAP) {
opts.flush_to = 0xffff; /* infinite */
opts.mode = L2CAP_MODE_ERTM;
opts.fcs = 1;
opts.txwin_size = 64;
opts.max_tx = 10;
}
err = setsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen);
}
/* Set larger SNDBUF & RCVBUF for EL2CAP connections */
if (mType == BluetoothSocketType::EL2CAP) {
sndbuf = L2CAP_SO_SNDBUF;
if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
return false;
}
rcvbuf = L2CAP_SO_RCVBUF;
if (setsockopt(aFd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) {
NS_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
return false;
}
}
}
return true;
}
@ -125,6 +176,9 @@ BluetoothUnixSocketConnector::Create()
case BluetoothSocketType::L2CAP:
fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
break;
case BluetoothSocketType::EL2CAP:
fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
break;
default:
MOZ_NOT_REACHED();
}
@ -136,7 +190,9 @@ BluetoothUnixSocketConnector::Create()
if (!SetUp(fd)) {
NS_WARNING("Could not set up socket!");
return -1;
}
return fd;
}
@ -156,6 +212,9 @@ BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
}
}
// Initialize
memset(&aAddr, 0, sizeof(aAddr));
switch (mType) {
case BluetoothSocketType::RFCOMM:
struct sockaddr_rc addr_rc;
@ -164,6 +223,14 @@ BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
aAddr.rc.rc_channel = mChannel;
memcpy(&aAddr.rc.rc_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
break;
case BluetoothSocketType::L2CAP:
case BluetoothSocketType::EL2CAP:
struct sockaddr_l2 addr_l2;
aAddrSize = sizeof(addr_l2);
aAddr.l2.l2_family = AF_BLUETOOTH;
aAddr.l2.l2_psm = mChannel;
memcpy(&aAddr.l2.l2_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
break;
case BluetoothSocketType::SCO:
struct sockaddr_sco addr_sco;
aAddrSize = sizeof(addr_sco);
@ -189,6 +256,10 @@ BluetoothUnixSocketConnector::GetSocketAddr(const sockaddr_any& aAddr,
case BluetoothSocketType::SCO:
get_bdaddr_as_string((bdaddr_t*)(&aAddr.sco.sco_bdaddr), addr);
break;
case BluetoothSocketType::L2CAP:
case BluetoothSocketType::EL2CAP:
get_bdaddr_as_string((bdaddr_t*)(&aAddr.l2.l2_bdaddr), addr);
break;
default:
MOZ_NOT_REACHED("Socket should be either RFCOMM or SCO!");
}

View File

@ -50,12 +50,13 @@ public:
// These were hardcoded into android
enum BluetoothReservedChannels {
CHANNEL_DIALUP_NETWORK = 1,
CHANNEL_HANDSFREE_AG = 10,
CHANNEL_HEADSET_AG = 11,
CHANNEL_OPUSH = 12,
CHANNEL_SIM_ACCESS = 15,
CHANNEL_PBAP_PSE = 19,
CHANNEL_FTP = 20,
CHANNEL_HANDSFREE_AG = 10,
CHANNEL_HEADSET_AG = 11,
CHANNEL_OPUSH = 12,
CHANNEL_SIM_ACCESS = 15,
CHANNEL_PBAP_PSE = 19,
CHANNEL_FTP = 20,
CHANNEL_OPUSH_L2CAP = 5255
};
END_BLUETOOTH_NAMESPACE

View File

@ -15,6 +15,7 @@
#ifdef MOZ_B2G_BT
#include <bluetooth/bluetooth.h>
#include <bluetooth/sco.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/rfcomm.h>
#endif
#include <stdlib.h>
@ -33,6 +34,7 @@ union sockaddr_any {
#ifdef MOZ_B2G_BT
sockaddr_sco sco;
sockaddr_rc rc;
sockaddr_l2 l2;
#endif
// ... others
};