Subject: Re: [RFC PATCH v3 5/8] CAIF Protocol Stack

From: Randy Dunlap <[email-masked]>
Date: Mon, 30 Nov 2009 08:41:55 -0800

[email-masked] wrote:
> From: Sjur Braendeland <[email-masked]>

what Patrick said:
patch description should be here and each email subject should be different
and describe what that patch does.
Please read Documentation/SubmittingPatches.

(more below)

> Signed-off-by: Sjur Braendeland <[email-masked]>
> ---
>  net/caif/Kconfig            |   51 ++
>  net/caif/Makefile           |   51 ++
>  net/caif/caif_chnlif.c      |  205 ++++++
>  net/caif/caif_config_util.c |  163 +++++
>  net/caif/caif_dev.c         |  520 ++++++++++++++
>  net/caif/caif_socket.c      | 1560 +++++++++++++++++++++++++++++++++++++++++++
>  net/caif/chnl_net.c         |  655 ++++++++++++++++++
>  7 files changed, 3205 insertions(+), 0 deletions(-)
>  create mode 100644 net/caif/Kconfig
>  create mode 100644 net/caif/Makefile
>  create mode 100644 net/caif/caif_chnlif.c
>  create mode 100644 net/caif/caif_config_util.c
>  create mode 100644 net/caif/caif_dev.c
>  create mode 100644 net/caif/caif_socket.c
>  create mode 100644 net/caif/chnl_net.c
> 
> diff --git a/net/caif/Kconfig b/net/caif/Kconfig
> new file mode 100644
> index 0000000..9349123
> --- /dev/null
> +++ b/net/caif/Kconfig
> @@ -0,0 +1,51 @@
> +#
> +# CAIF net configurations
> +#
> +
> +#menu "CAIF Support"
> +comment "CAIF Support"
> +
> +menuconfig CAIF
> +	tristate "Enable CAIF support"
> +	default n
> +	---help---

Tell us what CAIF means, probably in the help text.

> +	Say Y here if you need to use a phone modem that uses CAIF as transport.
> +	You will also need to say yes to any CAIF physical devices that your platform
> +	supports.
> +	This can be either built-in or a loadable module; if you select to build it as module
> +	then the rest of CAIF also needs to built as modules.
> +	See Documentation/CAIF for a further explanation on how to use and configure.
> +
> +if CAIF
> +
> +config CAIF_NETDEV
> +	tristate "CAIF Network device"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF based network device.

	                           a (or any) CAIF-based

> +	This can be either built-in or a loadable module.
> +	If you select to build it as a built-in then the main CAIF device must also be a built-in.
> +	If unsure say Y.
> +
> +config CAIF_SOCK
> +	tristate "CAIF Sockets"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF Sockets.

	drop "the" ----------------^^^

> +	This can be either built-in or a loadable module.
> +	If you select to build it as a built-in then the main CAIF device mist also be a built-in.

s/mist/must/

> +	If unsure say Y.
> +
> +config  CAIF_DEBUG
> +	bool "Enable Debug"
> +	default n
> +	--- help ---
> +	Enable the inclusion of debug code in the CAIF stack.
> +	Be aware that doing this will impact performance.
> +	If unsure say N.
> +
> +
> +# Include physical drivers
> +source "drivers/net/caif/Kconfig"
> +endif
> +#endmenu

