Bluetooth 커널 서브시스템 심화

Linux Bluetooth는 net/bluetooth/ 코어와 BlueZ 사용자 공간 도구가 결합되어 동작합니다. 이 문서는 커널 내부 데이터 경로, 드라이버 계층, 보안, 성능, 디버깅 관점에서 Bluetooth Classic과 BLE를 함께 정리합니다. Bluetooth Core Specification 5.4 기준으로 프로토콜 스택 전반, Mesh, LE Audio까지 포괄합니다.

전제 조건: Wireless 서브시스템Network Device 드라이버 문서를 먼저 읽으세요. 무선 PHY 계층, IRQ/NAPI, 패킷 버퍼 기본 지식이 있으면 Bluetooth 코어 흐름을 훨씬 쉽게 이해할 수 있습니다.
일상 비유: 이 개념은 택배 허브 분류 시스템과 비슷합니다. 무선 칩이 가져온 프레임(HCI 이벤트)을 허브(HCI 코어)가 분류하고, 각 라인(L2CAP/RFCOMM/GATT)으로 나눠 보냅니다.

핵심 요약

  • HCI -- 호스트와 컨트롤러 사이 표준 명령/이벤트 인터페이스
  • L2CAP -- 채널 기반 다중화, 재조립, 흐름 제어
  • SMP -- BLE 페어링/키 분배 보안 계층
  • GATT/GAP -- BLE 서비스 검색과 데이터 교환의 핵심 프로토콜
  • mgmt -- BlueZ가 커널 Bluetooth 스택을 제어하는 관리 인터페이스
  • btmon -- HCI, mgmt 트래픽을 동시에 보는 핵심 디버깅 도구

단계별 이해

  1. 컨트롤러 등록
    btusb 또는 hci_uart 드라이버가 HCI 장치를 등록합니다.
  2. 어댑터 활성화
    BlueZ가 mgmt 명령으로 스캔/광고/연결 모드를 설정합니다.
  3. 채널 협상
    L2CAP가 CID 채널을 열고 MTU/보안 파라미터를 협상합니다.
  4. 상위 서비스 사용
    RFCOMM, ATT/GATT, SCO 오디오가 각각 목적에 맞게 데이터 경로를 사용합니다.

Bluetooth 프로토콜 스택 아키텍처

Bluetooth Core Specification 구조

Bluetooth Core Specification은 Host와 Controller를 명확히 분리합니다. Controller는 무선 송수신(Radio), 베이스밴드(Baseband), 링크 매니저(Link Manager)를 담당하며, Host는 L2CAP, SDP, RFCOMM, GATT 등 상위 프로토콜을 처리합니다. 이 둘 사이의 표준 인터페이스가 HCI(Host Controller Interface)입니다.

HCI Transport 계층

HCI 패킷은 물리적으로 다양한 전송 수단을 통해 이동합니다. 리눅스 커널은 다음 HCI Transport를 지원합니다:

Transport커널 드라이버특징주요 사용 환경
USB btusb 인터럽트/벌크/아이소크러너스 엔드포인트 활용, 가장 범용적 PC/노트북 내장 어댑터, USB 동글
UART (H4) hci_uart 단순 직렬 프로토콜, 패킷 타입 바이트로 구분 임베디드 SoC, Raspberry Pi
UART (H5/3-Wire) hci_uart 슬립 모드, CRC, 재전송 지원으로 안정성 향상 전력 관리가 중요한 IoT 장치
SDIO btsdio SD 버스 기반 전송, 주로 WiFi+BT 콤보 칩에서 사용 모바일/태블릿 콤보 모듈
SPI 벤더별 구현 저전력, 단순 인터페이스 웨어러블, 센서 노드

BlueZ 커널 모듈 구조

리눅스 커널의 Bluetooth 구현은 net/bluetooth/ 디렉토리에 모듈화되어 있습니다. 각 모듈은 독립적으로 빌드 가능하며 CONFIG_BT_* 옵션으로 제어됩니다.

커널 모듈소스 위치역할
bluetoothnet/bluetooth/코어: AF_BLUETOOTH 소켓, HCI 코어, SMP
bnepnet/bluetooth/bnep/Bluetooth Network Encapsulation Protocol
cmtpnet/bluetooth/cmtp/CAPI Message Transport Protocol
hidpnet/bluetooth/hidp/Human Interface Device Protocol
rfcommnet/bluetooth/rfcomm/RS-232 에뮬레이션 프로토콜
btusbdrivers/bluetooth/btusb.cUSB HCI 드라이버
hci_uartdrivers/bluetooth/hci_uart.hUART HCI 드라이버 프레임워크
User Host Controller bluetoothd btmon bluetoothctl Application (D-Bus) 커널 경계 mgmt API AF_BLUETOOTH SMP ISO (LE Audio) GATT/ATT RFCOMM BNEP HIDP SCO/eSCO L2CAP (Logical Link Control and Adaptation Protocol) HCI Core (net/bluetooth/hci_core.c) HCI Transport btusb (USB) hci_uart (UART) btsdio (SDIO) 벤더별 (btintel 등) Bluetooth Controller Hardware (Radio + Baseband + Link Manager)

HCI (Host Controller Interface) 심화

HCI 패킷 형식

HCI는 네 가지 패킷 타입을 정의합니다. 각 패킷은 첫 번째 바이트(패킷 인디케이터)로 타입을 구분하며, 이후 타입별 헤더와 페이로드가 따릅니다.

패킷 타입인디케이터방향헤더 크기용도
Command0x01Host -> Controller3 바이트 (OpCode + Param Length)컨트롤러 제어 명령
ACL Data0x02양방향4 바이트 (Handle + Flags + Length)비동기 데이터 전송
SCO Data0x03양방향3 바이트 (Handle + Length)동기 음성 데이터
Event0x04Controller -> Host2 바이트 (Event Code + Param Length)상태/응답 이벤트
ISO Data0x05양방향4 바이트 (Handle + Flags + Length)LE Audio ISO 채널 데이터

