【BlueZ 】蓝牙 L2CAP 协议核心:BlueZ 中基础数据传输的源码落地

L2CAP(Logical Link Control and Adaptation Protocol)是蓝牙协议栈中承上启下的关键协议层,负责将上层协议数据适配到下层链路层。它是蓝牙数据传输的基石,所有 Profile(如 SDP、RFCOMM、ATT、AVCTP)的数据都必须通过 L2CAP 信道传输。本文基于蓝牙核心规范与 BlueZ 5.x 全套源码,深入剖析 L2CAP 协议原理与源码实现,揭示从协议帧到 socket 操作的完整映射关系。


目录

[一、L2CAP 协议核心框架](#一、L2CAP 协议核心框架)

[二、BlueZ 用户态 L2CAP Socket 操作](#二、BlueZ 用户态 L2CAP Socket 操作)

[三、L2CAP 信道建立完整流程](#三、L2CAP 信道建立完整流程)

四、数据收发与流量控制

[五、BLE 与经典蓝牙的差异化实现](#五、BLE 与经典蓝牙的差异化实现)

[六、L2CAP 在 BlueZ 中的典型应用](#六、L2CAP 在 BlueZ 中的典型应用)

七、开发要点与常见问题

八、总结


一、L2CAP 协议核心框架

1.1 协议分层定位

L2CAP 在蓝牙协议栈中的位置:

核心职责

  • 协议复用:多个上层协议共享同一物理链路

  • 数据分段与重组:将上层 SDU(Service Data Unit)分段为 MTU 大小的 PDU(Protocol Data Unit)

  • 信道 管理:建立、维护、释放逻辑信道

  • 流量控制:防止发送方过快导致接收方缓冲区溢出

  • QoS 保障:支持不同业务的服务质量需求

1.2 帧结构详解

L2CAP 定义了两种基本帧类型:数据帧命令帧

数据帧 结构

cpp 复制代码
 0       16       32      32+N
+--------+--------+--------+
| Length |  CID   |   Data |
| (16bit)| (16bit)|        |
+--------+--------+--------+
  • Length(16位):数据字段的长度(不包含 L2CAP 头部)

  • CID(16位):信道标识符,标识数据所属的逻辑信道

  • Data(变长):上层协议数据

BlueZ 源码 中的 数据帧 头结构体

cpp 复制代码
typedef struct {
    uint16_t    len;
    uint16_t    cid;
} __attribute__ ((packed)) l2cap_hdr;
#define L2CAP_HDR_SIZE 4

命令帧结构

cpp 复制代码
 0        8       16       32      32+N
+--------+--------+--------+--------+
|  Code  | Ident  | Length |  Data  |
| (8bit) | (8bit) | (16bit)|        |
+--------+--------+--------+--------+
  • Code(8位):命令码,标识命令类型

  • Ident(8位):标识符,用于匹配请求和响应

  • Length(16位):命令参数的长度

  • Data(变长):命令参数

BlueZ 源码 中的命令帧头结构体

cpp 复制代码
typedef struct {
    uint8_t     code;
    uint8_t     ident;
    uint16_t    len;
} __attribute__ ((packed)) l2cap_cmd_hdr;
#define L2CAP_CMD_HDR_SIZE 4

1.3 信道 类型

L2CAP 支持两种信道类型:

|-------------------------------|------------------|------------------|
| 信道 类型 | 特点 | 适用场景 |
| 面向连接(Connection-Oriented) | 需要建立连接、可靠传输、流量控制 | RFCOMM、ATT、AVCTP |
| 无连接(Connectionless) | 无需建立连接、不可靠传输、低延迟 | SDP 查询、广播数据 |

固定 信道 与动态信道

cpp 复制代码
/* L2CAP fixed channels */
#define L2CAP_FC_L2CAP      0x02    /* L2CAP 控制信道 */
#define L2CAP_FC_CONNLESS   0x04    /* 无连接信道 */
#define L2CAP_FC_A2MP       0x08    /* AMP 管理信道 */

固定信道(CID < 0x1000)用于协议控制,动态信道(CID >= 0x0040)由上层协议动态分配。

1.4 分片重组( SAR )机制

当上层 SDU 超过 L2CAP MTU 时,需要进行分片传输:

cpp 复制代码
/* L2CAP Segmentation and Reassembly */
#define L2CAP_SAR_UNSEGMENTED   0x00    /* 未分段 */
#define L2CAP_SAR_START         0x01    /* 起始分段 */
#define L2CAP_SAR_END           0x02    /* 结束分段 */
#define L2CAP_SAR_CONTINUE      0x03    /* 中间分段 */

/* L2CAP Control Field bit masks */
#define L2CAP_CTRL_SAR_MASK     0xC000
#define L2CAP_CTRL_SAR_SHIFT    14

分片规则

  1. SDU ≤ MTU:单个数据帧,SAR = UNSEGMENTED

  2. SDU > MTU:多个数据帧,SAR 依次为 START → CONTINUE → END

1.5 流量控制 模式

L2CAP 支持多种流量控制模式,在不同可靠性和延迟需求间权衡:

cpp 复制代码
#define L2CAP_MODE_BASIC        0x00    /* 基本模式:无重传,无流量控制 */
#define L2CAP_MODE_RETRANS      0x01    /* 重传模式:有限重传 */
#define L2CAP_MODE_FLOWCTL      0x02    /* 流量控制模式 */
#define L2CAP_MODE_ERTM         0x03    /* 增强重传模式:可靠传输 */
#define L2CAP_MODE_STREAMING    0x04    /* 流模式:有序但可能丢包 */

|-----------|---------|----------|---------------|
| 模式 | 可靠性 | 流量控制 | 适用场景 |
| Basic | 不可靠 | 无 | 广播、低延迟场景 |
| Retrans | 有限可靠 | 无 | 对延迟敏感的可靠传输 |
| FlowCtl | 可靠 | 有 | 需要流量控制的场景 |
| ERTM | 完全可靠 | 有 | 关键数据传输(如文件传输) |
| Streaming | 有序但不可靠 | 有 | 音视频流 |

二、BlueZ 用户态 L2CAP Socket 操作

2.1 Socket 创建与绑定

BlueZ 通过标准的 socket API 创建 L2CAP 套接字:

cpp 复制代码
/* 创建 L2CAP socket */
l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (l2cap_sock < 0) {
    error("opening L2CAP socket: %s", strerror(errno));
    return -1;
}

/* 设置地址结构 */
struct sockaddr_l2 l2addr;
memset(&l2addr, 0, sizeof(l2addr));
l2addr.l2_family = AF_BLUETOOTH;
bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
l2addr.l2_psm = htobs(SDP_PSM);

/* 绑定到指定 PSM */
if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
    error("binding L2CAP socket: %s", strerror(errno));
    return -1;
}

sockaddr_l2 结构体详解

cpp 复制代码
struct sockaddr_l2 {
    sa_family_t l2_family;        /* 地址族:AF_BLUETOOTH */
    unsigned short l2_psm;        /* 协议/服务复用器(用于绑定/连接) */
    bdaddr_t l2_bdaddr;           /* 蓝牙地址 */
    unsigned short l2_cid;        /* 信道标识符(用于固定信道) */
    uint8_t l2_bdaddr_type;       /* 地址类型:BDADDR_BREDR/BDADDR_LE_PUBLIC/BDADDR_LE_RANDOM */
};

PSM(Protocol/Service Multiplexer):用于标识上层协议,类似 TCP/UDP 的端口号。

2.2 btio 封装层

BlueZ 提供了 btio 库封装 L2CAP 操作,使上层代码更简洁:

绑定函数

cpp 复制代码
static int l2cap_bind(int sock, const bdaddr_t *src, uint8_t src_type,
                        uint16_t psm, uint16_t cid, GError **err)
{
    struct sockaddr_l2 addr;

    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    bacpy(&addr.l2_bdaddr, src);

    if (cid)
        addr.l2_cid = htobs(cid);      /* 使用 CID(固定信道) */
    else
        addr.l2_psm = htobs(psm);      /* 使用 PSM(动态信道) */

    addr.l2_bdaddr_type = src_type;

    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        int error = -errno;
        ERROR_FAILED(err, "l2cap_bind", errno);
        return error;
    }

    return 0;
}

连接函数

cpp 复制代码
static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
                        uint16_t psm, uint16_t cid)
{
    int err;
    struct sockaddr_l2 addr;

    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    bacpy(&addr.l2_bdaddr, dst);
    if (cid)
        addr.l2_cid = htobs(cid);
    else
        addr.l2_psm = htobs(psm);

    addr.l2_bdaddr_type = dst_type;

    err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
    if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
        return -errno;

    return 0;
}

注意 connect() 返回 EAGAINEINPROGRESS 是正常的,因为 L2CAP 连接建立需要时间(涉及多轮命令交互)。

2.3 选项设置

MTU 设置

cpp 复制代码
static gboolean set_l2opts(int sock, uint16_t imtu, uint16_t omtu,
                        uint8_t mode, GError **err)
{
    struct l2cap_options l2o;
    socklen_t len;

    memset(&l2o, 0, sizeof(l2o));
    len = sizeof(l2o);
    if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
        ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
        return FALSE;
    }

    if (imtu)
        l2o.imtu = imtu;
    if (omtu)
        l2o.omtu = omtu;

    if (mode) {
        l2o.mode = mode_l2mode(mode);
        if (l2o.mode == UINT8_MAX) {
            ERROR_FAILED(err, "Unsupported mode", errno);
            return FALSE;
        }
    }

    if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
        ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
        return FALSE;
    }

    return TRUE;
}

