1120 lines · 26.7 KB · C
RawDownload
/* * Copyright (C) ST-Ericsson AB 2010 * Author:	Sjur Brendeland * License terms: GNU General Public License (GPL) version 2 */ #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ #include <linux/fs.h>#include <linux/init.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <linux/mutex.h>#include <linux/list.h>#include <linux/wait.h>#include <linux/poll.h>#include <linux/tcp.h>#include <linux/uaccess.h>#include <linux/debugfs.h>#include <linux/caif/caif_socket.h>#include <linux/pkt_sched.h>#include <net/sock.h>#include <net/tcp_states.h>#include <net/caif/caif_layer.h>#include <net/caif/caif_dev.h>#include <net/caif/cfpkt.h> MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(AF_CAIF); /* * CAIF state is re-using the TCP socket states. * caif_states stored in sk_state reflect the state as reported by * the CAIF stack, while sk_socket->state is the state of the socket. */enum caif_states {	CAIF_CONNECTED		= TCP_ESTABLISHED,	CAIF_CONNECTING	= TCP_SYN_SENT,	CAIF_DISCONNECTED	= TCP_CLOSE}; #define TX_FLOW_ON_BIT	1#define RX_FLOW_ON_BIT	2 struct caifsock {	struct sock sk; /* must be first member */	struct cflayer layer;	u32 flow_state;	struct caif_connect_request conn_req;	struct mutex readlock;	struct dentry *debugfs_socket_dir;	int headroom, tailroom, maxframe;}; static int rx_flow_is_on(struct caifsock *cf_sk){	return test_bit(RX_FLOW_ON_BIT,			(void *) &cf_sk->flow_state);} static int tx_flow_is_on(struct caifsock *cf_sk){	return test_bit(TX_FLOW_ON_BIT,			(void *) &cf_sk->flow_state);} static void set_rx_flow_off(struct caifsock *cf_sk){	 clear_bit(RX_FLOW_ON_BIT,		 (void *) &cf_sk->flow_state);} static void set_rx_flow_on(struct caifsock *cf_sk){	 set_bit(RX_FLOW_ON_BIT,			(void *) &cf_sk->flow_state);} static void set_tx_flow_off(struct caifsock *cf_sk){	 clear_bit(TX_FLOW_ON_BIT,		(void *) &cf_sk->flow_state);} static void set_tx_flow_on(struct caifsock *cf_sk){	 set_bit(TX_FLOW_ON_BIT,		(void *) &cf_sk->flow_state);} static void caif_read_lock(struct sock *sk){	struct caifsock *cf_sk;	cf_sk = container_of(sk, struct caifsock, sk);	mutex_lock(&cf_sk->readlock);} static void caif_read_unlock(struct sock *sk){	struct caifsock *cf_sk;	cf_sk = container_of(sk, struct caifsock, sk);	mutex_unlock(&cf_sk->readlock);} static int sk_rcvbuf_lowwater(struct caifsock *cf_sk){	/* A quarter of full buffer is used a low water mark */	return cf_sk->sk.sk_rcvbuf / 4;} static void caif_flow_ctrl(struct sock *sk, int mode){	struct caifsock *cf_sk;	cf_sk = container_of(sk, struct caifsock, sk);	if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd)		cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode);} /* * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are * not dropped, but CAIF is sending flow off instead. */static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb){	int err;	int skb_len;	unsigned long flags;	struct sk_buff_head *list = &sk->sk_receive_queue;	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); 	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=		(unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {		net_dbg_ratelimited("sending flow OFF (queue len = %d %d)\n",				    atomic_read(&cf_sk->sk.sk_rmem_alloc),				    sk_rcvbuf_lowwater(cf_sk));		set_rx_flow_off(cf_sk);		caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);	} 	err = sk_filter(sk, skb);	if (err)		return err;	if (!sk_rmem_schedule(sk, skb, skb->truesize) && rx_flow_is_on(cf_sk)) {		set_rx_flow_off(cf_sk);		net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n");		caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);	}	skb->dev = NULL;	skb_set_owner_r(skb, sk);	/* Cache the SKB length before we tack it onto the receive	 * queue. Once it is added it no longer belongs to us and	 * may be freed by other threads of control pulling packets	 * from the queue.	 */	skb_len = skb->len;	spin_lock_irqsave(&list->lock, flags);	if (!sock_flag(sk, SOCK_DEAD))		__skb_queue_tail(list, skb);	spin_unlock_irqrestore(&list->lock, flags); 	if (!sock_flag(sk, SOCK_DEAD))		sk->sk_data_ready(sk, skb_len);	else		kfree_skb(skb);	return 0;} /* Packet Receive Callback function called from CAIF Stack */static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt){	struct caifsock *cf_sk;	struct sk_buff *skb; 	cf_sk = container_of(layr, struct caifsock, layer);	skb = cfpkt_tonative(pkt); 	if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) {		kfree_skb(skb);		return 0;	}	caif_queue_rcv_skb(&cf_sk->sk, skb);	return 0;} static void cfsk_hold(struct cflayer *layr){	struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);	sock_hold(&cf_sk->sk);} static void cfsk_put(struct cflayer *layr){	struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);	sock_put(&cf_sk->sk);} /* Packet Control Callback function called from CAIF */static void caif_ctrl_cb(struct cflayer *layr,			 enum caif_ctrlcmd flow,			 int phyid){	struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);	switch (flow) {	case CAIF_CTRLCMD_FLOW_ON_IND:		/* OK from modem to start sending again */		set_tx_flow_on(cf_sk);		cf_sk->sk.sk_state_change(&cf_sk->sk);		break; 	case CAIF_CTRLCMD_FLOW_OFF_IND:		/* Modem asks us to shut up */		set_tx_flow_off(cf_sk);		cf_sk->sk.sk_state_change(&cf_sk->sk);		break; 	case CAIF_CTRLCMD_INIT_RSP:		/* We're now connected */		caif_client_register_refcnt(&cf_sk->layer,						cfsk_hold, cfsk_put);		cf_sk->sk.sk_state = CAIF_CONNECTED;		set_tx_flow_on(cf_sk);		cf_sk->sk.sk_shutdown = 0;		cf_sk->sk.sk_state_change(&cf_sk->sk);		break; 	case CAIF_CTRLCMD_DEINIT_RSP:		/* We're now disconnected */		cf_sk->sk.sk_state = CAIF_DISCONNECTED;		cf_sk->sk.sk_state_change(&cf_sk->sk);		break; 	case CAIF_CTRLCMD_INIT_FAIL_RSP:		/* Connect request failed */		cf_sk->sk.sk_err = ECONNREFUSED;		cf_sk->sk.sk_state = CAIF_DISCONNECTED;		cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;		/*		 * Socket "standards" seems to require POLLOUT to		 * be set at connect failure.		 */		set_tx_flow_on(cf_sk);		cf_sk->sk.sk_state_change(&cf_sk->sk);		break; 	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:		/* Modem has closed this connection, or device is down. */		cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;		cf_sk->sk.sk_err = ECONNRESET;		set_rx_flow_on(cf_sk);		cf_sk->sk.sk_error_report(&cf_sk->sk);		break; 	default:		pr_debug("Unexpected flow command %d\n", flow);	}} static void caif_check_flow_release(struct sock *sk){	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); 	if (rx_flow_is_on(cf_sk))		return; 	if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) {			set_rx_flow_on(cf_sk);			caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ);	}} /* * Copied from unix_dgram_recvmsg, but removed credit checks, * changed locking, address handling and added MSG_TRUNC. */static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,			       struct msghdr *m, size_t len, int flags) {	struct sock *sk = sock->sk;	struct sk_buff *skb;	int ret;	int copylen; 	ret = -EOPNOTSUPP;	if (m->msg_flags&MSG_OOB)		goto read_error; 	skb = skb_recv_datagram(sk, flags, 0 , &ret);	if (!skb)		goto read_error;	copylen = skb->len;	if (len < copylen) {		m->msg_flags |= MSG_TRUNC;		copylen = len;	} 	ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, copylen);	if (ret)		goto out_free; 	ret = (flags & MSG_TRUNC) ? skb->len : copylen;out_free:	skb_free_datagram(sk, skb);	caif_check_flow_release(sk);	return ret; read_error:	return ret;}  /* Copied from unix_stream_wait_data, identical except for lock call. */static long caif_stream_data_wait(struct sock *sk, long timeo){	DEFINE_WAIT(wait);	lock_sock(sk); 	for (;;) {		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 		if (!skb_queue_empty(&sk->sk_receive_queue) ||			sk->sk_err ||			sk->sk_state != CAIF_CONNECTED ||			sock_flag(sk, SOCK_DEAD) ||			(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);	} 	finish_wait(sk_sleep(sk), &wait);	release_sock(sk);	return timeo;}  /* * Copied from unix_stream_recvmsg, but removed credit checks, * changed locking calls, changed address handling. */static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,			       struct msghdr *msg, size_t size,			       int flags){	struct sock *sk = sock->sk;	int copied = 0;	int target;	int err = 0;	long timeo; 	err = -EOPNOTSUPP;	if (flags&MSG_OOB)		goto out; 	/*	 * Lock the socket to prevent queue disordering	 * while sleeps in memcpy_tomsg	 */	err = -EAGAIN;	if (sk->sk_state == CAIF_CONNECTING)		goto out; 	caif_read_lock(sk);	target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);	timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT); 	do {		int chunk;		struct sk_buff *skb; 		lock_sock(sk);		skb = skb_dequeue(&sk->sk_receive_queue);		caif_check_flow_release(sk); 		if (skb == NULL) {			if (copied >= target)				goto unlock;			/*			 *	POSIX 1003.1g mandates this order.			 */			err = sock_error(sk);			if (err)				goto unlock;			err = -ECONNRESET;			if (sk->sk_shutdown & RCV_SHUTDOWN)				goto unlock; 			err = -EPIPE;			if (sk->sk_state != CAIF_CONNECTED)				goto unlock;			if (sock_flag(sk, SOCK_DEAD))				goto unlock; 			release_sock(sk); 			err = -EAGAIN;			if (!timeo)				break; 			caif_read_unlock(sk); 			timeo = caif_stream_data_wait(sk, timeo); 			if (signal_pending(current)) {				err = sock_intr_errno(timeo);				goto out;			}			caif_read_lock(sk);			continue;unlock:			release_sock(sk);			break;		}		release_sock(sk);		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 == 0)				copied = -EFAULT;			break;		}		copied += chunk;		size -= chunk; 		/* Mark read part of skb as used */		if (!(flags & MSG_PEEK)) {			skb_pull(skb, chunk); 			/* put the skb back if we didn't use it up. */			if (skb->len) {				skb_queue_head(&sk->sk_receive_queue, skb);				break;			}			kfree_skb(skb); 		} else {			/*			 * It is questionable, see note in unix_dgram_recvmsg.			 */			/* put message back and return */			skb_queue_head(&sk->sk_receive_queue, skb);			break;		}	} while (size);	caif_read_unlock(sk); out:	return copied ? : err;} /* * Copied from sock.c:sock_wait_for_wmem, but change to wait for * CAIF flow-on and sock_writable. */static long caif_wait_for_flow_on(struct caifsock *cf_sk,				  int wait_writeable, long timeo, int *err){	struct sock *sk = &cf_sk->sk;	DEFINE_WAIT(wait);	for (;;) {		*err = 0;		if (tx_flow_is_on(cf_sk) &&			(!wait_writeable || sock_writeable(&cf_sk->sk)))			break;		*err = -ETIMEDOUT;		if (!timeo)			break;		*err = -ERESTARTSYS;		if (signal_pending(current))			break;		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);		*err = -ECONNRESET;		if (sk->sk_shutdown & SHUTDOWN_MASK)			break;		*err = -sk->sk_err;		if (sk->sk_err)			break;		*err = -EPIPE;		if (cf_sk->sk.sk_state != CAIF_CONNECTED)			break;		timeo = schedule_timeout(timeo);	}	finish_wait(sk_sleep(sk), &wait);	return timeo;} /* * Transmit a SKB. The device may temporarily request re-transmission * by returning EAGAIN. */static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,			int noblock, long timeo){

Lines 1–500 of 1120.