hci_dev 구조체

struct hci_dev는 커널에서 하나의 Bluetooth 어댑터를 나타내는 핵심 자료구조입니다. net/bluetooth/hci_core.c에서 관리하며, 드라이버가 hci_alloc_dev()로 할당하고 hci_register_dev()로 등록합니다.

/* include/net/bluetooth/hci_core.h (주요 필드 발췌) */
struct hci_dev {
    struct list_head list;         /* 전역 hci_dev_list 링크 */
    struct mutex     lock;

    char            name[8];      /* "hci0", "hci1" ... */
    __u16           id;
    __u8            bus;           /* HCI_USB, HCI_UART, HCI_SDIO ... */
    __u8            dev_type;      /* HCI_PRIMARY, HCI_AMP */

    unsigned long   flags;         /* HCI_UP, HCI_RUNNING, HCI_PAIRABLE ... */
    __u8            dev_flags;
    __u16           manufacturer;  /* 벤더 식별자 */
    __u16           lmp_subver;

    /* 드라이버 콜백 */
    int             (*open)(struct hci_dev *hdev);
    int             (*close)(struct hci_dev *hdev);
    int             (*send)(struct hci_dev *hdev, struct sk_buff *skb);
    int             (*setup)(struct hci_dev *hdev);
    int             (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);

    /* ACL/SCO 연결 목록 */
    struct list_head conn_hash;
    struct list_head adv_instances;

    /* 명령/이벤트 큐 */
    struct sk_buff_head cmd_q;
    struct sk_buff_head raw_q;
    struct sk_buff      *sent_cmd;

    struct workqueue_struct *workqueue;
    struct workqueue_struct *req_workqueue;
};

HCI 코어 흐름과 상태 머신

HCI 명령은 hci_send_cmd()를 통해 cmd_q에 대기열에 추가된 뒤, hci_cmd_work() 워커가 하나씩 꺼내 드라이버의 send() 콜백으로 전송합니다. 컨트롤러 응답은 Command Complete/Command Status 이벤트로 돌아오며, hci_event_packet()에서 처리됩니다.

/* net/bluetooth/hci_core.c - RX 경로 흐름 요약 */
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
    switch (hci_skb_pkt_type(skb)) {
    case HCI_EVENT_PKT:
        return hci_event_packet(hdev, skb);
    case HCI_ACLDATA_PKT:
        return hci_acldata_packet(hdev, skb);
    case HCI_SCODATA_PKT:
        return hci_scodata_packet(hdev, skb);
    case HCI_ISODATA_PKT:
        return hci_isodata_packet(hdev, skb);
    }
    return -EINVAL;
}

HCI 장치의 상태 전이는 hdev->flags 비트 필드로 관리됩니다. 주요 상태 전이는 다음과 같습니다:

상태 플래그의미전이 조건
HCI_INIT초기화 진행 중hci_dev_open() 호출 시 설정
HCI_UP장치 활성 상태초기화 완료 후 설정
HCI_RUNNING드라이버 동작 중open() 콜백 성공 시
HCI_DISCOVERABLE검색 가능 모드mgmt Set Discoverable 명령
HCI_PAIRABLE페어링 허용 모드mgmt Set Pairable 명령
HCI_INQUIRY장치 검색(Inquiry) 진행 중Inquiry 명령 전송 시

L2CAP (Logical Link Control and Adaptation Protocol)

채널 멀티플렉싱

L2CAP는 하나의 ACL 링크 위에 여러 논리 채널을 다중화합니다. 각 채널은 CID(Channel Identifier)로 구분되며, 고정 CID(0x0001~0x003F)와 동적 CID(0x0040~)로 나뉩니다. 동적 채널은 PSM(Protocol/Service Multiplexer) 값으로 상위 프로토콜을 식별합니다.

CID용도프로토콜
0x0001L2CAP 시그널링 (BR/EDR)연결 요청/응답, 설정 협상
0x0002Connectionless그룹 브로드캐스트
0x0003AMP ManagerAMP 컨트롤러 관리
0x0004ATT (LE 고정 채널)GATT Attribute Protocol
0x0005LE 시그널링LE 연결 파라미터 업데이트
0x0006SMP (LE 고정 채널)Security Manager Protocol
0x0007SMP (BR/EDR)Cross-transport 키 분배

PSM (Protocol/Service Multiplexer)

PSM 값프로토콜설명
0x0001SDPService Discovery Protocol
0x0003RFCOMMRS-232 에뮬레이션
0x000FBNEPBluetooth Network Encapsulation
0x0011HID ControlHID 장치 제어 채널
0x0013HID InterruptHID 장치 데이터 채널
0x0017AVCTPAudio/Video Control Transport
0x0019AVDTPAudio/Video Distribution Transport

MTU 협상과 모드

L2CAP 채널 설정 시 양쪽이 MTU(Maximum Transmission Unit)를 협상합니다. 기본 MTU는 BR/EDR에서 672 바이트, LE에서 23 바이트입니다. 실제 대부분의 구현은 더 큰 MTU를 요청합니다.

L2CAP는 여러 전송 모드를 지원합니다:

모드약어특징사용 사례
Basic Mode-흐름 제어/재전송 없음, 단순기본 데이터 전송
Enhanced Retransmission ModeERTMI-frame 시퀀스 번호, 선택적 재전송, 흐름 제어OBEX, HID (신뢰성 필요)
Streaming ModeSM순서 보장, 재전송 없음 (실시간 우선)A2DP 오디오 스트리밍
LE Credit-based Flow ControlLE CoC크레딧 기반 흐름 제어, LE 전용LE 데이터 채널 (대용량 전송)
Enhanced Credit-based Flow ControlECBFC다중 채널 동시 설정, Bluetooth 5.2+LE Audio, 고성능 LE 전송
/* net/bluetooth/l2cap_core.c - L2CAP 연결 요청 처리 핵심 흐름 */
static struct l2cap_chan *l2cap_connect(
    struct l2cap_conn *conn,
    struct l2cap_cmd_hdr *cmd,
    u8 *data, u8 cmd_len)
{
    struct l2cap_conn_req *req = (struct l2cap_conn_req *)data;
    __le16 psm = req->psm;
    __le16 scid = req->scid;

    /* PSM으로 상위 프로토콜 핸들러를 검색 */
    struct l2cap_chan *pchan = l2cap_global_chan_by_psm(
        0, psm, &conn->hcon->src,
        &conn->hcon->dst, ACL_LINK);
    /* 채널 설정: MTU, 모드, 보안 레벨 협상 진행 */
    ...
}

