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

📄 sco.c

📁 Linux嵌入式平台蓝牙协议栈软件
💻 C
📖 第 1 页 / 共 2 页
字号:
static 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->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {		err = -EBADFD;		goto done;	}	sk->sk_max_ack_backlog = backlog;	sk->sk_ack_backlog = 0;	sk->sk_state = BT_LISTEN;done:	release_sock(sk);	return err;}static 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->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->sk_sleep, &wait);	while (!(ch = bt_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->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->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, &bt_sk(sk)->dst);	else		bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);	return 0;}static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, 			    struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	int err = 0;	BT_DBG("sock %p, sk %p", sock, sk);	if (sk->sk_err)		return sock_error(sk);	if (msg->msg_flags & MSG_OOB)		return -EOPNOTSUPP;	lock_sock(sk);	if (sk->sk_state == BT_CONNECTED)		err = sco_send_frame(sk, msg, len);	else		err = -ENOTCONN;	release_sock(sk);	return err;}static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *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;}static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *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->sk_state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}		opts.mtu = sco_pi(sk)->conn->mtu;		BT_DBG("mtu %d", opts.mtu);		len = min_t(unsigned int, len, sizeof(opts));		if (copy_to_user(optval, (char *)&opts, len))			err = -EFAULT;		break;	case SCO_CONNINFO:		if (sk->sk_state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;		len = min_t(unsigned int, 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;	int err = 0;	BT_DBG("sock %p, sk %p", sock, sk);	if (!sk)		return 0;	sco_sock_close(sk);	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {		lock_sock(sk);		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);		release_sock(sk);	}	sock_orphan(sk);	sco_sock_kill(sk);	return err;}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)		bt_accept_enqueue(parent, 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->sk_state = BT_CLOSED;	sk->sk_err   = err;	sk->sk_state_change(sk);	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->sk_state = BT_CONNECTED;		sk->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(&bt_sk(sk)->src, conn->src);		bacpy(&bt_sk(sk)->dst, conn->dst);		hci_conn_hold(conn->hcon);		__sco_chan_add(conn, sk, parent);		sk->sk_state = BT_CONNECTED;		/* Wake up parent */		parent->sk_data_ready(parent, 1);		bh_unlock_sock(parent);	}done:	sco_conn_unlock(conn);}/* ----- SCO interface with lower layer (HCI) ----- */static 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;}static 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, bt_err(status));	return 0;}static 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, bt_err(reason));	return 0;}static 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 ---- */#ifdef CONFIG_PROC_FSstatic void *sco_seq_start(struct seq_file *seq, loff_t *pos){	struct sock *sk;	struct hlist_node *node;	loff_t l = *pos;	read_lock_bh(&sco_sk_list.lock);	sk_for_each(sk, node, &sco_sk_list.head)		if (!l--)			goto found;	sk = NULL;found:	return sk;}static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos){	struct sock *sk = e;	(*pos)++;	return sk_next(sk);}static void sco_seq_stop(struct seq_file *seq, void *e){	read_unlock_bh(&sco_sk_list.lock);}static int  sco_seq_show(struct seq_file *seq, void *e){	struct sock *sk = e;	seq_printf(seq, "%s %s %d\n",			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state);	return 0;}static struct seq_operations sco_seq_ops = {	.start	= sco_seq_start,	.next	= sco_seq_next,	.stop	= sco_seq_stop,	.show	= sco_seq_show };static int sco_seq_open(struct inode *inode, struct file *file){	return seq_open(file, &sco_seq_ops);}static struct file_operations sco_seq_fops = {	.owner		= THIS_MODULE,	.open		= sco_seq_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release,};static int __init sco_proc_init(void){	struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt);	if (!p)		return -ENOMEM;	p->owner     = THIS_MODULE;	p->proc_fops = &sco_seq_fops;	return 0;}static void __exit sco_proc_cleanup(void){	remove_proc_entry("sco", proc_bt);}#else /* CONFIG_PROC_FS */static int __init sco_proc_init(void){	return 0;}static void __exit sco_proc_cleanup(void){	return;}#endif /* CONFIG_PROC_FS */static struct proto_ops sco_sock_ops = {	.family		= PF_BLUETOOTH,	.owner		= THIS_MODULE,	.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	= bt_sock_recvmsg,	.poll		= bt_sock_poll,	.ioctl		= sock_no_ioctl,	.mmap		= sock_no_mmap,	.socketpair	= sock_no_socketpair,	.shutdown	= sock_no_shutdown,	.setsockopt	= sco_sock_setsockopt,	.getsockopt	= sco_sock_getsockopt};static struct net_proto_family sco_sock_family_ops = {	.family	= PF_BLUETOOTH,	.owner	= THIS_MODULE,	.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};static int __init sco_init(void){	int err;	if ((err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {		BT_ERR("SCO socket registration failed");		return err;	}	if ((err = hci_register_proto(&sco_hci_proto))) {		BT_ERR("SCO protocol registration failed");		return err;	}	sco_proc_init();	BT_INFO("SCO (Voice Link) ver %s", VERSION);	BT_INFO("SCO socket layer initialized");	return 0;}static void __exit sco_exit(void){	int err;	sco_proc_cleanup();	/* Unregister socket, protocol and notifier */	if ((err = bt_sock_unregister(BTPROTO_SCO)))		BT_ERR("SCO socket unregistration failed. %d", err);	if ((err = hci_unregister_proto(&sco_hci_proto)))		BT_ERR("SCO protocol unregistration failed. %d", err);}module_init(sco_init);module_exit(sco_exit);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);MODULE_VERSION(VERSION);MODULE_LICENSE("GPL");MODULE_ALIAS("bt-proto-2");

⌨️ 快捷键说明

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