> diff --git a/net/caif/caif_chnlif.c b/net/caif/caif_chnlif.c
> new file mode 100644
> index 0000000..9c8a656
> --- /dev/null
> +++ b/net/caif/caif_chnlif.c
> @@ -0,0 +1,205 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Daniel Martensson / [email-masked]
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/skbuff.h>
> +#include <net/caif/caif_kernel.h>
> +#include <net/caif/generic/caif_layer.h>
> +#include <net/caif/caif_config_util.h>
> +#include <net/caif/caif_log.h>
> +#include <net/caif/generic/cfpkt.h>
> +#include <net/caif/generic/cfcnfg.h>
> +#include <net/caif/generic/cfglue.h>
> +#include <net/caif/caif_chr.h>
> +struct caif_kernelif {
> +	struct layer layer;
> +	struct caif_device *dev;
> +	struct cfctrl_link_param param;
> +};
> +
> +
> +/**
> + * func caif_create_skb - Creates a CAIF SKB buffer

Use documented/expected kernel-doc notation, please.  I.e., drop "func".

> + * @data:		data to add to buffer
> + * @data_length:	length of data
> + */
> +struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length)
> +{
> +	/* NOTE: Make room for CAIF headers when using SKB inside CAIF. */
> +	struct sk_buff *skb =
> +	    alloc_skb(data_length + CAIF_SKB_HEAD_RESERVE +
> +		      CAIF_SKB_TAIL_RESERVE, GFP_ATOMIC);
> +	if (skb == NULL)
> +		return NULL;
> +	skb_reserve(skb, CAIF_SKB_HEAD_RESERVE);
> +
> +	memcpy(skb_put(skb, data_length), data, data_length);
> +	return skb;
> +}
> +EXPORT_SYMBOL(caif_create_skb);
> +
...

> +
> +module_init(caif_device_init);
> +module_exit(caif_device_exit);
> +
> +
> +
> +
> +
> +
> +
> +
> +

delete all of those trailing empty lines.

> diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
> new file mode 100644
> index 0000000..492fcfb
> --- /dev/null
> +++ b/net/caif/caif_socket.c
> @@ -0,0 +1,1560 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Sjur BrÃ¦ndeland [email-masked]
> + *              Per Sigmond / [email-masked]
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#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 <asm/uaccess.h>
> +#include <asm/atomic.h>
> +
> +/* Caif header files. */
> +#include <linux/caif/caif_socket.h>
> +#include <net/caif/generic/caif_layer.h>
> +#include <linux/caif/caif_config.h>
> +#include <net/caif/caif_log.h>
> +#include <net/caif/caif_chr.h>
> +
> +MODULE_LICENSE("GPL");
> +
> +#define CHNL_SKT_READ_QUEUE_HIGH 2000
> +#define CHNL_SKT_READ_QUEUE_LOW 100
> +
> +#ifdef CAIF_USE_CACHE
> +int caif_max_links = 32;
> +#endif
> +
> +int caif_sockbuf_size = 40000; /* FIXME: Check this value! */
> +static struct kmem_cache *caif_sk_cachep;
> +static atomic_t caif_nr_socks = ATOMIC_INIT(0);
> +
> +#define CONN_STATE_OPEN_BIT           1
> +#define CONN_STATE_PENDING_BIT        2
> +#define CONN_STATE_PEND_DESTROY_BIT   3
> +#define CONN_REMOTE_SHUTDOWN_BIT      4
> +
> +#define TX_FLOW_ON_BIT                1
> +#define RX_FLOW_ON_BIT                2
> +
> +#define STATE_IS_OPEN(cf_sk) test_bit(CONN_STATE_OPEN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_REMOTE_SHUTDOWN(cf_sk) test_bit(CONN_REMOTE_SHUTDOWN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_PENDING(cf_sk) test_bit(CONN_STATE_PENDING_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_PENDING_DESTROY(cf_sk) test_bit(CONN_STATE_PEND_DESTROY_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +
> +#define SET_STATE_PENDING_DESTROY(cf_sk) set_bit(CONN_STATE_PEND_DESTROY_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_STATE_OPEN(cf_sk) set_bit(CONN_STATE_OPEN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_STATE_CLOSED(cf_sk) clear_bit(CONN_STATE_OPEN_BIT,\
> +					(void *) &(cf_sk)->conn_state)
> +#define SET_PENDING_ON(cf_sk) set_bit(CONN_STATE_PENDING_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_PENDING_OFF(cf_sk) clear_bit(CONN_STATE_PENDING_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +#define SET_REMOTE_SHUTDOWN(cf_sk) set_bit(CONN_REMOTE_SHUTDOWN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +
> +#define RX_FLOW_IS_ON(cf_sk) test_bit(RX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +#define TX_FLOW_IS_ON(cf_sk) test_bit(TX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +
> +#define SET_RX_FLOW_OFF(cf_sk) clear_bit(RX_FLOW_ON_BIT,\
> +				       (void *) &(cf_sk)->flow_state)
> +#define SET_RX_FLOW_ON(cf_sk) set_bit(RX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +#define SET_TX_FLOW_OFF(cf_sk) clear_bit(TX_FLOW_ON_BIT,\
> +				       (void *) &(cf_sk)->flow_state)
> +#define SET_TX_FLOW_ON(cf_sk) set_bit(TX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +
> +#define SKT_READ_FLAG 0x01
> +#define SKT_WRITE_FLAG 0x02
> +
> +#define MAX_CAIF_SOCKETS	200
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *debugfsdir;
> +#include <linux/debugfs.h>
> +
> +static int max_caif_sockets = MAX_CAIF_SOCKETS;
> +#endif
> +
> +/* The AF_CAIF socket */
> +struct caifsock {
> +	struct sock sk;		/* NOTE: sk has to be the first member */
> +	struct layer layer;
> +	char name[CAIF_LAYER_NAME_SZ];
> +	u32 conn_state;
> +	u32 flow_state;
> +	struct cfpktq *pktq;
> +	int file_mode;
> +	struct caif_channel_config config;
> +	int read_queue_len;
> +	spinlock_t read_queue_len_lock;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	struct dentry *debugfs_device_dir;
> +	atomic_t num_open;
> +	atomic_t num_close;
> +	atomic_t num_init;
> +	atomic_t num_init_resp;
> +	atomic_t num_init_fail_resp;
> +	atomic_t num_deinit;
> +	atomic_t num_deinit_resp;
> +	atomic_t num_remote_shutdown_ind;
> +	atomic_t num_tx_flow_off_ind;
> +	atomic_t num_tx_flow_on_ind;
> +	atomic_t num_rx_flow_off;
> +	atomic_t num_rx_flow_on;
> +#endif
> +};
> +
> +static void drain_queue(struct caifsock *cf_sk);
> +
> +/** Packet Receive Callback function called from CAIF Stack */

Do not use /** to begin comments that are not kernel-doc notation.
(more found below, but deleted for now)

> +static int caif_sktrecv_cb(struct layer *layr, struct cfpkt *pkt)
> +{

> +/* Send a signal as a consequence of sendmsg, sendto or caif_sendmsg. */
> +static int caif_sendmsg(struct kiocb *kiocb, struct socket *sock,
> +			struct msghdr *msg, size_t len)
> +{
> +
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
> +	void *payload;
> +	size_t payload_size = msg->msg_iov->iov_len;
> +	struct cfpkt *pkt = NULL;
> +	struct transmt_info info;
> +	unsigned char *txbuf;
> +	int err = 0;
> +	ssize_t ret = -EIO;
> +	int result;
> +	struct sk_buff *skb;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +	caif_assert(msg->msg_iovlen == 1);
> +
> +	if (cf_sk == NULL) {
> +		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
> +			      __func__, __LINE__);
> +		ret = -EBADFD;
> +		goto write_error_no_unlock;
> +	}
> +
> +	if (unlikely(msg->msg_iov->iov_base == NULL)) {
> +		CAIFLOG_WARN("Buffer is NULL.\n");
> +		ret = -EINVAL;
> +		goto write_error_no_unlock;
> +	}
> +
> +	payload = msg->msg_iov->iov_base;
> +	if (payload_size > CAIF_MAX_PAYLOAD_SIZE) {
> +		CAIFLOG_TRACE("[%s:%d] buffer too long\n", __func__, __LINE__);
> +		ret = -EINVAL;
> +		goto write_error_no_unlock;
> +	}
> +	/* I want to be alone on cf_sk (except status and queue) */
> +	lock_sock(&(cf_sk->sk));
> +
> +	caif_assert(cf_sk->pktq);
> +
> +	if (!STATE_IS_OPEN(cf_sk)) {
> +		/* Socket is closed or closing */
> +		if (!STATE_IS_PENDING(cf_sk)) {
> +			CAIFLOG_TRACE("socket is closed (by remote end)\n");
> +			ret = -EPIPE;
> +		} else {
> +			CAIFLOG_TRACE("socket is closing...\n");
> +			ret = -EBADF;
> +		}
> +		goto write_error;
> +	}
> +
> +	/* Socket is open or opening */
> +	if (STATE_IS_PENDING(cf_sk)) {
> +		CAIFLOG_TRACE("socket is opening...\n");
> +
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			/* We can't block */
> +			CAIFLOG_TRACE("state pending and MSG_DONTWAIT\n");
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* Let readers in */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Blocking mode; state is pending and we need to wait
> +		   for its conclusion */
> +		result =
> +		    wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					     !STATE_IS_PENDING(cf_sk));
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +		if (result == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +			    (" wait_event_interruptible woken by a signal (1)");
> +			ret = -ERESTARTSYS;
> +			goto write_error;
> +		}
> +	}
> +
> +	if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
> +		CAIFLOG_TRACE("received remote_shutdown indication\n");
> +		ret = -ESHUTDOWN;
> +		goto write_error;
> +	}
> +
> +	if (!TX_FLOW_IS_ON(cf_sk)) {
> +
> +		/* Flow is off. Check non-block flag */
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			CAIFLOG_TRACE
> +			("caif_sendmsg: MSG_DONTWAIT and tx flow off");
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* release lock before waiting */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Wait until flow is on or socket is closed */
> +		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					TX_FLOW_IS_ON(cf_sk)
> +					|| !STATE_IS_OPEN(cf_sk)
> +					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
> +					) == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +				("caif_sendmsg:"
> +				" wait_event_interruptible woken by a signal");
> +			ret = -ERESTARTSYS;
> +			goto write_error_no_unlock;
> +		}
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +		if (!STATE_IS_OPEN(cf_sk)) {
> +			/* someone closed the link, report error */
> +			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
> +				      __func__, __LINE__);
> +			ret = -EPIPE;
> +			goto write_error;
> +		}
> +
> +		if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
> +			CAIFLOG_TRACE("received remote_shutdown indication\n");
> +			ret = -ESHUTDOWN;
> +			goto write_error;
> +		}
> +	}
> +
> +	/* Create packet, buf=NULL means no copying */
> +	skb = caif_alloc_send_skb(sk,
> +				payload_size + CAIF_NEEDED_HEADROOM +
> +				CAIF_NEEDED_TAILROOM,
> +				&err);
> +	skb_reserve(skb, CAIF_NEEDED_HEADROOM);
> +	pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
> +	caif_assert((void *)pkt == (void *)skb);
> +
> +	if (pkt == NULL) {
> +		CAIFLOG_TRACE
> +			("caif_sendmsg: cfpkt_create_pkt returned NULL\n");
> +		ret = -EIO;
> +		goto write_error;
> +	}
> +
> +	if (!cfpkt_raw_append(pkt, (void **) &txbuf, payload_size)) {
> +		CAIFLOG_TRACE("caif_sendmsg: cfpkt_raw_append failed\n");
> +		cfpkt_destroy(pkt);
> +		ret = -EINVAL;
> +		goto write_error;
> +	}
> +
> +	/* Copy data into buffer. */
> +	if (copy_from_user(txbuf, payload, payload_size)) {
> +		CAIFLOG_TRACE
> +			("caif_sendmsg: copy_from_user returned non zero.\n");
> +		cfpkt_destroy(pkt);
> +		ret = -EINVAL;
> +		goto write_error;
> +	}
> +	memset(&info, 0, sizeof(info));
> +
> +	/* Send the packet down the stack. */
> +	caif_assert(cf_sk->layer.dn);
> +	caif_assert(cf_sk->layer.dn->transmit);
> +
> +	do {
> +			ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn,
> +							&info, pkt);

odd indentation?

> +		if (likely((ret >= 0) || (ret != -EAGAIN)))
> +			break;
> +
> +		/* EAGAIN - retry */
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			CAIFLOG_TRACE
> +			    ("NONBLOCK and transmit failed, error = %d\n",
> +			     ret);
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* Let readers in */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Wait until flow is on or socket is closed */
> +		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					TX_FLOW_IS_ON(cf_sk)
> +					|| !STATE_IS_OPEN(cf_sk)
> +					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
> +					) == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +			    ("wait_event_interruptible woken by a signal");
> +			ret = -ERESTARTSYS;
> +			goto write_error_no_unlock;
> +		}
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +	} while (ret == -EAGAIN);
> +
> +	if (ret < 0) {
> +		cfpkt_destroy(pkt);
> +		CAIFLOG_TRACE("transmit failed, error = %d\n",
> +			      ret);
> +
> +		goto write_error;
> +	}
> +
> +	release_sock(&cf_sk->sk);
> +	CAIFLOG_EXIT("");
> +	return payload_size;
> +
> +write_error:
> +	release_sock(&cf_sk->sk);
> +write_error_no_unlock:
> +	CAIFLOG_EXIT("");
> +	return ret;
> +}
> +

> +
> +static int setsockopt(struct socket *sock,
> +			int lvl, int opt, char __user *ov, int ol)
> +{
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
> +	struct caif_channel_opt confopt;
> +	int res;
> +
> +	if (lvl != SOL_CAIF) {
> +		CAIFLOG_TRACE("setsockopt bad level\n");
> +			return -ENOPROTOOPT;

odd indentation.

> +	}
> +
> +	switch (opt) {
> +	case CAIF_CHANNEL_OPT:
> +		if (ol < sizeof(struct caif_channel_opt)) {
> +			CAIFLOG_TRACE("setsockopt"
> +					" CAIF_CHANNEL_CONFIG bad size\n");
> +				return -EINVAL;

odd indentation.

> +		}
> +		res = copy_from_user(&confopt, ov, sizeof(confopt));
> +		if (res)
> +			return res;
> +		lock_sock(&(cf_sk->sk));
> +		cf_sk->config.priority = confopt.priority;
> +		cf_sk->config.phy_pref = confopt.link_selector;
> +		strncpy(cf_sk->config.phy_name, confopt.link_name,
> +			sizeof(cf_sk->config.phy_name));
> +		CAIFLOG_TRACE("Setting sockopt pri=%d pref=%d name=%s\n",
> +			      cf_sk->config.priority,
> +			      cf_sk->config.phy_pref,
> +			      cf_sk->config.phy_name);
> +		release_sock(&cf_sk->sk);
> +		return 0;
> +/* TODO: Implement the remaining options:
> + *	case CAIF_REQ_PARAM_OPT:
> + *	case CAIF_RSP_PARAM_OPT:
> + *	case CAIF_UTIL_FLOW_OPT:
> + *	case CAIF_CONN_INFO_OPT:
> + *	case CAIF_CONN_ID_OPT:
> + */
> +	default:
> +		CAIFLOG_TRACE("setsockopt: unhandled option %d\n",
> +			      opt);
> +		return -EINVAL;
> +	}
> +
> +
> +}

> +int caif_connect(struct socket *sock, struct sockaddr *uservaddr,
> +	       int sockaddr_len, int flags)
> +{
> +	struct caifsock *cf_sk = NULL;
> +	int result = -1;
> +	int mode = 0;
> +	int ret = -EIO;
> +    struct sock *sk = sock->sk;

indent above line with tab, not spaces.

> +
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +
> +	BUG_ON(sk == NULL);
> +
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	CAIFLOG_TRACE("cf_sk=%p OPEN=%d, TX_FLOW=%d, RX_FLOW=%d\n", cf_sk,
> +		      STATE_IS_OPEN(cf_sk),
> +		      TX_FLOW_IS_ON(cf_sk), RX_FLOW_IS_ON(cf_sk));
> +
> +	sk->sk_state    = TCP_CLOSE;
> +	sock->state     = SS_UNCONNECTED;
> +
> +	/* FIXME: SOCK_DGRAM should be removed? */
> +	if (sock->type == SOCK_DGRAM || sock->type == SOCK_SEQPACKET) {
> +		sock->state     = SS_CONNECTED;
> +		sk->sk_state    = TCP_ESTABLISHED;
> +	} else
> +		goto out;
> +
> +	/* I want to be alone on cf_sk (except status and queue) */
> +	lock_sock(&(cf_sk->sk));
> +
> +	ret = caif_channel_config(cf_sk, uservaddr, sockaddr_len,
> +				&cf_sk->config);
> +	if (ret) {
> +		CAIFLOG_TRACE
> +		    ("[%s:%d] Cannot set socket address\n",
> +		     __func__, __LINE__);
> +		goto open_error;
> +	}
> +
> +
> +#ifdef CONFIG_DEBUG_FS
> +	atomic_inc(&cf_sk->num_open);
> +#endif
> +	mode = SKT_READ_FLAG | SKT_WRITE_FLAG;
> +
> +	/* If socket is not open, make sure socket is in fully closed state */
> +	if (!STATE_IS_OPEN(cf_sk)) {
> +		/* Has link close response been received
> +		   (if we ever sent it)? */
> +		if (STATE_IS_PENDING(cf_sk)) {
> +			/* Still waiting for close response from remote.
> +			   If opened non-blocking, report "would block" */
> +			if (flags & MSG_DONTWAIT) {
> +				CAIFLOG_TRACE("MSG_DONTWAIT"
> +					" && close pending\n");
> +				ret = -EAGAIN;
> +				goto open_error;
> +			}
> +
> +			CAIFLOG_TRACE
> +			    ("wait for close response from remote...\n");
> +
> +			release_sock(&cf_sk->sk);
> +
> +			/* Blocking mode; close is pending and we need to wait
> +			   for its conclusion */
> +			result =
> +			    wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +						     !STATE_IS_PENDING(cf_sk));
> +
> +			lock_sock(&(cf_sk->sk));
> +			if (result == -ERESTARTSYS) {
> +				CAIFLOG_TRACE
> +				    ("wait_event_interruptible woken"
> +				     "by a signal (1)");
> +				ret = -ERESTARTSYS;
> +				goto open_error;
> +			}
> +		}
> +	}
...
> +}

