cregit-Linux how code gets into the kernel

Release 4.8 net/bluetooth/l2cap_core.c

Directory: net/bluetooth
/*
   BlueZ - Bluetooth protocol stack for Linux
   Copyright (C) 2000-2001 Qualcomm Incorporated
   Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
   Copyright (C) 2010 Google Inc.
   Copyright (C) 2011 ProFUSION Embedded Systems
   Copyright (c) 2012 Code Aurora Forum.  All rights reserved.

   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
   SOFTWARE IS DISCLAIMED.
*/

/* Bluetooth L2CAP core. */

#include <linux/module.h>

#include <linux/debugfs.h>
#include <linux/crc16.h>
#include <linux/filter.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>

#include "smp.h"
#include "a2mp.h"
#include "amp.h"


#define LE_FLOWCTL_MAX_CREDITS 65535


bool disable_ertm;


static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;

static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock);


static u16 le_max_credits = L2CAP_LE_MAX_CREDITS;

static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS;

static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
				       u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
			   void *data);
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);

static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
		     struct sk_buff_head *skbs, u8 event);


static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type) { if (link_type == LE_LINK) { if (bdaddr_type == ADDR_LE_DEV_PUBLIC) return BDADDR_LE_PUBLIC; else return BDADDR_LE_RANDOM; } return BDADDR_BREDR; }

Contributors

PersonTokensPropCommitsCommitProp
marcel holtmannmarcel holtmann3081.08%150.00%
johan hedbergjohan hedberg718.92%150.00%
Total37100.00%2100.00%


static inline u8 bdaddr_src_type(struct hci_conn *hcon) { return bdaddr_type(hcon->type, hcon->src_type); }

Contributors

PersonTokensPropCommitsCommitProp
johan hedbergjohan hedberg24100.00%1100.00%
Total24100.00%1100.00%


static inline u8 bdaddr_dst_type(struct hci_conn *hcon) { return bdaddr_type(hcon->type, hcon->dst_type); }

Contributors

PersonTokensPropCommitsCommitProp
johan hedbergjohan hedberg24100.00%1100.00%
Total24100.00%1100.00%

