/*
* Copyright (C) ST-Ericsson AB 2010
* Author: Sjur Brendeland sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/tcp.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/caif/caif_socket.h>
#include <asm/atomic.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/caif/caif_layer.h>
#include <net/caif/caif_dev.h>
#include <net/caif/cfpkt.h>
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(AF_CAIF);
#define CAIF_DEF_SNDBUF (4096*10)
#define CAIF_DEF_RCVBUF (4096*100)
/*
* CAIF state is re-using the TCP socket states.
* caif_states stored in sk_state reflect the state as reported by
* the CAIF stack, while sk_socket->state is the state of the socket.
*/
enum caif_states {
CAIF_CONNECTED = TCP_ESTABLISHED,
CAIF_CONNECTING = TCP_SYN_SENT,
CAIF_DISCONNECTED = TCP_CLOSE
};
#define TX_FLOW_ON_BIT 1
#define RX_FLOW_ON_BIT 2
static struct dentry *debugfsdir;
#ifdef CONFIG_DEBUG_FS
struct debug_fs_counter {
atomic_t caif_nr_socks;
atomic_t num_connect_req;
atomic_t num_connect_resp;
atomic_t num_connect_fail_resp;
atomic_t num_disconnect;
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;
};
static struct debug_fs_counter cnt;
#define dbfs_atomic_inc(v) atomic_inc(v)
#define dbfs_atomic_dec(v) atomic_dec(v)
#else
#define dbfs_atomic_inc(v)
#define dbfs_atomic_dec(v)
#endif
struct caifsock {
struct sock sk; /* must be first member */
struct cflayer layer;
char name[CAIF_LAYER_NAME_SZ]; /* Used for debugging */
u32 flow_state;
struct caif_connect_request conn_req;
struct mutex readlock;
struct dentry *debugfs_socket_dir;
int headroom, tailroom, maxframe;
};
static int rx_flow_is_on(struct caifsock *cf_sk)
{
return test_bit(RX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static int tx_flow_is_on(struct caifsock *cf_sk)
{
return test_bit(TX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static void set_rx_flow_off(struct caifsock *cf_sk)
{
clear_bit(RX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static void set_rx_flow_on(struct caifsock *cf_sk)
{
set_bit(RX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static void set_tx_flow_off(struct caifsock *cf_sk)
{
clear_bit(TX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static void set_tx_flow_on(struct caifsock *cf_sk)
{
set_bit(TX_FLOW_ON_BIT,
(void *) &cf_sk->flow_state);
}
static void caif_read_lock(struct sock *sk)
{
struct caifsock *cf_sk;
cf_sk =