> +
> +/* This function is called as part of close. */
> +static int caif_release(struct socket *sock)
> +{
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = NULL;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +
> +	caif_assert(sk != NULL);
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	caif_shutdown(sock, SHUT_RDWR);
> +	lock_sock(&(cf_sk->sk));
> +	/* NOTE: This is how the sock->sk structure is used all over the linux
> +	 *       socket implementation. Since there is no locking protecting
> +	 *       the sock->sk pointer, the linux socket implementation do not
> +	 *       support multiple threads using the same socket descriptor,
> +	 *       since if one of the threads close the socket, the other
> +	 *       threads may end up accessing a pointer to NULL. See for
> +	 *       instance sock_setsockopt in net/socket.c, it uses sock->sk
> +	 *       without checking if its value is NULL. */

	/*
	 * Note: This is the Linux long comment
	 * style.  Please use it.
	 */

> +	sock->sk = NULL;
> +
> +	/* Unlink the socket from the hunt name table. */
> +
> +
> +	/* Trigger the pending attachs from and to the socket.  This needs to
> +	 * be done before the socket starts to be released. */
> +
> +
> +	/* Remove pending new link requests. */
> +
> +	/* Detach the socket from its process context by making it orphan. */
> +	sock_orphan(sk);
> +
> +	/* Setting SHUTDOWN_MASK means that both send and receive are shutdown
> +	 * for the socket. */
> +	sk->sk_shutdown = SHUTDOWN_MASK;
> +
> +	/* Set the socket state to closed, the TCP_CLOSE macro is used when
> +	 * closing any socket. */
> +	sk->sk_state = TCP_CLOSE;
> +
> +	/* Flush out this sockets receive queue. */
> +	drain_queue(cf_sk);
> +
> +	/* Finally release the socket. */
> +	STATE_IS_PENDING_DESTROY(cf_sk);
> +	release_sock(&cf_sk->sk);
> +	sock_put(sk);
> +
> +	return 0;
> +
> +	/* The rest of the cleanup will be handled from the
> +	 * caif_sock_destructor */
> +}

> +/* This function is called when a socket is finally destructed. */

                                                       destroyed. */

