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

5.6 l2cap的bind分析

按照国际惯例,在建了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);elseaddr.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和chanstruct 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);//两个不能都有值,我们两个都是0if (la.l2_cid && la.l2_psm)return -EINVAL;lock_sock(sk);//这个开始就是open,这里只是double check一下if (sk->sk_state != BT_OPEN) {err = -EBADFD;goto done;}//若是传入了psmif (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.4err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);if (err < 0)goto done;//这个时特殊的psm值,sdpif (__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 spec中psm的规定

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 values may be usedto support multiple implementations of a particular protocol.

这段话大概的意思是PSM的长度最少是2byte,它的值应当是奇数,就是最低的byte的最低位必须为1.另外,psm的最高byte的最低位应当为0.它可以比2byte长,psm由两个范围段组成,第一个范围段是SIG用来表示对应protocol的,第二个范围段是动态申请的和SDP结合使用。这个值用来支持特定protocol的不同实现。这两个范围段的设置如下:

所以,我们在申请psm的时候都是从0x1001开始申请的。原因就是0x0001~0x0eff都是被SIG保留的。那么这些保留的值都各自对应了哪些protocol呢?具体见下表:


协议

PSM

SDP

0X0001

RFCOMM

0X0003

TCS-BIN

0X0005

TCS-BIN-CORDLESS

0X0007

BNEP

0X000F

HID_Control

0x0011

HID_Interrupt

0x0013

UPnP

0x0015

AVCTP

0X0017

AVDTP

0X0019

AVCTP_Browsing

0x001B

UDI_C-Plane

0x001D

ATT

0X001F

3DSP

0X0021

5.6.3 spec中cid的规定

CID的全称为ChannelIdentifer,他是用来标明不同的L2CAP通道的,每一个L2CAP通道都需要有一个不同的CID来表示。在spec中对CID的主要描述如下:

A channel identifier(CID) is the local name representing a logical channel endpoint on the device.The null identifier (0x0000) shall never be used as a destination endpoint.Identifiers from 0x0001 to 0x003F are reserved for specific L2CAP functions.These channels are referred to as Fixed Channels. At a minimum, the L2CAPSignaling channel (Fixed Channel 0x0001) or the L2CAP LE Signaling channel(Fixed Channel 0x0005) shall be supported. If Fixed Channel 0x0005 issupported, then Fixed Channels 0x0004 and 0x0006 shall be supported (see Table 2.1). Otherfixed channels may be supported. The Information Request / Response mechanism(described in Section 4.10 and Section 4.11) shall be used to determine which fixed channels aremote device supports over the ACL-U logical link.

在这段的描述中,我们可以发现0x0000是不能使用的,0x0001~0x003F是被征用的,他们被叫做FixedChannels,就是老弱病残孕专座,一般人还是不要去坐(不太恰当,在我们国家大家还是都会去坐的,哈哈~~)。这其中L2CAP Signaling channel(0x0001)和LESignaling channel(0x0005)是应当要支持的。若是支持0x0005(LE设备),那么0x004和0x006也应当被支持。其他的都是可能支持。Fix channel究竟有哪些呢,具体见下表:

总的来说,要建一个L2CAP通道就需要一个对应的cid值来表示,大概就是这个意思。

5.6.4 bluez中psm赋值的实现

在5.6.2中,我们有详细介绍psm在spec中是如何定义的,下面我们继续来看psm在bluez的代码中是如何实现的。

int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
{int err;write_lock_bh(&chan_list_lock);//若是有psm,又发现了和这个psm对应的chan,就直接返回in use的错误if (psm && __l2cap_global_chan_by_addr(psm, src)) { err = -EADDRINUSE;goto done;}if (psm) {//若是有psm,就是设置chan的psm和sport值chan->psm = psm;chan->sport = psm;err = 0;} else {u16 p;err = -EINVAL;for (p = 0x1001; p < 0x1100; p += 2)//若是没有,就是从低到高,找没有用到的psm。有了spec的解释,这里的为什么从1001开始就很清楚了吧if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {chan->psm   = cpu_to_le16(p);chan->sport = cpu_to_le16(p);err = 0;break;}}
done:write_unlock_bh(&chan_list_lock);return err;
}