RFCOMM

RS-232 에뮬레이션

RFCOMM은 L2CAP 위에서 RS-232 직렬 포트를 에뮬레이션하는 프로토콜입니다. GSM 07.10 멀티플렉서 프로토콜을 기반으로 하며, 하나의 L2CAP 채널(PSM 0x0003) 위에 최대 30개의 DLC(Data Link Connection)를 다중화할 수 있습니다. 각 DLC는 서버 채널 번호(1~30)로 식별됩니다.

rfcomm_tty 드라이버

커널의 rfcomm 모듈은 TTY 인터페이스(/dev/rfcomm0 등)를 제공합니다. 이를 통해 기존 직렬 포트 프로그램이 수정 없이 Bluetooth 통신에 사용될 수 있습니다.

/* net/bluetooth/rfcomm/tty.c - RFCOMM TTY 드라이버 등록 */
static const struct tty_operations rfcomm_ops = {
    .open           = rfcomm_tty_open,
    .close          = rfcomm_tty_close,
    .write          = rfcomm_tty_write,
    .write_room     = rfcomm_tty_write_room,
    .set_termios    = rfcomm_tty_set_termios,
    .tiocmget       = rfcomm_tty_tiocmget,
    .tiocmset       = rfcomm_tty_tiocmset,
};

/* RFCOMM TTY 생성 명령 예시 */
/* rfcomm bind /dev/rfcomm0 AA:BB:CC:DD:EE:FF 1 */
RFCOMM 서비스서버 채널용도
SPP (Serial Port Profile)보통 1범용 직렬 통신
DUN (Dial-up Networking)보통 1~2모뎀 에뮬레이션
OBEX Push보통 9~12파일 전송
HFP (Hands-Free Profile)SDP로 검색차량 핸즈프리 통화

BLE (Bluetooth Low Energy)

BLE vs Classic 비교

Bluetooth 4.0에서 도입된 BLE는 Classic BR/EDR과는 완전히 다른 PHY와 프로토콜 스택을 사용합니다. 동일한 2.4 GHz ISM 대역을 사용하지만, 채널 수, 변조 방식, 전력 소모, 데이터 전송 패턴이 크게 다릅니다.

항목Classic (BR/EDR)BLE (LE)
채널 수79 (1 MHz 간격)40 (2 MHz 간격, 3개 광고 채널)
최대 데이터 속도BR: 1 Mbps, EDR: 3 MbpsLE 1M: 1 Mbps, LE 2M: 2 Mbps
연결 지연100 ms 이상수 ms~수십 ms
전력 소모상대적으로 높음매우 낮음 (코인 셀 배터리 수 년)
토폴로지포인트 투 포인트 (피코넷)Star, Mesh, Broadcast
주요 용도오디오, 파일 전송, HID센서, 비콘, 웨어러블, IoT
보안SSP (Secure Simple Pairing)SMP (Security Manager Protocol)
서비스 검색SDPGATT

Advertising과 Scanning

BLE 장치 검색의 핵심은 AdvertisingScanning입니다. 광고자(Advertiser)는 37, 38, 39번 채널에서 주기적으로 광고 패킷을 브로드캐스트하고, 스캐너(Scanner)는 이 채널을 순회하며 패킷을 수집합니다.

광고 타입HCI 명칭특징
Connectable UndirectedADV_IND모든 장치가 연결 요청 가능, 가장 일반적
Connectable DirectedADV_DIRECT_IND특정 장치만 연결 가능, 빠른 재연결
Non-Connectable UndirectedADV_NONCONN_IND비콘용, 연결 불가, 브로드캐스트 전용
Scannable UndirectedADV_SCAN_INDScan Request로 추가 데이터 요청 가능

Connection Interval과 LE PHY

BLE 연결이 수립되면 Central과 Peripheral은 Connection Interval(7.5 ms ~ 4 s)에 따라 주기적으로 데이터를 교환합니다. Slave Latency는 Peripheral이 건너뛸 수 있는 연결 이벤트 수로, 전력 절감에 핵심적입니다.

LE PHY도입 버전데이터 속도특징
LE 1MBT 4.01 Mbps기본 PHY, 호환성 최대
LE 2MBT 5.02 Mbps전송 시간 단축으로 전력 절감, 도달 거리 약간 감소
LE Coded (S=2)BT 5.0500 kbpsFEC 코딩으로 도달 거리 2배 확장
LE Coded (S=8)BT 5.0125 kbpsFEC 코딩으로 도달 거리 4배 확장

Extended Advertising (Bluetooth 5.0+)

기존 Legacy Advertising은 31 바이트 페이로드 제한이 있었습니다. Bluetooth 5.0의 Extended Advertising은 보조 채널(Secondary Advertising Channel)을 활용하여 최대 255 바이트(체인 시 더 큰 데이터)의 광고 데이터를 전송할 수 있습니다. 또한 Advertising Sets를 통해 여러 광고 인스턴스를 동시에 운영할 수 있습니다.

BLE 연결 수립 과정 (Advertising -> Connection) Peripheral Central ADV_IND (ch 37, 38, 39) Connectable Undirected Advertising SCAN_REQ SCAN_RSP (추가 데이터) CONNECT_IND Access Address, Interval, Latency, Timeout, Channel Map Connection Established LL Data PDU (ATT/GATT) LL Data PDU (Response) LL_CONNECTION_PARAM_REQ Interval / Latency / Timeout 변경 요청 LL_CONNECTION_PARAM_RSP

