/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
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 and sockets. */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <linux/list.h>
#include <linux/device.h>
#include <net/sock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#define VERSION "2.13"
static u32 l2cap_feat_mask = 0x0080;
static u8 l2cap_fixed_chan[8] = { 0x02, };
static const struct proto_ops l2cap_sock_ops;
static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
/* ---- L2CAP timers ---- */
static void l2cap_sock_timeout(unsigned long arg)
{
struct sock *sk = (struct sock *) arg;
int reason;
BT_DBG("sock %p state %d", sk, sk->sk_state);
bh_lock_sock(sk);
if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
reason = ECONNREFUSED;
else if (sk->sk_state == BT_CONNECT &&
l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
reason = ECONNREFUSED;
else
reason = ETIMEDOUT;
__l2cap_sock_close(sk, reason);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
sock_put(sk);
}
static void l2cap_sock_set_timer(struct sock *sk, long timeout)
{
BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
}
static void l2cap_sock_clear_timer(struct sock *sk)
{
BT_DBG("sock %p state %d", sk, sk->sk_state);
sk_stop_timer(sk, &sk->sk_timer);
}
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
if (l2cap_pi(s)->dcid == cid)
break;
}
return s;
}
static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
if (l2cap_pi(s)->scid == cid)
break;
}
return s;
}
/* Find channel with given SCID.
* Returns locked socket */
static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
{
struct sock *s;
read_lock(&l->lock);
s = __l2cap_get_chan_by_scid(l, cid);
if (s) bh_lock_sock(s);
read_unlock(&l->lock);
return s;
}
static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
if (l2cap_pi(s)->ident == ident)
break;
}
return s;
}
static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
{
struct sock *s;
read_lock(&l->lock);
s = __l2cap_get_chan_by_ident(l, ident);
if (s) bh_lock_sock(s);
read_unlock(&l->lock);
return s;
}
static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
{
u16 cid = 0x0040;
for (; cid < 0xffff; cid++) {
if(!__l2cap_get_chan_by_scid(l, cid))
return cid;
}
return 0;
}
static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
{
sock_hold(sk);
if (l->head)
l2cap_pi(l->head)->prev_c = sk;
l2cap_pi(sk)->next_c = l->head;
l2cap_pi(sk)->prev_c = NULL;
l->head = sk;
}
static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
{
struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
write_lock_bh(&l->lock);
if (sk == l->head)
l->head = next;
if (next)
l2cap_pi(next)->prev_c = prev;
if (prev)
l2cap_pi(prev)->next_c = next;
write_unlock_bh(&l->lock);
__sock_put(sk);
}
static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
{
struct l2cap_chan_list *l = &conn->chan_list;
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
conn->disc_reason = 0x13;
l2cap_pi(sk)->conn = conn;
if (sk->sk_type == SOCK_SEQPACKET) {
/* Alloc CID for connection-oriented socket */
l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
} else if (sk->sk_type == SOCK_DGRAM) {
/* Connectionless socket */
l2cap_pi(sk)->scid = 0x0002;
l2cap_pi(sk)->dcid = 0x0002;
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
} else {
/* Raw socket can send/recv signalling messages only */
l2cap_pi(sk)->scid = 0x0001;
l2cap_pi(sk)->dcid = 0x0001;
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
}
__l2cap_chan_link(l, sk);
if (parent)
bt_accept_enqueue(parent, sk);
}
/* Delete channel.
* Must be called on the locked socket. */
static void l2cap_chan_del(struct sock *sk, int err)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct sock *parent = bt_sk(sk)->parent;
l2cap_sock_clear_timer(sk);
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
if (conn) {
/* Unlink from channel list */
l2cap_chan_unlink(&conn->chan_list, sk);
l2cap_pi(sk)->conn = NULL;
hci_conn_put(conn->hcon);
}
sk->sk_state = BT_CLOSED;
sock_set_flag(sk, SOCK_ZAPPED);
if (err)
sk->sk_err = err;
if (parent) {
bt_accept_unlink(sk);
parent->sk_data_ready(parent, 0);
} else
sk->sk_state_change(sk);
}
/* Service level security */
static inline int l2cap_check_security(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
__u8 auth_type;
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
}
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
auth_type);
}
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
{
u8 id;
/* Get next available identificator.
* 1 - 128 are used by kernel.
* 129 - 199 are reserved.
* 200 - 254 are used by utilities like l2ping, etc.
*/
spin_lock_bh(&conn->lock);
if (++conn->tx_ident > 128)
conn->tx_ident = 1;
id = conn->tx_ident;
spin_unlock_bh(&conn->lock);
return id;
}
static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
{
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return -ENOMEM;
return hci_
bluetooth.rar_linux c++ bluetooth
版权申诉
171 浏览量
2022-07-13
18:45:58
上传
评论 1
收藏 112KB RAR 举报
Kinonoyomeo
- 粉丝: 73
- 资源: 1万+
最新资源
- tensorflow-2.7.3-cp39-cp39-manylinux2010-x86-64.whl
- tensorflow-2.7.2-cp39-cp39-manylinux2010-x86-64.whl
- Python版本快速排序源代码
- Python 语言版的快速排序算法实现
- 450815388207377安卓_base.apk
- 超微主板 X9DRE-TF+ bios 支持 nvme启动
- 基于Python通过下载气象数据和插值拟合离散数据曲线实现对寒潮过程的能量分析
- 健身房系统的设计与实现论文Java项目
- 使用TCP实现的搜索可用服务器
- 使用贪心算法解决会议时间安排问题的 Java 示例代码
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