cregit-Linux how code gets into the kernel

Release 4.11 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 Holtmann3081.08%150.00%
Johan 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 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 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 Fernando Padovan1942.22%450.00%
Linus Torvalds1124.44%112.50%
Marcel Holtmann920.00%112.50%
Andrei Emeltchenko48.89%112.50%
Maksim 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 Fernando Padovan1840.00%342.86%
Linus Torvalds920.00%114.29%
Marcel Holtmann817.78%114.29%
Maksim Krasnyanskiy613.33%114.29%
Andrei 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 Martineau2136.21%228.57%
Maxim Krasnyansky1424.14%114.29%
Marcel Holtmann813.79%114.29%
Andrei Emeltchenko813.79%114.29%
Gustavo Fernando 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 Martineau4679.31%120.00%
Marcel Holtmann58.62%120.00%
Andrei Emeltchenko46.90%120.00%
Gustavo Fernando Padovan23.45%120.00%
Maxim 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 Holtmann2351.11%233.33%
Gustavo Fernando Padovan1840.00%350.00%
Andrei 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 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 Fernando Padovan5192.73%375.00%
Szymon 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 Fernando Padovan13974.73%480.00%
Johan 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 Fernando Padovan3472.34%375.00%
Johan 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 Holtmann3756.06%240.00%
Johan Hedberg2639.39%240.00%
Gustavo Fernando 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 Fernando Padovan5198.08%480.00%
Andrei 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 Fernando Padovan2051.28%266.67%
Andrei 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 Emeltchenko2170.00%150.00%
Gustavo Fernando 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 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 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 Martineau4797.92%150.00%
Johan 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 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 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 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 Martineau6688.00%150.00%
Johan 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 Martineau5491.53%150.00%
Gustavo Fernando 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 Martineau7997.53%150.00%
Gustavo Fernando 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 Fernando Padovan11076.92%660.00%
Andrei Emeltchenko3222.38%330.00%
Ulisses 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 Fernando Padovan8468.85%861.54%
Mat Martineau119.02%17.69%
Johan Hedberg119.02%17.69%
Andrei Emeltchenko86.56%17.69%
Szymon Janc64.92%17.69%
Syam 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 Fernando Padovan3255.17%360.00%
Syam Sidhardhan1729.31%120.00%
Jaganath Kanakkassery915.52%120.00%
Total58100.00%5100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Jaganath Kanakkassery2987.88%133.33%
Syam Sidhardhan39.09%133.33%
Peter Zijlstra13.03%133.33%
Total33100.00%3100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Jaganath Kanakkassery3085.71%250.00%
Syam Sidhardhan411.43%125.00%
Peter Zijlstra12.86%125.00%
Total35100.00%4100.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 Emeltchenko5052.08%133.33%
Jukka Rissanen4041.67%133.33%
Mat 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 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 Emeltchenko5526.07%827.59%
Marcel Holtmann5124.17%26.90%
Johan Hedberg3818.01%413.79%
Gustavo Fernando Padovan3516.59%931.03%
Maxim Krasnyansky125.69%13.45%
Linus Torvalds94.27%26.90%
Maksim Krasnyanskiy52.37%13.45%
Ville Tervo52.37%13.45%
Ulisses 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 Emeltchenko3797.37%266.67%
Maksim 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
Gustavo Fernando Padovan8131.27%1750.00%
Andrei Emeltchenko6223.94%514.71%
Johan Hedberg4416.99%514.71%
Marcel Holtmann3212.36%12.94%
Mat Martineau176.56%25.88%
Maksim Krasnyanskiy145.41%12.94%
Linus Torvalds72.70%12.94%
David Herrmann10.39%12.94%
Ulisses Furquim10.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 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(chan->scid); rsp.mtu = cpu_to_le16(chan->imtu); rsp.mps = cpu_to_le16(chan->mps); rsp.credits = cpu_to_le16(chan->rx_credits); rsp.result = cpu_to_le16(result); l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); }

Contributors

PersonTokensPropCommitsCommitProp
Johan Hedberg127100.00%3100.00%
Total127100.00%3100.00%


static void