https://github.com/python/cpython/commit/f2f86d3f459a89273ea22389bb57eed402908302
commit: f2f86d3f459a89273ea22389bb57eed402908302
branch: main
author: Serhiy Storchaka <storch...@gmail.com>
committer: serhiy-storchaka <storch...@gmail.com>
date: 2025-04-12T23:57:34+03:00
summary:

gh-132429: Fix support of Bluetooth sockets on NetBSD and DragonFly BSD 
(GH-132431)

* Also add support for cid and bdaddr_type in the BTPROTO_L2CAP address on 
FreeBSD.
* Return cid in getsockname() for BTPROTO_L2CAP if it is not zero.
* Fix a compiler warning on FreeBSD.

files:
A Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c
M Modules/socketmodule.h

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index cf46acbaab4b9e..fcadcb3fb884aa 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -2643,36 +2643,44 @@ def testCreateScoSocket(self):
 
     @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets 
required for this test')
     def testBindLeAttL2capSocket(self):
+        BDADDR_LE_PUBLIC = support.get_attribute(socket, 'BDADDR_LE_PUBLIC')
         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))
+            f.bind((socket.BDADDR_ANY, 0, CID_ATT, BDADDR_LE_PUBLIC))
             addr = f.getsockname()
-            self.assertEqual(addr, (socket.BDADDR_ANY, 0, CID_ATT, 
socket.BDADDR_LE_PUBLIC))
+            self.assertEqual(addr, (socket.BDADDR_ANY, 0, CID_ATT, 
BDADDR_LE_PUBLIC))
 
     @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets 
required for this test')
     def testBindLePsmL2capSocket(self):
+        BDADDR_LE_RANDOM = support.get_attribute(socket, 'BDADDR_LE_RANDOM')
         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))
+            f.bind((socket.BDADDR_ANY, psm, 0, BDADDR_LE_RANDOM))
             addr = f.getsockname()
-            self.assertEqual(addr, (socket.BDADDR_ANY, psm, 0, 
socket.BDADDR_LE_RANDOM))
+            self.assertEqual(addr, (socket.BDADDR_ANY, psm, 0, 
BDADDR_LE_RANDOM))
 
     @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets 
required for this test')
     def testBindBrEdrL2capSocket(self):
+        # First user PSM in BR/EDR L2CAP
+        psm = 0x1001
         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))
 
+        cid = 1
+        with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, 
socket.BTPROTO_L2CAP) as f:
+            f.bind((socket.BDADDR_ANY, psm, cid))
+            addr = f.getsockname()
+            self.assertEqual(addr, (socket.BDADDR_ANY, psm, cid))
+
     @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets 
required for this test')
     def testBadL2capAddr(self):
         with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, 
socket.BTPROTO_L2CAP) as f:
             with self.assertRaises(OSError):
-                f.bind((socket.BDADDR_ANY, 0, 0, socket.BDADDR_BREDR, 0))
+                f.bind((socket.BDADDR_ANY, 0, 0, 0, 0))
             with self.assertRaises(OSError):
                 f.bind((socket.BDADDR_ANY,))
             with self.assertRaises(OSError):
diff --git 
a/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst 
b/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst
new file mode 100644
index 00000000000000..95be9ec922bc93
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst
@@ -0,0 +1,3 @@
+Fix support of Bluetooth sockets on NetBSD and DragonFly BSD. Add support
+for *cid* and *bdaddr_type* in the BTPROTO_L2CAP address on FreeBSD. Return
+*cid* in ``getsockname()`` for BTPROTO_L2CAP if it is not zero.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 22a3a2effe2962..76e16bc3a2d3ec 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -460,39 +460,44 @@ remove_unusable_flags(PyObject *m)
 #  define SOCKETCLOSE close
 #endif
 
-#if (defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)) && 
!defined(__NetBSD__) && !defined(__DragonFly__)
-#define USE_BLUETOOTH 1
-#if defined(__FreeBSD__)
-#define BTPROTO_L2CAP BLUETOOTH_PROTO_L2CAP
-#define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM
-#define BTPROTO_HCI BLUETOOTH_PROTO_HCI
-#define BTPROTO_SCO BLUETOOTH_PROTO_SCO
-#define SOL_HCI SOL_HCI_RAW
-#define HCI_FILTER SO_HCI_RAW_FILTER
-#define sockaddr_l2 sockaddr_l2cap
-#define sockaddr_rc sockaddr_rfcomm
-#define hci_dev hci_node
-#define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb)
-#define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb)
-#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
-#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb)
-#elif defined(__NetBSD__) || defined(__DragonFly__)
-#define sockaddr_l2 sockaddr_bt
-#define sockaddr_rc sockaddr_bt
-#define sockaddr_hci sockaddr_bt
-#define sockaddr_sco sockaddr_bt
-#define SOL_HCI BTPROTO_HCI
-#define HCI_DATA_DIR SO_HCI_DIRECTION
-#define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb)
-#define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb)
-#define _BT_HCI_MEMB(sa, memb) ((sa)->bt_##memb)
-#define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb)
-#else
-#define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb)
-#define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb)
-#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
-#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb)
-#endif
+#if defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)
+# define USE_BLUETOOTH 1
+# if defined(HAVE_BLUETOOTH_BLUETOOTH_H) // Linux
+#   define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb)
+#   define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb)
+#   define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
+#   define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb)
+# elif defined(__FreeBSD__)
+#   define BTPROTO_L2CAP BLUETOOTH_PROTO_L2CAP
+#   define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM
+#   define BTPROTO_HCI BLUETOOTH_PROTO_HCI
+#   define BTPROTO_SCO BLUETOOTH_PROTO_SCO
+#   define SOL_HCI SOL_HCI_RAW
+#   define HCI_FILTER SO_HCI_RAW_FILTER
+#   define sockaddr_l2 sockaddr_l2cap
+#   define sockaddr_rc sockaddr_rfcomm
+#   define hci_dev hci_node
+#   define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb)
+#   define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb)
+#   define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
+#   define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb)
+# else // NetBSD, DragonFly BSD
+#   define sockaddr_l2 sockaddr_bt
+#   define sockaddr_rc sockaddr_bt
+#   define sockaddr_hci sockaddr_bt
+#   define sockaddr_sco sockaddr_bt
+#   define bt_l2 bt
+#   define bt_rc bt
+#   define bt_sco bt
+#   define bt_hci bt
+#   define bt_cid bt_channel
+#   define SOL_HCI BTPROTO_HCI
+#   define HCI_DATA_DIR SO_HCI_DIRECTION
+#   define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb)
+#   define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb)
+#   define _BT_HCI_MEMB(sa, memb) ((sa)->bt_##memb)
+#   define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb)
+# endif
 #endif
 
 #ifdef MS_WINDOWS_DESKTOP
@@ -1487,20 +1492,28 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, 
size_t addrlen, int proto)
             PyObject *addrobj = makebdaddr(&_BT_L2_MEMB(a, bdaddr));
             PyObject *ret = NULL;
             if (addrobj) {
-                /* 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 {
+#if defined(BDADDR_BREDR)  // Linux, FreeBSD
+                if (_BT_L2_MEMB(a, bdaddr_type) != BDADDR_BREDR) {
                     ret = Py_BuildValue("OiiB",
                                         addrobj,
                                         _BT_L2_MEMB(a, psm),
                                         _BT_L2_MEMB(a, cid),
                                         _BT_L2_MEMB(a, bdaddr_type));
                 }
+                else
+#endif
+                if (_BT_L2_MEMB(a, cid) != 0) {
+                    ret = Py_BuildValue("Oii",
+                                        addrobj,
+                                        _BT_L2_MEMB(a, psm),
+                                        _BT_L2_MEMB(a, cid));
+                }
+                else {
+                    /* Retain old format for non-LE address. */
+                    ret = Py_BuildValue("Oi",
+                                        addrobj,
+                                        _BT_L2_MEMB(a, psm));
+                }
                 Py_DECREF(addrobj);
             }
             return ret;
