Bluetooth 커널 서브시스템

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

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

핵심 요약

  • HCI -- 호스트와 컨트롤러 사이 표준 명령/이벤트 인터페이스
  • L2CAP -- 채널 기반 다중화(Multiplexing), 재조립, 흐름 제어(Flow Control)
  • 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 인터럽트(Interrupt)/벌크/아이소크러너스 엔드포인트 활용, 가장 범용적 PC/노트북 내장 어댑터, USB 동글
UART (H4) hci_uart 단순 직렬 프로토콜, 패킷 타입 바이트로 구분 임베디드 SoC, Raspberry Pi
UART (H5/3-Wire) hci_uart 슬립(Sleep) 모드, CRC, 재전송(Retransmission) 지원으로 안정성 향상 전력 관리가 중요한 IoT 장치
SDIO btsdio SD 버스(Bus) 기반 전송, 주로 WiFi+BT 콤보 칩에서 사용 모바일/태블릿 콤보 모듈
SPI 벤더별 구현 저전력, 단순 인터페이스 웨어러블, 센서 노드

BlueZ 커널 모듈(Kernel Module) 구조

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

커널 모듈소스 위치역할
bluetoothnet/bluetooth/코어: AF_BLUETOOTH 소켓(Socket), 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는 네 가지 패킷 타입을 정의합니다. 각 패킷은 첫 번째 바이트(패킷 인디케이터)로 타입을 구분하며, 이후 타입별 헤더와 페이로드(Payload)가 따릅니다.

패킷 타입인디케이터방향헤더 크기용도
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)

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() 콜백(Callback)으로 전송합니다. 컨트롤러 응답은 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 명령 전송 시

Bluetooth Classic 연결 수립 흐름

Bluetooth Classic(BR/EDR)에서 두 장치가 연결을 수립하는 과정은 Inquiry, Paging, 연결 설정, 인증의 4단계로 진행됩니다. 각 단계에서 HCI 명령과 이벤트가 호스트와 컨트롤러 사이를 오가며, 최종적으로 ACL 링크가 생성됩니다.

Host A (개시) Controller A Controller B Host B (수신) 1단계 Inquiry HCI_Inquiry Inquiry 패킷 (RF) FHS 패킷 (응답) Inquiry_Result 이벤트 2단계 Paging HCI_Create_Connection Page 패킷 (RF) Page Response (RF) Connection_Request 이벤트 3단계 연결 설정 HCI_Accept_Connection LMP 파라미터 협상 Connection_Complete Connection_Complete 4단계 인증 HCI_Authentication_Req LMP 인증 교환 Authentication_Complete HCI_Set_Conn_Encryption Encryption_Change 이벤트 ACL 링크 수립 완료 → L2CAP 채널 협상 진행

L2CAP (Logical Link Control and Adaptation Protocol)

채널 멀티플렉싱

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

CID용도프로토콜
0x0001L2CAP 시그널(Signal)링 (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

다음 다이어그램은 하나의 ACL 링크 위에서 여러 L2CAP 채널이 CID와 PSM을 통해 다중화되는 구조를 보여줍니다. 고정 채널(ATT, SMP, 시그널링)과 동적 채널(RFCOMM, A2DP 등)이 동시에 공존하며, 각 채널은 독립적인 MTU와 전송 모드를 가집니다.

상위 프로토콜 (응용 계층) SDP 서비스 검색 RFCOMM 직렬 포트 A2DP/AVDTP 오디오 스트림 HID 키보드/마우스 GATT/ATT BLE 속성 SMP 보안 관리 L2CAP 계층 (논리 채널 다중화) 고정 채널 (Fixed CID) 동적 채널 (Dynamic CID ≥ 0x0040) CID 0x0040 PSM 0x0001 (SDP) CID 0x0041 PSM 0x0003 (RFCOMM) CID 0x0042 PSM 0x0019 (AVDTP) CID 0x0043/44 PSM 0x0011/13 (HID Ctrl/Intr) CID 0x0001 시그널링 채널 CID 0x0004 ATT (LE) CID 0x0006 SMP (LE) L2CAP 헤더: Length (2B) | CID (2B) | Payload (가변) 동적 채널 설정: L2CAP_ConnReq(PSM) → L2CAP_ConnRsp(DCID) → ConfigReq/Rsp ACL 링크 (단일 물리 연결) Handle 기반 다중화 → Baseband HCI Transport (USB / UART / SDIO) Bluetooth Baseband (2.4 GHz RF)

MTU 협상과 모드

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

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

모드약어특징사용 사례
Basic Mode-흐름 제어/재전송 없음, 단순기본 데이터 전송
Enhanced Retransmission ModeERTMI-frame 시퀀스 번호, 선택적 재전송, 흐름 제어OBEX, HID (신뢰성 필요)
Streaming ModeSM순서 보장(Ordering), 재전송 없음 (실시간(Real-time) 우선)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 직렬 포트(Serial Port)를 에뮬레이션하는 프로토콜입니다. 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
연결 지연(Latency)100 ms 이상수 ms~수십 ms
전력 소모상대적으로 높음매우 낮음 (코인 셀 배터리 수 년)
토폴로지(Topology)포인트 투 포인트 (피코넷)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을 그룹화하는 최상위 컨테이너(Container). 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비암호화 데이터의 서명 검증(Signature Verification)/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 노드의 메시지를 임시 저장하고 폴링(Polling) 시 전달 메모리와 상시 전원 필요
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실시간 오디오 (대역폭(Bandwidth) 보장)

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펌웨어(Firmware) 로드, DDC(Device Dynamic Configuration), TLV 파싱
btbcmBroadcombtbcm.c펌웨어(.hcd) 로드, 패치(Patch) 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 프로브(Probe) 흐름

/* 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 열기

일반적인 문제와 해결

증상가능한 원인진단 방법해결 방안
페어링 실패 키 캐시(Cache) 불일치 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 데몬

HCI 패킷 구조와 커널 처리 경로

HCI Command 패킷 상세

HCI Command 패킷은 호스트에서 컨트롤러로 전송되는 제어 명령입니다. OpCode는 OGF(Opcode Group Field, 6비트)와 OCF(Opcode Command Field, 10비트)로 구성됩니다. 커널에서는 hci_send_cmd()로 명령을 큐에 넣고, hci_cmd_work() 워커가 순차 전송합니다.

OGF그룹대표 OCF설명
0x01Link ControlCreate Connection, DisconnectACL/SCO 연결 관리
0x02Link PolicyHold Mode, Sniff Mode전력 모드 전환
0x03Host Controller & BasebandReset, Set Event Mask컨트롤러 기본 설정
0x04InformationalRead BD_ADDR, Read Buffer Size컨트롤러 정보 조회
0x05StatusRead RSSI, Read Link Quality상태/통계 조회
0x08LE ControllerLE Set Scan, LE Create ConnectionBLE 전용 명령

ACL Data 패킷 구조

ACL 데이터 패킷은 비동기 데이터 전송에 사용됩니다. 헤더의 Handle 필드에는 연결 핸들(12비트)과 패킷 경계 플래그(PB Flag, 2비트), 브로드캐스트 플래그(BC Flag, 2비트)가 포함됩니다. PB 플래그로 L2CAP PDU의 첫 번째 조각인지 연속 조각인지를 구분합니다.

/* include/net/bluetooth/hci.h - ACL 헤더 구조 */
struct hci_acl_hdr {
    __le16  handle;     /* 12비트 handle + 2비트 PB + 2비트 BC */
    __le16  dlen;       /* 데이터 길이 */
} __packed;

#define ACL_START_NO_FLUSH   0x00
#define ACL_CONT             0x01
#define ACL_START            0x02
#define ACL_COMPLETE         0x03

/* PB 플래그 추출 매크로 */
#define hci_handle_pack(h, f)  ((__u16) ((h) | ((f) << 12)))
#define hci_handle(h)          ((h) & 0x0FFF)
#define hci_flags(h)           ((h) >> 12)

btusb에서 hci_core, L2CAP까지의 RX 경로

USB Bluetooth 어댑터에서 수신된 HCI 패킷이 L2CAP 프로토콜 핸들러(Handler)에 도달하기까지의 전체 경로를 추적합니다. 이 흐름을 이해하면 패킷 손실이나 지연의 원인을 정확히 진단할 수 있습니다.

btusb에서 L2CAP까지 HCI 패킷 수신 경로 HCI 패킷 수신 경로: btusb -> hci_core -> L2CAP USB URB 완료 btusb_recv_intr/bulk() skb 할당 + 타입 설정 hci_skb_pkt_type() hci_recv_frame() rx_q에 큐잉 hci_rx_work() 워크큐 처리 HCI_EVENT_PKT hci_event_packet() cmd_complete / cmd_status HCI_ACLDATA_PKT hci_acldata_packet() hci_conn_hash_lookup_handle() l2cap_recv_acldata() L2CAP 프레임 재조립 CID별 분배: ATT / SMP / RFCOMM / BNEP / HIDP SCO/ISO PKT sco/iso 소켓 전달
/* net/bluetooth/hci_core.c - ACL 데이터 수신 처리 */
static void hci_acldata_packet(struct hci_dev *hdev,
                               struct sk_buff *skb)
{
    struct hci_acl_hdr *hdr = (void *)skb->data;
    struct hci_conn *conn;
    __u16 handle = __le16_to_cpu(hdr->handle);
    __u16 flags  = hci_flags(handle);

    handle = hci_handle(handle);
    conn = hci_conn_hash_lookup_handle(hdev, handle);
    if (!conn) {
        bt_dev_err(hdev, "ACL packet for unknown handle %d", handle);
        kfree_skb(skb);
        return;
    }

    skb_pull(skb, HCI_ACL_HDR_SIZE);
    /* L2CAP로 전달 - PB 플래그에 따라 재조립 수행 */
    l2cap_recv_acldata(conn, skb, flags);
}

TX 경로: L2CAP에서 btusb까지

송신 경로는 수신의 역순으로 진행됩니다. l2cap_do_send()가 L2CAP PDU를 생성하고, hci_send_acl()이 ACL 프래그먼트로 분할한 뒤 hci_tx_work() 워커가 드라이버의 send() 콜백을 호출합니다. 컨트롤러의 버퍼 여유(Num_Completed_Packets 이벤트)를 추적하여 흐름 제어를 수행합니다.

/* net/bluetooth/hci_core.c - ACL TX 흐름 제어 */
static struct hci_conn *hci_low_sent(
    struct hci_dev *hdev, __u8 type, int *quote)
{
    /* 연결 간 공정 스케줄링: 가장 적게 보낸 연결을 선택 */
    /* cnt = hdev->acl_cnt (컨트롤러 여유 버퍼 수) */
    /* *quote = cnt / num_connections (연결당 할당량) */
    ...
}

BLE GATT 프로파일 구현과 커널 경로

ATT 패킷 처리 커널 경로

ATT 프로토콜 패킷은 L2CAP 고정 CID 0x0004를 통해 전달됩니다. 커널에서의 처리 경로는 다음과 같습니다:

  1. l2cap_recv_acldata()에서 CID 0x0004 확인
  2. l2cap_recv_frame() -> l2cap_data_channel()
  3. ATT 고정 채널의 recv() 콜백 호출
  4. 커널은 기본적인 ATT 라우팅(Routing)만 수행하고, 실제 GATT 로직은 BlueZ bluetoothd가 처리
/* net/bluetooth/l2cap_core.c - ATT 고정 채널 등록 */
static struct l2cap_chan *l2cap_le_connect(struct l2cap_conn *conn)
{
    struct l2cap_chan *chan;

    /* ATT 고정 채널 (CID 0x0004) 검색 */
    chan = l2cap_global_fixed_chan(conn, L2CAP_CID_ATT,
                                  &conn->hcon->src);
    if (!chan)
        return NULL;

    /* 채널 상태를 CONNECTED로 전환 */
    l2cap_chan_add(conn, chan);
    l2cap_chan_ready(chan);
    return chan;
}

GATT 서비스 UUID 체계

Bluetooth SIG가 할당한 표준 16비트 UUID는 Base UUID(00000000-0000-1000-8000-00805F9B34FB)의 상위 32비트 중 16비트를 대체하여 128비트로 확장됩니다. 커스텀 서비스는 128비트 UUID를 사용합니다.

서비스16비트 UUID용도
Generic Access0x1800장치명, 외형, 연결 파라미터
Generic Attribute0x1801서비스 변경 알림
Heart Rate0x180D심박수 모니터링
Battery Service0x180F배터리 잔량
Device Information0x180A모델/시리얼/펌웨어 버전
Current Time0x1805시각 동기화
Blood Pressure0x1810혈압 모니터링
Environmental Sensing0x181A온도/습도/압력 등 환경 센서

GATT Notification/Indication 메커니즘

GATT 서버가 클라이언트에게 데이터 변경을 능동적으로 알리는 두 가지 방법이 있습니다. Notification은 확인 응답 없이 전송하고, Indication은 확인을 받아야 다음 전송이 가능합니다. 두 방법 모두 CCCD(Client Characteristic Configuration Descriptor, UUID 0x2902)에 클라이언트가 구독 비트를 기록해야 활성화됩니다.

/* BlueZ bluetoothd - GATT Notification 전송 예시 (D-Bus 기반) */
/* bluetoothctl에서 Characteristic에 대해: */
# select-attribute /org/bluez/hci0/dev_.../service000a/char000b
# notify on     <-- CCCD에 0x0001 기록 (Notification 활성화)
# notify off    <-- CCCD에 0x0000 기록 (비활성화)

Bluetooth 5.x 신기능

Bluetooth 5.0 주요 기능

기능설명커널 관련
LE 2M PHY2 Mbps 물리 계층, 전송 시간 단축HCI_LE_SET_PHY 명령
LE Coded PHYFEC 코딩으로 도달 거리 4배 확장Long Range 모드
Extended Advertising보조 채널로 최대 255바이트 광고hci_request.c
Periodic Advertising정기적 브로드캐스트, 수신자 동기화Periodic Sync 명령
Advertising Sets다중 광고 인스턴스 동시 운영adv_instance 관리

Bluetooth 5.1 - Direction Finding

Bluetooth 5.1은 AoA(Angle of Arrival)와 AoD(Angle of Departure) 기술로 방향 탐지 기능을 도입했습니다. CTE(Constant Tone Extension)를 BLE 패킷에 부착하여 안테나 배열로 신호 방향을 측정합니다. 실내 위치 추적(IPS, Indoor Positioning System)의 핵심 기술입니다.

방식원리안테나 요구사용 사례
AoA수신 측 다중 안테나로 도래각 측정수신기: 배열 안테나에셋 트래킹, 실내 내비게이션
AoD송신 측 다중 안테나로 출발각 전달비콘: 배열 안테나실내 측위 비콘

Bluetooth 5.2 - LE Audio / EATT / Power Control

Bluetooth 5.2는 LE Audio의 기반 기술을 도입한 핵심 버전입니다:

Bluetooth 5.3 - AdvDataInfo / Channel Classification / Encryption Key Size

Bluetooth 5.4 - PAwR / eSL / Encrypted Advertising Data

Channel Sounding (Bluetooth 6.0)

Bluetooth 6.0에서 도입된 Channel Sounding은 센티미터 수준의 정밀 거리 측정 기술입니다. 기존 RSSI 기반 근접 감지의 한계를 극복하며, Phase-Based Ranging과 Round-Trip Time(RTT) 방식을 결합합니다. 디지털 키(자동차 잠금(Lock) 해제), 물리적 근접 검증, 실내 위치 추적에 핵심적입니다. 리눅스 커널에서의 지원은 6.x 이후 버전에서 HCI 명령/이벤트 추가로 진행 중입니다.

커널 소스 구조 (net/bluetooth/ 맵)

net/bluetooth/ 디렉토리 구조

Bluetooth 코어 프로토콜 스택의 소스 코드는 net/bluetooth/ 디렉토리에 위치합니다. 각 파일의 역할과 상호 의존 관계를 이해하면 커널 디버깅과 패치 작성이 수월해집니다.

파일줄 수 (6.x 기준)역할
hci_core.c~4,000HCI 코어: 장치 등록, RX/TX 워크큐, 연결 관리
hci_event.c~7,000HCI 이벤트 디스패치(Dispatch): Command Complete, LE 이벤트 등
hci_request.c~2,500HCI 요청 직렬화(Serialization), 초기화 시퀀스
hci_conn.c~2,500ACL/LE/SCO 연결 생성/해제/관리
hci_sync.c~6,000동기화된 HCI 명령 실행 (6.x 신규 인프라)
hci_sock.c~2,000HCI 소켓: raw/mgmt/monitor 채널
l2cap_core.c~7,500L2CAP 코어: 채널 관리, 시그널링, 재조립
l2cap_sock.c~1,800L2CAP 소켓 인터페이스
smp.c~3,500SMP: 페어링, 키 교환, 암호화 함수
mgmt.c~9,000mgmt API: 장치 관리 명령 처리
iso.c~2,000ISO 채널 소켓 (LE Audio)
sco.c~1,500SCO/eSCO 동기 음성 소켓
af_bluetooth.c~800AF_BLUETOOTH 소켓 패밀리 등록
lib.c~300Bluetooth 유틸리티 함수

drivers/bluetooth/ 디렉토리 구조

파일역할
btusb.cUSB HCI 드라이버 (~4,500줄), 대부분의 USB 어댑터 지원
hci_ldisc.cUART Line Discipline 기반 HCI 프레임워크
hci_serdev.cserdev(Serial Device) 기반 HCI 프레임워크 (최신)
hci_h4.c / hci_h5.cH:4, H:5(3-Wire) UART 프로토콜
hci_qca.cQualcomm UART 프로토콜 (IBS 슬립 지원)
btintel.cIntel 벤더 초기화 (~3,000줄)
btrtl.cRealtek 벤더 초기화
btbcm.cBroadcom 벤더 초기화
btmtk.cMediaTek 벤더 초기화
btqca.cQualcomm 벤더 초기화
btsdio.cSDIO HCI 드라이버
virtio_bt.cVirtIO Bluetooth 드라이버 (가상화(Virtualization))
net/bluetooth/ 소스 파일 의존성 맵 net/bluetooth/ 소스 파일 의존성 맵 User Space: bluetoothd / btmon / btmgmt mgmt.c hci_sock.c af_bluetooth.c iso.c / sco.c l2cap_core.c l2cap_sock.c smp.c rfcomm/*.c bnep/*.c hci_core.c hci_event.c hci_sync.c hci_conn.c drivers/bluetooth/btusb.c hci_uart (H4/H5/QCA) btintel / btrtl / btbcm Bluetooth Controller Hardware

btmon/hcidump 디버깅

btmon 고급 사용법

btmon은 커널의 HCI_CHANNEL_MONITOR를 사용하여 모든 HCI 및 mgmt 트래픽을 사용자 공간에서 캡처합니다. Wireshark의 BT Snoop 형식과 호환되며, 원격 장비에서 캡처한 로그를 워크스테이션에서 분석할 수 있습니다.

# 상세 타임스탬프 + 특정 어댑터 모니터링
sudo btmon --index 0 --date --time

# BT Snoop 형식으로 저장 (Wireshark에서 분석용)
sudo btmon --write /tmp/bt_trace.snoop

# 기존 스눕 파일 읽기 (오프라인 분석)
btmon --read /tmp/bt_trace.snoop

# 실시간 + 파일 저장 동시 수행
sudo btmon --write /tmp/bt_trace.snoop 2>&1 | tee /tmp/bt_console.log

# Priority 기반 필터 (priority는 btmon 자체는 미지원, 대안:)
# Wireshark에서 btmon 파일을 열고 Display Filter 적용
# 예: bthci_evt.code == 0x0e (Command Complete)

hcidump (레거시 도구)

hcidumpbtmon 이전에 사용되던 레거시 캡처 도구입니다. 현재는 btmon 사용을 권장하지만, 일부 환경에서 여전히 유용합니다.

# 전체 패킷 덤프
sudo hcidump -X

# 특정 패킷 타입만 필터링
sudo hcidump -t HCI   # HCI 이벤트/명령만
sudo hcidump -t L2CAP # L2CAP 패킷만
sudo hcidump -t SMP   # SMP 페어링 패킷만

# pcap 형식으로 저장
sudo hcidump -w /tmp/bt.pcap

Wireshark로 Bluetooth 트래픽 분석

btmon의 BT Snoop 출력을 Wireshark에서 열면 프로토콜별 계층 분석이 가능합니다. 주요 Display Filter:

필터대상
bthci_cmdHCI 명령 패킷
bthci_evtHCI 이벤트 패킷
bthci_aclHCI ACL 데이터
btl2capL2CAP 프레임
btattATT 프로토콜 (GATT)
btsmpSMP 페어링
btrfcommRFCOMM 데이터
btatt.opcode == 0x1bATT Notification만
bthci_evt.code == 0x3eLE Meta Event만

커널 tracing으로 Bluetooth 디버깅

# ftrace로 Bluetooth 함수 추적
echo 'hci_*' > /sys/kernel/debug/tracing/set_ftrace_filter
echo 'l2cap_*' >> /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on

# 추적 결과 확인
cat /sys/kernel/debug/tracing/trace

# Bluetooth tracepoint 이벤트
ls /sys/kernel/debug/tracing/events/bluetooth/
# hci_send_cmd, hci_recv_frame, l2cap_send, l2cap_recv 등

# 특정 tracepoint 활성화
echo 1 > /sys/kernel/debug/tracing/events/bluetooth/hci_recv_frame/enable

Bluetooth/Wi-Fi 공존 메커니즘

간섭 문제

Bluetooth(2.402~2.480 GHz)와 Wi-Fi 2.4 GHz(2.412~2.462 GHz)는 동일한 ISM 대역을 공유합니다. 특히 Wi-Fi 채널 1, 6, 11과 Bluetooth 호핑 채널이 겹칠 수 있으며, 콤보 칩(같은 안테나 공유)에서는 물리적으로 동시 전송이 불가능합니다. 이 문제를 해결하기 위해 여러 공존 메커니즘이 사용됩니다.

공존 메커니즘 비교

메커니즘방식특징지원 칩셋
AFH (Adaptive Frequency Hopping) Bluetooth가 Wi-Fi 점유 채널을 회피 Bluetooth 자체 기능, 모든 BT 2.0+ 지원 표준 Bluetooth 기능
2-wire Coex (PTA) BT_ACTIVE/BT_STATUS 신호로 우선순위(Priority) 중재 하드웨어 GPIO 연결 필요, 반응 빠름 대부분의 콤보/분리 칩
3-wire Coex 2-wire + BT_PRIORITY 신호 추가 SCO 음성 등 우선순위 높은 트래픽 보호 Intel, Qualcomm 일부
TDM (Time Division Multiplexing) 시분할로 BT/Wi-Fi 교대 사용 콤보 칩 내부 펌웨어에서 처리 대부분의 콤보 칩
MWS (Mobile Wireless Standard) LTE/Wi-Fi/BT 3자 간 공존 HCI MWS 명령으로 커널에서 제어 가능 모바일 SoC
Bluetooth/Wi-Fi 공존 메커니즘 다이어그램 Bluetooth/Wi-Fi 공존 메커니즘 2.4 GHz ISM 대역 (2.400 ~ 2.4835 GHz) Wi-Fi ch1(2.412) / ch6(2.437) / ch11(2.462) + BT 79채널(1MHz) / LE 40채널(2MHz) Bluetooth Controller AFH: 간섭 채널 회피 BT_ACTIVE 신호 출력 Wi-Fi Controller CTS-to-self: 매체 예약 BT_ACTIVE 신호 수신 Coex Arbiter (PTA) 우선순위 기반 시분할 중재 공유 안테나 BT_ACTIVE BT_STATUS

커널에서의 공존 설정

# Intel 칩셋: btintel coex 파라미터
# dmesg에서 공존 설정 확인
dmesg | grep -i coex

# iwlwifi + btusb 콤보에서 공존 상태 확인
cat /sys/kernel/debug/iwlwifi/*/bt_coex

# Qualcomm 칩: IBS(In-Band Sleep)와 공존
# Device Tree에서 공존 핀 설정
# bt-coex-pin = <GPIO_NUM>;

# Wi-Fi 채널을 5 GHz로 전환하여 간섭 회피 (가장 효과적)
iw dev wlan0 set channel 36
실무 권장: Bluetooth 오디오(A2DP/SCO)와 Wi-Fi 동시 사용 시 간섭이 심하면, Wi-Fi를 5 GHz 대역으로 전환하는 것이 가장 효과적입니다. 콤보 칩에서는 펌웨어의 TDM 설정을 조정하여 Bluetooth 우선순위를 높일 수도 있습니다.

커널 버전별 Bluetooth 변경 이력

커널 버전주요 변경 사항
3.0Bluetooth 4.0 LE 기본 지원 추가
3.5mgmt API 도입 (hciconfig/hcitool 대체 시작)
3.12LE Dual Mode, Privacy 1.1 지원
3.16LE Secure Connections (Bluetooth 4.2) 지원
3.19Privacy 1.2 (RPA Resolution Offloading)
4.2Extended Advertising 예비 코드, LE Data Length Extension
4.8LE PHY 2M/Coded 지원 (Bluetooth 5.0)
4.20Extended Advertising / Periodic Advertising 지원
5.0Mesh 지원 기반, LE Extended Scanning
5.4Advertising Sets 다중 인스턴스, hci_sync.c 기반 리팩토링 시작
5.12MSFT Vendor Extension (모니터 광고), mgmt Quality Report
5.13hci_sync.c 도입: 비동기 HCI 요청을 동기화된 워크큐로 대체
5.15ISO 소켓(BTPROTO_ISO), CIS/BIS 기본 지원 (LE Audio)
5.19LC3 코덱 ID 등록, ISO Test 모드
6.0LE BIG(Broadcast Isochronous Group) 생성/종료, hci_request.c 제거 시작
6.2Quality of Service 개선, ISO 소켓 안정화
6.3EATT(Enhanced ATT) 커널 측 지원 개선
6.5hci_sync.c 전면 전환 완료, hci_request.c 제거
6.7ISO Connected/Broadcast 안정화, 다중 CIS 지원 개선
6.8+PAwR(Periodic Advertising with Responses) 초기 지원
hci_sync.c 전환: 커널 5.13~6.5에 걸쳐 hci_request.c의 비동기 HCI 요청 메커니즘이 hci_sync.c의 동기화된 워크큐 기반으로 완전히 대체되었습니다. 이 리팩토링은 레이스 컨디션과 타이밍 관련 버그를 대폭 줄였으며, 새로운 Bluetooth 기능(ISO, Extended Advertising 등)의 구현을 크게 단순화했습니다.

L2CAP ERTM/Streaming 모드

ERTM (Enhanced Retransmission Mode) 상세

ERTM은 L2CAP에 TCP와 유사한 신뢰성을 제공합니다. I-Frame(Information Frame)에 시퀀스 번호 (TxSeq/ReqSeq)를 부여하고, S-Frame(Supervisory Frame)으로 흐름 제어와 재전송을 관리합니다. OBEX 파일 전송이나 AVRCP 같은 신뢰성이 중요한 프로토콜에서 사용됩니다.

ERTM 프레임 타입

프레임유형설명
I-Frame정보TxSeq + ReqSeq 포함, SDU 데이터 전달
S-Frame (RR)감독Receiver Ready: ACK + 수신 준비 완료
S-Frame (REJ)감독Reject: 특정 시퀀스부터 재전송 요청 (Go-Back-N)
S-Frame (SREJ)감독Selective Reject: 특정 시퀀스만 재전송 요청
S-Frame (RNR)감독Receiver Not Ready: 흐름 제어 일시 정지
/* net/bluetooth/l2cap_core.c - ERTM I-Frame 전송 */
static void l2cap_ertm_send(struct l2cap_chan *chan)
{
    struct sk_buff *skb;

    while (chan->tx_send_head &&
           chan->unacked_frames < chan->remote_tx_win) {
        skb = chan->tx_send_head;

        /* TxSeq/ReqSeq 설정 */
        l2cap_set_txseq(chan, skb);
        chan->next_tx_seq = (chan->next_tx_seq + 1) %
                           chan->tx_win_max;
        chan->unacked_frames++;

        /* 재전송 타이머 시작 */
        l2cap_set_retrans_timer(chan);
        l2cap_do_send(chan, skb);
    }
}

ERTM 타이머(Timer)

타이머기본값용도
Retransmission Timer2000 msI-Frame ACK 미수신 시 재전송 트리거
Monitor Timer12000 msS-Frame 폴 요청 후 응답 대기
Acknowledgement Timer200 ms지연 ACK: 데이터 없을 때 단독 ACK 전송

Streaming Mode

Streaming Mode는 ERTM과 유사하지만 재전송이 없습니다. 순서 번호로 패킷 누락을 감지하되, 재전송 대신 상위 계층에 누락을 알립니다. A2DP 오디오 스트리밍처럼 약간의 패킷 손실보다 지연이 더 치명적인 경우에 적합합니다.

LE Credit-based Flow Control (LE CoC)

BLE에서 대용량 데이터를 전송할 때 사용하는 모드입니다. 수신 측이 크레딧(Credit)을 발급하고, 송신 측은 크레딧만큼만 SDU를 전송할 수 있습니다. 크레딧이 소진되면 수신 측이 추가 크레딧을 발급할 때까지 대기합니다. GATT의 20바이트 ATT MTU 제한을 우회하여 수백 KB 단위 데이터를 효율적으로 전송할 수 있습니다.

/* net/bluetooth/l2cap_core.c - LE CoC 크레딧 관리 */
static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
{
    struct l2cap_le_credits pkt;
    u16 return_credits;

    /* 수신 버퍼 여유량에 기반하여 크레딧 발급 */
    return_credits = chan->rx_credits_max - chan->rx_credits;
    if (return_credits < chan->rx_credits_max / 2)
        return;

    pkt.cid     = cpu_to_le16(chan->scid);
    pkt.credits = cpu_to_le16(return_credits);

    chan->rx_credits += return_credits;
    l2cap_send_cmd(chan->conn, chan->ident,
                  L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
}

SMP 페어링 상세

IO Capability 매트릭스

SMP 페어링 방식은 양쪽 장치의 IO Capability 조합에 의해 자동으로 결정됩니다. 다음 매트릭스는 LE Secure Connections 모드에서의 페어링 방식 선택을 보여줍니다:

Initiator \ Responder DisplayOnly DisplayYesNo KeyboardOnly NoInputNoOutput KeyboardDisplay
DisplayOnly Just Works Just Works Passkey Entry Just Works Passkey Entry
DisplayYesNo Just Works Numeric Comparison Passkey Entry Just Works Numeric Comparison
KeyboardOnly Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry
NoInputNoOutput Just Works Just Works Just Works Just Works Just Works
KeyboardDisplay Passkey Entry Numeric Comparison Passkey Entry Just Works Numeric Comparison

OOB (Out-of-Band) 페어링

OOB 페어링은 Bluetooth 무선 채널이 아닌 외부 채널(NFC, QR 코드 등)을 통해 인증 데이터를 교환합니다. NFC 탭으로 페어링하는 경우가 대표적입니다. 커널에서는 SMP_CMD_PAIRING_REQ의 OOB 플래그와 mgmt API의 Add Remote OOB Data 명령으로 처리합니다.

/* net/bluetooth/smp.c - OOB 데이터 확인 */
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn,
                              struct sk_buff *skb)
{
    ...
    /* OOB 데이터 가용 여부 확인 */
    if (req->oob_flag == SMP_OOB_PRESENT) {
        /* 로컬에 OOB 데이터가 있으면 사용 */
        if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags))
            smp->method = REQ_OOB;
    }
    ...
}