GATT/GAP

GAP (Generic Access Profile)

GAP는 Bluetooth 장치의 검색 가능성, 연결 모드, 보안 요구사항을 정의합니다. BLE에서 GAP 역할은 다음 네 가지로 나뉩니다:

GAP 역할설명리눅스 커널 관련
Broadcaster광고만 전송, 연결 불가비콘, 센서 브로드캐스트
Observer스캔만 수행, 연결 불가패시브 수집기
Peripheral광고 전송 + 연결 수락 (Slave)센서, 웨어러블
Central스캔 + 연결 개시 (Master)스마트폰, 게이트웨이

GATT (Generic Attribute Profile)

GATT는 BLE 데이터 교환의 핵심 프레임워크입니다. ATT(Attribute Protocol) 위에서 동작하며, 데이터를 Service -> Characteristic -> Descriptor 계층으로 구조화합니다. L2CAP 고정 CID 0x0004를 사용합니다.

GATT 데이터 계층

계층UUID 예시설명
Service 0x180D (Heart Rate) 관련 Characteristic을 그룹화하는 최상위 컨테이너. Primary/Secondary 구분
Characteristic 0x2A37 (Heart Rate Measurement) 실제 데이터 값을 담는 단위. Properties(Read/Write/Notify/Indicate) 정의
Descriptor 0x2902 (CCCD) Characteristic의 메타데이터. CCCD는 Notification/Indication 활성화에 필수

ATT 프로토콜 주요 연산

ATT PDUOpCode방향설명
Read Request0x0AClient -> Server핸들 기반 값 읽기
Read Response0x0BServer -> Client읽기 응답
Write Request0x12Client -> Server값 쓰기 (응답 필요)
Write Response0x13Server -> Client쓰기 확인
Write Command0x52Client -> Server값 쓰기 (응답 없음)
Notification0x1BServer -> Client서버 주도 값 전달 (확인 없음)
Indication0x1DServer -> Client서버 주도 값 전달 (확인 필요)
Find By Type Value0x06Client -> ServerUUID로 서비스 검색
GATT Client vs Server: 일반적으로 스마트폰(Central)이 GATT Client, 센서(Peripheral)가 GATT Server입니다. 하지만 GAP 역할과 GATT 역할은 독립적이므로, Central이 GATT Server가 될 수도 있습니다. 리눅스 커널에서는 net/bluetooth/l2cap_core.c의 ATT 채널이 GATT 패킷을 처리하며, 실제 GATT 프로파일 로직 대부분은 BlueZ bluetoothd에서 구현됩니다.

SMP (Security Manager Protocol)

페어링 절차 개요

SMP는 BLE 연결의 보안을 담당하며, L2CAP 고정 CID 0x0006에서 동작합니다. 페어링 과정은 크게 세 단계로 진행됩니다:

  1. Phase 1 - Pairing Feature Exchange: 양쪽 장치가 IO Capability, 인증 요구사항, 지원 기능을 교환합니다.
  2. Phase 2 - Authentication (STK/LTK 생성): 선택된 페어링 방식에 따라 키를 생성합니다. Legacy Pairing은 STK(Short Term Key), LE Secure Connections는 LTK를 직접 생성합니다.
  3. Phase 3 - Key Distribution: LTK, IRK(Identity Resolving Key), CSRK(Connection Signature Resolving Key)를 교환합니다.

페어링 방식 비교

방식IO Capability 조합MITM 방어사용자 경험
Just WorksNoInput/NoOutput 포함 시없음사용자 입력 없이 즉시 페어링
Passkey EntryDisplay+Keyboard 조합있음한쪽이 표시한 6자리 숫자를 다른 쪽이 입력
Numeric Comparison양쪽 Display+YesNo (SC 전용)있음양쪽에 동일한 6자리 숫자를 표시, 사용자가 확인
OOB (Out of Band)OOB 데이터 사용 가능 시OOB 채널에 따라 다름NFC 탭 등 외부 채널로 인증 데이터 교환

LE Secure Connections

Bluetooth 4.2에서 도입된 LE Secure Connections는 ECDH(Elliptic Curve Diffie-Hellman) P-256 키 교환을 사용합니다. Legacy Pairing의 STK 방식보다 훨씬 강력한 보안을 제공하며, 패시브 도청에 대한 방어력이 있습니다. 커널에서는 net/bluetooth/smp.csc_send_public_key()에서 ECDH 공개키를 교환합니다.

키 분배

키 종류약어용도저장 위치
Long Term KeyLTK연결 암호화 (재연결 시 사용)/var/lib/bluetooth/
Identity Resolving KeyIRK랜덤 주소에서 실제 장치 식별/var/lib/bluetooth/
Connection Signature Resolving KeyCSRK비암호화 데이터의 서명 검증/var/lib/bluetooth/
Identity Address-장치의 고정 BD_ADDRIRK와 함께 저장
/* net/bluetooth/smp.c - SMP 페어링 요청 처리 */
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn,
                              struct sk_buff *skb)
{
    struct smp_cmd_pairing *req = (void *)skb->data;
    struct smp_chan *smp;

    /* IO Capability와 인증 요구사항 확인 */
    smp->preq[0] = SMP_CMD_PAIRING_REQ;
    memcpy(&smp->preq[1], req, sizeof(*req));

    /* SC 지원 여부에 따라 Legacy/SC 분기 */
    if (req->auth_req & SMP_AUTH_SC)
        set_bit(SMP_FLAG_SC, &smp->flags);

    /* 페어링 방식 결정: IO Capability 매트릭스 참조 */
    smp->method = get_auth_method(smp, req->io_capability,
                                  rsp->io_capability);
    ...
}
보안 주의: Just Works 모드는 MITM(Man-in-the-Middle) 공격에 취약합니다. 민감한 데이터를 다루는 BLE 장치는 반드시 Passkey 또는 Numeric Comparison 방식을 사용해야 합니다. 커널 설정에서 SMP_AUTH_MITM 플래그가 설정되어 있는지 확인하세요.

A2DP와 LE Audio

A2DP 오디오 프로파일

A2DP(Advanced Audio Distribution Profile)는 Classic Bluetooth에서 고품질 스테레오 오디오 스트리밍에 사용됩니다. AVDTP(Audio/Video Distribution Transport Protocol) 위에서 동작하며, L2CAP의 Streaming Mode를 사용하여 재전송 없이 실시간 전송을 우선합니다.

A2DP 코덱 비교

코덱필수/선택비트레이트지연비고
SBC필수 (기본)198~345 kbps높음 (~100-150 ms)모든 A2DP 장치 지원, 품질 보통
AAC선택최대 256 kbps (CBR)중간Apple 생태계 선호, 라이선스 필요
aptX선택 (Qualcomm)352 kbps낮음 (~40 ms)Qualcomm 칩셋 필요
aptX HD선택 (Qualcomm)576 kbps중간 (~80 ms)24-bit/48 kHz 고해상도
LDAC선택 (Sony)최대 990 kbps중간24-bit/96 kHz, Android 8+ 기본 지원
리눅스에서의 A2DP: 커널은 L2CAP/AVDTP 전송 계층만 담당하고, 실제 코덱 인코딩/디코딩은 PipeWire 또는 PulseAudio의 Bluetooth 모듈에서 수행합니다. pipewire-media-session 또는 wireplumber가 BlueZ의 D-Bus MediaEndpoint API를 통해 코덱을 협상합니다.

LE Audio와 ISO Channels

Bluetooth 5.2에서 도입된 LE Audio는 BLE 기반의 차세대 오디오 표준입니다. 기존 A2DP의 Classic Bluetooth 의존성을 제거하고, 저전력과 새로운 기능을 제공합니다.

항목A2DP (Classic)LE Audio
전송 방식L2CAP Streaming ModeISO Channels (CIS/BIS)
필수 코덱SBCLC3
멀티 스트림하나의 싱크만여러 싱크 동시 전송 가능
브로드캐스트불가Auracast (BIS)
보청기 지원제한적ASHA/HAP 프로파일 지원
전력 소모상대적으로 높음BLE 기반으로 저전력

LC3 코덱과 Broadcast Audio

LC3(Low Complexity Communication Codec)는 LE Audio의 필수 코덱으로, SBC보다 절반의 비트레이트에서 동등 이상의 품질을 제공합니다. Broadcast Audio (Auracast)는 BIS(Broadcast ISO Stream)를 통해 하나의 소스에서 다수의 수신기로 오디오를 동시 전송하는 기능입니다.

커널에서 ISO 채널은 HCI ISO Data 패킷(타입 0x05)을 통해 전송되며, net/bluetooth/iso.c에서 소켓 인터페이스를 제공합니다.

/* net/bluetooth/iso.c - ISO 소켓 생성 */
static int iso_sock_create(struct net *net,
                          struct socket *sock, int protocol,
                          int kern)
{
    struct sock *sk;

    sock->ops = &iso_sock_ops;
    sk = iso_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
    if (!sk)
        return -ENOMEM;

    iso_sock_init(sk, NULL);
    return 0;
}

Bluetooth Mesh

Mesh 네트워크 토폴로지

Bluetooth Mesh는 BLE Advertising/Scanning 기반의 관리형 플러딩(Managed Flooding) 메시 네트워크입니다. 기존 BLE의 포인트 투 포인트 토폴로지를 넘어 수백~수천 노드의 대규모 네트워크를 구성할 수 있습니다. 메시지는 TTL(Time To Live) 기반으로 네트워크 전체에 전파됩니다.

노드 역할

역할설명특징
Relay 노드 수신한 메시지를 재전송하여 도달 범위를 확장 항상 스캔/광고 상태, 전력 소모 높음
Proxy 노드 GATT Bearer를 통해 BLE 연결 기반 장치와 Mesh 네트워크를 연결 스마트폰 등 Mesh 미지원 장치의 게이트웨이
Friend 노드 Low Power 노드의 메시지를 임시 저장하고 폴링 시 전달 메모리와 상시 전원 필요
Low Power 노드 대부분 슬립 상태, Friend 노드에 폴링하여 메시지 수신 배터리 구동 센서에 최적

Provisioning

Provisioning은 새로운 장치를 Mesh 네트워크에 추가하는 과정입니다. Provisioner가 인증 후 NetKey, IV Index, Unicast Address를 할당합니다. 이 과정은 PB-ADV(Advertising Bearer) 또는 PB-GATT(GATT Bearer)를 통해 수행됩니다.

메시지 전달 과정

  1. Application Layer: 모델(Model)이 메시지를 생성하고 AppKey로 암호화
  2. Upper Transport: 접근 메시지(Access Message)를 세그먼트화하고 Application/Device Key로 암호화/인증
  3. Lower Transport: 세그먼트 조립/분해, SAR(Segmentation and Reassembly) 처리
  4. Network Layer: NetKey로 암호화/인증, TTL 관리, 릴레이 결정
  5. Bearer Layer: BLE Advertising 패킷으로 변환하여 전송
리눅스 Mesh 지원: BlueZ는 bluetooth-meshd 데몬을 통해 Mesh 기능을 지원합니다. 커널은 BLE Advertising/Scanning 기반 전송만 담당하고, Mesh 프로토콜 스택(프로비저닝, 암호화, 릴레이 로직)은 사용자 공간에서 처리합니다.

BlueZ 아키텍처

bluetoothd 데몬

bluetoothd는 BlueZ의 핵심 데몬으로, D-Bus를 통해 응용 프로그램에 Bluetooth 기능을 노출합니다. GATT 프로파일, 에이전트 기반 페어링, 장치 관리 등 대부분의 상위 로직을 담당합니다.

D-Bus API 구조

