[Android源码分析]L2CAP的bind分析以及psm和cid的介绍和实现

本文分析了Android中L2CAP协议的bind过程,探讨了PSM(Protocol/Service Multiplexer)和CID(Channel Identifier)的规范及实现。PSM必须为奇数且最高位为0,用于标识协议和服务;CID用于区分不同的L2CAP通道,0x0000不可用,0x0001至0x003F为固定通道。在BlueZ实现中,bind操作将PSM和CID与协议及L2CAP通道关联。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继续上文的socke的创建之后,我们自然而然就会想到下面的工作了,没错就是bind。

5.6 l2capbind分析

    按照国际惯例,在建了socket之后,必然会有bind,哈哈~~


if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
                                                        opts->cid, err) < 0)

这个函数如下:

static int l2cap_bind(int sock, const bdaddr_t *src, 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);

        //cid是0,psm是0?
        if (cid)
                addr.l2_cid = htobs(cid);
        else
                addr.l2_psm = htobs(psm);

        //bind,这里仍然会调用到kernel中去,详细见5.6.1的分析
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                ERROR_FAILED(err, "l2cap_bind", errno);
                return -1;
        }

        return 0;
}

5.6.1 kernel bind的分析

static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
        //得到对应的sock和chan
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
        struct sockaddr_l2 la;
        int len, err = 0;

        BT_DBG("sk %p", sk);

        //检查一下传入的参数
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;

        memset(&la, 0, sizeof(la));
        len = min_t(unsigned int, sizeof(la), alen);
        //把传入的内容拷贝到la中
        memcpy(&la, addr, len);

        //两个不能都有值,我们两个都是0
        if (la.l2_cid && la.l2_psm)
                return -EINVAL;

        lock_sock(sk);
        //这个开始就是open,这里只是double check一下
        if (sk->sk_state != BT_OPEN) {
                err = -EBADFD;
                goto done;
        }

        //若是传入了psm
        if (la.l2_psm) {
                __u16 psm = __le16_to_cpu(la.l2_psm);

                //psm必须是奇数,并且高位是0,这个是spec规定的。具体的介绍见5.6.2
                /* PSM must be odd and lsb of upper byte must be 0 */
                if ((psm & 0x0101) != 0x0001) {
                        err = -EINVAL;
                        goto done;
                }

                /* Restrict usage of well-known PSMs */
                //psm范围的检查以及权限的检查
                if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
                        err = -EACCES;
                        goto done;
                }
        }
        //若是有cid,就add cid,否则就add psm,关于cid的概念,我们在5.6.3中分析
        if (la.l2_cid)
                err = l2cap_add_scid(chan, la.l2_cid);
        else
                //这里不管有没有psm都是可以的,没有就生成一个,这里是psm的赋值,详细分析见5.6.4
                err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);

        if (err < 0)
                goto done;

        //这个时特殊的psm值,sdp
        if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
                                __le16_to_cpu(la.l2_psm) == 0x0003)
                chan->sec_level = BT_SECURITY_SDP;

        //这里设置的是源
        bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);

        //chan的state设为bound,就是binded了
        chan->state = BT_BOUND;
        sk->sk_state = BT_BOUND;

done:
        release_sock(sk);
        return err;
}

5.6.2 specpsm的规定

                   Psm全称为Protocol/ServiceMultiplexer。在spec中是这样描述的:

    The PSM fieldis at least two octets in length. The structure of the PSM field is based onthe ISO 3309 extension mechanism for address fields. All PSM values shall beODD, that is, the least significant bit of the least significant octet must be’1’. Also, all PSM values shall have the least significant bit of the mostsignificant octet equal to ’0’. This allows the PSM field to be extended beyond16 bits. PSM values are separated into two ranges. Valid values in the firstrange are assigned by the Bluetooth SIG and indicate protocols. The secondrange of values are dynamically allocated and used in conjunction with theService Discovery Protocol (SDP). The dynamically assigned value

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值