@@ -1526,16 +1539,16 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, 
size_t addrlen, int proto)
         case BTPROTO_HCI:
         {
             struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
-#if defined(__NetBSD__) || defined(__DragonFly__)
-            return makebdaddr(&_BT_HCI_MEMB(a, bdaddr));
+#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
+            PyObject *ret = NULL;
+            ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
+            return ret;
 #elif defined(__FreeBSD__)
-            char *node = _BT_HCI_MEMB(a, node);
+            const char *node = _BT_HCI_MEMB(a, node);
             size_t len = strnlen(node, sizeof(_BT_HCI_MEMB(a, node)));
             return PyBytes_FromStringAndSize(node, (Py_ssize_t)len);
 #else
-            PyObject *ret = NULL;
-            ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
-            return ret;
+            return makebdaddr(&_BT_HCI_MEMB(a, bdaddr));
 #endif
         }
 #endif /* BTPROTO_HCI */
@@ -2060,6 +2073,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
             memset(addr, 0, sizeof(struct sockaddr_l2));
             _BT_L2_MEMB(addr, family) = AF_BLUETOOTH;
             unsigned short psm;
+#if defined(BDADDR_BREDR)  // Linux, FreeBSD
             unsigned short cid = 0;
             unsigned char bdaddr_type = BDADDR_BREDR;
             if (!PyArg_ParseTuple(args, "sH|HB", &straddr,
@@ -2070,9 +2084,18 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
                              "%s(): wrong format", caller);
                 return 0;
             }
+            _BT_L2_MEMB(addr, bdaddr_type) = bdaddr_type;
+#else
+            unsigned char cid = 0;
+            if (!PyArg_ParseTuple(args, "sH|B", &straddr,
+                                  &psm, &cid)) {
+                PyErr_Format(PyExc_OSError,
+                             "%s(): wrong format", caller);
+                return 0;
+            }
+#endif
             _BT_L2_MEMB(addr, psm) = psm;
             _BT_L2_MEMB(addr, cid) = cid;
-            _BT_L2_MEMB(addr, bdaddr_type) = bdaddr_type;
 
             if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0)
                 return 0;
