Thread (25 messages) 25 messages, 4 authors, 2009-12-16

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

From: Randy Dunlap <hidden>
Date: 2009-11-30 16:42:21

sjur.brandeland@stericsson.com wrote:
From: Sjur Braendeland <redacted>
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)
quoted hunk ↗ jump to hunk
Signed-off-by: Sjur Braendeland <redacted>
---
 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
quoted hunk ↗ jump to hunk
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 / Daniel.Martensson@stericsson.com
+ * 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.
quoted hunk ↗ jump to hunk
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 sjur.brandlenad@stericsson.com
+ *              Per Sigmond / Per.Sigmond@stericsson.com
+ * 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;
+}
+
quoted hunk ↗ jump to hunk
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 / Daniel.Martensson@stericsson.com
+ * 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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help