Passkey Entry 내부 동작

Passkey Entry에서는 6자리 숫자(000000~999999)를 20비트로 변환하여 각 비트에 대해 Confirm/Random 교환을 반복합니다(LE SC 모드). 총 20라운드의 교환으로 MITM을 방어합니다. Legacy Pairing에서는 단일 라운드로 처리되어 보안이 약합니다.

Numeric Comparison

Numeric Comparison은 LE Secure Connections에서만 사용됩니다. ECDH 키 교환 후 양쪽이 동일한 6자리 숫자를 계산하여 표시하고, 사용자가 양쪽의 숫자가 같은지 확인하여 Yes/No로 응답합니다. 패시브/능동 MITM 공격 모두에 강력한 방어를 제공합니다.

SMP LE Secure Connections 페어링 시퀀스 SMP LE Secure Connections 페어링 시퀀스 Initiator Responder Phase 1: Feature Exchange Pairing Request (IO Cap, Auth Req, Key Size) Pairing Response (IO Cap, Auth Req, Key Size) Phase 2: ECDH Key Exchange + Authentication Public Key (P-256) Public Key (P-256) DHKey = ECDH(SKa, PKb) DHKey = ECDH(SKb, PKa) Pairing Confirm (Commitment) Pairing Confirm (Commitment) Pairing Random (Nonce) Pairing Random (Nonce) 사용자 확인: Numeric Comparison / Passkey DHKey Check (Ea) DHKey Check (Eb) Phase 3: Key Distribution Encryption Started (LTK) IRK + CSRK + Identity Address IRK + CSRK + Identity Address

Address Resolution과 Privacy

BLE Privacy 기능은 Resolvable Private Address(RPA)를 사용하여 장치 추적을 방지합니다. RPA는 IRK(Identity Resolving Key)로 생성/검증되며, 주기적으로 변경됩니다(기본 15분). 커널의 hci_conn.c에서 RPA 해석을 수행하며, 하드웨어 오프로딩(Offloading)이 가능한 칩셋에서는 컨트롤러가 직접 해석합니다.

# Privacy 활성 상태 확인
btmgmt info
# Privacy: enabled (addr-resolution: on, rpa-timeout: 900s)

# RPA timeout 설정 (초 단위, 기본 900초 = 15분)
# /sys/kernel/debug/bluetooth/hci0/rpa_timeout

Bluetooth Mesh 프로비저닝/릴레이

프로비저닝 프로토콜 상세

Mesh 프로비저닝은 비보안 상태의 장치를 안전하게 네트워크에 추가하는 과정입니다. ECDH 키 교환과 인증을 거쳐 NetKey, AppKey, Unicast Address를 배포합니다.

  1. Beaconing: 비프로비저닝 장치가 Unprovisioned Device Beacon을 브로드캐스트
  2. Invitation: Provisioner가 Provisioning Invite PDU를 전송, 장치가 Capabilities로 응답
  3. Public Key Exchange: ECDH P-256 공개키 교환 (OOB 또는 In-Band)
  4. Authentication: Output OOB(LED 깜빡임), Input OOB(버튼 누름), Static OOB(QR 코드), No OOB 중 선택
  5. Confirmation: 양쪽이 Confirm/Random 값을 교환하여 인증 확인
  6. Distribution: Provisioner가 Provisioning Data(NetKey, IV Index, Unicast Address)를 암호화하여 전송

