summaryrefslogtreecommitdiffstats
path: root/net/qrtr
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2017-10-11 02:45:23 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-11 18:28:39 -0400
commit194ccc88297ae78d0803adad83c6dcc369787c9e (patch)
treec067940c5ffd99874b625013c724aad2fb69ca8a /net/qrtr
parentf507a9b6e63b9f41b61d199c36ae046d17b5fe4b (diff)
net: qrtr: Support decoding incoming v2 packets
Add the necessary logic for decoding incoming messages of version 2 as well. Also make sure there's room for the bigger of version 1 and 2 headers in the code allocating skbs for outgoing messages. Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/qrtr')
-rw-r--r--net/qrtr/qrtr.c132
1 files changed, 94 insertions, 38 deletions
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index 7bca6ec892a5..e458ece96d3d 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -20,14 +20,15 @@
20 20
21#include "qrtr.h" 21#include "qrtr.h"
22 22
23#define QRTR_PROTO_VER 1 23#define QRTR_PROTO_VER_1 1
24#define QRTR_PROTO_VER_2 3
24 25
25/* auto-bind range */ 26/* auto-bind range */
26#define QRTR_MIN_EPH_SOCKET 0x4000 27#define QRTR_MIN_EPH_SOCKET 0x4000
27#define QRTR_MAX_EPH_SOCKET 0x7fff 28#define QRTR_MAX_EPH_SOCKET 0x7fff
28 29
29/** 30/**
30 * struct qrtr_hdr - (I|R)PCrouter packet header 31 * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1
31 * @version: protocol version 32 * @version: protocol version
32 * @type: packet type; one of QRTR_TYPE_* 33 * @type: packet type; one of QRTR_TYPE_*
33 * @src_node_id: source node 34 * @src_node_id: source node
@@ -37,7 +38,7 @@
37 * @dst_node_id: destination node 38 * @dst_node_id: destination node
38 * @dst_port_id: destination port 39 * @dst_port_id: destination port
39 */ 40 */
40struct qrtr_hdr { 41struct qrtr_hdr_v1 {
41 __le32 version; 42 __le32 version;
42 __le32 type; 43 __le32 type;
43 __le32 src_node_id; 44 __le32 src_node_id;
@@ -48,6 +49,32 @@ struct qrtr_hdr {
48 __le32 dst_port_id; 49 __le32 dst_port_id;
49} __packed; 50} __packed;
50 51
52/**
53 * struct qrtr_hdr_v2 - (I|R)PCrouter packet header later versions
54 * @version: protocol version
55 * @type: packet type; one of QRTR_TYPE_*
56 * @flags: bitmask of QRTR_FLAGS_*
57 * @optlen: length of optional header data
58 * @size: length of packet, excluding this header and optlen
59 * @src_node_id: source node
60 * @src_port_id: source port
61 * @dst_node_id: destination node
62 * @dst_port_id: destination port
63 */
64struct qrtr_hdr_v2 {
65 u8 version;
66 u8 type;
67 u8 flags;
68 u8 optlen;
69 __le32 size;
70 __le16 src_node_id;
71 __le16 src_port_id;
72 __le16 dst_node_id;
73 __le16 dst_port_id;
74};
75
76#define QRTR_FLAGS_CONFIRM_RX BIT(0)
77
51struct qrtr_cb { 78struct qrtr_cb {
52 u32 src_node; 79 u32 src_node;
53 u32 src_port; 80 u32 src_port;
@@ -58,7 +85,8 @@ struct qrtr_cb {
58 u8 confirm_rx; 85 u8 confirm_rx;
59}; 86};
60 87
61#define QRTR_HDR_SIZE sizeof(struct qrtr_hdr) 88#define QRTR_HDR_MAX_SIZE max_t(size_t, sizeof(struct qrtr_hdr_v1), \
89 sizeof(struct qrtr_hdr_v2))
62 90
63struct qrtr_sock { 91struct qrtr_sock {
64 /* WARNING: sk must be the first member */ 92 /* WARNING: sk must be the first member */
@@ -154,12 +182,12 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
154 int type, struct sockaddr_qrtr *from, 182 int type, struct sockaddr_qrtr *from,
155 struct sockaddr_qrtr *to) 183 struct sockaddr_qrtr *to)
156{ 184{
157 struct qrtr_hdr *hdr; 185 struct qrtr_hdr_v1 *hdr;
158 size_t len = skb->len; 186 size_t len = skb->len;
159 int rc = -ENODEV; 187 int rc = -ENODEV;
160 188
161 hdr = skb_push(skb, QRTR_HDR_SIZE); 189 hdr = skb_push(skb, sizeof(*hdr));
162 hdr->version = cpu_to_le32(QRTR_PROTO_VER); 190 hdr->version = cpu_to_le32(QRTR_PROTO_VER_1);
163 hdr->type = cpu_to_le32(type); 191 hdr->type = cpu_to_le32(type);
164 hdr->src_node_id = cpu_to_le32(from->sq_node); 192 hdr->src_node_id = cpu_to_le32(from->sq_node);
165 hdr->src_port_id = cpu_to_le32(from->sq_port); 193 hdr->src_port_id = cpu_to_le32(from->sq_port);
@@ -224,52 +252,80 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
224int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) 252int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
225{ 253{
226 struct qrtr_node *node = ep->node; 254 struct qrtr_node *node = ep->node;
227 const struct qrtr_hdr *phdr = data; 255 const struct qrtr_hdr_v1 *v1;
256 const struct qrtr_hdr_v2 *v2;
228 struct sk_buff *skb; 257 struct sk_buff *skb;
229 struct qrtr_cb *cb; 258 struct qrtr_cb *cb;
230 unsigned int psize;
231 unsigned int size; 259 unsigned int size;
232 unsigned int type;
233 unsigned int ver; 260 unsigned int ver;
234 unsigned int dst; 261 size_t hdrlen;
235 262
236 if (len < QRTR_HDR_SIZE || len & 3) 263 if (len & 3)
237 return -EINVAL; 264 return -EINVAL;
238 265
239 ver = le32_to_cpu(phdr->version); 266 skb = netdev_alloc_skb(NULL, len);
240 size = le32_to_cpu(phdr->size); 267 if (!skb)
241 type = le32_to_cpu(phdr->type); 268 return -ENOMEM;
242 dst = le32_to_cpu(phdr->dst_port_id);
243 269
244 psize = (size + 3) & ~3; 270 cb = (struct qrtr_cb *)skb->cb;
245 271
246 if (ver != QRTR_PROTO_VER) 272 /* Version field in v1 is little endian, so this works for both cases */
247 return -EINVAL; 273 ver = *(u8*)data;
248 274
249 if (len != psize + QRTR_HDR_SIZE) 275 switch (ver) {
250 return -EINVAL; 276 case QRTR_PROTO_VER_1:
277 v1 = data;
278 hdrlen = sizeof(*v1);
251 279
252 if (dst != QRTR_PORT_CTRL && type != QRTR_TYPE_DATA) 280 cb->type = le32_to_cpu(v1->type);
253 return -EINVAL; 281 cb->src_node = le32_to_cpu(v1->src_node_id);
282 cb->src_port = le32_to_cpu(v1->src_port_id);
283 cb->confirm_rx = !!v1->confirm_rx;
284 cb->dst_node = le32_to_cpu(v1->dst_node_id);
285 cb->dst_port = le32_to_cpu(v1->dst_port_id);
254 286
255 skb = netdev_alloc_skb(NULL, len); 287 size = le32_to_cpu(v1->size);
256 if (!skb) 288 break;
257 return -ENOMEM; 289 case QRTR_PROTO_VER_2:
290 v2 = data;
291 hdrlen = sizeof(*v2) + v2->optlen;
292
293 cb->type = v2->type;
294 cb->confirm_rx = !!(v2->flags & QRTR_FLAGS_CONFIRM_RX);
295 cb->src_node = le16_to_cpu(v2->src_node_id);
296 cb->src_port = le16_to_cpu(v2->src_port_id);
297 cb->dst_node = le16_to_cpu(v2->dst_node_id);
298 cb->dst_port = le16_to_cpu(v2->dst_port_id);
299
300 if (cb->src_port == (u16)QRTR_PORT_CTRL)
301 cb->src_port = QRTR_PORT_CTRL;
302 if (cb->dst_port == (u16)QRTR_PORT_CTRL)
303 cb->dst_port = QRTR_PORT_CTRL;
304
305 size = le32_to_cpu(v2->size);
306 break;
307 default:
308 pr_err("qrtr: Invalid version %d\n", ver);
309 goto err;
310 }
258 311
259 cb = (struct qrtr_cb *)skb->cb; 312 if (len != ALIGN(size, 4) + hdrlen)
260 cb->src_node = le32_to_cpu(phdr->src_node_id); 313 goto err;
261 cb->src_port = le32_to_cpu(phdr->src_port_id);
262 cb->dst_node = le32_to_cpu(phdr->dst_node_id);
263 cb->dst_port = le32_to_cpu(phdr->dst_port_id);
264 cb->type = type;
265 cb->confirm_rx = !!phdr->confirm_rx;
266 314
267 skb_put_data(skb, data + QRTR_HDR_SIZE, size); 315 if (cb->dst_port != QRTR_PORT_CTRL && cb->type != QRTR_TYPE_DATA)
316 goto err;
317
318 skb_put_data(skb, data + hdrlen, size);
268 319
269 skb_queue_tail(&node->rx_queue, skb); 320 skb_queue_tail(&node->rx_queue, skb);
270 schedule_work(&node->work); 321 schedule_work(&node->work);
271 322
272 return 0; 323 return 0;
324
325err:
326 kfree_skb(skb);
327 return -EINVAL;
328
273} 329}
274EXPORT_SYMBOL_GPL(qrtr_endpoint_post); 330EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
275 331
@@ -287,11 +343,11 @@ static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
287 const int pkt_len = sizeof(struct qrtr_ctrl_pkt); 343 const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
288 struct sk_buff *skb; 344 struct sk_buff *skb;
289 345
290 skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL); 346 skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL);
291 if (!skb) 347 if (!skb)
292 return NULL; 348 return NULL;
293 349
294 skb_reserve(skb, QRTR_HDR_SIZE); 350 skb_reserve(skb, QRTR_HDR_MAX_SIZE);
295 *pkt = skb_put_zero(skb, pkt_len); 351 *pkt = skb_put_zero(skb, pkt_len);
296 352
297 return skb; 353 return skb;
@@ -720,12 +776,12 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
720 } 776 }
721 777
722 plen = (len + 3) & ~3; 778 plen = (len + 3) & ~3;
723 skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_SIZE, 779 skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_MAX_SIZE,
724 msg->msg_flags & MSG_DONTWAIT, &rc); 780 msg->msg_flags & MSG_DONTWAIT, &rc);
725 if (!skb) 781 if (!skb)
726 goto out_node; 782 goto out_node;
727 783
728 skb_reserve(skb, QRTR_HDR_SIZE); 784 skb_reserve(skb, QRTR_HDR_MAX_SIZE);
729 785
730 rc = memcpy_from_msg(skb_put(skb, len), msg, len); 786 rc = memcpy_from_msg(skb_put(skb, len), msg, len);
731 if (rc) { 787 if (rc) {