@@ -2113,19 +2136,16 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
         {
             struct sockaddr_hci *addr = &addrbuf->bt_hci;
             memset(addr, 0, sizeof(struct sockaddr_hci));
-#if defined(__NetBSD__) || defined(__DragonFly__)
-            const char *straddr;
             _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
-            if (!PyBytes_Check(args)) {
-                PyErr_Format(PyExc_OSError, "%s: "
-                             "wrong format", caller);
+#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
+            unsigned short dev = _BT_HCI_MEMB(addr, dev);
+            if (!PyArg_ParseTuple(args, "H", &dev)) {
+                PyErr_Format(PyExc_OSError,
+                             "%s(): wrong format", caller);
                 return 0;
             }
-            straddr = PyBytes_AS_STRING(args);
-            if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
-                return 0;
+            _BT_HCI_MEMB(addr, dev) = dev;
 #elif defined(__FreeBSD__)
-            _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
             if (!PyBytes_Check(args)) {
                 PyErr_Format(PyExc_OSError, "%s: "
                              "wrong node format", caller);
@@ -2146,14 +2166,15 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
             strncpy(_BT_HCI_MEMB(addr, node), straddr,
                     sizeof(_BT_HCI_MEMB(addr, node)));
 #else
-            _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
-            unsigned short dev = _BT_HCI_MEMB(addr, dev);
-            if (!PyArg_ParseTuple(args, "H", &dev)) {
-                PyErr_Format(PyExc_OSError,
-                             "%s(): wrong format", caller);
+            const char *straddr;
+            if (!PyBytes_Check(args)) {
+                PyErr_Format(PyExc_OSError, "%s: "
+                             "wrong format", caller);
                 return 0;
             }
-            _BT_HCI_MEMB(addr, dev) = dev;
+            straddr = PyBytes_AS_STRING(args);
+            if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
+                return 0;
 #endif
             *len_ret = sizeof *addr;
             return 1;
@@ -2739,7 +2760,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
         case BTPROTO_SCO:
             *len_ret = sizeof (struct sockaddr_sco);
             return 1;
-#endif /* BTPROTO_HCI */
+#endif /* BTPROTO_SCO */
         default:
             PyErr_SetString(PyExc_OSError, "getsockaddrlen: "
                             "unknown BT protocol");
@@ -7845,20 +7866,22 @@ socket_exec(PyObject *m)
     ADD_INT_MACRO(m, AF_BLUETOOTH);
 #ifdef BTPROTO_L2CAP
     ADD_INT_MACRO(m, BTPROTO_L2CAP);
+#if defined(BDADDR_BREDR)
     ADD_INT_MACRO(m, BDADDR_BREDR);
     ADD_INT_MACRO(m, BDADDR_LE_PUBLIC);
     ADD_INT_MACRO(m, BDADDR_LE_RANDOM);
+#endif
 #endif /* BTPROTO_L2CAP */
 #ifdef BTPROTO_HCI
     ADD_INT_MACRO(m, BTPROTO_HCI);
     ADD_INT_MACRO(m, SOL_HCI);
-#if !defined(__NetBSD__) && !defined(__DragonFly__)
+#if defined(HCI_FILTER)
     ADD_INT_MACRO(m, HCI_FILTER);
-#if !defined(__FreeBSD__)
+#endif
+#if defined(HCI_TIME_STAMP)
     ADD_INT_MACRO(m, HCI_TIME_STAMP);
     ADD_INT_MACRO(m, HCI_DATA_DIR);
-#endif /* !__FreeBSD__ */
-#endif /* !__NetBSD__ && !__DragonFly__ */
+#endif
 #endif /* BTPROTO_HCI */
 #ifdef BTPROTO_RFCOMM
     ADD_INT_MACRO(m, BTPROTO_RFCOMM);
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index e1d96377728eb9..63624d511c35a0 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -122,6 +122,9 @@ typedef int socklen_t;
 #endif
 
 #ifdef HAVE_BLUETOOTH_H
+#ifdef __FreeBSD__
+#define L2CAP_SOCKET_CHECKED
+#endif
 #include <bluetooth.h>
 #endif
 
@@ -274,18 +277,22 @@ typedef union sock_addr {
     struct sockaddr_in6 in6;
     struct sockaddr_storage storage;
 #endif
-#if defined(HAVE_BLUETOOTH_H) && defined(__FreeBSD__)
-    struct sockaddr_l2cap bt_l2;
-    struct sockaddr_rfcomm bt_rc;
-    struct sockaddr_sco bt_sco;
-    struct sockaddr_hci bt_hci;
-#elif defined(HAVE_BLUETOOTH_BLUETOOTH_H)
+#if defined(MS_WINDOWS)
+    struct SOCKADDR_BTH_REDEF bt_rc;
+#elif defined(HAVE_BLUETOOTH_BLUETOOTH_H) // Linux
     struct sockaddr_l2 bt_l2;
     struct sockaddr_rc bt_rc;
     struct sockaddr_sco bt_sco;
     struct sockaddr_hci bt_hci;
-#elif defined(MS_WINDOWS)
-    struct SOCKADDR_BTH_REDEF bt_rc;
+#elif defined(HAVE_BLUETOOTH_H)
+# if defined(__FreeBSD__)
+    struct sockaddr_l2cap bt_l2;
+    struct sockaddr_rfcomm bt_rc;
+    struct sockaddr_sco bt_sco;
+    struct sockaddr_hci bt_hci;
+# else // NetBSD, DragonFly BSD
+    struct sockaddr_bt bt;
+# endif
 #endif
 #ifdef HAVE_NETPACKET_PACKET_H
     struct sockaddr_ll ll;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to