⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l2cap.c

📁 基于liunx的蓝牙协议栈源代码版本為2.13,可以方便的下載和移植!
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	if (!l2cap_pi(sk)->psm) {		err = -EINVAL;		goto done;	}	sk->max_ack_backlog = backlog;	sk->ack_backlog = 0;	sk->state = BT_LISTEN;done:	release_sock(sk);	return err;}int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags){	DECLARE_WAITQUEUE(wait, current);	struct sock *sk = sock->sk, *nsk;	long timeo;	int err = 0;	lock_sock(sk);	if (sk->state != BT_LISTEN) {		err = -EBADFD;		goto done;	}	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);	BT_DBG("sk %p timeo %ld", sk, timeo);	/* Wait for an incoming connection. (wake-one). */	add_wait_queue_exclusive(sk->sleep, &wait);	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {		set_current_state(TASK_INTERRUPTIBLE);		if (!timeo) {			err = -EAGAIN;			break;		}		release_sock(sk);		timeo = schedule_timeout(timeo);		lock_sock(sk);		if (sk->state != BT_LISTEN) {			err = -EBADFD;			break;		}		if (signal_pending(current)) {			err = sock_intr_errno(timeo);			break;		}	}	set_current_state(TASK_RUNNING);	remove_wait_queue(sk->sleep, &wait);	if (err)		goto done;	newsock->state = SS_CONNECTED;	BT_DBG("new socket %p", nsk);done:	release_sock(sk);	return err;}static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer){	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;	struct sock *sk = sock->sk;	BT_DBG("sock %p, sk %p", sock, sk);	addr->sa_family = AF_BLUETOOTH;	*len = sizeof(struct sockaddr_l2);	if (peer)		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);	else		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);	la->l2_psm = l2cap_pi(sk)->psm;	return 0;}static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm){	struct sock *sk = sock->sk;	int err = 0;	BT_DBG("sock %p, sk %p", sock, sk);	if (sk->err)		return sock_error(sk);	if (msg->msg_flags & MSG_OOB)		return -EOPNOTSUPP;	/* Check outgoing MTU */	if (len > l2cap_pi(sk)->omtu)		return -EINVAL;	lock_sock(sk);	if (sk->state == BT_CONNECTED)		err = l2cap_chan_send(sk, msg, len);	else		err = -ENOTCONN;	release_sock(sk);	return err;}static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen){	struct sock *sk = sock->sk;	struct l2cap_options opts;	int err = 0, len;	__u32 opt;	BT_DBG("sk %p", sk);	lock_sock(sk);	switch (optname) {	case L2CAP_OPTIONS:		len = MIN(sizeof(opts), optlen);		if (copy_from_user((char *)&opts, optval, len)) {			err = -EFAULT;			break;		}		l2cap_pi(sk)->imtu  = opts.imtu;		l2cap_pi(sk)->omtu  = opts.omtu;		break;	case L2CAP_LM:		if (get_user(opt, (__u32 *)optval)) {			err = -EFAULT;			break;		}		l2cap_pi(sk)->link_mode = opt;		break;	default:		err = -ENOPROTOOPT;		break;	}	release_sock(sk);	return err;}static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){	struct sock *sk = sock->sk;	struct l2cap_options opts;	struct l2cap_conninfo cinfo;	int len, err = 0; 	if (get_user(len, optlen))		return -EFAULT;	lock_sock(sk);	switch (optname) {	case L2CAP_OPTIONS:		opts.imtu     = l2cap_pi(sk)->imtu;		opts.omtu     = l2cap_pi(sk)->omtu;		opts.flush_to = l2cap_pi(sk)->flush_to;		len = MIN(len, sizeof(opts));		if (copy_to_user(optval, (char *)&opts, len))			err = -EFAULT;		break;	case L2CAP_LM:		if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))			err = -EFAULT;		break;	case L2CAP_CONNINFO:		if (sk->state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;		len = MIN(len, sizeof(cinfo));		if (copy_to_user(optval, (char *)&cinfo, len))			err = -EFAULT;		break;	default:		err = -ENOPROTOOPT;		break;	}	release_sock(sk);	return err;}static int l2cap_sock_shutdown(struct socket *sock, int how){	struct sock *sk = sock->sk;	int err = 0;	BT_DBG("sock %p, sk %p", sock, sk);	if (!sk) return 0;	lock_sock(sk);	if (!sk->shutdown) {		sk->shutdown = SHUTDOWN_MASK;		l2cap_sock_clear_timer(sk);		__l2cap_sock_close(sk, 0);		if (sk->linger)			err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);	}	release_sock(sk);	return err;}static int l2cap_sock_release(struct socket *sock){	struct sock *sk = sock->sk;	int err;	BT_DBG("sock %p, sk %p", sock, sk);	if (!sk) return 0;	err = l2cap_sock_shutdown(sock, 2);	sock_orphan(sk);	l2cap_sock_kill(sk);	return err;}/* --------- 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 __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(&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(&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);	l2cap_pi(sk)->conn = conn;	if (sk->type == SOCK_SEQPACKET) {		/* Alloc CID for connection-oriented socket */		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);	} else if (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)		bluez_accept_enqueue(parent, sk);}static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent){	struct l2cap_chan_list *l = &conn->chan_list;	write_lock(&l->lock);	__l2cap_chan_add(conn, sk, parent);	write_unlock(&l->lock);}/* 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 = bluez_pi(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->state  = BT_CLOSED;	sk->zapped = 1;	if (err)		sk->err = err;	if (parent)		parent->data_ready(parent, 0);	else		sk->state_change(sk);}static void l2cap_conn_ready(struct l2cap_conn *conn){	struct l2cap_chan_list *l = &conn->chan_list;	struct sock *sk;	BT_DBG("conn %p", conn);	read_lock(&l->lock);	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {		bh_lock_sock(sk);		if (sk->type != SOCK_SEQPACKET) {			l2cap_sock_clear_timer(sk);			sk->state = BT_CONNECTED;			sk->state_change(sk);		} else if (sk->state == BT_CONNECT) {			l2cap_conn_req req;			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);			req.psm  = l2cap_pi(sk)->psm;			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);		}		bh_unlock_sock(sk);	}	read_unlock(&l->lock);}/* Notify sockets that we cannot guaranty reliability anymore */static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err){	struct l2cap_chan_list *l = &conn->chan_list;	struct sock *sk;	BT_DBG("conn %p", conn);	read_lock(&l->lock);	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {		if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)			sk->err = err;	}	read_unlock(&l->lock);}static void l2cap_chan_ready(struct sock *sk){	struct sock *parent = bluez_pi(sk)->parent;	BT_DBG("sk %p, parent %p", sk, parent);	l2cap_pi(sk)->conf_state = 0;	l2cap_sock_clear_timer(sk);	if (!parent) {		/* Outgoing channel.		 * Wake up socket sleeping on connect.		 */		sk->state = BT_CONNECTED;		sk->state_change(sk);	} else {		/* Incomming channel.		 * Wake up socket sleeping on accept.		 */		parent->data_ready(parent, 0);	}}/* Copy frame to all raw sockets on that connection */void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb){	struct l2cap_chan_list *l = &conn->chan_list;	struct sk_buff *nskb;	struct sock * sk;	BT_DBG("conn %p", conn);	read_lock(&l->lock);	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {		if (sk->type != SOCK_RAW)			continue;		/* Don't send frame to the socket it came from */		if (skb->sk == sk)			continue;		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))			continue;		if (sock_queue_rcv_skb(sk, nskb))			kfree_skb(nskb);	}	read_unlock(&l->lock);}static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len){	struct l2cap_conn *conn = l2cap_pi(sk)->conn;	struct sk_buff *skb, **frag;	int err, hlen, count, sent=0;	l2cap_hdr *lh;	BT_DBG("sk %p len %d", sk, len);	/* First fragment (with L2CAP header) */	if (sk->type == SOCK_DGRAM)		hlen = L2CAP_HDR_SIZE + 2;	else		hlen = L2CAP_HDR_SIZE;	count = MIN(conn->mtu - hlen, len);	skb = bluez_skb_send_alloc(sk, hlen + count,			msg->msg_flags & MSG_DONTWAIT, &err);	if (!skb)		return err;	/* Create L2CAP header */	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));	if (sk->type == SOCK_DGRAM)		put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {		err = -EFAULT;		goto fail;	}	sent += count;	len  -= count;	/* Continuation fragments (no L2CAP header) */	frag = &skb_shinfo(skb)->frag_list;	while (len) {		count = MIN(conn->mtu, len);		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);		if (!*frag)			goto fail;				if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {			err = -EFAULT;			goto fail;		}		sent += count;		len  -= count;		frag = &(*frag)->next;	}	if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)		goto fail;	return sent;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -