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