lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening PHC | |
Open Source and information security mailing list archives
| ||
|
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