Chapter 10

L2CAP: 채널, 신호, 크레딧 기반 흐름 제어

HCI의 ACL 데이터(2장) 위, ATT와 SMP 아래에 L2CAP이 있다. 하는 일은 셋이다. 한 연결 위에 여러 “채널”을 나눠 싣고, 채널을 열고 닫는 신호를 주고받고, 큰 데이터(SDU)를 작은 조각으로 나눠 상대가 받을 수 있는 만큼만 보낸다. 이 장은 LE의 L2CAP을 따라가며, 파일 하나가 SDU → K-frame → HCI ACL 조각 → LL PDU로 쪼개지는 과정을 바이트 단위로 계산한다.

채널과 CID

L2CAP 패킷은 4바이트 머리말(길이 2바이트 + CID 2바이트)로 시작한다. CID는 “이 연결 안에서 어느 채널로 가는가”다. LE 연결에서는 몇몇 채널이 연결이 생기자마자 열려 있다.

CIDLE-U에서의 쓰임
0x0004ATT(11장, 1권 7장)
0x0005LE 신호 채널
0x0006SMP(7장)
0x0020~0x003E할당 번호 문서가 정함
0x0040~0x007F동적 채널(크레딧 기반 연결로 열고 닫음)

고정 채널은 양쪽 CID가 같지만, 동적 채널은 각자 자기 쪽 CID를 정해 알려 준다(내가 받을 CID = 소스 CID). 그래서 같은 채널이라도 방향마다 CID가 다를 수 있다.

한 트럭, 여러 칸의 화물칸

연결 하나는 트럭 한 대고, CID는 화물칸 번호다. 0x0004번 칸은 늘 서류(ATT), 0x0006번은 늘 열쇠(SMP)를 싣는다. 큰 짐(파일 전송, 오디오 설정)을 실으려면 신호 칸(0x0005)으로 “새 칸 하나 붙이자”고 합의해 0x0040번 이후 칸을 연다. 받는 쪽이 하역을 끝낸 만큼만 다음 짐을 싣는 것이 크레딧이다.

CID와 LE-U 이름 공간(Table 2.3): [Vol 3] Part A §2.1 · 기본 머리말: §3.1

신호 명령

신호 채널의 L2CAP 페이로드(C-frame)는 코드(1) · 식별자(1) · 길이(2) · 데이터다. 식별자로 요청과 응답을 짝짓는다. LE 신호 채널(0x0005)에는 C-frame 하나에 명령 하나만 싣는다(클래식 0x0001은 여러 개 가능). 받은 명령을 모르면 L2CAP_COMMAND_REJECT_RSP(0x01)로 답한다.

코드명령쓰임
0x06 / 0x07DISCONNECTION_REQ / RSP동적 채널 닫기
0x12 / 0x13CONNECTION_PARAMETER_UPDATE_REQ / RSP페리페럴 호스트가 연결 파라미터를 요청. LL의 연결 파라미터 요청 절차(4장)를 쓸 수 없을 때만
0x14 / 0x15LE_CREDIT_BASED_CONNECTION_REQ / RSPLE 크레딧 기반 채널 하나 열기
0x16FLOW_CONTROL_CREDIT_IND크레딧 돌려주기
0x17 / 0x18CREDIT_BASED_CONNECTION_REQ / RSPECFC 채널 최대 5개 한 번에 열기
0x19 / 0x1ACREDIT_BASED_RECONFIGURE_REQ / RSPECFC 채널의 MTU·MPS 바꾸기

채널을 열 때는 SPSM(서비스 번호)을 준다. 0x0001~0x007F는 SIG가 할당한 프로토콜(EATT 등), 0x0080~0x00FF는 동적 번호로, 클라이언트가 GATT에서 매번 다시 읽어야 한다.

신호 패킷 형식과 LE 한 명령 규칙: [Vol 3] Part A §4 · 명령: §4.1~§4.28 · 연결 파라미터 갱신은 페리페럴만, LL 절차를 못 쓸 때만: §4.20 · SPSM 범위(Table 4.15): §4.22

LE 크레딧 기반 흐름 제어

동적 채널의 데이터 단위는 K-frame이다. 상위 계층의 데이터 덩어리(SDU)를 K-frame 여러 개로 나누고, 첫 K-frame에만 SDU 전체 길이(2바이트)를 붙인다. 두 숫자가 크기를 정한다.

그리고 크레딧. 채널을 열 때 서로 “처음에 K-frame을 몇 개까지 보내도 된다”(0~65535)를 주고, K-frame 하나를 보낼 때마다 하나씩 쓴다. 받는 쪽은 처리한 만큼 FLOW_CONTROL_CREDIT_IND로 돌려준다. 규칙은 엄격하다. 크레딧이 0인데 K-frame을 받으면, 크레딧 합이 65535를 넘으면, SDU가 MTU를 넘거나 K-frame이 MPS를 넘거나 조각 합이 SDU 길이를 넘으면 받는 쪽이 채널을 끊는다. 크레딧 0을 돌려주는 IND는 무시한다(보내면 안 된다).

CALCULATOR

SDU 하나가 각 층에서 몇 조각이 되나

LL 최대 페이로드(데이터 길이 갱신)
K-frame / HCI 조각 / LL PDU—
머리말 오버헤드—
필요한 크레딧—
층마다: K-frame = L2CAP 머리말 4 + (첫 조각만 SDU 길이 2) + 페이로드 ≤ MPS. HCI ACL 조각 = L2CAP PDU를 버퍼 크기로 자른 것(첫 조각 PB = 00, 나머지 01, 2장). LL PDU = 2바이트 헤더 + 페이로드 ≤ 27 또는 251(1권 6장). 오버헤드는 L2CAP 머리말·SDU 길이와 LL 헤더를 더한 값(HCI 머리말은 공중에 나가지 않으므로 뺐다). 해볼 것: ① MPS 247, LL 251이면 K-frame 하나가 LL PDU 하나에 딱 들어간다(4 + 247 = 251). ② LL을 27로 내리면 K-frame마다 LL PDU 10개로 쪼개져 헤더가 늘어난다. ③ MPS를 23으로 내리면 크레딧이 SDU당 수십 개 필요하다.
예측해 보기

수신 앱이 느려서 크레딧을 늦게 돌려준다. 송신 쪽 크레딧이 0이 되었을 때, 송신 쪽 L2CAP은 무엇을 해야 할까?

크레딧 0에서 K-frame을 받으면 상대는 무엇을 하나?

크레딧 0에서 K-frame을 보내면 상대가 채널을 끊는다. 크레딧은 수신 버퍼의 약속이므로 기다려야 한다. 이때 다른 채널(예: ATT)은 따로 흐르므로 막히지 않는다. 다만 2장에서 본 HCI 버퍼 크레딧은 연결 전체가 함께 쓰므로, 호스트 스택은 L2CAP 채널 크레딧과 HCI 크레딧을 둘 다 관리한다.

K-frame과 SDU 길이·MTU·MPS 위반 시 끊기: [Vol 3] Part A §3.4 · MTU·MPS 최소 23, 초기 크레딧 0~65535: §4.22 · 크레딧 규칙(65535, 0 크레딧, 0 값 IND): §10.1 · 크레딧 IND: §4.24 · 조각내기: §7.2

SDU (≤ MTU) 앱 데이터 한 덩어리 K-frame 길이2 CID2 SDU길이 2 ≤ MPS 길이2 CID2 ≤ MPS 길이2 CID2 ≤ MPS K-frame 하나 = 크레딧 하나 · SDU 길이는 첫 K-frame에만 LL PDU 헤더2 페이로드 ≤ 27 또는 251 ← K-frame이 크면 LL PDU 여러 개로 (LLID 10 시작, 01 이어짐) MPS 247 · LL 251이면 K-frame 하나(4 + 247)가 LL PDU 하나에 딱 맞는다
그림 10-1. SDU가 공중으로 나가는 모양. L2CAP은 SDU를 상대가 정한 MPS 이하의 K-frame으로 나누고, 첫 K-frame에만 SDU 길이 2바이트를 붙인다. K-frame 하나를 보낼 때마다 크레딧 하나를 쓴다. 각 K-frame은 다시 링크 계층 PDU에 실리고, LL 페이로드보다 크면 여러 PDU로 나뉜다(그 사이의 HCI ACL 조각은 공중에 나가지 않아 그리지 않았다).

