Commit | Line | Data |
---|---|---|
6c37f0e6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
a5cbd5fc | 2 | #include <linux/ceph/ceph_debug.h> |
6c37f0e6 JL |
3 | |
4 | #include <linux/ceph/decode.h> | |
5 | ||
6 | static int | |
7 | ceph_decode_entity_addr_versioned(void **p, void *end, | |
8 | struct ceph_entity_addr *addr) | |
9 | { | |
10 | int ret; | |
11 | u8 struct_v; | |
12 | u32 struct_len, addr_len; | |
13 | void *struct_end; | |
14 | ||
15 | ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v, | |
16 | &struct_len); | |
17 | if (ret) | |
18 | goto bad; | |
19 | ||
20 | ret = -EINVAL; | |
21 | struct_end = *p + struct_len; | |
22 | ||
23 | ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad); | |
24 | ||
6c37f0e6 JL |
25 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
26 | ||
27 | ceph_decode_32_safe(p, end, addr_len, bad); | |
28 | if (addr_len > sizeof(addr->in_addr)) | |
29 | goto bad; | |
30 | ||
31 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
32 | if (addr_len) { | |
33 | ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad); | |
34 | ||
35 | addr->in_addr.ss_family = | |
36 | le16_to_cpu((__force __le16)addr->in_addr.ss_family); | |
37 | } | |
38 | ||
39 | /* Advance past anything the client doesn't yet understand */ | |
40 | *p = struct_end; | |
41 | ret = 0; | |
42 | bad: | |
43 | return ret; | |
44 | } | |
45 | ||
46 | static int | |
47 | ceph_decode_entity_addr_legacy(void **p, void *end, | |
48 | struct ceph_entity_addr *addr) | |
49 | { | |
50 | int ret = -EINVAL; | |
51 | ||
52 | /* Skip rest of type field */ | |
53 | ceph_decode_skip_n(p, end, 3, bad); | |
d3c3c0a8 JL |
54 | |
55 | /* | |
56 | * Clients that don't support ADDR2 always send TYPE_NONE, change it | |
57 | * to TYPE_LEGACY for forward compatibility. | |
58 | */ | |
59 | addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY; | |
6c37f0e6 JL |
60 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
61 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
62 | ceph_decode_copy_safe(p, end, &addr->in_addr, | |
63 | sizeof(addr->in_addr), bad); | |
64 | addr->in_addr.ss_family = | |
65 | be16_to_cpu((__force __be16)addr->in_addr.ss_family); | |
66 | ret = 0; | |
67 | bad: | |
68 | return ret; | |
69 | } | |
70 | ||
71 | int | |
72 | ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) | |
73 | { | |
74 | u8 marker; | |
75 | ||
76 | ceph_decode_8_safe(p, end, marker, bad); | |
77 | if (marker == 1) | |
78 | return ceph_decode_entity_addr_versioned(p, end, addr); | |
79 | else if (marker == 0) | |
80 | return ceph_decode_entity_addr_legacy(p, end, addr); | |
81 | bad: | |
82 | return -EINVAL; | |
83 | } | |
84 | EXPORT_SYMBOL(ceph_decode_entity_addr); | |
85 | ||
a5cbd5fc ID |
86 | /* |
87 | * Return addr of desired type (MSGR2 or LEGACY) or error. | |
88 | * Make sure there is only one match. | |
89 | * | |
90 | * Assume encoding with MSG_ADDR2. | |
91 | */ | |
92 | int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2, | |
93 | struct ceph_entity_addr *addr) | |
94 | { | |
95 | __le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 : | |
96 | CEPH_ENTITY_ADDR_TYPE_LEGACY; | |
97 | struct ceph_entity_addr tmp_addr; | |
98 | int addr_cnt; | |
99 | bool found; | |
100 | u8 marker; | |
101 | int ret; | |
102 | int i; | |
103 | ||
104 | ceph_decode_8_safe(p, end, marker, e_inval); | |
105 | if (marker != 2) { | |
106 | pr_err("bad addrvec marker %d\n", marker); | |
107 | return -EINVAL; | |
108 | } | |
109 | ||
110 | ceph_decode_32_safe(p, end, addr_cnt, e_inval); | |
111 | ||
112 | found = false; | |
113 | for (i = 0; i < addr_cnt; i++) { | |
114 | ret = ceph_decode_entity_addr(p, end, &tmp_addr); | |
115 | if (ret) | |
116 | return ret; | |
117 | ||
118 | if (tmp_addr.type == my_type) { | |
119 | if (found) { | |
120 | pr_err("another match of type %d in addrvec\n", | |
121 | le32_to_cpu(my_type)); | |
122 | return -EINVAL; | |
123 | } | |
124 | ||
125 | memcpy(addr, &tmp_addr, sizeof(*addr)); | |
126 | found = true; | |
127 | } | |
128 | } | |
129 | if (!found && addr_cnt != 0) { | |
130 | pr_err("no match of type %d in addrvec\n", | |
131 | le32_to_cpu(my_type)); | |
132 | return -ENOENT; | |
133 | } | |
134 | ||
135 | return 0; | |
136 | ||
137 | e_inval: | |
138 | return -EINVAL; | |
139 | } | |
140 | EXPORT_SYMBOL(ceph_decode_entity_addrvec); |