l2cap_options 结构体

cpp 复制代码
struct l2cap_options {
    uint16_t    omtu;           /* 输出 MTU */
    uint16_t    imtu;           /* 输入 MTU */
    uint16_t    flush_to;       /* 刷新超时 */
    uint8_t     mode;           /* 传输模式 */
    uint8_t     fcs;            /* 帧检查序列 */
    uint8_t     max_tx;         /* 最大重传次数 */
    uint16_t    txwin_size;     /* 发送窗口大小 */
};

安全级别设置

cpp 复制代码
static int l2cap_set_lm(int sock, int level)
{
    int lm_map[] = {
        0,
        L2CAP_LM_AUTH,                                      /* 认证 */
        L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,                  /* 认证 + 加密 */
        L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE, /* 认证 + 加密 + 安全连接 */
    }, opt = lm_map[level];

    if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
        return -errno;

    return 0;
}

三、L2CAP 信道建立完整流程

3.1 建立流程时序图

3.2 连接请求/响应

连接请求结构体

cpp 复制代码
typedef struct {
    uint16_t    psm;            /* 目标 PSM */
    uint16_t    scid;           /* 源信道 ID */
} __attribute__ ((packed)) l2cap_conn_req;
#define L2CAP_CONN_REQ_SIZE 4

typedef struct {
    uint16_t    dcid;           /* 目标信道 ID */
    uint16_t    scid;           /* 源信道 ID */
    uint16_t    result;         /* 连接结果 */
    uint16_t    status;         /* 状态 */
} __attribute__ ((packed)) l2cap_conn_rsp;
#define L2CAP_CONN_RSP_SIZE 8

连接结果码

cpp 复制代码
#define L2CAP_CR_SUCCESS     0x0000    /* 成功 */
#define L2CAP_CR_PEND        0x0001    /* 挂起 */
#define L2CAP_CR_BAD_PSM     0x0002    /* PSM 无效 */
#define L2CAP_CR_SEC_BLOCK   0x0003    /* 安全阻塞 */
#define L2CAP_CR_NO_MEM      0x0004    /* 内存不足 */

3.3 配置请求/响应

配置请求结构体

cpp 复制代码
typedef struct {
    uint16_t    dcid;           /* 目标信道 ID */
    uint16_t    flags;          /* 标志位 */
    uint8_t     data[0];        /* 配置选项 */
} __attribute__ ((packed)) l2cap_conf_req;
#define L2CAP_CONF_REQ_SIZE 4

typedef struct {
    uint16_t    scid;           /* 源信道 ID */
    uint16_t    flags;          /* 标志位 */
    uint16_t    result;         /* 配置结果 */
    uint8_t     data[0];        /* 配置选项 */
} __attribute__ ((packed)) l2cap_conf_rsp;
#define L2CAP_CONF_RSP_SIZE 6

配置选项类型

cpp 复制代码
#define L2CAP_CONF_MTU       0x01    /* MTU */
#define L2CAP_CONF_FLUSH_TO  0x02    /* 刷新超时 */
#define L2CAP_CONF_QOS       0x03    /* QoS 参数 */
#define L2CAP_CONF_RFC       0x04    /* 重传/流量控制 */
#define L2CAP_CONF_FCS       0x05    /* 帧检查序列 */
#define L2CAP_CONF_EFS       0x06    /* 扩展特性 */
#define L2CAP_CONF_EWS       0x07    /* 扩展窗口大小 */