D-Bus 인터페이스객체 경로역할
org.bluez.Adapter1/org/bluez/hci0어댑터 관리 (스캔, 전원, 검색 모드)
org.bluez.Device1/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX장치 관리 (연결, 페어링, 프로퍼티)
org.bluez.GattService1.../service00XXGATT 서비스 표현
org.bluez.GattCharacteristic1.../char00XXGATT Characteristic 표현
org.bluez.AgentManager1/org/bluez페어링 에이전트 등록/관리
org.bluez.ProfileManager1/org/bluez커스텀 프로파일 등록
org.bluez.MediaEndpoint1에이전트가 등록A2DP 코덱 엔드포인트

mgmt API (커널-유저 인터페이스)

mgmt API는 bluetoothd가 커널 Bluetooth 스택을 제어하는 전용 인터페이스입니다. 기존의 hciconfig/hcitool이 사용하던 raw HCI 소켓 방식을 대체합니다. AF_BLUETOOTH 소켓의 BTPROTO_HCI에서 HCI_CHANNEL_CONTROL로 접근합니다.

/* mgmt 소켓 생성 (사용자 공간) */
int fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC,
                BTPROTO_HCI);

struct sockaddr_hci addr = {
    .hci_family  = AF_BLUETOOTH,
    .hci_dev     = HCI_DEV_NONE,
    .hci_channel = HCI_CHANNEL_CONTROL,  /* mgmt 채널 */
};
bind(fd, (struct sockaddr *)&addr, sizeof(addr));

주요 mgmt 명령

명령OpCode설명
Read Management Version0x0001mgmt 프로토콜 버전 확인
Set Powered0x0005어댑터 전원 켜기/끄기
Set Discoverable0x0006검색 가능 모드 설정
Start Discovery0x0023장치 검색 시작
Pair Device0x0019페어링 개시
Add Advertising0x003ELE 광고 인스턴스 추가
# btmgmt로 mgmt 명령 직접 실행
btmgmt info               # 어댑터 정보 확인
btmgmt power on            # 전원 켜기
btmgmt find                # 장치 검색
btmgmt advertising on      # LE 광고 활성화
btmgmt bondable on         # 페어링 허용

커널 드라이버

btusb

btusb는 가장 널리 사용되는 Bluetooth HCI 드라이버입니다. USB 인터페이스를 통해 HCI 패킷을 송수신하며, 다양한 벤더의 USB Bluetooth 어댑터를 지원합니다.

/* drivers/bluetooth/btusb.c - 핵심 구조 */
static int btusb_probe(struct usb_interface *intf,
                      const struct usb_device_id *id)
{
    struct btusb_data *data;
    struct hci_dev *hdev;

    data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
    hdev = hci_alloc_dev();

    hdev->bus   = HCI_USB;
    hdev->open  = btusb_open;     /* URB 제출 시작 */
    hdev->close = btusb_close;    /* URB 취소 */
    hdev->send  = btusb_send_frame; /* TX: 패킷 타입별 엔드포인트 선택 */
    hdev->flush = btusb_flush;

    /* 벤더별 초기화 콜백 설정 */
    if (id->driver_info & BTUSB_INTEL_NEW)
        hdev->setup = btintel_setup_combined;
    else if (id->driver_info & BTUSB_REALTEK)
        hdev->setup = btrtl_setup_realtek;
    else if (id->driver_info & BTUSB_MEDIATEK)
        hdev->setup = btmtk_usb_setup;

    return hci_register_dev(hdev);
}

USB 엔드포인트 사용

엔드포인트 타입방향HCI 패킷 타입특징
ControlTX (Host->Controller)CommandSetup 패킷으로 전송
Interrupt INRX (Controller->Host)Event주기적 폴링
Bulk OUTTXACL Data비동기 대량 전송
Bulk INRXACL Data비동기 대량 수신
Isochronous양방향SCO/ISO Data실시간 오디오 (대역폭 보장)

hci_uart (UART HCI 드라이버)

hci_uart는 UART 기반 Bluetooth 칩과 통신하는 프레임워크 드라이버입니다. 여러 프로토콜 변형을 플러그인 방식으로 지원합니다:

프로토콜소스 파일특징
H:4 (H4)hci_h4.c가장 단순, 패킷 타입 바이트만 추가. 에러 복구 없음
H:5 (3-Wire)hci_h5.cSLIP 인코딩, CRC-16, 재전송, 슬립 모드 지원
BCSPhci_bcsp.cBlueCore Serial Protocol (CSR/Qualcomm)
LLhci_ll.cTI WiLink 칩 전용, 슬립/웨이크업 최적화
QCAhci_qca.cQualcomm 칩 전용, IBS(In-Band Sleep) 지원
Marvellhci_mrvl.cMarvell/NXP 칩 전용
AG6XXhci_ag6xx.cIntel AG6XX 시리즈 전용

벤더별 초기화 드라이버

드라이버벤더소스 파일주요 기능
btintelIntelbtintel.c펌웨어 로드, DDC(Device Dynamic Configuration), TLV 파싱
btbcmBroadcombtbcm.c펌웨어(.hcd) 로드, 패치 RAM 기록
btrtlRealtekbtrtl.c펌웨어/설정 로드, ROM 버전 파싱
btmtkMediaTekbtmtk.c펌웨어 로드, 칩 리셋 시퀀스
btqcaQualcommbtqca.cNVM/RAMPATCH 로드, EDL(Enhanced Data Length) 프로토콜
펌웨어 로드: 대부분의 Bluetooth 칩은 부팅 시 호스트에서 펌웨어를 로드해야 합니다. 펌웨어 파일은 /lib/firmware/에 위치하며, 드라이버의 setup() 콜백에서 request_firmware()를 통해 로드됩니다. 펌웨어가 없으면 dmesg"firmware file not found" 오류가 출력되며 어댑터가 동작하지 않습니다.

구성 요소와 계층

커널 Bluetooth는 크게 컨트롤러 I/O 계층(HCI 드라이버), 프로토콜 계층(L2CAP/RFCOMM/SCO), 소켓 계층(AF_BLUETOOTH), 정책/관리 계층(mgmt)으로 나뉩니다. 아래 다이어그램은 패킷이 하드웨어에서 사용자 공간까지 이동하는 전체 경로를 보여줍니다.

사용자 공간: bluetoothd / btmon / btmgmt / 앱 mgmt AF_BLUETOOTH L2CAP/RFCOMM/ATT SCO/ISO HCI Core (net/bluetooth/hci_*.c) btusb (USB HCI) hci_uart (UART/serdev)

AF_BLUETOOTH 소켓 패밀리

리눅스 커널은 AF_BLUETOOTH 주소 패밀리를 통해 사용자 공간에 Bluetooth 소켓 인터페이스를 제공합니다. 프로토콜 번호에 따라 다양한 소켓 타입을 사용할 수 있습니다:

프로토콜상수소켓 타입용도
L2CAPBTPROTO_L2CAPSOCK_SEQPACKET / SOCK_STREAML2CAP 채널 직접 접근
HCIBTPROTO_HCISOCK_RAWHCI 패킷 직접 송수신, mgmt 접근
RFCOMMBTPROTO_RFCOMMSOCK_STREAMRFCOMM 직렬 통신
SCOBTPROTO_SCOSOCK_SEQPACKET동기 음성 데이터
ISOBTPROTO_ISOSOCK_SEQPACKETLE Audio ISO 채널

보안 모델: SSP와 SMP

Classic은 SSP(Secure Simple Pairing), BLE는 SMP(Security Manager Protocol)를 중심으로 링크 키/LTK를 교환합니다. 보안 레벨은 페어링 방식(Just Works, Passkey, Numeric Comparison)에 따라 달라집니다.

보안 레벨 정의

레벨이름암호화인증대상
1No Security없음없음BLE/Classic
2Unauthenticated Encryption있음없음 (Just Works)BLE/Classic
3Authenticated Encryption있음있음 (MITM 방어)BLE/Classic
4Authenticated LE SC + 128-bit있음 (AES-CCM)있음 (P-256 ECDH)BLE 4.2+

페어링 방식별 특징

모드대상특징주의점
Just WorksBLE/Classic사용자 입력 없이 빠름MITM 방어 약함
PasskeyBLE/Classic숫자 입력 기반 검증UI 동기화 필요
Numeric ComparisonBLE 4.2+MITM 방어 강함양쪽 표시/확인 인터페이스 필요
OOBBLE/Classic외부 채널(NFC 등) 활용OOB 채널 가용 여부에 의존

Cross-Transport Key Derivation

Bluetooth 4.2+에서는 한 번의 페어링으로 Classic과 BLE 양쪽 키를 동시에 생성할 수 있습니다. 이를 Cross-Transport Key Derivation(CTKD)이라 합니다. Classic에서 페어링한 키를 BLE LTK로 변환하거나, 그 반대도 가능합니다. 이 과정은 L2CAP CID 0x0007(BR/EDR SMP 채널)을 통해 수행됩니다.

드라이버 모델: btusb와 hci_uart

btusb는 USB 인터럽트/벌크 엔드포인트를 통해 HCI 패킷을 수집하고, hci_uart는 H4/H5 프로토콜로 UART 컨트롤러와 통신합니다.

btusb 프로브 흐름

/* drivers/bluetooth/btusb.c 프로브 패턴 요약 */
static int btusb_probe(struct usb_interface *intf,
                      const struct usb_device_id *id)
{
    struct hci_dev *hdev = hci_alloc_dev();
    if (!hdev)
        return -ENOMEM;

    hdev->bus = HCI_USB;
    hdev->open  = btusb_open;
    hdev->close = btusb_close;
    hdev->send  = btusb_send_frame;

    /* btusb_send_frame()은 패킷 타입에 따라
       Control(Command), Bulk(ACL), Isoc(SCO) 엔드포인트를 선택 */

    return hci_register_dev(hdev);
}

hci_uart 초기화 흐름

/* drivers/bluetooth/hci_ldisc.c - Line Discipline 기반 초기화 */
static int hci_uart_tty_open(struct tty_struct *tty)
{
    struct hci_uart *hu;

    hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL);
    hu->tty = tty;
    tty->disc_data = hu;

    /* 이후 HCIUARTSETPROTO ioctl로 프로토콜(H4/H5/QCA 등) 설정
       hdev = hci_alloc_dev() -> hci_register_dev() */
    return 0;
}

/* serdev 기반 초기화 (최신 커널 권장) */
static int hci_uart_probe(struct serdev_device *serdev)
{
    /* Device Tree 또는 ACPI 매칭으로 자동 프로브
       별도의 userspace 설정(hciattach) 불필요 */
}
hciattach vs serdev: 레거시 UART 설정은 hciattach 유틸리티를 사용했으나, 최신 커널은 Device Tree/ACPI 기반의 serdev 프레임워크를 권장합니다. serdev를 사용하면 별도의 유저 공간 설정 없이 부팅 시 자동으로 HCI 장치가 등록됩니다.

성능 튜닝 포인트

연결 파라미터 최적화

LE Connection Parameter 가이드라인

사용 사례Connection IntervalSlave LatencySupervision Timeout
고속 데이터 전송 (OTA 업데이트)7.5~15 ms02~6 s
주기적 센서 데이터100~500 ms0~44~10 s
초저전력 비콘 연결1~4 s4~1010~30 s
HID (키보드/마우스)7.5~15 ms0~42~6 s
오디오 (LE Audio)7.5~10 ms02 s

USB autosuspend 설정

# Bluetooth USB 어댑터의 autosuspend 비활성화 (오디오 끊김 방지)
echo -1 > /sys/bus/usb/devices/1-3/power/autosuspend_delay_ms

# 또는 udev 규칙으로 영구 설정
# /etc/udev/rules.d/99-bluetooth-power.rules
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="8087", ATTR{idProduct}=="0a2b", \
  ATTR{power/autosuspend_delay_ms}="-1"
광고/스캔 파라미터 연결 파라미터 전력/지연시간 목표: 안정 연결 + 배터리 효율 + 오디오 품질 btmon/conn params/재전송 카운터를 함께 관찰

디버깅과 성능 분석

btmon: 핵심 디버깅 도구

btmon은 HCI와 mgmt 트래픽을 실시간으로 모니터링하는 BlueZ의 핵심 도구입니다. 커널의 HCI 모니터 채널(HCI_CHANNEL_MONITOR)을 통해 패킷을 수집합니다.

# 실시간 HCI + mgmt 트래픽 모니터링
sudo btmon

# 파일로 저장 (BT Snoop 형식, Wireshark에서 열기 가능)
sudo btmon --write /tmp/bluetooth.log

# 특정 어댑터만 모니터링
sudo btmon --index 0

# 타임스탬프와 함께 출력
sudo btmon --date

bluetoothctl 디버깅

# 어댑터 상태 확인
bluetoothctl show

# 장치 검색
bluetoothctl scan on

# 연결된 장치 목록
bluetoothctl devices Connected

# 장치 정보 상세 확인
bluetoothctl info AA:BB:CC:DD:EE:FF

# GATT 서비스 탐색
bluetoothctl menu gatt
bluetoothctl list-attributes

debugfs 인터페이스

커널은 /sys/kernel/debug/bluetooth/에 디버깅 정보를 노출합니다.

# HCI 장치별 디버그 정보
ls /sys/kernel/debug/bluetooth/hci0/

# 주요 파일:
# features       - 지원 기능 비트맵
# manufacturer   - 벤더 정보
# hci_revision   - HCI 리비전
# blacklist      - 장치 블랙리스트
# uuids          - 등록된 서비스 UUID 목록
# conn_info_min/max_age - 연결 정보 캐시 수명

cat /sys/kernel/debug/bluetooth/hci0/features

커널 로그 분석

# Bluetooth 관련 커널 로그 필터링
dmesg | grep -i -E "bluetooth|hci|l2cap|smp|btusb|rfcomm"

# 동적 디버그 활성화 (상세 추적)
echo "module bluetooth +p" > /sys/kernel/debug/dynamic_debug/control
echo "module btusb +p" > /sys/kernel/debug/dynamic_debug/control

# BT Snoop 로그를 Wireshark로 분석
sudo btmon --write /tmp/bt_snoop.log
# Wireshark에서 File -> Open으로 /tmp/bt_snoop.log 열기

일반적인 문제와 해결

증상가능한 원인진단 방법해결 방안
페어링 실패 키 캐시 불일치 btmon에서 SMP 오류 확인 양쪽에서 페어링 정보 삭제 후 재시도
연결 끊김 반복 Supervision Timeout, RF 간섭 btmon에서 Disconnection 이벤트 reason 확인 Connection Interval/Timeout 조정, 환경 점검
오디오 끊김 (A2DP) USB autosuspend, Wi-Fi 간섭 btmon에서 ACL 패킷 손실 확인 autosuspend 비활성화, Wi-Fi 채널 분리
어댑터 미인식 펌웨어 미설치, 드라이버 미로드 dmesg에서 firmware 오류 확인 linux-firmware 패키지 설치
BLE 스캔 실패 LE 기능 비활성화, rfkill rfkill list, btmgmt info rfkill unblock bluetooth, LE 활성화
실무 팁: 페어링 실패는 단순 신호 문제보다 키 캐시 불일치가 원인인 경우가 많습니다. 한쪽에서 페어링 정보를 삭제한 뒤 재시도하세요. /var/lib/bluetooth/ 디렉토리에서 해당 장치 폴더를 직접 삭제할 수도 있습니다.

커널 설정

옵션설명권장
CONFIG_BTBluetooth 코어 서브시스템y
CONFIG_BT_BREDRClassic BR/EDR 지원y
CONFIG_BT_LEBLE(Low Energy) 지원y
CONFIG_BT_RFCOMMRFCOMM 프로토콜m
CONFIG_BT_RFCOMM_TTYRFCOMM TTY 지원 (/dev/rfcomm*)y (RFCOMM 사용 시)
CONFIG_BT_BNEPBNEP (Bluetooth PAN)m
CONFIG_BT_HIDPHIDP (HID over Bluetooth)m
CONFIG_BT_HCIBTUSBUSB HCI 드라이버m
CONFIG_BT_HCIUARTUART HCI 드라이버 프레임워크m
CONFIG_BT_HCIUART_H4UART H4 프로토콜y (UART 사용 시)
CONFIG_BT_HCIUART_3WIREUART H5(3-Wire) 프로토콜y (3-Wire 필요 시)
CONFIG_BT_HCIUART_QCAQualcomm UART 프로토콜y (QCA 칩셋)
CONFIG_BT_HCISDIOSDIO HCI 드라이버m (SDIO 칩셋)
CONFIG_BT_INTELIntel Bluetooth 지원m (Intel 칩셋)
CONFIG_BT_BCMBroadcom Bluetooth 지원m (Broadcom 칩셋)
CONFIG_BT_RTLRealtek Bluetooth 지원m (Realtek 칩셋)
CONFIG_BT_MTKMediaTek Bluetooth 지원m (MediaTek 칩셋)
CONFIG_BT_QCAQualcomm Bluetooth 지원m (Qualcomm 칩셋)

필수 사용자 공간 패키지

패키지제공 도구역할
bluezbluetoothd, bluetoothctl, btmgmt, btmonBlueZ 핵심 데몬과 관리 도구
bluez-utilshciconfig, hcitool, sdptool레거시 도구 (deprecated, 참조용)
linux-firmware-Bluetooth 칩 펌웨어 파일
pipewire-pulse-Bluetooth 오디오 통합 (PipeWire)
bluez-meshbluetooth-meshdBluetooth Mesh 데몬

참고자료

다음 학습: Wireless, ethtool, devlink