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

📄 sock.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		goto done;	}	if (sk->sk_type != SOCK_STREAM) {		err = -EINVAL;		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 (!(nsk = 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", nsk);done:	release_sock(sk);	return err;}static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer){	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;	struct sock *sk = sock->sk;	BT_DBG("sock %p, sk %p", sock, sk);	sa->rc_family  = AF_BLUETOOTH;	sa->rc_channel = rfcomm_pi(sk)->channel;	if (peer)		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->dst);	else		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->src);	*len = sizeof(struct sockaddr_rc);	return 0;}static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,			       struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;	struct sk_buff *skb;	int err;	int sent = 0;	if (msg->msg_flags & MSG_OOB)		return -EOPNOTSUPP;	if (sk->sk_shutdown & SEND_SHUTDOWN)		return -EPIPE;	BT_DBG("sock %p, sk %p", sock, sk);	lock_sock(sk);	while (len) {		size_t size = min_t(size_t, len, d->mtu);				skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,				msg->msg_flags & MSG_DONTWAIT, &err);		if (!skb)			break;		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);		if (err) {			kfree_skb(skb);			sent = err;			break;		}		err = rfcomm_dlc_send(d, skb);		if (err < 0) {			kfree_skb(skb);			break;		}		sent += size;		len  -= size;	}	release_sock(sk);	return sent ? sent : err;}static long rfcomm_sock_data_wait(struct sock *sk, long timeo){	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(sk->sk_sleep, &wait);	for (;;) {		set_current_state(TASK_INTERRUPTIBLE);		if (!skb_queue_empty(&sk->sk_receive_queue) ||		    sk->sk_err ||		    (sk->sk_shutdown & RCV_SHUTDOWN) ||		    signal_pending(current) ||		    !timeo)			break;		set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);		release_sock(sk);		timeo = schedule_timeout(timeo);		lock_sock(sk);		clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(sk->sk_sleep, &wait);	return timeo;}static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,			       struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	int err = 0;	size_t target, copied = 0;	long timeo;	if (flags & MSG_OOB)		return -EOPNOTSUPP;	msg->msg_namelen = 0;	BT_DBG("sk %p size %d", sk, size);	lock_sock(sk);	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);	do {		struct sk_buff *skb;		int chunk;		skb = skb_dequeue(&sk->sk_receive_queue);		if (!skb) {			if (copied >= target)				break;			if ((err = sock_error(sk)) != 0)				break;			if (sk->sk_shutdown & RCV_SHUTDOWN)				break;			err = -EAGAIN;			if (!timeo)				break;			timeo = rfcomm_sock_data_wait(sk, timeo);			if (signal_pending(current)) {				err = sock_intr_errno(timeo);				goto out;			}			continue;		}		chunk = min_t(unsigned int, skb->len, size);		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {			skb_queue_head(&sk->sk_receive_queue, skb);			if (!copied)				copied = -EFAULT;			break;		}		copied += chunk;		size   -= chunk;		if (!(flags & MSG_PEEK)) {			atomic_sub(chunk, &sk->sk_rmem_alloc);			skb_pull(skb, chunk);			if (skb->len) {				skb_queue_head(&sk->sk_receive_queue, skb);				break;			}			kfree_skb(skb);		} else {			/* put message back and return */			skb_queue_head(&sk->sk_receive_queue, skb);			break;		}	} while (size);out:	if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);	release_sock(sk);	return copied ? : err;}static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen){	struct sock *sk = sock->sk;	int err = 0;	u32 opt;	BT_DBG("sk %p", sk);	lock_sock(sk);	switch (optname) {	case RFCOMM_LM:		if (get_user(opt, (u32 __user *) optval)) {			err = -EFAULT;			break;		}		rfcomm_pi(sk)->link_mode = opt;		break;	default:		err = -ENOPROTOOPT;		break;	}	release_sock(sk);	return err;}static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	struct sock *l2cap_sk;	struct rfcomm_conninfo cinfo;	int len, err = 0;	BT_DBG("sk %p", sk);	if (get_user(len, optlen))		return -EFAULT;	lock_sock(sk);	switch (optname) {	case RFCOMM_LM:		if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))			err = -EFAULT;		break;	case RFCOMM_CONNINFO:		if (sk->sk_state != BT_CONNECTED) {			err = -ENOTCONN;			break;		}		l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;		cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;		memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);		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 rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	int err;	lock_sock(sk);#ifdef CONFIG_BT_RFCOMM_TTY	err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg);#else	err = -EOPNOTSUPP;#endif	release_sock(sk);	return err;}static int rfcomm_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->sk_shutdown) {		sk->sk_shutdown = SHUTDOWN_MASK;		__rfcomm_sock_close(sk);		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)			err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);	}	release_sock(sk);	return err;}static int rfcomm_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 = rfcomm_sock_shutdown(sock, 2);	sock_orphan(sk);	rfcomm_sock_kill(sk);	return err;}/* ---- RFCOMM core layer callbacks ----  * * called under rfcomm_lock() */int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d){	struct sock *sk, *parent;	bdaddr_t src, dst;	int result = 0;	BT_DBG("session %p channel %d", s, channel);	rfcomm_session_getaddr(s, &src, &dst);	/* Check if we have socket listening on channel */	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);	if (!parent)		return 0;	/* Check for backlog size */	if (sk_acceptq_is_full(parent)) {		BT_DBG("backlog full %d", parent->sk_ack_backlog); 		goto done;	}	sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);	if (!sk)		goto done;	rfcomm_sock_init(sk, parent);	bacpy(&bt_sk(sk)->src, &src);	bacpy(&bt_sk(sk)->dst, &dst);	rfcomm_pi(sk)->channel = channel;	sk->sk_state = BT_CONFIG;	bt_accept_enqueue(parent, sk);	/* Accept connection and return socket DLC */	*d = rfcomm_pi(sk)->dlc;	result = 1;done:	bh_unlock_sock(parent);	return result;}static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf){	struct sock *sk;	struct hlist_node *node;	char *str = buf;	read_lock_bh(&rfcomm_sk_list.lock);	sk_for_each(sk, node, &rfcomm_sk_list.head) {		str += sprintf(str, "%s %s %d %d\n",				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),				sk->sk_state, rfcomm_pi(sk)->channel);	}	read_unlock_bh(&rfcomm_sk_list.lock);	return (str - buf);}static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);static struct proto_ops rfcomm_sock_ops = {	.family		= PF_BLUETOOTH,	.owner		= THIS_MODULE,	.release	= rfcomm_sock_release,	.bind		= rfcomm_sock_bind,	.connect	= rfcomm_sock_connect,	.listen		= rfcomm_sock_listen,	.accept		= rfcomm_sock_accept,	.getname	= rfcomm_sock_getname,	.sendmsg	= rfcomm_sock_sendmsg,	.recvmsg	= rfcomm_sock_recvmsg,	.shutdown	= rfcomm_sock_shutdown,	.setsockopt	= rfcomm_sock_setsockopt,	.getsockopt	= rfcomm_sock_getsockopt,	.ioctl		= rfcomm_sock_ioctl,	.poll		= bt_sock_poll,	.socketpair	= sock_no_socketpair,	.mmap		= sock_no_mmap};static struct net_proto_family rfcomm_sock_family_ops = {	.family		= PF_BLUETOOTH,	.owner		= THIS_MODULE,	.create		= rfcomm_sock_create};int __init rfcomm_init_sockets(void){	int err;	err = proto_register(&rfcomm_proto, 0);	if (err < 0)		return err;	err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);	if (err < 0)		goto error;	class_create_file(&bt_class, &class_attr_rfcomm);	BT_INFO("RFCOMM socket layer initialized");	return 0;error:	BT_ERR("RFCOMM socket layer registration failed");	proto_unregister(&rfcomm_proto);	return err;}void __exit rfcomm_cleanup_sockets(void){	class_remove_file(&bt_class, &class_attr_rfcomm);	if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)		BT_ERR("RFCOMM socket layer unregistration failed");	proto_unregister(&rfcomm_proto);}

⌨️ 快捷键说明

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