1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* AFS Volume Location Service client |
3 | * |
4 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/gfp.h> |
9 | #include <linux/init.h> |
10 | #include <linux/sched.h> |
11 | #include "afs_fs.h" |
12 | #include "internal.h" |
13 | |
14 | /* |
15 | * Deliver reply data to a VL.GetEntryByNameU call. |
16 | */ |
17 | static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call) |
18 | { |
19 | struct afs_uvldbentry__xdr *uvldb; |
20 | struct afs_vldb_entry *entry; |
21 | u32 nr_servers, vlflags; |
22 | int i, ret; |
23 | |
24 | _enter("" ); |
25 | |
26 | ret = afs_transfer_reply(call); |
27 | if (ret < 0) |
28 | return ret; |
29 | |
30 | /* unmarshall the reply once we've received all of it */ |
31 | uvldb = call->buffer; |
32 | entry = call->ret_vldb; |
33 | |
34 | nr_servers = ntohl(uvldb->nServers); |
35 | if (nr_servers > AFS_NMAXNSERVERS) |
36 | nr_servers = AFS_NMAXNSERVERS; |
37 | |
38 | for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++) |
39 | entry->name[i] = (u8)ntohl(uvldb->name[i]); |
40 | entry->name[i] = 0; |
41 | entry->name_len = strlen(entry->name); |
42 | |
43 | vlflags = ntohl(uvldb->flags); |
44 | for (i = 0; i < nr_servers; i++) { |
45 | struct afs_uuid__xdr *xdr; |
46 | struct afs_uuid *uuid; |
47 | u32 tmp = ntohl(uvldb->serverFlags[i]); |
48 | int j; |
49 | int n = entry->nr_servers; |
50 | |
51 | if (tmp & AFS_VLSF_RWVOL) { |
52 | entry->fs_mask[n] |= AFS_VOL_VTM_RW; |
53 | if (vlflags & AFS_VLF_BACKEXISTS) |
54 | entry->fs_mask[n] |= AFS_VOL_VTM_BAK; |
55 | } |
56 | if (tmp & AFS_VLSF_ROVOL) |
57 | entry->fs_mask[n] |= AFS_VOL_VTM_RO; |
58 | if (!entry->fs_mask[n]) |
59 | continue; |
60 | |
61 | xdr = &uvldb->serverNumber[i]; |
62 | uuid = (struct afs_uuid *)&entry->fs_server[n]; |
63 | uuid->time_low = xdr->time_low; |
64 | uuid->time_mid = htons(ntohl(xdr->time_mid)); |
65 | uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version)); |
66 | uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved); |
67 | uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low); |
68 | for (j = 0; j < 6; j++) |
69 | uuid->node[j] = (u8)ntohl(xdr->node[j]); |
70 | |
71 | entry->vlsf_flags[n] = tmp; |
72 | entry->addr_version[n] = ntohl(uvldb->serverUnique[i]); |
73 | entry->nr_servers++; |
74 | } |
75 | |
76 | for (i = 0; i < AFS_MAXTYPES; i++) |
77 | entry->vid[i] = ntohl(uvldb->volumeId[i]); |
78 | |
79 | if (vlflags & AFS_VLF_RWEXISTS) |
80 | __set_bit(AFS_VLDB_HAS_RW, &entry->flags); |
81 | if (vlflags & AFS_VLF_ROEXISTS) |
82 | __set_bit(AFS_VLDB_HAS_RO, &entry->flags); |
83 | if (vlflags & AFS_VLF_BACKEXISTS) |
84 | __set_bit(AFS_VLDB_HAS_BAK, &entry->flags); |
85 | |
86 | if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) { |
87 | entry->error = -ENOMEDIUM; |
88 | __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags); |
89 | } |
90 | |
91 | __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags); |
92 | _leave(" = 0 [done]" ); |
93 | return 0; |
94 | } |
95 | |
96 | /* |
97 | * VL.GetEntryByNameU operation type. |
98 | */ |
99 | static const struct afs_call_type afs_RXVLGetEntryByNameU = { |
100 | .name = "VL.GetEntryByNameU" , |
101 | .op = afs_VL_GetEntryByNameU, |
102 | .deliver = afs_deliver_vl_get_entry_by_name_u, |
103 | .destructor = afs_flat_call_destructor, |
104 | }; |
105 | |
106 | /* |
107 | * Dispatch a get volume entry by name or ID operation (uuid variant). If the |
108 | * volname is a decimal number then it's a volume ID not a volume name. |
109 | */ |
110 | struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc, |
111 | const char *volname, |
112 | int volnamesz) |
113 | { |
114 | struct afs_vldb_entry *entry; |
115 | struct afs_call *call; |
116 | struct afs_net *net = vc->cell->net; |
117 | size_t reqsz, padsz; |
118 | __be32 *bp; |
119 | |
120 | _enter("" ); |
121 | |
122 | padsz = (4 - (volnamesz & 3)) & 3; |
123 | reqsz = 8 + volnamesz + padsz; |
124 | |
125 | entry = kzalloc(size: sizeof(struct afs_vldb_entry), GFP_KERNEL); |
126 | if (!entry) |
127 | return ERR_PTR(error: -ENOMEM); |
128 | |
129 | call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz, |
130 | sizeof(struct afs_uvldbentry__xdr)); |
131 | if (!call) { |
132 | kfree(objp: entry); |
133 | return ERR_PTR(error: -ENOMEM); |
134 | } |
135 | |
136 | call->key = vc->key; |
137 | call->ret_vldb = entry; |
138 | call->max_lifespan = AFS_VL_MAX_LIFESPAN; |
139 | call->peer = rxrpc_kernel_get_peer(peer: vc->alist->addrs[vc->addr_index].peer); |
140 | call->service_id = vc->server->service_id; |
141 | |
142 | /* Marshall the parameters */ |
143 | bp = call->request; |
144 | *bp++ = htonl(VLGETENTRYBYNAMEU); |
145 | *bp++ = htonl(volnamesz); |
146 | memcpy(bp, volname, volnamesz); |
147 | if (padsz > 0) |
148 | memset((void *)bp + volnamesz, 0, padsz); |
149 | |
150 | trace_afs_make_vl_call(call); |
151 | afs_make_call(call, GFP_KERNEL); |
152 | afs_wait_for_call_to_complete(call); |
153 | vc->call_abort_code = call->abort_code; |
154 | vc->call_error = call->error; |
155 | vc->call_responded = call->responded; |
156 | afs_put_call(call); |
157 | if (vc->call_error) { |
158 | kfree(objp: entry); |
159 | return ERR_PTR(error: vc->call_error); |
160 | } |
161 | return entry; |
162 | } |
163 | |
164 | /* |
165 | * Deliver reply data to a VL.GetAddrsU call. |
166 | * |
167 | * GetAddrsU(IN ListAddrByAttributes *inaddr, |
168 | * OUT afsUUID *uuidp1, |
169 | * OUT uint32_t *uniquifier, |
170 | * OUT uint32_t *nentries, |
171 | * OUT bulkaddrs *blkaddrs); |
172 | */ |
173 | static int afs_deliver_vl_get_addrs_u(struct afs_call *call) |
174 | { |
175 | struct afs_addr_list *alist; |
176 | __be32 *bp; |
177 | u32 uniquifier, nentries, count; |
178 | int i, ret; |
179 | |
180 | _enter("{%u,%zu/%u}" , |
181 | call->unmarshall, iov_iter_count(call->iter), call->count); |
182 | |
183 | switch (call->unmarshall) { |
184 | case 0: |
185 | afs_extract_to_buf(call, |
186 | size: sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32)); |
187 | call->unmarshall++; |
188 | |
189 | /* Extract the returned uuid, uniquifier, nentries and |
190 | * blkaddrs size */ |
191 | fallthrough; |
192 | case 1: |
193 | ret = afs_extract_data(call, true); |
194 | if (ret < 0) |
195 | return ret; |
196 | |
197 | bp = call->buffer + sizeof(struct afs_uuid__xdr); |
198 | uniquifier = ntohl(*bp++); |
199 | nentries = ntohl(*bp++); |
200 | count = ntohl(*bp); |
201 | |
202 | nentries = min(nentries, count); |
203 | alist = afs_alloc_addrlist(nr: nentries); |
204 | if (!alist) |
205 | return -ENOMEM; |
206 | alist->version = uniquifier; |
207 | call->ret_alist = alist; |
208 | call->count = count; |
209 | call->count2 = nentries; |
210 | call->unmarshall++; |
211 | |
212 | more_entries: |
213 | count = min(call->count, 4U); |
214 | afs_extract_to_buf(call, size: count * sizeof(__be32)); |
215 | |
216 | fallthrough; /* and extract entries */ |
217 | case 2: |
218 | ret = afs_extract_data(call, call->count > 4); |
219 | if (ret < 0) |
220 | return ret; |
221 | |
222 | alist = call->ret_alist; |
223 | bp = call->buffer; |
224 | count = min(call->count, 4U); |
225 | for (i = 0; i < count; i++) { |
226 | if (alist->nr_addrs < call->count2) { |
227 | ret = afs_merge_fs_addr4(net: call->net, addr: alist, xdr: *bp++, AFS_FS_PORT); |
228 | if (ret < 0) |
229 | return ret; |
230 | } |
231 | } |
232 | |
233 | call->count -= count; |
234 | if (call->count > 0) |
235 | goto more_entries; |
236 | call->unmarshall++; |
237 | break; |
238 | } |
239 | |
240 | _leave(" = 0 [done]" ); |
241 | return 0; |
242 | } |
243 | |
244 | /* |
245 | * VL.GetAddrsU operation type. |
246 | */ |
247 | static const struct afs_call_type afs_RXVLGetAddrsU = { |
248 | .name = "VL.GetAddrsU" , |
249 | .op = afs_VL_GetAddrsU, |
250 | .deliver = afs_deliver_vl_get_addrs_u, |
251 | .destructor = afs_flat_call_destructor, |
252 | }; |
253 | |
254 | /* |
255 | * Dispatch an operation to get the addresses for a server, where the server is |
256 | * nominated by UUID. |
257 | */ |
258 | struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc, |
259 | const uuid_t *uuid) |
260 | { |
261 | struct afs_ListAddrByAttributes__xdr *r; |
262 | struct afs_addr_list *alist; |
263 | const struct afs_uuid *u = (const struct afs_uuid *)uuid; |
264 | struct afs_call *call; |
265 | struct afs_net *net = vc->cell->net; |
266 | __be32 *bp; |
267 | int i; |
268 | |
269 | _enter("" ); |
270 | |
271 | call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU, |
272 | sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr), |
273 | sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32)); |
274 | if (!call) |
275 | return ERR_PTR(error: -ENOMEM); |
276 | |
277 | call->key = vc->key; |
278 | call->ret_alist = NULL; |
279 | call->max_lifespan = AFS_VL_MAX_LIFESPAN; |
280 | call->peer = rxrpc_kernel_get_peer(peer: vc->alist->addrs[vc->addr_index].peer); |
281 | call->service_id = vc->server->service_id; |
282 | |
283 | /* Marshall the parameters */ |
284 | bp = call->request; |
285 | *bp++ = htonl(VLGETADDRSU); |
286 | r = (struct afs_ListAddrByAttributes__xdr *)bp; |
287 | r->Mask = htonl(AFS_VLADDR_UUID); |
288 | r->ipaddr = 0; |
289 | r->index = 0; |
290 | r->spare = 0; |
291 | r->uuid.time_low = u->time_low; |
292 | r->uuid.time_mid = htonl(ntohs(u->time_mid)); |
293 | r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version)); |
294 | r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved); |
295 | r->uuid.clock_seq_low = htonl(u->clock_seq_low); |
296 | for (i = 0; i < 6; i++) |
297 | r->uuid.node[i] = htonl(u->node[i]); |
298 | |
299 | trace_afs_make_vl_call(call); |
300 | afs_make_call(call, GFP_KERNEL); |
301 | afs_wait_for_call_to_complete(call); |
302 | vc->call_abort_code = call->abort_code; |
303 | vc->call_error = call->error; |
304 | vc->call_responded = call->responded; |
305 | alist = call->ret_alist; |
306 | afs_put_call(call); |
307 | if (vc->call_error) { |
308 | afs_put_addrlist(alist, reason: afs_alist_trace_put_getaddru); |
309 | return ERR_PTR(error: vc->call_error); |
310 | } |
311 | return alist; |
312 | } |
313 | |
314 | /* |
315 | * Deliver reply data to an VL.GetCapabilities operation. |
316 | */ |
317 | static int afs_deliver_vl_get_capabilities(struct afs_call *call) |
318 | { |
319 | u32 count; |
320 | int ret; |
321 | |
322 | _enter("{%u,%zu/%u}" , |
323 | call->unmarshall, iov_iter_count(call->iter), call->count); |
324 | |
325 | switch (call->unmarshall) { |
326 | case 0: |
327 | afs_extract_to_tmp(call); |
328 | call->unmarshall++; |
329 | |
330 | fallthrough; /* and extract the capabilities word count */ |
331 | case 1: |
332 | ret = afs_extract_data(call, true); |
333 | if (ret < 0) |
334 | return ret; |
335 | |
336 | count = ntohl(call->tmp); |
337 | call->count = count; |
338 | call->count2 = count; |
339 | |
340 | call->unmarshall++; |
341 | afs_extract_discard(call, size: count * sizeof(__be32)); |
342 | |
343 | fallthrough; /* and extract capabilities words */ |
344 | case 2: |
345 | ret = afs_extract_data(call, false); |
346 | if (ret < 0) |
347 | return ret; |
348 | |
349 | /* TODO: Examine capabilities */ |
350 | |
351 | call->unmarshall++; |
352 | break; |
353 | } |
354 | |
355 | _leave(" = 0 [done]" ); |
356 | return 0; |
357 | } |
358 | |
359 | static void afs_destroy_vl_get_capabilities(struct afs_call *call) |
360 | { |
361 | afs_put_addrlist(alist: call->vl_probe, reason: afs_alist_trace_put_vlgetcaps); |
362 | afs_put_vlserver(call->net, call->vlserver); |
363 | afs_flat_call_destructor(call); |
364 | } |
365 | |
366 | /* |
367 | * VL.GetCapabilities operation type |
368 | */ |
369 | static const struct afs_call_type afs_RXVLGetCapabilities = { |
370 | .name = "VL.GetCapabilities" , |
371 | .op = afs_VL_GetCapabilities, |
372 | .deliver = afs_deliver_vl_get_capabilities, |
373 | .done = afs_vlserver_probe_result, |
374 | .destructor = afs_destroy_vl_get_capabilities, |
375 | }; |
376 | |
377 | /* |
378 | * Probe a volume server for the capabilities that it supports. This can |
379 | * return up to 196 words. |
380 | * |
381 | * We use this to probe for service upgrade to determine what the server at the |
382 | * other end supports. |
383 | */ |
384 | struct afs_call *afs_vl_get_capabilities(struct afs_net *net, |
385 | struct afs_addr_list *alist, |
386 | unsigned int addr_index, |
387 | struct key *key, |
388 | struct afs_vlserver *server, |
389 | unsigned int server_index) |
390 | { |
391 | struct afs_call *call; |
392 | __be32 *bp; |
393 | |
394 | _enter("" ); |
395 | |
396 | call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4); |
397 | if (!call) |
398 | return ERR_PTR(error: -ENOMEM); |
399 | |
400 | call->key = key; |
401 | call->vlserver = afs_get_vlserver(vlserver: server); |
402 | call->server_index = server_index; |
403 | call->peer = rxrpc_kernel_get_peer(peer: alist->addrs[addr_index].peer); |
404 | call->vl_probe = afs_get_addrlist(alist, reason: afs_alist_trace_get_vlgetcaps); |
405 | call->probe_index = addr_index; |
406 | call->service_id = server->service_id; |
407 | call->upgrade = true; |
408 | call->async = true; |
409 | call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; |
410 | |
411 | /* marshall the parameters */ |
412 | bp = call->request; |
413 | *bp++ = htonl(VLGETCAPABILITIES); |
414 | |
415 | /* Can't take a ref on server */ |
416 | trace_afs_make_vl_call(call); |
417 | afs_make_call(call, GFP_KERNEL); |
418 | return call; |
419 | } |
420 | |
421 | /* |
422 | * Deliver reply data to a YFSVL.GetEndpoints call. |
423 | * |
424 | * GetEndpoints(IN yfsServerAttributes *attr, |
425 | * OUT opr_uuid *uuid, |
426 | * OUT afs_int32 *uniquifier, |
427 | * OUT endpoints *fsEndpoints, |
428 | * OUT endpoints *volEndpoints) |
429 | */ |
430 | static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) |
431 | { |
432 | struct afs_addr_list *alist; |
433 | __be32 *bp; |
434 | u32 uniquifier, size; |
435 | int ret; |
436 | |
437 | _enter("{%u,%zu,%u}" , |
438 | call->unmarshall, iov_iter_count(call->iter), call->count2); |
439 | |
440 | switch (call->unmarshall) { |
441 | case 0: |
442 | afs_extract_to_buf(call, size: sizeof(uuid_t) + 3 * sizeof(__be32)); |
443 | call->unmarshall = 1; |
444 | |
445 | /* Extract the returned uuid, uniquifier, fsEndpoints count and |
446 | * either the first fsEndpoint type or the volEndpoints |
447 | * count if there are no fsEndpoints. */ |
448 | fallthrough; |
449 | case 1: |
450 | ret = afs_extract_data(call, true); |
451 | if (ret < 0) |
452 | return ret; |
453 | |
454 | bp = call->buffer + sizeof(uuid_t); |
455 | uniquifier = ntohl(*bp++); |
456 | call->count = ntohl(*bp++); |
457 | call->count2 = ntohl(*bp); /* Type or next count */ |
458 | |
459 | if (call->count > YFS_MAXENDPOINTS) |
460 | return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num); |
461 | |
462 | alist = afs_alloc_addrlist(nr: call->count); |
463 | if (!alist) |
464 | return -ENOMEM; |
465 | alist->version = uniquifier; |
466 | call->ret_alist = alist; |
467 | |
468 | if (call->count == 0) |
469 | goto extract_volendpoints; |
470 | |
471 | next_fsendpoint: |
472 | switch (call->count2) { |
473 | case YFS_ENDPOINT_IPV4: |
474 | size = sizeof(__be32) * (1 + 1 + 1); |
475 | break; |
476 | case YFS_ENDPOINT_IPV6: |
477 | size = sizeof(__be32) * (1 + 4 + 1); |
478 | break; |
479 | default: |
480 | return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type); |
481 | } |
482 | |
483 | size += sizeof(__be32); |
484 | afs_extract_to_buf(call, size); |
485 | call->unmarshall = 2; |
486 | |
487 | fallthrough; /* and extract fsEndpoints[] entries */ |
488 | case 2: |
489 | ret = afs_extract_data(call, true); |
490 | if (ret < 0) |
491 | return ret; |
492 | |
493 | alist = call->ret_alist; |
494 | bp = call->buffer; |
495 | switch (call->count2) { |
496 | case YFS_ENDPOINT_IPV4: |
497 | if (ntohl(bp[0]) != sizeof(__be32) * 2) |
498 | return afs_protocol_error( |
499 | call, afs_eproto_yvl_fsendpt4_len); |
500 | ret = afs_merge_fs_addr4(net: call->net, addr: alist, xdr: bp[1], ntohl(bp[2])); |
501 | if (ret < 0) |
502 | return ret; |
503 | bp += 3; |
504 | break; |
505 | case YFS_ENDPOINT_IPV6: |
506 | if (ntohl(bp[0]) != sizeof(__be32) * 5) |
507 | return afs_protocol_error( |
508 | call, afs_eproto_yvl_fsendpt6_len); |
509 | ret = afs_merge_fs_addr6(net: call->net, addr: alist, xdr: bp + 1, ntohl(bp[5])); |
510 | if (ret < 0) |
511 | return ret; |
512 | bp += 6; |
513 | break; |
514 | default: |
515 | return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type); |
516 | } |
517 | |
518 | /* Got either the type of the next entry or the count of |
519 | * volEndpoints if no more fsEndpoints. |
520 | */ |
521 | call->count2 = ntohl(*bp++); |
522 | |
523 | call->count--; |
524 | if (call->count > 0) |
525 | goto next_fsendpoint; |
526 | |
527 | : |
528 | /* Extract the list of volEndpoints. */ |
529 | call->count = call->count2; |
530 | if (!call->count) |
531 | goto end; |
532 | if (call->count > YFS_MAXENDPOINTS) |
533 | return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type); |
534 | |
535 | afs_extract_to_buf(call, size: 1 * sizeof(__be32)); |
536 | call->unmarshall = 3; |
537 | |
538 | /* Extract the type of volEndpoints[0]. Normally we would |
539 | * extract the type of the next endpoint when we extract the |
540 | * data of the current one, but this is the first... |
541 | */ |
542 | fallthrough; |
543 | case 3: |
544 | ret = afs_extract_data(call, true); |
545 | if (ret < 0) |
546 | return ret; |
547 | |
548 | bp = call->buffer; |
549 | |
550 | next_volendpoint: |
551 | call->count2 = ntohl(*bp++); |
552 | switch (call->count2) { |
553 | case YFS_ENDPOINT_IPV4: |
554 | size = sizeof(__be32) * (1 + 1 + 1); |
555 | break; |
556 | case YFS_ENDPOINT_IPV6: |
557 | size = sizeof(__be32) * (1 + 4 + 1); |
558 | break; |
559 | default: |
560 | return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type); |
561 | } |
562 | |
563 | if (call->count > 1) |
564 | size += sizeof(__be32); /* Get next type too */ |
565 | afs_extract_to_buf(call, size); |
566 | call->unmarshall = 4; |
567 | |
568 | fallthrough; /* and extract volEndpoints[] entries */ |
569 | case 4: |
570 | ret = afs_extract_data(call, true); |
571 | if (ret < 0) |
572 | return ret; |
573 | |
574 | bp = call->buffer; |
575 | switch (call->count2) { |
576 | case YFS_ENDPOINT_IPV4: |
577 | if (ntohl(bp[0]) != sizeof(__be32) * 2) |
578 | return afs_protocol_error( |
579 | call, afs_eproto_yvl_vlendpt4_len); |
580 | bp += 3; |
581 | break; |
582 | case YFS_ENDPOINT_IPV6: |
583 | if (ntohl(bp[0]) != sizeof(__be32) * 5) |
584 | return afs_protocol_error( |
585 | call, afs_eproto_yvl_vlendpt6_len); |
586 | bp += 6; |
587 | break; |
588 | default: |
589 | return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type); |
590 | } |
591 | |
592 | /* Got either the type of the next entry or the count of |
593 | * volEndpoints if no more fsEndpoints. |
594 | */ |
595 | call->count--; |
596 | if (call->count > 0) |
597 | goto next_volendpoint; |
598 | |
599 | end: |
600 | afs_extract_discard(call, size: 0); |
601 | call->unmarshall = 5; |
602 | |
603 | fallthrough; /* Done */ |
604 | case 5: |
605 | ret = afs_extract_data(call, false); |
606 | if (ret < 0) |
607 | return ret; |
608 | call->unmarshall = 6; |
609 | fallthrough; |
610 | |
611 | case 6: |
612 | break; |
613 | } |
614 | |
615 | _leave(" = 0 [done]" ); |
616 | return 0; |
617 | } |
618 | |
619 | /* |
620 | * YFSVL.GetEndpoints operation type. |
621 | */ |
622 | static const struct afs_call_type afs_YFSVLGetEndpoints = { |
623 | .name = "YFSVL.GetEndpoints" , |
624 | .op = afs_YFSVL_GetEndpoints, |
625 | .deliver = afs_deliver_yfsvl_get_endpoints, |
626 | .destructor = afs_flat_call_destructor, |
627 | }; |
628 | |
629 | /* |
630 | * Dispatch an operation to get the addresses for a server, where the server is |
631 | * nominated by UUID. |
632 | */ |
633 | struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc, |
634 | const uuid_t *uuid) |
635 | { |
636 | struct afs_addr_list *alist; |
637 | struct afs_call *call; |
638 | struct afs_net *net = vc->cell->net; |
639 | __be32 *bp; |
640 | |
641 | _enter("" ); |
642 | |
643 | call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints, |
644 | sizeof(__be32) * 2 + sizeof(*uuid), |
645 | sizeof(struct in6_addr) + sizeof(__be32) * 3); |
646 | if (!call) |
647 | return ERR_PTR(error: -ENOMEM); |
648 | |
649 | call->key = vc->key; |
650 | call->ret_alist = NULL; |
651 | call->max_lifespan = AFS_VL_MAX_LIFESPAN; |
652 | call->peer = rxrpc_kernel_get_peer(peer: vc->alist->addrs[vc->addr_index].peer); |
653 | call->service_id = vc->server->service_id; |
654 | |
655 | /* Marshall the parameters */ |
656 | bp = call->request; |
657 | *bp++ = htonl(YVLGETENDPOINTS); |
658 | *bp++ = htonl(YFS_SERVER_UUID); |
659 | memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */ |
660 | |
661 | trace_afs_make_vl_call(call); |
662 | afs_make_call(call, GFP_KERNEL); |
663 | afs_wait_for_call_to_complete(call); |
664 | vc->call_abort_code = call->abort_code; |
665 | vc->call_error = call->error; |
666 | vc->call_responded = call->responded; |
667 | alist = call->ret_alist; |
668 | afs_put_call(call); |
669 | if (vc->call_error) { |
670 | afs_put_addrlist(alist, reason: afs_alist_trace_put_getaddru); |
671 | return ERR_PTR(error: vc->call_error); |
672 | } |
673 | return alist; |
674 | } |
675 | |
676 | /* |
677 | * Deliver reply data to a YFSVL.GetCellName operation. |
678 | */ |
679 | static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call) |
680 | { |
681 | char *cell_name; |
682 | u32 namesz, paddedsz; |
683 | int ret; |
684 | |
685 | _enter("{%u,%zu/%u}" , |
686 | call->unmarshall, iov_iter_count(call->iter), call->count); |
687 | |
688 | switch (call->unmarshall) { |
689 | case 0: |
690 | afs_extract_to_tmp(call); |
691 | call->unmarshall++; |
692 | |
693 | fallthrough; /* and extract the cell name length */ |
694 | case 1: |
695 | ret = afs_extract_data(call, true); |
696 | if (ret < 0) |
697 | return ret; |
698 | |
699 | namesz = ntohl(call->tmp); |
700 | if (namesz > AFS_MAXCELLNAME) |
701 | return afs_protocol_error(call, afs_eproto_cellname_len); |
702 | paddedsz = (namesz + 3) & ~3; |
703 | call->count = namesz; |
704 | call->count2 = paddedsz - namesz; |
705 | |
706 | cell_name = kmalloc(size: namesz + 1, GFP_KERNEL); |
707 | if (!cell_name) |
708 | return -ENOMEM; |
709 | cell_name[namesz] = 0; |
710 | call->ret_str = cell_name; |
711 | |
712 | afs_extract_begin(call, buf: cell_name, size: namesz); |
713 | call->unmarshall++; |
714 | |
715 | fallthrough; /* and extract cell name */ |
716 | case 2: |
717 | ret = afs_extract_data(call, true); |
718 | if (ret < 0) |
719 | return ret; |
720 | |
721 | afs_extract_discard(call, size: call->count2); |
722 | call->unmarshall++; |
723 | |
724 | fallthrough; /* and extract padding */ |
725 | case 3: |
726 | ret = afs_extract_data(call, false); |
727 | if (ret < 0) |
728 | return ret; |
729 | |
730 | call->unmarshall++; |
731 | break; |
732 | } |
733 | |
734 | _leave(" = 0 [done]" ); |
735 | return 0; |
736 | } |
737 | |
738 | /* |
739 | * VL.GetCapabilities operation type |
740 | */ |
741 | static const struct afs_call_type afs_YFSVLGetCellName = { |
742 | .name = "YFSVL.GetCellName" , |
743 | .op = afs_YFSVL_GetCellName, |
744 | .deliver = afs_deliver_yfsvl_get_cell_name, |
745 | .destructor = afs_flat_call_destructor, |
746 | }; |
747 | |
748 | /* |
749 | * Probe a volume server for the capabilities that it supports. This can |
750 | * return up to 196 words. |
751 | * |
752 | * We use this to probe for service upgrade to determine what the server at the |
753 | * other end supports. |
754 | */ |
755 | char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc) |
756 | { |
757 | struct afs_call *call; |
758 | struct afs_net *net = vc->cell->net; |
759 | __be32 *bp; |
760 | char *cellname; |
761 | |
762 | _enter("" ); |
763 | |
764 | call = afs_alloc_flat_call(net, &afs_YFSVLGetCellName, 1 * 4, 0); |
765 | if (!call) |
766 | return ERR_PTR(error: -ENOMEM); |
767 | |
768 | call->key = vc->key; |
769 | call->ret_str = NULL; |
770 | call->max_lifespan = AFS_VL_MAX_LIFESPAN; |
771 | call->peer = rxrpc_kernel_get_peer(peer: vc->alist->addrs[vc->addr_index].peer); |
772 | call->service_id = vc->server->service_id; |
773 | |
774 | /* marshall the parameters */ |
775 | bp = call->request; |
776 | *bp++ = htonl(YVLGETCELLNAME); |
777 | |
778 | /* Can't take a ref on server */ |
779 | trace_afs_make_vl_call(call); |
780 | afs_make_call(call, GFP_KERNEL); |
781 | afs_wait_for_call_to_complete(call); |
782 | vc->call_abort_code = call->abort_code; |
783 | vc->call_error = call->error; |
784 | vc->call_responded = call->responded; |
785 | cellname = call->ret_str; |
786 | afs_put_call(call); |
787 | if (vc->call_error) { |
788 | kfree(objp: cellname); |
789 | return ERR_PTR(error: vc->call_error); |
790 | } |
791 | return cellname; |
792 | } |
793 | |