- :const:`AF_BLUETOOTH` supports the following protocols and address
formats:
- - :const:`BTPROTO_L2CAP` accepts ``(bdaddr, psm)`` where ``bdaddr`` is
- the Bluetooth address as a string and ``psm`` is an integer.
+ - :const:`BTPROTO_L2CAP` accepts a tuple
+ ``(bdaddr, psm[, cid[, bdaddr_type]])`` where:
+
+ - ``bdaddr`` is a string specifying the Bluetooth address.
+ - ``psm`` is an integer specifying the Protocol/Service Multiplexer.
+ - ``cid`` is an optional integer specifying the Channel Identifier.
+ If not given, defaults to zero.
+ - ``bdaddr_type`` is an optional integer specifying the address type;
+ one of :const:`BDADDR_BREDR` (default), :const:`BDADDR_LE_PUBLIC`,
+ :const:`BDADDR_LE_RANDOM`.
+
+ .. versionchanged:: next
+ Added ``cid`` and ``bdaddr_type`` fields.
- :const:`BTPROTO_RFCOMM` accepts ``(bdaddr, channel)`` where ``bdaddr``
is the Bluetooth address as a string and ``channel`` is an integer.
This constant contains a boolean value which indicates if IPv6 is supported on
this platform.
+.. data:: AF_BLUETOOTH
+ BTPROTO_L2CAP
+ BTPROTO_RFCOMM
+ BTPROTO_HCI
+ BTPROTO_SCO
+
+ Integer constants for use with Bluetooth addresses.
+
.. data:: BDADDR_ANY
BDADDR_LOCAL
any address when specifying the binding socket with
:const:`BTPROTO_RFCOMM`.
+.. data:: BDADDR_BREDR
+ BDADDR_LE_PUBLIC
+ BDADDR_LE_RANDOM
+
+ These constants describe the Bluetooth address type when binding or
+ connecting a :const:`BTPROTO_L2CAP` socket.
+
+ .. versionadded:: next
+
.. data:: HCI_FILTER
HCI_TIME_STAMP
HCI_DATA_DIR
return True
+def _have_socket_bluetooth_l2cap():
+ """Check whether BTPROTO_L2CAP sockets are supported on this host."""
+ try:
+ s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP)
+ except (AttributeError, OSError):
+ return False
+ else:
+ s.close()
+ return True
+
+
def _have_socket_hyperv():
"""Check whether AF_HYPERV sockets are supported on this host."""
try:
HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth()
+HAVE_SOCKET_BLUETOOTH_L2CAP = _have_socket_bluetooth_l2cap()
+
HAVE_SOCKET_HYPERV = _have_socket_hyperv()
# Size in bytes of the int type
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s:
pass
+ @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test')
+ def testBindLeAttL2capSocket(self):
+ with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f:
+ # ATT is the only CID allowed in userspace by the Linux kernel
+ CID_ATT = 4
+ f.bind((socket.BDADDR_ANY, 0, CID_ATT, socket.BDADDR_LE_PUBLIC))
+ addr = f.getsockname()
+ self.assertEqual(addr, (socket.BDADDR_ANY, 0, CID_ATT, socket.BDADDR_LE_PUBLIC))
+
+ @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test')
+ def testBindLePsmL2capSocket(self):
+ with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f:
+ # First user PSM in LE L2CAP
+ psm = 0x80
+ f.bind((socket.BDADDR_ANY, psm, 0, socket.BDADDR_LE_RANDOM))
+ addr = f.getsockname()
+ self.assertEqual(addr, (socket.BDADDR_ANY, psm, 0, socket.BDADDR_LE_RANDOM))
+
+ @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test')
+ def testBindBrEdrL2capSocket(self):
+ with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f:
+ # First user PSM in BR/EDR L2CAP
+ psm = 0x1001
+ f.bind((socket.BDADDR_ANY, psm))
+ addr = f.getsockname()
+ self.assertEqual(addr, (socket.BDADDR_ANY, psm))
+
@unittest.skipUnless(HAVE_SOCKET_HYPERV,
'Hyper-V sockets required for this test.')
--- /dev/null
+Add optional ``l2_cid`` and ``l2_bdaddr_type`` fields to :mod:`socket` ``BTPROTO_L2CAP`` sockaddr tuple.
PyObject *addrobj = makebdaddr(&_BT_L2_MEMB(a, bdaddr));
PyObject *ret = NULL;
if (addrobj) {
- ret = Py_BuildValue("Oi",
- addrobj,
- _BT_L2_MEMB(a, psm));
+ /* Retain old format for non-LE address.
+ (cid may be set for BR/EDR, but we're discarding it for now)
+ */
+ if (_BT_L2_MEMB(a, bdaddr_type) == BDADDR_BREDR) {
+ ret = Py_BuildValue("Oi",
+ addrobj,
+ _BT_L2_MEMB(a, psm));
+ } else {
+ ret = Py_BuildValue("OiiB",
+ addrobj,
+ _BT_L2_MEMB(a, psm),
+ _BT_L2_MEMB(a, cid),
+ _BT_L2_MEMB(a, bdaddr_type));
+ }
Py_DECREF(addrobj);
}
return ret;
struct sockaddr_l2 *addr = &addrbuf->bt_l2;
memset(addr, 0, sizeof(struct sockaddr_l2));
_BT_L2_MEMB(addr, family) = AF_BLUETOOTH;
- if (!PyArg_ParseTuple(args, "si", &straddr,
- &_BT_L2_MEMB(addr, psm))) {
+ _BT_L2_MEMB(addr, bdaddr_type) = BDADDR_BREDR;
+ if (!PyArg_ParseTuple(args, "si|iB", &straddr,
+ &_BT_L2_MEMB(addr, psm),
+ &_BT_L2_MEMB(addr, cid),
+ &_BT_L2_MEMB(addr, bdaddr_type))) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
return 0;
ADD_INT_MACRO(m, AF_BLUETOOTH);
#ifdef BTPROTO_L2CAP
ADD_INT_MACRO(m, BTPROTO_L2CAP);
+ ADD_INT_MACRO(m, BDADDR_BREDR);
+ ADD_INT_MACRO(m, BDADDR_LE_PUBLIC);
+ ADD_INT_MACRO(m, BDADDR_LE_RANDOM);
#endif /* BTPROTO_L2CAP */
#ifdef BTPROTO_HCI
ADD_INT_MACRO(m, BTPROTO_HCI);