/* ---- L2CAP channels ---- */
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { if (c->dcid == cid) return c; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan1942.22%450.00%
linus torvaldslinus torvalds1124.44%112.50%
marcel holtmannmarcel holtmann920.00%112.50%
andrei emeltchenkoandrei emeltchenko48.89%112.50%
maksim krasnyanskiymaksim krasnyanskiy24.44%112.50%
Total45100.00%8100.00%


static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { if (c->scid == cid) return c; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan1840.00%342.86%
linus torvaldslinus torvalds920.00%114.29%
marcel holtmannmarcel holtmann817.78%114.29%
maksim krasnyanskiymaksim krasnyanskiy613.33%114.29%
andrei emeltchenkoandrei emeltchenko48.89%114.29%
Total45100.00%7100.00%

/* Find channel with given SCID. * Returns locked channel. */
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau2136.21%228.57%
maxim krasnyanskymaxim krasnyansky1424.14%114.29%
andrei emeltchenkoandrei emeltchenko813.79%114.29%
marcel holtmannmarcel holtmann813.79%114.29%
gustavo f. padovangustavo f. padovan712.07%228.57%
Total58100.00%7100.00%

/* Find channel with given DCID. * Returns locked channel. */
static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_dcid(conn, cid); if (c) l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau4679.31%120.00%
marcel holtmannmarcel holtmann58.62%120.00%
andrei emeltchenkoandrei emeltchenko46.90%120.00%
gustavo f. padovangustavo f. padovan23.45%120.00%
maxim krasnyanskymaxim krasnyansky11.72%120.00%
Total58100.00%5100.00%


static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { if (c->ident == ident) return c; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
marcel holtmannmarcel holtmann2351.11%233.33%
gustavo f. padovangustavo f. padovan1840.00%350.00%
andrei emeltchenkoandrei emeltchenko48.89%116.67%
Total45100.00%6100.00%


static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau58100.00%1100.00%
Total58100.00%1100.00%


static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) { struct l2cap_chan *c; list_for_each_entry(c, &chan_list, global_l) { if (c->sport == psm && !bacmp(&c->src, src)) return c; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan5192.73%375.00%
szymon jancszymon janc47.27%125.00%
Total55100.00%4100.00%


int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) { int err; write_lock(&chan_list_lock); if (psm && __l2cap_global_chan_by_addr(psm, src)) { err = -EADDRINUSE; goto done; } if (psm) { chan->psm = psm; chan->sport = psm; err = 0; } else { u16 p, start, end, incr; if (chan->src_type == BDADDR_BREDR) { start = L2CAP_PSM_DYN_START; end = L2CAP_PSM_AUTO_END; incr = 2; } else { start = L2CAP_PSM_LE_DYN_START; end = L2CAP_PSM_LE_DYN_END; incr = 1; } err = -EINVAL; for (p = start; p <= end; p += incr) if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) { chan->psm = cpu_to_le16(p); chan->sport = cpu_to_le16(p); err = 0; break; } } done: write_unlock(&chan_list_lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan13974.73%480.00%
johan hedbergjohan hedberg4725.27%120.00%
Total186100.00%5100.00%

EXPORT_SYMBOL_GPL(l2cap_add_psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { write_lock(&chan_list_lock); /* Override the defaults (which are for conn-oriented) */ chan->omtu = L2CAP_DEFAULT_MTU; chan->chan_type = L2CAP_CHAN_FIXED; chan->scid = scid; write_unlock(&chan_list_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan3472.34%375.00%
johan hedbergjohan hedberg1327.66%125.00%
Total47100.00%4100.00%


static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { u16 cid, dyn_end; if (conn->hcon->type == LE_LINK) dyn_end = L2CAP_CID_LE_DYN_END; else dyn_end = L2CAP_CID_DYN_END; for (cid = L2CAP_CID_DYN_START; cid <= dyn_end; cid++) { if (!__l2cap_get_chan_by_scid(conn, cid)) return cid; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
marcel holtmannmarcel holtmann3756.06%240.00%
johan hedbergjohan hedberg2639.39%240.00%
gustavo f. padovangustavo f. padovan34.55%120.00%
Total66100.00%5100.00%


static void l2cap_state_change(struct l2cap_chan *chan, int state) { BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), state_to_string(state)); chan->state = state; chan->ops->state_change(chan, state, 0); }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan4892.31%240.00%
gustavo padovangustavo padovan35.77%240.00%
andrei emeltchenkoandrei emeltchenko11.92%120.00%
Total52100.00%5100.00%


static inline void l2cap_state_change_and_error(struct l2cap_chan *chan, int state, int err) { chan->state = state; chan->ops->state_change(chan, chan->state, err); }

Contributors

PersonTokensPropCommitsCommitProp
gustavo padovangustavo padovan2051.28%266.67%
andrei emeltchenkoandrei emeltchenko1948.72%133.33%
Total39100.00%3100.00%


static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) { chan->ops->state_change(chan, chan->state, err); }

Contributors

PersonTokensPropCommitsCommitProp
andrei emeltchenkoandrei emeltchenko2170.00%150.00%
gustavo padovangustavo padovan930.00%150.00%
Total30100.00%2100.00%


static void __set_retrans_timer(struct l2cap_chan *chan) { if (!delayed_work_pending(&chan->monitor_timer) && chan->retrans_timeout) { l2cap_set_timer(chan, &chan->retrans_timer, msecs_to_jiffies(chan->retrans_timeout)); } }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau45100.00%1100.00%
Total45100.00%1100.00%


static void __set_monitor_timer(struct l2cap_chan *chan) { __clear_retrans_timer(chan); if (chan->monitor_timeout) { l2cap_set_timer(chan, &chan->monitor_timer, msecs_to_jiffies(chan->monitor_timeout)); } }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau41100.00%1100.00%
Total41100.00%1100.00%


static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head, u16 seq) { struct sk_buff *skb; skb_queue_walk(head, skb) { if (bt_cb(skb)->l2cap.txseq == seq) return skb; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau4797.92%150.00%
johan hedbergjohan hedberg12.08%150.00%
Total48100.00%2100.00%

/* ---- L2CAP sequence number lists ---- */ /* For ERTM, ordered lists of sequence numbers must be tracked for * SREJ requests that are received and for frames that are to be * retransmitted. These seq_list functions implement a singly-linked * list in an array, where membership in the list can also be checked * in constant time. Items can also be added to the tail of the list * and removed from the head in constant time, without further memory * allocs or frees. */
static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) { size_t alloc_size, i; /* Allocated size is a power of 2 to map sequence numbers * (which may be up to 14 bits) in to a smaller array that is * sized for the negotiated ERTM transmit windows. */ alloc_size = roundup_pow_of_two(size); seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); if (!seq_list->list) return -ENOMEM; seq_list->mask = alloc_size - 1; seq_list->head = L2CAP_SEQ_LIST_CLEAR; seq_list->tail = L2CAP_SEQ_LIST_CLEAR; for (i = 0; i < alloc_size; i++) seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau99100.00%1100.00%
Total99100.00%1100.00%


static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) { kfree(seq_list->list); }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau19100.00%1100.00%
Total19100.00%1100.00%


static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, u16 seq) { /* Constant-time check for list membership */ return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau30100.00%1100.00%
Total30100.00%1100.00%


static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) { u16 seq = seq_list->head; u16 mask = seq_list->mask; seq_list->head = seq_list->list[seq & mask]; seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { seq_list->head = L2CAP_SEQ_LIST_CLEAR; seq_list->tail = L2CAP_SEQ_LIST_CLEAR; } return seq; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau6688.00%150.00%
johan hedbergjohan hedberg912.00%150.00%
Total75100.00%2100.00%


static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) { u16 i; if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) return; for (i = 0; i <= seq_list->mask; i++) seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; seq_list->head = L2CAP_SEQ_LIST_CLEAR; seq_list->tail = L2CAP_SEQ_LIST_CLEAR; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau5491.53%150.00%
gustavo padovangustavo padovan58.47%150.00%
Total59100.00%2100.00%


static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) { u16 mask = seq_list->mask; /* All appends happen in constant time */ if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR) return; if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) seq_list->head = seq; else seq_list->list[seq_list->tail & mask] = seq; seq_list->tail = seq; seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; }

Contributors

PersonTokensPropCommitsCommitProp
mat martineaumat martineau7997.53%150.00%
gustavo padovangustavo padovan22.47%150.00%
Total81100.00%2100.00%


static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); struct l2cap_conn *conn = chan->conn; int reason; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); mutex_lock(&conn->chan_lock); l2cap_chan_lock(chan); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; else if (chan->state == BT_CONNECT && chan->sec_level != BT_SECURITY_SDP) reason = ECONNREFUSED; else reason = ETIMEDOUT; l2cap_chan_close(chan, reason); l2cap_chan_unlock(chan); chan->ops->close(chan); mutex_unlock(&conn->chan_lock); l2cap_chan_put(chan); }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan11076.92%660.00%
andrei emeltchenkoandrei emeltchenko3222.38%330.00%
ulisses furquimulisses furquim10.70%110.00%
Total143100.00%10100.00%


struct l2cap_chan *l2cap_chan_create(void) { struct l2cap_chan *chan; chan = kzalloc(sizeof(*chan), GFP_ATOMIC); if (!chan) return NULL; mutex_init(&chan->lock); /* Set default lock nesting level */ atomic_set(&chan->nesting, L2CAP_NESTING_NORMAL); write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); write_unlock(&chan_list_lock); INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); chan->state = BT_OPEN; kref_init(&chan->kref); /* This flag is cleared in l2cap_chan_ready() */ set_bit(CONF_NOT_COMPLETE, &chan->conf_state); BT_DBG("chan %p", chan); return chan; }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan8267.21%753.85%
mat martineaumat martineau119.02%17.69%
johan hedbergjohan hedberg119.02%17.69%
andrei emeltchenkoandrei emeltchenko86.56%17.69%
szymon jancszymon janc64.92%17.69%
gustavo padovangustavo padovan21.64%17.69%
syam sidhardhansyam sidhardhan21.64%17.69%
Total122100.00%13100.00%

EXPORT_SYMBOL_GPL(l2cap_chan_create);
static void l2cap_chan_destroy(struct kref *kref) { struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref); BT_DBG("chan %p", chan); write_lock(&chan_list_lock); list_del(&chan->global_l); write_unlock(&chan_list_lock); kfree(chan); }

Contributors

PersonTokensPropCommitsCommitProp
gustavo f. padovangustavo f. padovan3255.17%360.00%
syam sidhardhansyam sidhardhan1729.31%120.00%
jaganath kanakkasseryjaganath kanakkassery915.52%120.00%
Total58100.00%5100.00%


void l2cap_chan_hold(struct l2cap_chan *c) { BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); kref_get(&c->kref); }

Contributors

PersonTokensPropCommitsCommitProp
jaganath kanakkasseryjaganath kanakkassery3085.71%150.00%
syam sidhardhansyam sidhardhan514.29%150.00%
Total35100.00%2100.00%


void l2cap_chan_put(struct l2cap_chan *c) { BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); kref_put(&c->kref, l2cap_chan_destroy); }

Contributors

PersonTokensPropCommitsCommitProp
jaganath kanakkasseryjaganath kanakkassery3183.78%266.67%
syam sidhardhansyam sidhardhan616.22%133.33%
Total37100.00%3100.00%

EXPORT_SYMBOL_GPL(l2cap_chan_put);
void l2cap_chan_set_defaults(struct l2cap_chan *chan) { chan->fcs = L2CAP_FCS_CRC16; chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; chan->remote_max_tx = chan->max_tx; chan->remote_tx_win = chan->tx_win; chan->ack_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; chan->conf_state = 0; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); }

Contributors

PersonTokensPropCommitsCommitProp
andrei emeltchenkoandrei emeltchenko5052.08%133.33%
jukka rissanenjukka rissanen4041.67%133.33%
mat martineaumat martineau66.25%133.33%
Total96100.00%3100.00%

EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
static void l2cap_le_flowctl_init(struct l2cap_chan *chan) { chan->sdu = NULL; chan->sdu_last_frag = NULL; chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; chan->mps = min_t(u16, chan->imtu, le_default_mps); skb_queue_head_init(&chan->tx_q); }

Contributors

PersonTokensPropCommitsCommitProp
johan hedbergjohan hedberg64100.00%7100.00%
Total64100.00%7100.00%


void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, __le16_to_cpu(chan->psm), chan->dcid); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; chan->conn = conn; switch (chan->chan_type) { case L2CAP_CHAN_CONN_ORIENTED: /* Alloc CID for connection-oriented socket */ chan->scid = l2cap_alloc_cid(conn); if (conn->hcon->type == ACL_LINK) chan->omtu = L2CAP_DEFAULT_MTU; break; case L2CAP_CHAN_CONN_LESS: /* Connectionless socket */ chan->scid = L2CAP_CID_CONN_LESS; chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; break; case L2CAP_CHAN_FIXED: /* Caller will set CID and CID specific MTU values */ break; default: /* Raw socket can send/recv signalling messages only */ chan->scid = L2CAP_CID_SIGNALING; chan->dcid = L2CAP_CID_SIGNALING; chan->omtu = L2CAP_DEFAULT_MTU; } chan->local_id = L2CAP_BESTEFFORT_ID; chan->local_stype = L2CAP_SERV_BESTEFFORT; chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE; chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME; chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT; chan->local_flush_to = L2CAP_EFS_DEFAULT_FLUSH_TO; l2cap_chan_hold(chan); /* Only keep a reference for fixed channels if they requested it */ if (chan->chan_type != L2CAP_CHAN_FIXED || test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) hci_conn_hold(conn->hcon); list_add(&chan->list, &conn->chan_l); }

Contributors

PersonTokensPropCommitsCommitProp
andrei emeltchenkoandrei emeltchenko5526.07%827.59%
marcel holtmannmarcel holtmann5124.17%26.90%
johan hedbergjohan hedberg3818.01%413.79%
gustavo f. padovangustavo f. padovan3114.69%827.59%
maxim krasnyanskymaxim krasnyansky125.69%13.45%
linus torvaldslinus torvalds94.27%26.90%
ville tervoville tervo52.37%13.45%
maksim krasnyanskiymaksim krasnyanskiy52.37%13.45%
gustavo padovangustavo padovan41.90%13.45%
ulisses furquimulisses furquim10.47%13.45%
Total211100.00%29100.00%


void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); mutex_unlock(&conn->chan_lock); }

Contributors

PersonTokensPropCommitsCommitProp
andrei emeltchenkoandrei emeltchenko3797.37%266.67%
maksim krasnyanskiymaksim krasnyanskiy12.63%133.33%
Total38100.00%3100.00%


void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; __clear_chan_timer(chan); BT_DBG("chan %p, conn %p, err %d, state %s", chan, conn, err, state_to_string(chan->state)); chan->ops->teardown(chan, err); if (conn) { struct amp_mgr *mgr = conn->hcon->amp_mgr; /* Delete from channel list */ list_del(&chan->list); l2cap_chan_put(chan); chan->conn = NULL; /* Reference was only held for non-fixed channels or * fixed channels that explicitly requested it using the * FLAG_HOLD_HCI_CONN flag. */ if (chan->chan_type != L2CAP_CHAN_FIXED || test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) hci_conn_drop(conn->hcon); if (mgr && mgr->bredr_chan == chan) mgr->bredr_chan = NULL; } if (chan->hs_hchan) { struct hci_chan *hs_hchan = chan->hs_hchan; BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan); amp_disconnect_logical_link(hs_hchan); } if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) return; switch(chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_LE_FLOWCTL: skb_queue_purge(&chan->tx_q); break; case L2CAP_MODE_ERTM: __clear_retrans_timer(chan); __clear_monitor_timer(chan); __clear_ack_timer(chan); skb_queue_purge(&chan->srej_q); l2cap_seq_list_free(&chan->srej_list); l2cap_seq_list_free(&chan->retrans_list); /* fall through */ case L2CAP_MODE_STREAMING: skb_queue_purge(&chan->tx_q); break; } return; }

Contributors

PersonTokensPropCommitsCommitProp
andrei emeltchenkoandrei emeltchenko6223.94%514.71%
gustavo f. padovangustavo f. padovan5922.78%1647.06%
johan hedbergjohan hedberg4416.99%514.71%
marcel holtmannmarcel holtmann3212.36%12.94%
gustavo padovangustavo padovan228.49%12.94%
mat martineaumat martineau176.56%25.88%
maksim krasnyanskiymaksim krasnyanskiy145.41%12.94%
linus torvaldslinus torvalds72.70%12.94%
ulisses furquimulisses furquim10.39%12.94%
david herrmanndavid herrmann10.39%12.94%
Total259100.00%34100.00%

EXPORT_SYMBOL_GPL(l2cap_chan_del);
static void l2cap_conn_update_id_addr(struct work_struct *work) { struct l2cap_conn *conn = container_of(work, struct l2cap_conn, id_addr_update_work); struct hci_conn *hcon = conn->hcon; struct l2cap_chan *chan; mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); bacpy(&chan->dst, &hcon->dst); chan->dst_type = bdaddr_dst_type(hcon); l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); }

Contributors

PersonTokensPropCommitsCommitProp
johan hedbergjohan hedberg98100.00%3100.00%
Total98100.00%3100.00%


static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; struct l2cap_le_conn_rsp rsp; u16 result; if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) result = L2CAP_CR_AUTHORIZATION; else result = L2CAP_CR_BAD_PSM; l2cap_state_change(chan, BT_DISCONN); rsp.dcid = cpu_to_le16