Commit c7c64bca authored by David S. Miller's avatar David S. Miller

Merge branch 'qrtr-Fixes-and-support-receiving-version-2-packets'

Bjorn Andersson says:

====================
net: qrtr: Fixes and support receiving version 2 packets

On the latest Qualcomm platforms remote processors are sending packets with
version 2 of the message header. This series starts off with some fixes and
then refactors the qrtr code to support receiving messages of both version 1
and version 2.

As all remotes are backwards compatible transmitted packets continues to be
send as version 1, but some groundwork has been done to make this a per-link
property.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7822b083 194ccc88
...@@ -4,10 +4,45 @@ ...@@ -4,10 +4,45 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/types.h> #include <linux/types.h>
#define QRTR_NODE_BCAST 0xffffffffu
#define QRTR_PORT_CTRL 0xfffffffeu
struct sockaddr_qrtr { struct sockaddr_qrtr {
__kernel_sa_family_t sq_family; __kernel_sa_family_t sq_family;
__u32 sq_node; __u32 sq_node;
__u32 sq_port; __u32 sq_port;
}; };
enum qrtr_pkt_type {
QRTR_TYPE_DATA = 1,
QRTR_TYPE_HELLO = 2,
QRTR_TYPE_BYE = 3,
QRTR_TYPE_NEW_SERVER = 4,
QRTR_TYPE_DEL_SERVER = 5,
QRTR_TYPE_DEL_CLIENT = 6,
QRTR_TYPE_RESUME_TX = 7,
QRTR_TYPE_EXIT = 8,
QRTR_TYPE_PING = 9,
QRTR_TYPE_NEW_LOOKUP = 10,
QRTR_TYPE_DEL_LOOKUP = 11,
};
struct qrtr_ctrl_pkt {
__le32 cmd;
union {
struct {
__le32 service;
__le32 instance;
__le32 node;
__le32 port;
} server;
struct {
__le32 node;
__le32 port;
} client;
};
} __packed;
#endif /* _LINUX_QRTR_H */ #endif /* _LINUX_QRTR_H */
...@@ -20,26 +20,15 @@ ...@@ -20,26 +20,15 @@
#include "qrtr.h" #include "qrtr.h"
#define QRTR_PROTO_VER 1 #define QRTR_PROTO_VER_1 1
#define QRTR_PROTO_VER_2 3
/* auto-bind range */ /* auto-bind range */
#define QRTR_MIN_EPH_SOCKET 0x4000 #define QRTR_MIN_EPH_SOCKET 0x4000
#define QRTR_MAX_EPH_SOCKET 0x7fff #define QRTR_MAX_EPH_SOCKET 0x7fff
enum qrtr_pkt_type {
QRTR_TYPE_DATA = 1,
QRTR_TYPE_HELLO = 2,
QRTR_TYPE_BYE = 3,
QRTR_TYPE_NEW_SERVER = 4,
QRTR_TYPE_DEL_SERVER = 5,
QRTR_TYPE_DEL_CLIENT = 6,
QRTR_TYPE_RESUME_TX = 7,
QRTR_TYPE_EXIT = 8,
QRTR_TYPE_PING = 9,
};
/** /**
* struct qrtr_hdr - (I|R)PCrouter packet header * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1
* @version: protocol version * @version: protocol version
* @type: packet type; one of QRTR_TYPE_* * @type: packet type; one of QRTR_TYPE_*
* @src_node_id: source node * @src_node_id: source node
...@@ -49,7 +38,7 @@ enum qrtr_pkt_type { ...@@ -49,7 +38,7 @@ enum qrtr_pkt_type {
* @dst_node_id: destination node * @dst_node_id: destination node
* @dst_port_id: destination port * @dst_port_id: destination port
*/ */
struct qrtr_hdr { struct qrtr_hdr_v1 {
__le32 version; __le32 version;
__le32 type; __le32 type;
__le32 src_node_id; __le32 src_node_id;
...@@ -60,9 +49,44 @@ struct qrtr_hdr { ...@@ -60,9 +49,44 @@ struct qrtr_hdr {
__le32 dst_port_id; __le32 dst_port_id;
} __packed; } __packed;
#define QRTR_HDR_SIZE sizeof(struct qrtr_hdr) /**
#define QRTR_NODE_BCAST ((unsigned int)-1) * struct qrtr_hdr_v2 - (I|R)PCrouter packet header later versions
#define QRTR_PORT_CTRL ((unsigned int)-2) * @version: protocol version
* @type: packet type; one of QRTR_TYPE_*
* @flags: bitmask of QRTR_FLAGS_*
* @optlen: length of optional header data
* @size: length of packet, excluding this header and optlen
* @src_node_id: source node
* @src_port_id: source port
* @dst_node_id: destination node
* @dst_port_id: destination port
*/
struct qrtr_hdr_v2 {
u8 version;
u8 type;
u8 flags;
u8 optlen;
__le32 size;
__le16 src_node_id;
__le16 src_port_id;
__le16 dst_node_id;
__le16 dst_port_id;
};
#define QRTR_FLAGS_CONFIRM_RX BIT(0)
struct qrtr_cb {
u32 src_node;
u32 src_port;
u32 dst_node;
u32 dst_port;
u8 type;
u8 confirm_rx;
};
#define QRTR_HDR_MAX_SIZE max_t(size_t, sizeof(struct qrtr_hdr_v1), \
sizeof(struct qrtr_hdr_v2))
struct qrtr_sock { struct qrtr_sock {
/* WARNING: sk must be the first member */ /* WARNING: sk must be the first member */
...@@ -111,8 +135,12 @@ struct qrtr_node { ...@@ -111,8 +135,12 @@ struct qrtr_node {
struct list_head item; struct list_head item;
}; };
static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb); static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb); int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to);
static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to);
/* Release node resources and free the node. /* Release node resources and free the node.
* *
...@@ -150,10 +178,27 @@ static void qrtr_node_release(struct qrtr_node *node) ...@@ -150,10 +178,27 @@ static void qrtr_node_release(struct qrtr_node *node)
} }
/* Pass an outgoing packet socket buffer to the endpoint driver. */ /* Pass an outgoing packet socket buffer to the endpoint driver. */
static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb) static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to)
{ {
struct qrtr_hdr_v1 *hdr;
size_t len = skb->len;
int rc = -ENODEV; int rc = -ENODEV;
hdr = skb_push(skb, sizeof(*hdr));
hdr->version = cpu_to_le32(QRTR_PROTO_VER_1);
hdr->type = cpu_to_le32(type);
hdr->src_node_id = cpu_to_le32(from->sq_node);
hdr->src_port_id = cpu_to_le32(from->sq_port);
hdr->dst_node_id = cpu_to_le32(to->sq_node);
hdr->dst_port_id = cpu_to_le32(to->sq_port);
hdr->size = cpu_to_le32(len);
hdr->confirm_rx = 0;
skb_put_padto(skb, ALIGN(len, 4));
mutex_lock(&node->ep_lock); mutex_lock(&node->ep_lock);
if (node->ep) if (node->ep)
rc = node->ep->xmit(node->ep, skb); rc = node->ep->xmit(node->ep, skb);
...@@ -207,125 +252,103 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) ...@@ -207,125 +252,103 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
{ {
struct qrtr_node *node = ep->node; struct qrtr_node *node = ep->node;
const struct qrtr_hdr *phdr = data; const struct qrtr_hdr_v1 *v1;
const struct qrtr_hdr_v2 *v2;
struct sk_buff *skb; struct sk_buff *skb;
unsigned int psize; struct qrtr_cb *cb;
unsigned int size; unsigned int size;
unsigned int type;
unsigned int ver; unsigned int ver;
unsigned int dst; size_t hdrlen;
if (len < QRTR_HDR_SIZE || len & 3)
return -EINVAL;
ver = le32_to_cpu(phdr->version);
size = le32_to_cpu(phdr->size);
type = le32_to_cpu(phdr->type);
dst = le32_to_cpu(phdr->dst_port_id);
psize = (size + 3) & ~3;
if (ver != QRTR_PROTO_VER) if (len & 3)
return -EINVAL;
if (len != psize + QRTR_HDR_SIZE)
return -EINVAL;
if (dst != QRTR_PORT_CTRL && type != QRTR_TYPE_DATA)
return -EINVAL; return -EINVAL;
skb = netdev_alloc_skb(NULL, len); skb = netdev_alloc_skb(NULL, len);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
skb_reset_transport_header(skb); cb = (struct qrtr_cb *)skb->cb;
skb_put_data(skb, data, len);
skb_queue_tail(&node->rx_queue, skb);
schedule_work(&node->work);
return 0;
}
EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
static struct sk_buff *qrtr_alloc_ctrl_packet(u32 type, size_t pkt_len, /* Version field in v1 is little endian, so this works for both cases */
u32 src_node, u32 dst_node) ver = *(u8*)data;
{
struct qrtr_hdr *hdr;
struct sk_buff *skb;
skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
if (!skb)
return NULL;
skb_reset_transport_header(skb);
hdr = skb_put(skb, QRTR_HDR_SIZE); switch (ver) {
hdr->version = cpu_to_le32(QRTR_PROTO_VER); case QRTR_PROTO_VER_1:
hdr->type = cpu_to_le32(type); v1 = data;
hdr->src_node_id = cpu_to_le32(src_node); hdrlen = sizeof(*v1);
hdr->src_port_id = cpu_to_le32(QRTR_PORT_CTRL);
hdr->confirm_rx = cpu_to_le32(0);
hdr->size = cpu_to_le32(pkt_len);
hdr->dst_node_id = cpu_to_le32(dst_node);
hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
return skb; cb->type = le32_to_cpu(v1->type);
} cb->src_node = le32_to_cpu(v1->src_node_id);
cb->src_port = le32_to_cpu(v1->src_port_id);
cb->confirm_rx = !!v1->confirm_rx;
cb->dst_node = le32_to_cpu(v1->dst_node_id);
cb->dst_port = le32_to_cpu(v1->dst_port_id);
/* Allocate and construct a resume-tx packet. */ size = le32_to_cpu(v1->size);
static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node, break;
u32 dst_node, u32 port) case QRTR_PROTO_VER_2:
{ v2 = data;
const int pkt_len = 20; hdrlen = sizeof(*v2) + v2->optlen;
struct sk_buff *skb;
__le32 *buf; cb->type = v2->type;
cb->confirm_rx = !!(v2->flags & QRTR_FLAGS_CONFIRM_RX);
cb->src_node = le16_to_cpu(v2->src_node_id);
cb->src_port = le16_to_cpu(v2->src_port_id);
cb->dst_node = le16_to_cpu(v2->dst_node_id);
cb->dst_port = le16_to_cpu(v2->dst_port_id);
if (cb->src_port == (u16)QRTR_PORT_CTRL)
cb->src_port = QRTR_PORT_CTRL;
if (cb->dst_port == (u16)QRTR_PORT_CTRL)
cb->dst_port = QRTR_PORT_CTRL;
size = le32_to_cpu(v2->size);
break;
default:
pr_err("qrtr: Invalid version %d\n", ver);
goto err;
}
skb = qrtr_alloc_ctrl_packet(QRTR_TYPE_RESUME_TX, pkt_len, if (len != ALIGN(size, 4) + hdrlen)
src_node, dst_node); goto err;
if (!skb)
return NULL;
buf = skb_put_zero(skb, pkt_len); if (cb->dst_port != QRTR_PORT_CTRL && cb->type != QRTR_TYPE_DATA)
buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX); goto err;
buf[1] = cpu_to_le32(src_node);
buf[2] = cpu_to_le32(port);
return skb; skb_put_data(skb, data + hdrlen, size);
}
/* Allocate and construct a BYE message to signal remote termination */ skb_queue_tail(&node->rx_queue, skb);
static struct sk_buff *qrtr_alloc_local_bye(u32 src_node) schedule_work(&node->work);
{
const int pkt_len = 20;
struct sk_buff *skb;
__le32 *buf;
skb = qrtr_alloc_ctrl_packet(QRTR_TYPE_BYE, pkt_len, return 0;
src_node, qrtr_local_nid);
if (!skb)
return NULL;
buf = skb_put_zero(skb, pkt_len); err:
buf[0] = cpu_to_le32(QRTR_TYPE_BYE); kfree_skb(skb);
return -EINVAL;
return skb;
} }
EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
static struct sk_buff *qrtr_alloc_del_client(struct sockaddr_qrtr *sq) /**
* qrtr_alloc_ctrl_packet() - allocate control packet skb
* @pkt: reference to qrtr_ctrl_pkt pointer
*
* Returns newly allocated sk_buff, or NULL on failure
*
* This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and
* on success returns a reference to the control packet in @pkt.
*/
static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
{ {
const int pkt_len = 20; const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
struct sk_buff *skb; struct sk_buff *skb;
__le32 *buf;
skb = qrtr_alloc_ctrl_packet(QRTR_TYPE_DEL_CLIENT, pkt_len, skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL);
sq->sq_node, QRTR_NODE_BCAST);
if (!skb) if (!skb)
return NULL; return NULL;
buf = skb_put_zero(skb, pkt_len); skb_reserve(skb, QRTR_HDR_MAX_SIZE);
buf[0] = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); *pkt = skb_put_zero(skb, pkt_len);
buf[1] = cpu_to_le32(sq->sq_node);
buf[2] = cpu_to_le32(sq->sq_port);
return skb; return skb;
} }
...@@ -340,24 +363,26 @@ static void qrtr_port_put(struct qrtr_sock *ipc); ...@@ -340,24 +363,26 @@ static void qrtr_port_put(struct qrtr_sock *ipc);
static void qrtr_node_rx_work(struct work_struct *work) static void qrtr_node_rx_work(struct work_struct *work)
{ {
struct qrtr_node *node = container_of(work, struct qrtr_node, work); struct qrtr_node *node = container_of(work, struct qrtr_node, work);
struct qrtr_ctrl_pkt *pkt;
struct sockaddr_qrtr dst;
struct sockaddr_qrtr src;
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue(&node->rx_queue)) != NULL) { while ((skb = skb_dequeue(&node->rx_queue)) != NULL) {
const struct qrtr_hdr *phdr;
u32 dst_node, dst_port;
struct qrtr_sock *ipc; struct qrtr_sock *ipc;
u32 src_node; struct qrtr_cb *cb;
int confirm; int confirm;
phdr = (const struct qrtr_hdr *)skb_transport_header(skb); cb = (struct qrtr_cb *)skb->cb;
src_node = le32_to_cpu(phdr->src_node_id); src.sq_node = cb->src_node;
dst_node = le32_to_cpu(phdr->dst_node_id); src.sq_port = cb->src_port;
dst_port = le32_to_cpu(phdr->dst_port_id); dst.sq_node = cb->dst_node;
confirm = !!phdr->confirm_rx; dst.sq_port = cb->dst_port;
confirm = !!cb->confirm_rx;
qrtr_node_assign(node, src_node); qrtr_node_assign(node, cb->src_node);
ipc = qrtr_port_lookup(dst_port); ipc = qrtr_port_lookup(cb->dst_port);
if (!ipc) { if (!ipc) {
kfree_skb(skb); kfree_skb(skb);
} else { } else {
...@@ -368,10 +393,16 @@ static void qrtr_node_rx_work(struct work_struct *work) ...@@ -368,10 +393,16 @@ static void qrtr_node_rx_work(struct work_struct *work)
} }
if (confirm) { if (confirm) {
skb = qrtr_alloc_resume_tx(dst_node, node->nid, dst_port); skb = qrtr_alloc_ctrl_packet(&pkt);
if (!skb) if (!skb)
break; break;
if (qrtr_node_enqueue(node, skb))
pkt->cmd = cpu_to_le32(QRTR_TYPE_RESUME_TX);
pkt->client.node = cpu_to_le32(dst.sq_node);
pkt->client.port = cpu_to_le32(dst.sq_port);
if (qrtr_node_enqueue(node, skb, QRTR_TYPE_RESUME_TX,
&dst, &src))
break; break;
} }
} }
...@@ -421,6 +452,9 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_register); ...@@ -421,6 +452,9 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_register);
void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
{ {
struct qrtr_node *node = ep->node; struct qrtr_node *node = ep->node;
struct sockaddr_qrtr src = {AF_QIPCRTR, node->nid, QRTR_PORT_CTRL};
struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL};
struct qrtr_ctrl_pkt *pkt;
struct sk_buff *skb; struct sk_buff *skb;
mutex_lock(&node->ep_lock); mutex_lock(&node->ep_lock);
...@@ -428,9 +462,11 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) ...@@ -428,9 +462,11 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
mutex_unlock(&node->ep_lock); mutex_unlock(&node->ep_lock);
/* Notify the local controller about the event */ /* Notify the local controller about the event */
skb = qrtr_alloc_local_bye(node->nid); skb = qrtr_alloc_ctrl_packet(&pkt);
if (skb) if (skb) {
qrtr_local_enqueue(NULL, skb); pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
}
qrtr_node_release(node); qrtr_node_release(node);
ep->node = NULL; ep->node = NULL;
...@@ -466,13 +502,24 @@ static void qrtr_port_put(struct qrtr_sock *ipc) ...@@ -466,13 +502,24 @@ static void qrtr_port_put(struct qrtr_sock *ipc)
/* Remove port assignment. */ /* Remove port assignment. */
static void qrtr_port_remove(struct qrtr_sock *ipc) static void qrtr_port_remove(struct qrtr_sock *ipc)
{ {
struct qrtr_ctrl_pkt *pkt;
struct sk_buff *skb; struct sk_buff *skb;
int port = ipc->us.sq_port; int port = ipc->us.sq_port;
struct sockaddr_qrtr to;
skb = qrtr_alloc_del_client(&ipc->us); to.sq_family = AF_QIPCRTR;
to.sq_node = QRTR_NODE_BCAST;
to.sq_port = QRTR_PORT_CTRL;
skb = qrtr_alloc_ctrl_packet(&pkt);
if (skb) { if (skb) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
pkt->client.port = cpu_to_le32(ipc->us.sq_port);
skb_set_owner_w(skb, &ipc->sk); skb_set_owner_w(skb, &ipc->sk);
qrtr_bcast_enqueue(NULL, skb); qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us,
&to);
} }
if (port == QRTR_PORT_CTRL) if (port == QRTR_PORT_CTRL)
...@@ -541,7 +588,7 @@ static void qrtr_reset_ports(void) ...@@ -541,7 +588,7 @@ static void qrtr_reset_ports(void)
sock_hold(&ipc->sk); sock_hold(&ipc->sk);
ipc->sk.sk_err = ENETRESET; ipc->sk.sk_err = ENETRESET;
wake_up_interruptible(sk_sleep(&ipc->sk)); ipc->sk.sk_error_report(&ipc->sk);
sock_put(&ipc->sk); sock_put(&ipc->sk);
} }
mutex_unlock(&qrtr_port_lock); mutex_unlock(&qrtr_port_lock);
...@@ -620,19 +667,23 @@ static int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len) ...@@ -620,19 +667,23 @@ static int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len)
} }
/* Queue packet to local peer socket. */ /* Queue packet to local peer socket. */
static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb) static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to)
{ {
const struct qrtr_hdr *phdr;
struct qrtr_sock *ipc; struct qrtr_sock *ipc;
struct qrtr_cb *cb;
phdr = (const struct qrtr_hdr *)skb_transport_header(skb); ipc = qrtr_port_lookup(to->sq_port);
ipc = qrtr_port_lookup(le32_to_cpu(phdr->dst_port_id));
if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */ if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
kfree_skb(skb); kfree_skb(skb);
return -ENODEV; return -ENODEV;
} }
cb = (struct qrtr_cb *)skb->cb;
cb->src_node = from->sq_node;
cb->src_port = from->sq_port;
if (sock_queue_rcv_skb(&ipc->sk, skb)) { if (sock_queue_rcv_skb(&ipc->sk, skb)) {
qrtr_port_put(ipc); qrtr_port_put(ipc);
kfree_skb(skb); kfree_skb(skb);
...@@ -645,7 +696,9 @@ static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb) ...@@ -645,7 +696,9 @@ static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb)
} }
/* Queue packet for broadcast. */ /* Queue packet for broadcast. */
static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb) static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to)
{ {
struct sk_buff *skbn; struct sk_buff *skbn;
...@@ -655,11 +708,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb) ...@@ -655,11 +708,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb)
if (!skbn) if (!skbn)
break; break;
skb_set_owner_w(skbn, skb->sk); skb_set_owner_w(skbn, skb->sk);
qrtr_node_enqueue(node, skbn); qrtr_node_enqueue(node, skbn, type, from, to);
} }
mutex_unlock(&qrtr_node_lock); mutex_unlock(&qrtr_node_lock);
qrtr_local_enqueue(node, skb); qrtr_local_enqueue(node, skb, type, from, to);
return 0; return 0;
} }
...@@ -667,13 +720,14 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb) ...@@ -667,13 +720,14 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb)
static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
{ {
DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name); DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *); int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *, int,
struct sockaddr_qrtr *, struct sockaddr_qrtr *);
struct qrtr_sock *ipc = qrtr_sk(sock->sk); struct qrtr_sock *ipc = qrtr_sk(sock->sk);
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct qrtr_node *node; struct qrtr_node *node;
struct qrtr_hdr *hdr;
struct sk_buff *skb; struct sk_buff *skb;
size_t plen; size_t plen;
u32 type = QRTR_TYPE_DATA;
int rc; int rc;
if (msg->msg_flags & ~(MSG_DONTWAIT)) if (msg->msg_flags & ~(MSG_DONTWAIT))
...@@ -722,37 +776,19 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -722,37 +776,19 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
} }
plen = (len + 3) & ~3; plen = (len + 3) & ~3;
skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_SIZE, skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_MAX_SIZE,
msg->msg_flags & MSG_DONTWAIT, &rc); msg->msg_flags & MSG_DONTWAIT, &rc);
if (!skb) if (!skb)
goto out_node; goto out_node;
skb_reset_transport_header(skb); skb_reserve(skb, QRTR_HDR_MAX_SIZE);
skb_put(skb, len + QRTR_HDR_SIZE);
hdr = (struct qrtr_hdr *)skb_transport_header(skb);
hdr->version = cpu_to_le32(QRTR_PROTO_VER);
hdr->src_node_id = cpu_to_le32(ipc->us.sq_node);
hdr->src_port_id = cpu_to_le32(ipc->us.sq_port);
hdr->confirm_rx = cpu_to_le32(0);
hdr->size = cpu_to_le32(len);
hdr->dst_node_id = cpu_to_le32(addr->sq_node);
hdr->dst_port_id = cpu_to_le32(addr->sq_port);
rc = skb_copy_datagram_from_iter(skb, QRTR_HDR_SIZE, rc = memcpy_from_msg(skb_put(skb, len), msg, len);
&msg->msg_iter, len);
if (rc) { if (rc) {
kfree_skb(skb); kfree_skb(skb);
goto out_node; goto out_node;
} }
if (plen != len) {
rc = skb_pad(skb, plen - len);
if (rc)
goto out_node;
skb_put(skb, plen - len);
}
if (ipc->us.sq_port == QRTR_PORT_CTRL) { if (ipc->us.sq_port == QRTR_PORT_CTRL) {
if (len < 4) { if (len < 4) {
rc = -EINVAL; rc = -EINVAL;
...@@ -761,12 +797,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -761,12 +797,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
} }
/* control messages already require the type as 'command' */ /* control messages already require the type as 'command' */
skb_copy_bits(skb, QRTR_HDR_SIZE, &hdr->type, 4); skb_copy_bits(skb, 0, &type, 4);
} else { type = le32_to_cpu(type);
hdr->type = cpu_to_le32(QRTR_TYPE_DATA);
} }
rc = enqueue_fn(node, skb); rc = enqueue_fn(node, skb, type, &ipc->us, addr);
if (rc >= 0) if (rc >= 0)
rc = len; rc = len;
...@@ -781,9 +816,9 @@ static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -781,9 +816,9 @@ static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags) size_t size, int flags)
{ {
DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name); DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
const struct qrtr_hdr *phdr;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
struct qrtr_cb *cb;
int copied, rc; int copied, rc;
lock_sock(sk); lock_sock(sk);
...@@ -800,22 +835,22 @@ static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -800,22 +835,22 @@ static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg,
return rc; return rc;
} }
phdr = (const struct qrtr_hdr *)skb_transport_header(skb); copied = skb->len;
copied = le32_to_cpu(phdr->size);
if (copied > size) { if (copied > size) {
copied = size; copied = size;
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
} }
rc = skb_copy_datagram_msg(skb, QRTR_HDR_SIZE, msg, copied); rc = skb_copy_datagram_msg(skb, 0, msg, copied);
if (rc < 0) if (rc < 0)
goto out; goto out;
rc = copied; rc = copied;
if (addr) { if (addr) {
cb = (struct qrtr_cb *)skb->cb;
addr->sq_family = AF_QIPCRTR; addr->sq_family = AF_QIPCRTR;
addr->sq_node = le32_to_cpu(phdr->src_node_id); addr->sq_node = cb->src_node;
addr->sq_port = le32_to_cpu(phdr->src_port_id); addr->sq_port = cb->src_port;
msg->msg_namelen = sizeof(*addr); msg->msg_namelen = sizeof(*addr);
} }
...@@ -908,7 +943,7 @@ static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -908,7 +943,7 @@ static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case TIOCINQ: case TIOCINQ:
skb = skb_peek(&sk->sk_receive_queue); skb = skb_peek(&sk->sk_receive_queue);
if (skb) if (skb)
len = skb->len - QRTR_HDR_SIZE; len = skb->len;
rc = put_user(len, (int __user *)argp); rc = put_user(len, (int __user *)argp);
break; break;
case SIOCGIFADDR: case SIOCGIFADDR:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment