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

📄 sco.c

📁 linux下蓝牙
💻 C
📖 第 1 页 / 共 2 页
字号:
	if ((err = sco_connect(sk)))		goto done;	err = bluez_sock_w4_connect(sk, flags);done:	release_sock(sk);	return err;}int sco_sock_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	int err = 0;	BT_DBG("sk %p backlog %d", sk, backlog);	lock_sock(sk);	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {		err = -EBADFD;		goto done;	}	sk->max_ack_backlog = backlog;	sk->ack_backlog = 0;	sk->state = BT_LISTEN;done:	release_sock(sk);	return err;}int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags){	DECLARE_WAITQUEUE(wait, current);	struct sock *sk = sock->sk, *ch;	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 (!(ch = 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", ch);done:	release_sock(sk);	return err;}static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer){	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;	struct sock *sk = sock->sk;	BT_DBG("sock %p, sk %p", sock, sk);	addr->sa_family = AF_BLUETOOTH;	*len = sizeof(struct sockaddr_sco);	if (peer)		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);	else		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);	return 0;}static int sco_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;	lock_sock(sk);	if (sk->state == BT_CONNECTED)		err = sco_send_frame(sk, msg, len);	else		err = -ENOTCONN;	release_sock(sk);	return err;}int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen){	struct sock *sk = sock->sk;	int err = 0;	BT_DBG("sk %p", sk);	lock_sock(sk);	switch (optname) {	default:		err = -ENOPROTOOPT;		break;	};	release_sock(sk);	return err;}int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){	struct sock *sk = sock->sk;	struct sco_options opts;	struct sco_conninfo cinfo;	int len, err = 0; 	BT_DBG("sk %p", sk);	if (get_user(len, optlen))		return -EFAULT;	lock_sock(sk);	switch (optname) {	case SCO_OPTIONS:		if (sk->state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}				opts.mtu = sco_pi(sk)->conn->mtu;		BT_INFO("mtu %d", opts.mtu);		len = MIN(len, sizeof(opts));		if (copy_to_user(optval, (char *)&opts, len))			err = -EFAULT;		break;	case SCO_CONNINFO:		if (sk->state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}		cinfo.hci_handle = sco_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 sco_sock_release(struct socket *sock){	struct sock *sk = sock->sk;	BT_DBG("sock %p, sk %p", sock, sk);	if (!sk)		return 0;	sock_orphan(sk);	sco_sock_close(sk);	return 0;}static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent){	BT_DBG("conn %p", conn);	sco_pi(sk)->conn = conn;	conn->sk = sk;	if (parent)		bluez_accept_enqueue(parent, sk);}static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent){	int err = 0;	sco_conn_lock(conn);	if (conn->sk) {		err = -EBUSY;	} else {		__sco_chan_add(conn, sk, parent);	}	sco_conn_unlock(conn);	return err;}static inline struct sock * sco_chan_get(struct sco_conn *conn){	struct sock *sk = NULL;	sco_conn_lock(conn);	sk = conn->sk;	sco_conn_unlock(conn);	return sk;}/* Delete channel.  * Must be called on the locked socket. */static void sco_chan_del(struct sock *sk, int err){	struct sco_conn *conn;	conn = sco_pi(sk)->conn;	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);	if (conn) { 		sco_conn_lock(conn);		conn->sk = NULL;		sco_pi(sk)->conn = NULL;		sco_conn_unlock(conn);		hci_conn_put(conn->hcon);	}	sk->state = BT_CLOSED;	sk->err   = err;	sk->state_change(sk);	sk->zapped = 1;}static void sco_conn_ready(struct sco_conn *conn){	struct sock *parent, *sk;	BT_DBG("conn %p", conn);	sco_conn_lock(conn);	if ((sk = conn->sk)) {		sco_sock_clear_timer(sk);		bh_lock_sock(sk);		sk->state = BT_CONNECTED;		sk->state_change(sk);		bh_unlock_sock(sk);	} else {		parent = sco_get_sock_listen(conn->src);		if (!parent)			goto done;		bh_lock_sock(parent);		sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);		if (!sk) {			bh_unlock_sock(parent);                	goto done;		}		sco_sock_init(sk, parent);		bacpy(&bluez_pi(sk)->src, conn->src);		bacpy(&bluez_pi(sk)->dst, conn->dst);		hci_conn_hold(conn->hcon);        	__sco_chan_add(conn, sk, parent);        	sk->state = BT_CONNECTED;		/* Wake up parent */		parent->data_ready(parent, 1);	        	bh_unlock_sock(parent);	}done:	sco_conn_unlock(conn);}/* ----- SCO interface with lower layer (HCI) ----- */int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type){	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));	/* Always accept connection */	return HCI_LM_ACCEPT;}int sco_connect_cfm(struct hci_conn *hcon, __u8 status){	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);	if (hcon->type != SCO_LINK)		return 0;	if (!status) {		struct sco_conn *conn;		conn = sco_conn_add(hcon, status);		if (conn)			sco_conn_ready(conn);	} else 		sco_conn_del(hcon, bterr(status));		return 0;}int sco_disconn_ind(struct hci_conn *hcon, __u8 reason){	BT_DBG("hcon %p reason %d", hcon, reason);	if (hcon->type != SCO_LINK)		return 0;	sco_conn_del(hcon, bterr(reason));	return 0;}int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb){	struct sco_conn *conn = hcon->sco_data;	if (!conn)		goto drop;	BT_DBG("conn %p len %d", conn, skb->len);	if (skb->len) {		sco_recv_frame(conn, skb);		return 0;	}drop:	kfree_skb(skb);		return 0;}/* ----- Proc fs support ------ */static int sco_sock_dump(char *buf, struct bluez_sock_list *list){	struct sco_pinfo *pi;	struct sock *sk;	char *ptr = buf;	write_lock_bh(&list->lock);	for (sk = list->head; sk; sk = sk->next) {		pi = sco_pi(sk);		ptr += sprintf(ptr, "%s %s %d\n",				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),				sk->state); 	}	write_unlock_bh(&list->lock);	ptr += sprintf(ptr, "\n");	return ptr - buf;}static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv){	char *ptr = buf;	int len;	BT_DBG("count %d, offset %ld", count, offset);	ptr += sco_sock_dump(ptr, &sco_sk_list);	len  = ptr - buf;	if (len <= count + offset)		*eof = 1;	*start = buf + offset;	len -= offset;	if (len > count)		len = count;	if (len < 0)		len = 0;	return len;}static struct proto_ops sco_sock_ops = {	family:		PF_BLUETOOTH,	release:	sco_sock_release,	bind:		sco_sock_bind,	connect:	sco_sock_connect,	listen:		sco_sock_listen,	accept:		sco_sock_accept,	getname:	sco_sock_getname,	sendmsg:	sco_sock_sendmsg,	recvmsg:	bluez_sock_recvmsg,	poll:		bluez_sock_poll,	socketpair:	sock_no_socketpair,	ioctl:		sock_no_ioctl,	shutdown:	sock_no_shutdown,	setsockopt:	sco_sock_setsockopt,	getsockopt:	sco_sock_getsockopt,	mmap:		sock_no_mmap};static struct net_proto_family sco_sock_family_ops = {	family:		PF_BLUETOOTH,	create:		sco_sock_create};static struct hci_proto sco_hci_proto = {	name:		"SCO",	id:		HCI_PROTO_SCO,	connect_ind:	sco_connect_ind,	connect_cfm:	sco_connect_cfm,	disconn_ind:	sco_disconn_ind,	recv_scodata:	sco_recv_scodata,};int __init sco_init(void){	int err;	if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {		BT_ERR("Can't register SCO socket layer");		return err;	}	if ((err = hci_register_proto(&sco_hci_proto))) {		BT_ERR("Can't register SCO protocol");		return err;	}	create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);	BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");	return 0;}void sco_cleanup(void){	int err;	remove_proc_entry("bluetooth/sco", NULL);	/* Unregister socket, protocol and notifier */	if ((err = bluez_sock_unregister(BTPROTO_SCO)))		BT_ERR("Can't unregister SCO socket layer %d", err);	if ((err = hci_unregister_proto(&sco_hci_proto)))		BT_ERR("Can't unregister SCO protocol %d", err);}module_init(sco_init);module_exit(sco_cleanup);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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