/*
* 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/debugfs.h>
#include <linux/caif/caif_socket.h>
#include <linux/pkt_sched.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);
/*
* 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
struct caifsock {
struct sock sk; /* must be first member */
struct cflayer layer;
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 = container_of(sk, struct caifsock, sk);
mutex_lock(&cf_sk->readlock);
}
static void caif_read_unlock(struct sock *sk)
{
struct caifsock *cf_sk;
cf_sk = container_of(sk, struct caifsock, sk);
mutex_unlock(&cf_sk->readlock);
}
static int sk_rcvbuf_lowwater(struct caifsock *cf_sk)
{
/* A quarter of full buffer is used a low water mark */
return cf_sk->sk.sk_rcvbuf / 4;
}
static void caif_flow_ctrl(struct sock *sk, int mode)
{
struct caifsock *cf_sk;
cf_sk = container_of(sk, struct caifsock, sk);
if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd)
cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode);
}
/*
* Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
* not dropped, but CAIF is sending flow off instead.
*/
static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int err;
int skb_len;
unsigned long flags;
struct sk_buff_head *list = &sk->sk_receive_queue;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
if (atomic_read(&sk->sk_rmem_alloc)