3.4 断连流程

cpp 复制代码
typedef struct {
    uint16_t    dcid;
    uint16_t    scid;
} __attribute__ ((packed)) l2cap_disconn_req;

typedef struct {
    uint16_t    dcid;
    uint16_t    scid;
} __attribute__ ((packed)) l2cap_disconn_rsp;

四、数据收发与流量控制

4.1 数据发送流程

在 BlueZ 中,上层协议通过 write()send() 发送数据:

cpp 复制代码
/* att.c 中的数据发送 */
static ssize_t att_send_pdu(struct bt_att *att, uint8_t opcode,
                            const void *pdu, uint16_t len)
{
    struct att_send_op *op;
    uint8_t *buf;

    /* 检查 MTU */
    if (len > att->mtu) {
        att_log(att, ATT_LOG_ERROR, "PDU too big (%u > %u)", len, att->mtu);
        return -EINVAL;
    }

    buf = malloc(len + 1);
    if (!buf)
        return -ENOMEM;

    buf[0] = opcode;
    memcpy(buf + 1, pdu, len);

    /* 入队等待发送 */
    op = g_new0(struct att_send_op, 1);
    op->opcode = opcode;
    op->pdu = buf;
    op->len = len + 1;

    queue_push_head(att->write_queue, op);

    /* 触发写入 */
    if (!att->writer_active)
        att_writer(att);

    return op->len;
}

4.2 MTU 获取

cpp 复制代码
static uint16_t io_get_mtu(int fd)
{
    socklen_t len;
    struct l2cap_options l2o;

    len = sizeof(l2o);
    if (!getsockopt(fd, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len))
        return l2o.omtu;

    if (!getsockopt(fd, SOL_BLUETOOTH, BT_SNDMTU, &l2o.omtu, &len))
        return l2o.omtu;

    return 0;
}

4.3 ERTM 模式流量控制

ERTM(Enhanced Retransmission Mode)是最常用的可靠传输模式:

监控器中的 ERTM 帧解析

cpp 复制代码
/* L2CAP Control Field bit masks */
#define L2CAP_CTRL_REQSEQ_MASK   0x3F00
#define L2CAP_CTRL_TXSEQ_MASK    0x007E
#define L2CAP_CTRL_SUPERVISE_MASK 0x000C

#define L2CAP_CTRL_POLL          0x0010
#define L2CAP_CTRL_FINAL         0x0080
#define L2CAP_CTRL_FRAME_TYPE    0x0001 /* I- or S-Frame */

/* L2CAP Supervisory Function */
#define L2CAP_SUPER_RR       0x00    /* 接收准备好 */
#define L2CAP_SUPER_REJ      0x01    /* 拒绝 */
#define L2CAP_SUPER_RNR      0x02    /* 接收未准备好 */
#define L2CAP_SUPER_SREJ     0x03    /* 选择性拒绝 */

五、BLE 与经典蓝牙的差异化实现

5.1 PSM 差异

|--------|--------------------|---------------------------------|
| 特性 | 经典蓝牙 | BLE |
| PSM 分配 | 静态分配(如 SDP=0x0001) | 动态分配(0x0080-0xFFFF) |
| CoC 支持 | 不支持 | 支持 Connection-Oriented Channels |

cpp 复制代码
#define BREDR_DEFAULT_PSM    0x1011
#define LE_DEFAULT_PSM       0x0080    /* BLE 动态 PSM 起始 */

5.2 MTU 差异

|------------|------------|------------|
| 协议 | 默认 MTU | 最大 MTU |
| 经典蓝牙 L2CAP | 672 | 65535 |
| BLE L2CAP | 23(ATT 默认) | 517 |

5.3 BLE 特有设置