> +static void caif_sock_destructor(struct sock *sk)
> +{
> +	struct caifsock *cf_sk = NULL;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	/* Error checks. */
> +	caif_assert(!atomic_read(&sk->sk_wmem_alloc));
> +	caif_assert(sk_unhashed(sk));
> +	caif_assert(!sk->sk_socket);
> +
> +	if (!sock_flag(sk, SOCK_DEAD)) {
> +		CAIFLOG_TRACE("Attempt to release alive caif socket: 0x%p", sk);
> +		return;
> +	}
> +
> +	lock_sock(&(cf_sk->sk));
> +
> +	if (STATE_IS_OPEN(cf_sk)) {
> +		CAIFLOG_TRACE
> +			("[%s:%d] socket is opened (cf_sk=%p)"
> +				" file_mode = 0x%x\n", __func__, __LINE__,
> +				cf_sk, cf_sk->file_mode);
> +		release_sock(&cf_sk->sk);
> +		return;
> +	}
> +
> +	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
> +	drain_queue(cf_sk);
> +	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
> +
> +	cfglu_free(cf_sk->pktq);
> +
> +#ifdef CONFIG_DEBUG_FS
> +	if (cf_sk->debugfs_device_dir != NULL)
> +		debugfs_remove_recursive(cf_sk->debugfs_device_dir);
> +#endif
> +
> +	release_sock(&cf_sk->sk);
> +	CAIFLOG_WARN("caif_sock_destructor: Removing socket %s\n",
> +		cf_sk->name);
> +	/* Decrease the global caif socket counter. */
> +	atomic_dec(&caif_nr_socks);
> +	return;
> +}
> +

> diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
> new file mode 100644
> index 0000000..fbc8a64
> --- /dev/null
> +++ b/net/caif/chnl_net.c
> @@ -0,0 +1,655 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Daniel Martensson / [email-masked]
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/version.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_ether.h>
> +#include <linux/moduleparam.h>
> +#include <linux/ip.h>
> +#include <linux/sched.h>
> +#include <linux/sockios.h>
> +
> +/* CAIF header files. */
> +#include <net/caif/generic/caif_layer.h>
> +#include <net/caif/generic/cfcnfg.h>
> +#include <net/caif/generic/cfpkt.h>
> +#include <net/caif/caif_chr.h>
> +#include <net/caif/caif_log.h>
> +
> +/*NetLink Header files*/
> +#include <net/rtnetlink.h>
> +#include <linux/caif/if_caif.h>
> +
> +#define CAIF_CONNECT_TIMEOUT 30
> +#define SIZE_MTU 1500
> +#define SIZE_MTU_MAX 4080
> +#define SIZE_MTU_MIN 68
> +
> +static LIST_HEAD(chnl_net_list);
> +static spinlock_t list_lock;
> +
> +MODULE_LICENSE("GPL");
> +
> +struct chnl_net {
> +	struct layer chnl;
> +	struct net_device_stats stats;
> +	spinlock_t lock;
> +	struct caif_channel_config config;
> +	struct list_head list_field;
> +	struct net_device *netdev;
> +	char name[256];
> +	wait_queue_head_t netmgmt_wq;
> +	/* Flow status to remember and control the transmission. */
> +	bool flowenabled;
> +};
> +
> +
> +static struct chnl_net *find_device(char *name, bool remove_from_list)
> +{
> +	struct list_head *list_node;
> +	struct list_head *n;
> +	struct chnl_net *dev = NULL;
> +	struct chnl_net *tmp;
> +	CAIFLOG_ENTER("");
> +	spin_lock(&list_lock);
> +	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__,
> +		__LINE__);
> +	list_for_each_safe(list_node, n, &chnl_net_list) {
> +		tmp =
> +			list_entry(list_node, struct chnl_net, list_field);

Above doesn't need to be on 2 lines.

> +		/* Find from name. */
> +		if (name) {
> +			if (!strncmp(tmp->name, name, sizeof(tmp->name)))
> +				dev = tmp;
> +		} else
> +			/* Get the first element if name is not specified. */
> +			dev = tmp;
> +		if (dev) {
> +			CAIFLOG_TRACE("[%s:%d] match %s \n",
> +				__func__, __LINE__,  name);
> +			if (remove_from_list)
> +				list_del(list_node);
> +			break;
> +		}
> +	}
> +	spin_unlock(&list_lock);
> +	return dev;
> +}

-- 
~Randy