ECFC: 채널 여럿을 한 번에, 그리고 EATT

5.2에서 더한 향상된 크레딧 기반 흐름 제어(ECFC)는 같은 크레딧 방식을 LE와 클래식 모두에 쓰고, 요청 하나로 채널을 최대 5개 연다. MTU와 MPS는 최소 64바이트다. 열린 뒤에도 RECONFIGURE로 MTU·MPS를 바꿀 수 있는데, MTU는 줄일 수 없고, 채널을 여럿 함께 바꿀 때는 MPS도 줄일 수 없다(이미 보낸 조각이 새 한도를 넘지 않게). 받는 쪽은 옛 MPS로 보내던 PDU를 다 보낸 뒤에야 응답한다.

ECFC의 대표 사용자가 EATT(Enhanced ATT)다. 0x0004 고정 채널 하나뿐이던 ATT를 ECFC 채널 여럿으로 늘려, 한 채널에서 긴 읽기가 진행 중이어도 다른 채널로 알림이나 다른 요청을 동시에 보낸다. EATT 채널은 암호화된 연결에서만 열고, K-frame 하나에 ATT PDU 하나만 싣는다(11장).

CALCULATOR

ECFC 재설정 요청 검사

요청—
지금 MPS는 지금 MTU의 절반으로 두었다. 해볼 것: ① 새 MTU를 지금보다 작게 하면 거절. ② 채널 2개에서 MPS를 줄이면 거절, 채널 1개면 허용. ③ 64 미만은 ECFC 최소값 위반.

ECFC 연결(최대 5채널, MTU·MPS ≥ 64): [Vol 3] Part A §4.25 · 재설정 규칙: §7.11·§4.27 · ECFC 흐름 제어: §10.2 · EATT 베어러 요구: [Vol 3] Part G §5.3

핵심 정리

  1. L2CAP 머리말 = 길이 2 + CID 2. LE 고정 채널: ATT 0x0004, 신호 0x0005, SMP 0x0006. 동적 채널 0x0040~0x007F.
  2. 신호 C-frame = 코드 · 식별자 · 길이 · 데이터. LE 신호 채널에는 명령 하나씩. 연결 파라미터 갱신 요청(0x12)은 LL 절차를 못 쓸 때 페리페럴만.
  3. K-frame: 첫 조각에만 SDU 길이. MTU·MPS ≥ 23(LE 크레딧 기반), ≥ 64(ECFC). K-frame 하나 = 크레딧 하나.
  4. 크레딧 0에서 받음, 65535 초과, MTU·MPS·SDU 길이 위반이면 받는 쪽이 채널을 끊는다.
  5. ECFC는 한 번에 최대 5채널, 재설정으로 MTU는 늘리기만, 여러 채널이면 MPS도 줄이지 못한다. EATT가 이 채널들을 쓴다.

확인 퀴즈

LE에서 SMP가 쓰는 L2CAP CID는?

[Vol 3] Part A Table 2.3.

SDU 600바이트를 MPS 200으로 보내면 K-frame은 몇 개인가?

첫 K-frame은 SDU 길이 2바이트를 싣고 198바이트, 이후 200씩: 198 + 200 + 200 = 598, 남은 2바이트에 하나 더. 모두 4개.

크레딧 IND의 Credits 값으로 보낼 수 없는 것은?

1~65535. 0은 보내면 안 되고, 받으면 무시한다.

ECFC 재설정에서 항상 금지되는 것은?

[Vol 3] Part A §7.11: MTU는 줄일 수 없다. MPS는 채널이 하나일 때만 줄일 수 있다.