Skip to content

BTPROTO_L2CAP not exposed on Windows despite Winsock supporting it #148449

@Leclowndu93150

Description

@Leclowndu93150

Summary

CPython defines BTPROTO_RFCOMM on Windows by mapping it to BTHPROTO_RFCOMM, but does not do the same for BTPROTO_L2CAP (BTHPROTO_L2CAP = 0x0100). The socket address parsing code for L2CAP is also #ifdef'd out on Windows.

However, Windows Winsock does accept L2CAP sockets. Creating a socket with AF_BTH (32) + BTHPROTO_L2CAP (0x0100) + SOCK_STREAM succeeds and returns a valid socket handle.

Test

I tested this on Windows 11 with Python 3.13 by calling ws2_32.socket() directly via ctypes:

import ctypes
ws2_32 = ctypes.windll.ws2_32

AF_BTH = 32
BTHPROTO_L2CAP = 0x0100
SOCK_STREAM = 1

wsadata = ctypes.create_string_buffer(512)
ws2_32.WSAStartup(0x0202, wsadata)

sock = ws2_32.socket(AF_BTH, SOCK_STREAM, BTHPROTO_L2CAP)
print(sock)  # prints a valid socket fd, not INVALID_SOCKET

Output:

BTHPROTO_RFCOMM + SOCK_STREAM: OK (socket=356)
BTHPROTO_L2CAP + SOCK_STREAM: OK (socket=356)

Both work fine.

What's missing in CPython

In Modules/socketmodule.c:

  1. BTPROTO_L2CAP is never #define'd on Windows (only BTPROTO_RFCOMM gets mapped from BTHPROTO_RFCOMM)
  2. The #ifdef BTPROTO_L2CAP block in getsockaddrarg() / getsockaddrlen() is compiled out on Windows since the constant doesn't exist

The SOCKADDR_BTH struct already has a port field documented as accepting either an RFCOMM channel or an L2CAP PSM, so the address format is the same. It would just need:

#ifdef MS_WINDOWS_DESKTOP
#define BTPROTO_L2CAP BTHPROTO_L2CAP
#endif

And then the BTPROTO_L2CAP case in getsockaddrarg() should handle the SOCKADDR_BTH struct on Windows (using the port field for the PSM, same as Linux uses l2_psm).

Why this matters

L2CAP is required for communicating with many Bluetooth devices (headphones, game controllers, medical devices). Right now, anyone needing L2CAP on Windows from Python has to either use ctypes to call Winsock directly, or use an entirely separate Bluetooth stack like Google Bumble with a dedicated USB adapter. This is a big gap since the underlying OS does support it.

Versions

  • Windows 11 24H2
  • Python 3.13
  • Tested with the built-in Bluetooth adapter

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions