Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android源碼分析]L2CAP的創建過程分析

[Android源碼分析]L2CAP的創建過程分析

編輯:關於Android編程

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中涉及的內容和新的概念比較多,我們會在下一篇中和大家詳細分析。







  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved