summaryrefslogtreecommitdiffstats
path: root/net/caif/caif_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/caif/caif_socket.c')
-rw-r--r--net/caif/caif_socket.c89
1 files changed, 49 insertions, 40 deletions
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 3d0e09584fae..2eca2dd0000f 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -4,6 +4,8 @@
* 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>
@@ -15,7 +17,6 @@
#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>
@@ -28,9 +29,6 @@
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(AF_CAIF);
-#define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10)
-#define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100)
-
/*
* CAIF state is re-using the TCP socket states.
* caif_states stored in sk_state reflect the state as reported by
@@ -76,6 +74,7 @@ struct caifsock {
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)
@@ -156,9 +155,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
- trace_printk("CAIF: %s():"
- " sending flow OFF (queue len = %d %d)\n",
- __func__,
+ pr_debug("sending flow OFF (queue len = %d %d)\n",
atomic_read(&cf_sk->sk.sk_rmem_alloc),
sk_rcvbuf_lowwater(cf_sk));
set_rx_flow_off(cf_sk);
@@ -171,9 +168,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
set_rx_flow_off(cf_sk);
- trace_printk("CAIF: %s():"
- " sending flow OFF due to rmem_schedule\n",
- __func__);
+ pr_debug("sending flow OFF due to rmem_schedule\n");
dbfs_atomic_inc(&cnt.num_rx_flow_off);
caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
}
@@ -274,8 +269,7 @@ static void caif_ctrl_cb(struct cflayer *layr,
break;
default:
- pr_debug("CAIF: %s(): Unexpected flow command %d\n",
- __func__, flow);
+ pr_debug("Unexpected flow command %d\n", flow);
}
}
@@ -535,8 +529,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
/* Slight paranoia, probably not needed. */
if (unlikely(loopcnt++ > 1000)) {
- pr_warning("CAIF: %s(): transmit retries failed,"
- " error = %d\n", __func__, ret);
+ pr_warn("transmit retries failed, error = %d\n", ret);
break;
}
@@ -594,27 +587,32 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto err;
noblock = msg->msg_flags & MSG_DONTWAIT;
- buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM;
-
- ret = -EMSGSIZE;
- if (buffer_size > CAIF_MAX_PAYLOAD_SIZE)
- goto err;
-
timeo = sock_sndtimeo(sk, noblock);
timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
1, timeo, &ret);
+ if (ret)
+ goto err;
ret = -EPIPE;
if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
sock_flag(sk, SOCK_DEAD) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
goto err;
+ /* Error if trying to write more than maximum frame size. */
+ ret = -EMSGSIZE;
+ if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM)
+ goto err;
+
+ buffer_size = len + cf_sk->headroom + cf_sk->tailroom;
+
ret = -ENOMEM;
skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
- if (!skb)
+
+ if (!skb || skb_tailroom(skb) < buffer_size)
goto err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+
+ skb_reserve(skb, cf_sk->headroom);
ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
@@ -645,7 +643,6 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
long timeo;
err = -EOPNOTSUPP;
-
if (unlikely(msg->msg_flags&MSG_OOB))
goto out_err;
@@ -662,8 +659,8 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = len-sent;
- if (size > CAIF_MAX_PAYLOAD_SIZE)
- size = CAIF_MAX_PAYLOAD_SIZE;
+ if (size > cf_sk->maxframe)
+ size = cf_sk->maxframe;
/* If size is more than half of sndbuf, chop up message */
if (size > ((sk->sk_sndbuf >> 1) - 64))
@@ -673,14 +670,14 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = SKB_MAX_ALLOC;
skb = sock_alloc_send_skb(sk,
- size + CAIF_NEEDED_HEADROOM
- + CAIF_NEEDED_TAILROOM,
+ size + cf_sk->headroom +
+ cf_sk->tailroom,
msg->msg_flags&MSG_DONTWAIT,
&err);
if (skb == NULL)
goto out_err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+ skb_reserve(skb, cf_sk->headroom);
/*
* If you pass two values to the sock_alloc_send_skb
* it tries to grab the large buffer with GFP_NOFS
@@ -821,17 +818,16 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
long timeo;
int err;
+ int ifindex, headroom, tailroom;
+ unsigned int mtu;
+ struct net_device *dev;
+
lock_sock(sk);
err = -EAFNOSUPPORT;
if (uaddr->sa_family != AF_CAIF)
goto out;
- err = -ESOCKTNOSUPPORT;
- if (unlikely(!(sk->sk_type == SOCK_STREAM &&
- cf_sk->sk.sk_protocol == CAIFPROTO_AT) &&
- sk->sk_type != SOCK_SEQPACKET))
- goto out;
switch (sock->state) {
case SS_UNCONNECTED:
/* Normal case, a fresh connect */
@@ -874,8 +870,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sk_stream_kill_queues(&cf_sk->sk);
err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_caif) ||
- !uaddr)
+ if (addr_len != sizeof(struct sockaddr_caif))
goto out;
memcpy(&cf_sk->conn_req.sockaddr, uaddr,
@@ -888,13 +883,31 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
dbfs_atomic_inc(&cnt.num_connect_req);
cf_sk->layer.receive = caif_sktrecv_cb;
err = caif_connect_client(&cf_sk->conn_req,
- &cf_sk->layer);
+ &cf_sk->layer, &ifindex, &headroom, &tailroom);
if (err < 0) {
cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
cf_sk->sk.sk_state = CAIF_DISCONNECTED;
goto out;
}
+ err = -ENODEV;
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
+ if (!dev) {
+ rcu_read_unlock();
+ goto out;
+ }
+ cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
+ mtu = dev->mtu;
+ rcu_read_unlock();
+
+ cf_sk->tailroom = tailroom;
+ cf_sk->maxframe = mtu - (headroom + tailroom);
+ if (cf_sk->maxframe < 1) {
+ pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+ goto out;
+ }
+
err = -EINPROGRESS;
wait_connect:
@@ -1110,10 +1123,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
/* Store the protocol */
sk->sk_protocol = (unsigned char) protocol;
- /* Sendbuf dictates the amount of outbound packets not yet sent */
- sk->sk_sndbuf = CAIF_DEF_SNDBUF;
- sk->sk_rcvbuf = CAIF_DEF_RCVBUF;
-
/*
* Lock in order to try to stop someone from opening the socket
* too early.