L2CAP層的實現在整個藍牙的使用過程中尤爲關鍵和複雜的,它涉及的方方面面比較多,曉東可能會要花幾篇文章才能講個大概,這篇文章先介紹L2CAP的初始化,這還是沒有和controller交互的部分,要先建立整個L2CAP,還需要實現很多,後面的文章會慢慢道來。
5.5, L2CAPsocket的創建
上層調用的函數就是這個:
sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
很清晰地可以看到,其實就是L2CAP的proto了。所以,我們直接去l2cap_sock.c中去看看創建的函數吧,爲什麼會走到這裏,我就不詳細分析了,網上關於socket的文章實在是太多了。
static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
//會調用這裏的create socket的函數
BT_DBG("sock %p", sock);
sock->state = SS_UNCONNECTED;
//傳入的type但是SOCK_RWA
if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
//若是應用層創建需要有net raw的權限,顯然我們是應用層過來的,所以一定要有NET_RAW的權限哦
if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
return -EPERM;
//賦值l2cap層的ops
sock->ops = &l2cap_sock_ops;
//申請並初始化一個sock,詳細見5.5.1
sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
if (!sk)
return -ENOMEM;
//其實是進一步初始化l2cap channel,詳細見5.5.2
l2cap_sock_init(sk, NULL);
return 0;
}
5.5.1 l2capsocket的申請
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
struct l2cap_chan *chan;
//申請sock
sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
if (!sk)
return NULL;
//初始化申請的sock,和對應的socket關聯
sock_init_data(sock, sk);
//初始化accept queue
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
//destruct和timeout的設置
sk->sk_destruct = l2cap_sock_destruct;
sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
//清空SOCK——ZAPPED位
sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = proto;
//state設爲open
sk->sk_state = BT_OPEN;
//創建l2cap的通道,這個是l2cap channel相關的一些初始化
chan = l2cap_chan_create(sk);
//賦值l2cap channel
l2cap_pi(sk)->chan = chan;
return sk;
}
struct l2cap_chan *l2cap_chan_create(struct sock *sk)
{
struct l2cap_chan *chan;
//l2cap channel結構體的申請
chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
if (!chan)
return NULL;
chan->sk = sk;
write_lock_bh(&chan_list_lock);
//把申請的chan加入chan_list雙向鏈表中
list_add(&chan->global_l, &chan_list);
write_unlock_bh(&chan_list_lock);
//初始化計時器
setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
//chanenl的state初始化位open
chan->state = BT_OPEN;
//chan refcnt 設爲1
atomic_set(&chan->refcnt, 1);
return chan;
}
5.5.2 l2cap channel的進一步初始化
這個函數就是進一步的初始化l2cap的socket中的各個方面
static void l2cap_sock_init(struct sock *sk, struct sock *parent)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_chan *chan = pi->chan;
BT_DBG("sk %p", sk);
if (parent) {
……
} else {
//我們傳入的是null,若是會走到這裏
//得到sk的sk_type
switch (sk->sk_type) {
case SOCK_RAW:
//若是raw,channel的type也是raw
chan->chan_type = L2CAP_CHAN_RAW;
break;
case SOCK_DGRAM:
chan->chan_type = L2CAP_CHAN_CONN_LESS;
break;
case SOCK_SEQPACKET:
case SOCK_STREAM:
chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
break;
}
//設置default mtu
chan->imtu = L2CAP_DEFAULT_MTU;
chan->omtu = 0;
if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
chan->mode = L2CAP_MODE_ERTM;
set_bit(CONF_STATE2_DEVICE, &chan->conf_state);
} else {
//raw是basic
chan->mode = L2CAP_MODE_BASIC;
}
//設置chan的別的值
chan->max_tx = L2CAP_DEFAULT_MAX_TX;//max tx是3
chan->fcs = L2CAP_FCS_CRC16;//l2cap的check是crc16
chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;//tx window是63
chan->sec_level = BT_SECURITY_LOW;//sec level默認是low
chan->role_switch = 0;
chan->force_reliable = 0;
chan->flushable = BT_FLUSHABLE_OFF;//flush disable
chan->force_active = BT_POWER_FORCE_ACTIVE_ON;//power force active on
}
/* Default config options */
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;//flush timeout 默認是FFFF
chan->data = sk;
chan->ops = &l2cap_chan_ops;//chan ops設置
}
到這裏,基本的L2CAP相關的初始化就完成了,還是蠻基本的,下面我們可以猜到就是bind了,因爲bind中涉及的內容和新的概念比較多,我們會在下一篇中和大家詳細分析。