cpp 复制代码
static gboolean set_le_imtu(int sock, uint16_t imtu, GError **err)
{
    /* BLE 使用 BT_RCVMTU 而非 L2CAP_OPTIONS */
    if (setsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, &imtu,
                            sizeof(imtu)) < 0) {
        ERROR_FAILED(err, "setsockopt(BT_RCVMTU)", errno);
        return FALSE;
    }

    return TRUE;
}

static gboolean set_le_mode(int sock, uint8_t mode, GError **err)
{
    /* BLE 使用 BT_MODE 而非 L2CAP_OPTIONS */
    if (setsockopt(sock, SOL_BLUETOOTH, BT_MODE, &mode,
                        sizeof(mode)) < 0) {
        ERROR_FAILED(err, "setsockopt(BT_MODE)", errno);
        return FALSE;
    }

    return TRUE;
}

5.4 BLE 基于信用的流量控制

BLE 使用基于信用(Credit-based)的流量控制机制,与经典蓝牙的滑动窗口机制不同:

cpp 复制代码
#define L2CAP_MODE_LE_FLOWCTL   0x80    /* BLE 流量控制模式 */
#define L2CAP_MODE_ECRED        0x81    /* 增强信用模式 */

六、L2CAP 在 BlueZ 中的典型应用

6.1 SDP 服务发现

cpp 复制代码
/* SDP 服务器初始化 */
static int init_server(uint16_t mtu, int central, int compat)
{
    /* 创建 L2CAP socket */
    l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
    ...
    
    /* 绑定到 SDP_PSM (0x0001) */
    l2addr.l2_psm = htobs(SDP_PSM);
    bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr));
    
    /* 设置 MTU */
    opts.omtu = mtu;
    opts.imtu = mtu;
    setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
    
    /* 监听 */
    listen(l2cap_sock, 5);
    ...
}

6.2 GATT Client 通信

cpp 复制代码
static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
{
    ...
    /* BLE 设备需要交换 MTU */
    if (bt_att_get_link_type(client->att) == BT_ATT_BREDR)
        goto discover;

    mtu = MAX(BT_ATT_DEFAULT_LE_MTU, mtu);
    if (mtu == BT_ATT_DEFAULT_LE_MTU)
        goto discover;

    /* 发送 MTU 交换请求 */
    client->mtu_req_id = bt_gatt_exchange_mtu(client->att, mtu,
                                exchange_mtu_cb, ...);
    ...
}

6.3 Profile L2CAP 服务器

cpp 复制代码
static void ext_start_servers(struct ext_profile *ext, struct btd_adapter *adapter)
{
    ...
    if (ext->local_psm) {
        uint16_t psm;

        if (ext->local_psm > 0)
            psm = ext->local_psm;
        else
            psm = 0;

        /* 创建 L2CAP 监听服务器 */
        io = bt_io_listen(connect, confirm, l2cap, NULL, &err,
                    BT_IO_OPT_SOURCE_BDADDR,
                    btd_adapter_get_address(adapter),
                    BT_IO_OPT_MODE, ext->mode,
                    BT_IO_OPT_PSM, psm,
                    BT_IO_OPT_SEC_LEVEL, ext->sec_level,
                    BT_IO_OPT_INVALID);
        ...
    }
    ...
}

七、开发要点与常见问题

7.1 开发要点

1. Socket 类型选择

cpp 复制代码
/* 面向连接的可靠传输 */
sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);

/* 无连接的不可靠传输 */
sock = socket(PF_BLUETOOTH, SOCK_DGRAM, BTPROTO_L2CAP);

2. PSM 分配规范

  • 动态 PSM(0x0080-0xFFFF):运行时动态分配

  • 静态 PSM(0x0001-0x007F):需要蓝牙 SIG 注册

3. MTU 协商

cpp 复制代码
/* 获取当前 MTU */
struct l2cap_options opts;
getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
printf("Current MTU: %d\n", opts.omtu);

/* 设置 MTU(需要在 connect/bind 之前) */
opts.omtu = 1024;
opts.imtu = 1024;
setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));

4. 异步连接处理

cpp 复制代码
/* 非阻塞连接 */
fcntl(sock, F_SETFL, O_NONBLOCK);
err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));

if (err < 0) {
    if (errno == EINPROGRESS) {
        /* 连接进行中,等待完成 */
        struct pollfd fds;
        fds.fd = sock;
        fds.events = POLLOUT;
        poll(&fds, 1, timeout);
    } else {
        /* 真正的错误 */
        perror("connect");
        close(sock);
        return -1;
    }
}

