[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4B13F5D3.6090009@oracle.com>
Date: Mon, 30 Nov 2009 08:41:55 -0800
From: Randy Dunlap <randy.dunlap@...cle.com>
To: sjur.brandeland@...ricsson.com
CC: netdev@...r.kernel.org, stefano.babic@...ic.homelinux.org,
kim.xx.lilliestierna@...ricsson.com,
christian.bejram@...ricsson.com, daniel.martensson@...ricsson.com
Subject: Re: [RFC PATCH v3 5/8] CAIF Protocol Stack
sjur.brandeland@...ricsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@...ricsson.com>
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 <sjur.brandeland@...ricsson.com>
> ---
> 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 / Daniel.Martensson@...ricsson.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.
> 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@...ricsson.com
> + * Per Sigmond / Per.Sigmond@...ricsson.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;
> +}
> +
> 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@...ricsson.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
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists