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中涉及的内容和新的概念比较多,我们会在下一篇中和大家详细分析。