至此,bind的分析就全部结束了,其实就是把对应的psm和cid与下面申请的protocol和L2cap关联起来,若是没有就申请对应的psm或者cid值。



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

  1. Android 源码 Camera2 预览流程分析四

    <Android 源码 Camera2 预览流程分析二>中进行了流启动,这是调用 QCamera3Channel start() 方法实现的,对应于 HAL_PIXEL_FORMAT_YC ...

  2. 编译Android源码(2) ---- envsetup.sh文件分析

    在Android源码下载完成后,只需要简单的三个步骤就能把Android编译完成( http://source.android.com/source/building.html): 1.当前目录切换到 ...

  3. android device目录,Android源码下device目录的分析

    一般源码的编译前都会执行lunch命令,选择编译目标: source build/envsetup.sh lunch BUILD_BUILDTYPE 其中BUILDTYPE可以为user.userde ...

  4. android lunch 选择写入脚本,Android源码编译之 lunch命令分析及user和userdebug编译选项区别...

    不同厂商在编译Android系统时,会选择不同产品和编译版本.在Android编译过程中,通过source,lunch来选择. 1.souuce build/envsetup.sh:加载命令 2.lu ...

  5. Android 源码 Camera2 预览流程分析一

    先上一段典型的预览代码,梳理一下相机预览流程. 从 TextureView 获取到 SurfaceTexture 将 SurfaceTexture 默认缓冲区的大小配置为相机预览的大小 新建一个 Su ...

  6. 《深入理解Android内核设计思想(第2版)(上下册)》之Android源码下载及编译

    本文摘自人民邮电出版社异步社区<深入理解Android内核设计思想(第2版)(上下册)> 购书地址:http://item.jd.com/12212640.html 试读地址:http:/ ...

  7. 《深入理解Android内核设计思想(第2版)(上下册)》之Android源码下载及编译...

    本文摘自人民邮电出版社异步社区<深入理解Android内核设计思想(第2版)(上下册)> 购书地址:item.jd.com/12212640.ht- 试读地址:www.epubit.com ...

  8. 菜鸟学Android源码——Setting(1)

    菜鸟学Android源码--Setting(1) 在上一篇中,我简单介绍了Android源码的下载和编译,还没有下载编译源码的小伙伴请看这里:Android源码分析之--下载并编译源码 关于系统设置A ...

  9. Android核心服务解析篇(二)——Android源码结构分析

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 获得Android源码后,我们来分析源码结构.源码的全部工程分为如下三个部分. ①Core Project:核心工程部分,这是建 ...

最新文章

  1. 组策略脚本的趣味应用
  2. Kubernetes1.13.1部署Kuberneted-dashboard v1.10.1
  3. DTS和PTS的解释(FFMPEG、HLS相关)
  4. 个人对北理工2020级硕士研究生张××一篇学术论文涉嫌抄袭的看法
  5. 用户注册的mysql代码_用户的注册登陆流程及代码实现
  6. python enumeration_python模块之enum_上
  7. 文档对象模型dom_什么是文档对象模型,以及为什么应该知道如何使用它。
  8. js实现的省市县三级联动的最新源码
  9. Java异常处理课后作业
  10. java常用算法_五分钟记住Java常用的八种排序算法与代码实现
  11. NIPS 又!放!票!了!
  12. 11.CSS border边框
  13. .net 移动端 web 上传图片_vue使用cropperjs实现移动端图片裁剪上传组件
  14. sql server 链接服务器 中文乱码_【小问题】Centos服务器下MySQL中文乱码问题
  15. window11在注册表修改用户名后登陆不了账户
  16. wd移动硬盘不能识别_WD移动硬盘读不出来了
  17. ERP管理web后台_数字化、智能化工厂管理系统原型、erp生产管理、仓库管理、采购管理、设备能源管理、计划管理、数字化工厂erp管理系统、生产计划、采购计划、用料请领、产品bom、工序管理、车间设备
  18. 可以插卡的ipad_平板电脑可以插手机卡吗,终于能插卡了!苹果iPad 2018蜂窝网络版上架国内官网...
  19. 《智能路由器开发指南》核心笔记(全)
  20. Airtest框架和Poco框架常见问题

热门文章

  1. mysql编译安装指定端口_在CentOS7系统上编译安装MySQL 5.7.13步骤详解
  2. 域前置,水太深,偷学六娃来隐身
  3. 产品管理NeoceanI网络存储产品开局指导书
  4. php抓取页面方法汇总
  5. 赵雅智:android发彩信操作
  6. 刮刮彩票 (20 分)
  7. 怎么限制使用计算机软件,如何禁止计算机用户使用IE浏览器
  8. Chrome浏览器怎么调试网页标题字体大小和颜色?
  9. 基于STM32楼梯层控制系统
  10. 查看创表语句 SHOW CREATE TABLE t_idcard