Mesh 보안 계층

범위용도
NetKey네트워크 전체Network Layer 암호화/인증, 네트워크 접근 제어(Access Control)
AppKey애플리케이션 범위Application Layer 암호화, 서비스별 접근 제어
DevKey장치별 고유프로비저너와 장치 간 설정 통신

Relay 동작 상세

Relay 노드는 수신한 Network PDU를 재전송하여 메시지 도달 범위를 확장합니다. 중복 전송 방지를 위해 Network Message Cache에 최근 메시지의 (SRC, SEQ) 쌍을 저장하고, 이미 처리한 메시지는 폐기합니다. TTL이 0이면 더 이상 릴레이하지 않습니다.

Mesh Relay 결정 로직은 다음과 같은 순서로 동작합니다 (bluetooth-meshd 내부).

  1. TTL > 1인지 확인합니다.
  2. SRC가 자신이 아닌지 확인합니다.
  3. Network Message Cache에 (SRC, SEQ) 쌍이 없는지 확인합니다.
  4. 조건 충족 시 TTL-1로 재전송합니다.
  5. 캐시에 (SRC, SEQ)를 추가합니다.

Friend/Low Power 노드 상호작용

Low Power(LP) 노드는 대부분의 시간을 슬립 상태로 보내며, Friend 노드가 LP 노드 대신 메시지를 수신/저장합니다. LP 노드는 주기적으로 깨어나 Friend Poll 메시지를 보내 대기 중인 메시지를 수신합니다.

