您的位置:首页 > 移动开发 > Android开发

[Android源码分析]L2CAP的创建过程分析

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


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: