(L2CAP协议简介,L2CAP在BlueZ中的实现以及L2CAP编程接口) git
一:L2CAP协议简介: 编程
Logical Link Control and Adaptation Protocol(L2CAP) dom
逻辑链接控制和适配协议 (L2CAP) 为上层协议提供面向链接和无链接的数据服务,并提供多协议功能和分割重组操做。L2CAP 充许上层协议和应用软件传输和接收最大长度为 64K 的 L2CAP 数据包。 socket
L2CAP 基于 通道(channel) 的概念。 通道 (Channel) 是位于基带 (baseband) 链接之上的逻辑链接。每一个通道以多对一的方式绑定一个单一协议 (single protocol)。多个通道能够绑定同一个协议,但一个通道不能够绑定多个协议。 每一个在通道里接收到的 L2CAP 数据包被传到相应的上层协议。 多个通道可共享同一个基带链接。 ide
L2CAP处于Bluetooth协议栈的位置以下: ui
也就是说,全部L2CAP数据均经过HCI传输到Remote Device。且上层协议的数据,大都也经过L2CAP来传送。 spa
L2CAP能够发送Command。例如链接,断连等等。 rest
下面看Command例子:Connection Request: orm
其中PSM比较须要注意,L2CAP 使用L2CAP链接请求(Connection Request )命令中的PSM字段实现协议复用。L2CAP能够复用发给上层协议的链接请求,这些上层协议包括服务发现协议SDP(PSM = 0x0001)、RFCOMM(PSM = 0x0003)和电话控制(PSM = 0x0005)等。 htm
Protocol | PSM | Reference |
---|---|---|
SDP | 0x0001 | See Bluetooth Service Discovery Protocol (SDP), Bluetooth SIG. |
RFCOMM | 0x0003 | See RFCOMM with TS 07.10, Bluetooth SIG. |
TCS-BIN | 0x0005 | See Bluetooth Telephony Control Specification / TCS Binary, Bluetooth SIG. |
TCS-BIN-CORDLESS | 0x0007 | See Bluetooth Telephony Control Specification / TCS Binary, Bluetooth SIG. |
BNEP | 0x000F | See Bluetooth Network Encapsulation Protocal, Bluetooth SIG. |
HID_Control | 0x0011 | See Human Interface Device , Bluetooth SIG. |
HID_Interrupt | 0x0013 | See Human Interface Device, Bluetooth SIG. |
UPnP | 0x0015 | See [ESDP] , Bluetooth SIG. |
AVCTP | 0x0017 | See Audio/Video Control Transport Protocol , Bluetooth SIG. |
AVDTP | 0x0019 | See Audio/Video Distribution Transport Protocol , Bluetooth SIG. |
AVCTP_Browsing | 0x001B | See Audio/Video Remote Control Profile, Bluetooth SIG |
UDI_C-Plane | 0x001D | See the Unrestricted Digital Information Profile [UDI], Bluetooth SIG |
二:L2CAP编程方法:
L2CAP编程很是重要,它和HCI基本就是Linux Bluetooth编程的基础了。几乎全部协议的链接,断连,读写都是用L2CAP链接来作的。
1.建立L2CAP Socket:
socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
domain=PF_BLUETOOTH, type能够是多种类型。protocol=BTPROTO_L2CAP.
2.绑定:
// Bind to local address
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&addr.l2_bdaddr, &bdaddr); //bdaddr为本地Dongle BDAddr
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Can't bind socket");
goto error;
}
3.链接
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(addr.l2_bdaddr, src);
addr.l2_psm = xxx;
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Can't connect");
goto error;
}
注意:
struct sockaddr_l2 {
sa_family_t l2_family; //必须为 AF_BLUETOOTH
unsigned short l2_psm; //与前面PSM对应,这一项很重要
bdaddr_t l2_bdaddr; //Remote Device BDADDR
unsigned short l2_cid;
};
4. 发送数据到Remote Device:
send()或write()均可以。
5. 接收数据:
revc() 或read()
如下为实例:
注:在Bluetooth下,主动去链接的一端做为主机端。被动等别人链接的做为Client端。
背景知识1:Bluetooth设备的状态
以前HCI编程时,是用 ioctl(HCIGETDEVINFO)获得某个Device Info(hci_dev_info).其中flags当时解释的很简单。其实它存放着Bluetooth Device(例如:USB Bluetooth Dongle)的当前状态:
其中,UP,Down状态表示此Device是否启动起来。可使用ioctl(HCIDEVUP)等修改这些状态。
另外:就是Inquiry Scan, PAGE Scan这些状态:
Sam在刚开始本身作L2CAP层链接时,使用另外一台Linux机器插USB Bluetooth Dongle做Remote Device。怎么也无法使用inquiry扫描到remote设备,也无法链接remote设备,甚至没法使用l2ping ping到remote设备。以为很是奇怪,后来才发现Remote Device状态设置有问题。没有设置PSCAN和ISCAN。
Inquiry Scan状态表示设备可被inquiry. Page Scan状态表示设备可被链接。
#hciconfig hci0 iscan
#hciconfig hci0 pscan
或者:#hciconfig hci0 piscan
就能够设置为PSCAN或者iSCAN状态了。
编程则可使用ioctl(HCISETSCAN) . dev_opt = SCAN_INQUIRY;dr.dev_opt = SCAN_PAGE;dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
则能够inquiry或者connect了。