Commit | Line | Data |
---|---|---|
6c37f0e6 JL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | #include <linux/ceph/decode.h> | |
4 | ||
5 | static int | |
6 | ceph_decode_entity_addr_versioned(void **p, void *end, | |
7 | struct ceph_entity_addr *addr) | |
8 | { | |
9 | int ret; | |
10 | u8 struct_v; | |
11 | u32 struct_len, addr_len; | |
12 | void *struct_end; | |
13 | ||
14 | ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v, | |
15 | &struct_len); | |
16 | if (ret) | |
17 | goto bad; | |
18 | ||
19 | ret = -EINVAL; | |
20 | struct_end = *p + struct_len; | |
21 | ||
22 | ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad); | |
23 | ||
6c37f0e6 JL |
24 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
25 | ||
26 | ceph_decode_32_safe(p, end, addr_len, bad); | |
27 | if (addr_len > sizeof(addr->in_addr)) | |
28 | goto bad; | |
29 | ||
30 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
31 | if (addr_len) { | |
32 | ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad); | |
33 | ||
34 | addr->in_addr.ss_family = | |
35 | le16_to_cpu((__force __le16)addr->in_addr.ss_family); | |
36 | } | |
37 | ||
38 | /* Advance past anything the client doesn't yet understand */ | |
39 | *p = struct_end; | |
40 | ret = 0; | |
41 | bad: | |
42 | return ret; | |
43 | } | |
44 | ||
45 | static int | |
46 | ceph_decode_entity_addr_legacy(void **p, void *end, | |
47 | struct ceph_entity_addr *addr) | |
48 | { | |
49 | int ret = -EINVAL; | |
50 | ||
51 | /* Skip rest of type field */ | |
52 | ceph_decode_skip_n(p, end, 3, bad); | |
d3c3c0a8 JL |
53 | |
54 | /* | |
55 | * Clients that don't support ADDR2 always send TYPE_NONE, change it | |
56 | * to TYPE_LEGACY for forward compatibility. | |
57 | */ | |
58 | addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY; | |
6c37f0e6 JL |
59 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
60 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
61 | ceph_decode_copy_safe(p, end, &addr->in_addr, | |
62 | sizeof(addr->in_addr), bad); | |
63 | addr->in_addr.ss_family = | |
64 | be16_to_cpu((__force __be16)addr->in_addr.ss_family); | |
65 | ret = 0; | |
66 | bad: | |
67 | return ret; | |
68 | } | |
69 | ||
70 | int | |
71 | ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) | |
72 | { | |
73 | u8 marker; | |
74 | ||
75 | ceph_decode_8_safe(p, end, marker, bad); | |
76 | if (marker == 1) | |
77 | return ceph_decode_entity_addr_versioned(p, end, addr); | |
78 | else if (marker == 0) | |
79 | return ceph_decode_entity_addr_legacy(p, end, addr); | |
80 | bad: | |
81 | return -EINVAL; | |
82 | } | |
83 | EXPORT_SYMBOL(ceph_decode_entity_addr); | |
84 |