파라미터설명전력 영향
PollTimeoutLP 노드가 폴링하는 최대 간격길수록 절전, 짧을수록 응답 빠름
ReceiveDelayFriend Update 수신 전 대기 시간(Latency)라디오 온 시간에 영향
ReceiveWindow메시지 수신을 위한 창 크기넓을수록 수신 확률 증가
Friend Queue SizeFriend가 저장하는 최대 메시지 수메모리 사용량에 영향

Directed Forwarding (Mesh Protocol 1.1)

Mesh Protocol 1.1에서 도입된 Directed Forwarding은 기존 Managed Flooding 방식의 비효율성을 개선합니다. 경로 탐색(Path Discovery)을 통해 최적 경로를 찾고, 해당 경로의 노드만 메시지를 중계하여 네트워크 트래픽을 크게 줄입니다. 대규모 Mesh 네트워크(수백 노드 이상)에서 특히 효과적입니다.

Bluetooth 에러 코드와 Disconnection Reason

HCI 에러 코드

HCI 이벤트에서 반환되는 에러 코드는 연결 실패, 끊김, 명령 거부의 원인을 진단하는 핵심 정보입니다. btmon에서 확인 가능하며, 커널 로그(dmesg)에도 출력됩니다.

에러 코드이름의미진단 포인트
0x05Authentication Failure인증 실패 (키 불일치)양쪽 페어링 정보 삭제 후 재시도
0x06PIN/Key Missing링크 키 없음재페어링 필요
0x08Connection Timeout연결 시도 시간 초과RF 환경, 거리, 간섭 확인
0x0ERejected (Limited Resources)리소스 부족으로 거부최대 연결 수 확인
0x13Remote User Terminated원격 장치가 의도적 연결 해제정상 종료, 문제 아님
0x16Connection Terminated (Local)로컬 호스트가 연결 해제소프트웨어 의도적 종료
0x22LMP Response TimeoutLMP 응답 시간 초과컨트롤러 간 통신 문제
0x3BUnacceptable Connection Parameters연결 파라미터 거부Interval/Latency/Timeout 조정
에러 코드 0x08 (Connection Timeout) 반복 시: btmon에서 마지막 유효 패킷 시점을 확인하고, Supervision Timeout 값과 비교하세요. Wi-Fi 간섭이 의심되면 iw dev wlan0 station dump로 Wi-Fi 측 재전송률도 함께 확인합니다.

실전 시나리오와 트러블슈팅

시나리오 1: BLE 센서 데이터 수집 게이트웨이

리눅스 장치(Raspberry Pi 등)를 BLE Central로 사용하여 다수의 BLE 센서에서 데이터를 수집하는 산업용 게이트웨이 시나리오입니다.

# 1. 어댑터 상태 확인
btmgmt info
# supported-settings: powered connectable le
# current-settings:  powered le

# 2. LE 스캔 시작 (passive, 중복 허용)
btmgmt find -l        # LE only 스캔

# 3. bluetoothctl로 연결 및 GATT 서비스 탐색
bluetoothctl
# [bluetooth]# scan on
# [bluetooth]# connect AA:BB:CC:DD:EE:FF
# [bluetooth]# menu gatt
# [bluetooth]# list-attributes
# [bluetooth]# select-attribute /org/bluez/hci0/dev_.../service000a/char000b
# [bluetooth]# read
# [bluetooth]# notify on

# 4. 다수 연결 시 파라미터 튜닝
# Connection Interval을 100ms 이상으로 설정하여 다수 연결 안정화
# Supervision Timeout은 10초 이상 권장

시나리오 2: A2DP 오디오 끊김 해결

# 1. btmon으로 패킷 손실 확인
sudo btmon --write /tmp/a2dp_debug.snoop

# 2. USB autosuspend 비활성화
# Bluetooth 어댑터의 USB 경로 확인
lsusb -t | grep -i bluetooth
echo -1 > /sys/bus/usb/devices/1-3/power/autosuspend_delay_ms

# 3. Wi-Fi 간섭 확인
iw dev wlan0 station dump | grep -E "signal|tx retries"
# Wi-Fi 재전송이 높으면 5GHz로 전환
iw dev wlan0 set channel 36

# 4. A2DP 코덱 확인 (PipeWire)
pw-dump | grep -A5 bluetooth
# SBC -> AAC 또는 LDAC로 변경 시도

시나리오 3: 임베디드 BLE Peripheral 개발

# 리눅스를 BLE Peripheral (GATT Server)로 설정

# 1. 광고 활성화
btmgmt advertising on
btmgmt name "Linux-Sensor"
btmgmt connectable on

# 2. bluetoothd에 GATT 서비스 등록 (D-Bus API 사용)
# Python 예시 (bluez의 example-gatt-server.py 참조)
# dbus.service.Object로 GattService1, GattCharacteristic1 구현

# 3. 광고 데이터에 서비스 UUID 포함
# bluetoothctl: advertise on
# advertise.uuids 0x180D  (Heart Rate Service)

관련 커널 데이터 구조 요약

주요 자료구조 관계

구조체파일역할주요 필드
struct hci_dev hci_core.h Bluetooth 어댑터 표현 name, flags, conn_hash, cmd_q, open/close/send 콜백
struct hci_conn hci_core.h ACL/LE/SCO 연결 표현 handle, type, state, dst(BD_ADDR), l2cap_data
struct l2cap_conn l2cap_core.h L2CAP 연결 (hci_conn에 1:1 매핑(Mapping)) hcon, chan_list, info_state, feat_mask
struct l2cap_chan l2cap_core.h L2CAP 채널 scid/dcid, psm, state, mode, imtu/omtu, ops 콜백
struct smp_chan smp.c SMP 페어링 상태 method, flags, preq/prsp, tk, ltk, irk, csrk
struct bt_sock bluetooth.h Bluetooth 소켓 기본 구조 sk, parent, flags
struct mgmt_hdr mgmt.h mgmt API 패킷 헤더 opcode, index, len
struct btusb_data btusb.c btusb 드라이버 인스턴스 데이터 hdev, udev, intf, intr/bulk/isoc URB
/* include/net/bluetooth/hci_core.h - hci_conn 구조체 주요 필드 */
struct hci_conn {
    struct list_head  list;
    atomic_t          refcnt;

    bdaddr_t          dst;          /* 원격 장치 주소 */
    __u8              dst_type;     /* 주소 타입 (Public/Random) */
    __u16             handle;       /* HCI 연결 핸들 */
    __u16             state;        /* BT_CONNECTED, BT_OPEN 등 */
    __u8              type;         /* ACL_LINK, LE_LINK, SCO_LINK */

    __u8              sec_level;    /* 현재 보안 레벨 */
    __u8              pending_sec_level;

    __u16             le_conn_interval;
    __u16             le_conn_latency;
    __u16             le_supv_timeout;

    struct l2cap_conn *l2cap_data;  /* L2CAP 연결 데이터 */
    struct smp_chan   *smp_chan;    /* SMP 채널 (페어링 중) */

    struct hci_dev   *hdev;        /* 소속 어댑터 */
    void             *l2cap_data;
    void             *sco_data;
    void             *iso_data;
};

참고자료

다음 학습: Wireless, ethtool, devlink