Commit | Line | Data |
---|---|---|
6c37f0e6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
a5cbd5fc | 2 | #include <linux/ceph/ceph_debug.h> |
6c37f0e6 | 3 | |
cd1a677c ID |
4 | #include <linux/inet.h> |
5 | ||
6c37f0e6 | 6 | #include <linux/ceph/decode.h> |
3f1c6f21 | 7 | #include <linux/ceph/messenger.h> /* for ceph_pr_addr() */ |
6c37f0e6 JL |
8 | |
9 | static int | |
10 | ceph_decode_entity_addr_versioned(void **p, void *end, | |
11 | struct ceph_entity_addr *addr) | |
12 | { | |
13 | int ret; | |
14 | u8 struct_v; | |
15 | u32 struct_len, addr_len; | |
16 | void *struct_end; | |
17 | ||
18 | ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v, | |
19 | &struct_len); | |
20 | if (ret) | |
21 | goto bad; | |
22 | ||
23 | ret = -EINVAL; | |
24 | struct_end = *p + struct_len; | |
25 | ||
26 | ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad); | |
27 | ||
6c37f0e6 JL |
28 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
29 | ||
30 | ceph_decode_32_safe(p, end, addr_len, bad); | |
31 | if (addr_len > sizeof(addr->in_addr)) | |
32 | goto bad; | |
33 | ||
34 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
35 | if (addr_len) { | |
36 | ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad); | |
37 | ||
38 | addr->in_addr.ss_family = | |
39 | le16_to_cpu((__force __le16)addr->in_addr.ss_family); | |
40 | } | |
41 | ||
42 | /* Advance past anything the client doesn't yet understand */ | |
43 | *p = struct_end; | |
44 | ret = 0; | |
45 | bad: | |
46 | return ret; | |
47 | } | |
48 | ||
49 | static int | |
50 | ceph_decode_entity_addr_legacy(void **p, void *end, | |
51 | struct ceph_entity_addr *addr) | |
52 | { | |
53 | int ret = -EINVAL; | |
54 | ||
55 | /* Skip rest of type field */ | |
56 | ceph_decode_skip_n(p, end, 3, bad); | |
d3c3c0a8 JL |
57 | |
58 | /* | |
59 | * Clients that don't support ADDR2 always send TYPE_NONE, change it | |
60 | * to TYPE_LEGACY for forward compatibility. | |
61 | */ | |
62 | addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY; | |
6c37f0e6 JL |
63 | ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); |
64 | memset(&addr->in_addr, 0, sizeof(addr->in_addr)); | |
65 | ceph_decode_copy_safe(p, end, &addr->in_addr, | |
66 | sizeof(addr->in_addr), bad); | |
67 | addr->in_addr.ss_family = | |
68 | be16_to_cpu((__force __be16)addr->in_addr.ss_family); | |
69 | ret = 0; | |
70 | bad: | |
71 | return ret; | |
72 | } | |
73 | ||
74 | int | |
75 | ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) | |
76 | { | |
77 | u8 marker; | |
78 | ||
79 | ceph_decode_8_safe(p, end, marker, bad); | |
80 | if (marker == 1) | |
81 | return ceph_decode_entity_addr_versioned(p, end, addr); | |
82 | else if (marker == 0) | |
83 | return ceph_decode_entity_addr_legacy(p, end, addr); | |
84 | bad: | |
85 | return -EINVAL; | |
86 | } | |
87 | EXPORT_SYMBOL(ceph_decode_entity_addr); | |
88 | ||
a5cbd5fc ID |
89 | /* |
90 | * Return addr of desired type (MSGR2 or LEGACY) or error. | |
91 | * Make sure there is only one match. | |
92 | * | |
93 | * Assume encoding with MSG_ADDR2. | |
94 | */ | |
95 | int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2, | |
96 | struct ceph_entity_addr *addr) | |
97 | { | |
98 | __le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 : | |
99 | CEPH_ENTITY_ADDR_TYPE_LEGACY; | |
100 | struct ceph_entity_addr tmp_addr; | |
101 | int addr_cnt; | |
102 | bool found; | |
103 | u8 marker; | |
104 | int ret; | |
105 | int i; | |
106 | ||
107 | ceph_decode_8_safe(p, end, marker, e_inval); | |
108 | if (marker != 2) { | |
109 | pr_err("bad addrvec marker %d\n", marker); | |
110 | return -EINVAL; | |
111 | } | |
112 | ||
113 | ceph_decode_32_safe(p, end, addr_cnt, e_inval); | |
3f1c6f21 | 114 | dout("%s addr_cnt %d\n", __func__, addr_cnt); |
a5cbd5fc ID |
115 | |
116 | found = false; | |
117 | for (i = 0; i < addr_cnt; i++) { | |
118 | ret = ceph_decode_entity_addr(p, end, &tmp_addr); | |
119 | if (ret) | |
120 | return ret; | |
121 | ||
3f1c6f21 | 122 | dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr)); |
a5cbd5fc ID |
123 | if (tmp_addr.type == my_type) { |
124 | if (found) { | |
125 | pr_err("another match of type %d in addrvec\n", | |
126 | le32_to_cpu(my_type)); | |
127 | return -EINVAL; | |
128 | } | |
129 | ||
130 | memcpy(addr, &tmp_addr, sizeof(*addr)); | |
131 | found = true; | |
132 | } | |
133 | } | |
a5cbd5fc | 134 | |
3f1c6f21 ID |
135 | if (found) |
136 | return 0; | |
137 | ||
138 | if (!addr_cnt) | |
139 | return 0; /* normal -- e.g. unused OSD id/slot */ | |
140 | ||
141 | if (addr_cnt == 1 && !memchr_inv(&tmp_addr, 0, sizeof(tmp_addr))) | |
142 | return 0; /* weird but effectively the same as !addr_cnt */ | |
143 | ||
144 | pr_err("no match of type %d in addrvec\n", le32_to_cpu(my_type)); | |
145 | return -ENOENT; | |
a5cbd5fc ID |
146 | |
147 | e_inval: | |
148 | return -EINVAL; | |
149 | } | |
150 | EXPORT_SYMBOL(ceph_decode_entity_addrvec); | |
cd1a677c ID |
151 | |
152 | static int get_sockaddr_encoding_len(sa_family_t family) | |
153 | { | |
154 | union { | |
155 | struct sockaddr sa; | |
156 | struct sockaddr_in sin; | |
157 | struct sockaddr_in6 sin6; | |
158 | } u; | |
159 | ||
160 | switch (family) { | |
161 | case AF_INET: | |
162 | return sizeof(u.sin); | |
163 | case AF_INET6: | |
164 | return sizeof(u.sin6); | |
165 | default: | |
166 | return sizeof(u); | |
167 | } | |
168 | } | |
169 | ||
170 | int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr) | |
171 | { | |
172 | sa_family_t family = get_unaligned(&addr->in_addr.ss_family); | |
173 | int addr_len = get_sockaddr_encoding_len(family); | |
174 | ||
175 | return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len; | |
176 | } | |
177 | ||
178 | void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr) | |
179 | { | |
180 | sa_family_t family = get_unaligned(&addr->in_addr.ss_family); | |
181 | int addr_len = get_sockaddr_encoding_len(family); | |
182 | ||
183 | ceph_encode_8(p, 1); /* marker */ | |
184 | ceph_start_encoding(p, 1, 1, sizeof(addr->type) + | |
185 | sizeof(addr->nonce) + | |
186 | sizeof(u32) + addr_len); | |
187 | ceph_encode_copy(p, &addr->type, sizeof(addr->type)); | |
188 | ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce)); | |
189 | ||
190 | ceph_encode_32(p, addr_len); | |
191 | ceph_encode_16(p, family); | |
192 | ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family)); | |
193 | } |