7.2 常见问题与解决方案

问题 1:connect 返回 EINPROGRESS

原因:L2CAP 连接需要多轮命令交互,无法立即完成。

解决方案:使用非阻塞模式 + poll/select 等待连接完成。

问题 2:数据发送失败,errno = EMSGSIZE

原因:发送数据超过 MTU。

解决方案

cpp 复制代码
/* 检查数据大小 */
if (data_len > mtu) {
    /* 需要应用层分片 */
    uint16_t offset = 0;
    while (offset < data_len) {
        uint16_t chunk_len = MIN(data_len - offset, mtu);
        send(sock, data + offset, chunk_len, 0);
        offset += chunk_len;
    }
}

问题 3:BLE 设备连接失败

原因:地址类型错误。

解决方案

cpp 复制代码
struct sockaddr_l2 addr;
addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;  /* 或 BDADDR_LE_RANDOM */

问题 4:ERTM 模式下数据丢失

原因:发送窗口耗尽,需要等待接收方的 RR 帧。

解决方案:检查 txwin_size 设置,确保发送速率匹配接收能力。

八、总结

L2CAP 作为蓝牙协议栈的数据传输基石,其设计体现了协议复用、流量控制、可靠传输等核心思想。BlueZ 通过标准 socket API 和 btio 封装层,将复杂的 L2CAP 协议转化为简洁的编程接口:

  1. 帧结构:数据帧(l2cap_hdr)+ 命令帧(l2cap_cmd_hdr)

  2. 信道管理:通过 PSM/CID 标识,支持固定信道和动态信道

  3. 流量控制:Basic/Retrans/ERTM/Streaming 四种模式

  4. 差异化实现:BLE 使用动态 PSM、基于信用的流量控制

开发建议

  • 使用 btio 库简化 L2CAP 操作

  • 根据业务需求选择合适的传输模式

  • 注意 BLE 与经典蓝牙的差异

  • 合理设置 MTU 和安全级别


附录:核心函数索引

|-------------------|---------------|------------------|
| 文件 | 函数 | 功能 |
| btio/btio.c | l2cap_bind | L2CAP socket 绑定 |
| btio/btio.c | l2cap_connect | L2CAP socket 连接 |
| btio/btio.c | set_l2opts | 设置 L2CAP 选项 |
| btio/btio.c | l2cap_set_lm | 设置安全级别 |
| btio/btio.c | set_le_imtu | 设置 BLE 输入 MTU |
| src/sdpd-server.c | init_server | SDP L2CAP 服务器初始化 |
| src/shared/att.c | io_get_mtu | 获取 L2CAP MTU |
| lib/l2cap.h | l2cap_hdr | 数据帧头结构 |
| lib/l2cap.h | l2cap_cmd_hdr | 命令帧头结构 |


相关推荐
数据知道1 小时前
网络安全实战:漏洞扫描器对比——Nessus、OpenVAS、Nuclei 实战评测
网络·安全·web安全·网络安全
袁小皮皮不皮1 小时前
数通完整讲义-上册-HCIA篇
服务器·网络·网络协议·tcp/ip·智能路由器
sunoo-2291 小时前
【C 语言标准 IO 入门】第二天学习笔记:文件操作核心函数 + 实战案例 + 踩坑合集
linux·笔记·vscode·学习
波特率1152002 小时前
pthread库函数解析
linux·线程·pthread
Escalating_xu2 小时前
【Linux线程同步】从数据竞争到 mutex、条件变量与生产者消费者(上篇)
android·java·linux
晨曦花锦2 小时前
Vim基础操作与Ollama模型管理,顺便配置Nginx反向代理
linux·nginx·编辑器·vim
Eloudy2 小时前
Ubuntu 22.04 从源码编译安装 ROS 2 Jazzy 笔记
linux·笔记·ubuntu
Amir_zy2 小时前
TCP/IP 与 WebSocket 测试实战:从底层原理到场景落地
websocket·网络协议·tcp/ip
运维行者_2 小时前
预测性云监控怎么做?AI驱动的7大核心能力与落地路径
服务器·开发语言·网络·数据库·人工智能·python·php