diff options
author | Bjorn Andersson <bjorn.andersson@linaro.org> | 2017-10-11 02:45:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-11 18:28:39 -0400 |
commit | 194ccc88297ae78d0803adad83c6dcc369787c9e (patch) | |
tree | c067940c5ffd99874b625013c724aad2fb69ca8a /net/qrtr | |
parent | f507a9b6e63b9f41b61d199c36ae046d17b5fe4b (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.c | 132 |
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 | */ |
40 | struct qrtr_hdr { | 41 | struct 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 | */ | ||
64 | struct 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 | |||
51 | struct qrtr_cb { | 78 | struct 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 | ||
63 | struct qrtr_sock { | 91 | struct 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) | |||
224 | int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) | 252 | int 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 | |||
325 | err: | ||
326 | kfree_skb(skb); | ||
327 | return -EINVAL; | ||
328 | |||
273 | } | 329 | } |
274 | EXPORT_SYMBOL_GPL(qrtr_endpoint_post); | 330 | EXPORT_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) { |