blob: 1d38cbdf6cada86ad1b7ba9a0fcbaab758f3fba5 [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* AFS Volume Location Service client
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/init.h>
14#include <linux/sched.h>
David Howells4d9df982017-11-02 15:27:47 +000015#include "afs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "internal.h"
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018/*
David Howellsd2ddc772017-11-02 15:27:50 +000019 * Deliver reply data to a VL.GetEntryByNameU call.
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
David Howellsd2ddc772017-11-02 15:27:50 +000021static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{
David Howellsd2ddc772017-11-02 15:27:50 +000023 struct afs_uvldbentry__xdr *uvldb;
24 struct afs_vldb_entry *entry;
25 bool new_only = false;
David Howells08e0e7c2007-04-26 15:55:03 -070026 u32 tmp;
David Howellsd2ddc772017-11-02 15:27:50 +000027 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
David Howellsd0016482016-08-30 20:42:14 +010029 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
David Howellsd0016482016-08-30 20:42:14 +010031 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +010032 if (ret < 0)
33 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
David Howells08e0e7c2007-04-26 15:55:03 -070035 /* unmarshall the reply once we've received all of it */
David Howellsd2ddc772017-11-02 15:27:50 +000036 uvldb = call->buffer;
David Howells97e30432017-11-02 15:27:48 +000037 entry = call->reply[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
David Howellsd2ddc772017-11-02 15:27:50 +000039 for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
40 entry->name[i] = (u8)ntohl(uvldb->name[i]);
41 entry->name[i] = 0;
42 entry->name_len = strlen(entry->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
David Howellsd2ddc772017-11-02 15:27:50 +000044 /* If there is a new replication site that we can use, ignore all the
45 * sites that aren't marked as new.
46 */
47 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
48 tmp = ntohl(uvldb->serverFlags[i]);
49 if (!(tmp & AFS_VLSF_DONTUSE) &&
50 (tmp & AFS_VLSF_NEWREPSITE))
51 new_only = true;
David Howells4d9df982017-11-02 15:27:47 +000052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
David Howellsd2ddc772017-11-02 15:27:50 +000054 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
55 struct afs_uuid__xdr *xdr;
56 struct afs_uuid *uuid;
57 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
David Howellsd2ddc772017-11-02 15:27:50 +000059 tmp = ntohl(uvldb->serverFlags[i]);
60 if (tmp & AFS_VLSF_DONTUSE ||
61 (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
62 continue;
David Howells08e0e7c2007-04-26 15:55:03 -070063 if (tmp & AFS_VLSF_RWVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000064 entry->fs_mask[i] |= AFS_VOL_VTM_RW;
David Howells08e0e7c2007-04-26 15:55:03 -070065 if (tmp & AFS_VLSF_ROVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000066 entry->fs_mask[i] |= AFS_VOL_VTM_RO;
David Howells08e0e7c2007-04-26 15:55:03 -070067 if (tmp & AFS_VLSF_BACKVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000068 entry->fs_mask[i] |= AFS_VOL_VTM_BAK;
69 if (!entry->fs_mask[i])
70 continue;
71
72 xdr = &uvldb->serverNumber[i];
73 uuid = (struct afs_uuid *)&entry->fs_server[i];
74 uuid->time_low = xdr->time_low;
75 uuid->time_mid = htons(ntohl(xdr->time_mid));
76 uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version));
77 uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved);
78 uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low);
79 for (j = 0; j < 6; j++)
80 uuid->node[j] = (u8)ntohl(xdr->node[j]);
81
82 entry->nr_servers++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 }
84
David Howellsd2ddc772017-11-02 15:27:50 +000085 for (i = 0; i < AFS_MAXTYPES; i++)
86 entry->vid[i] = ntohl(uvldb->volumeId[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
David Howellsd2ddc772017-11-02 15:27:50 +000088 tmp = ntohl(uvldb->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070089 if (tmp & AFS_VLF_RWEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000090 __set_bit(AFS_VLDB_HAS_RW, &entry->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070091 if (tmp & AFS_VLF_ROEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000092 __set_bit(AFS_VLDB_HAS_RO, &entry->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070093 if (tmp & AFS_VLF_BACKEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000094 __set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
95
96 if (!(tmp & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
97 entry->error = -ENOMEDIUM;
98 __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
99 }
100
101 __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
102 _leave(" = 0 [done]");
103 return 0;
104}
105
106static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
107{
108 kfree(call->reply[0]);
109 afs_flat_call_destructor(call);
110}
111
112/*
113 * VL.GetEntryByNameU operation type.
114 */
115static const struct afs_call_type afs_RXVLGetEntryByNameU = {
116 .name = "VL.GetEntryByNameU",
117 .deliver = afs_deliver_vl_get_entry_by_name_u,
118 .destructor = afs_destroy_vl_get_entry_by_name_u,
119};
120
121/*
122 * Dispatch a get volume entry by name or ID operation (uuid variant). If the
123 * volname is a decimal number then it's a volume ID not a volume name.
124 */
125struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
126 struct afs_addr_cursor *ac,
127 struct key *key,
128 const char *volname,
129 int volnamesz)
130{
131 struct afs_vldb_entry *entry;
132 struct afs_call *call;
133 size_t reqsz, padsz;
134 __be32 *bp;
135
136 _enter("");
137
138 padsz = (4 - (volnamesz & 3)) & 3;
139 reqsz = 8 + volnamesz + padsz;
140
141 entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
142 if (!entry)
143 return ERR_PTR(-ENOMEM);
144
145 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
146 sizeof(struct afs_uvldbentry__xdr));
147 if (!call) {
148 kfree(entry);
149 return ERR_PTR(-ENOMEM);
150 }
151
152 call->key = key;
153 call->reply[0] = entry;
154 call->ret_reply0 = true;
155
156 /* Marshall the parameters */
157 bp = call->request;
158 *bp++ = htonl(VLGETENTRYBYNAMEU);
159 *bp++ = htonl(volnamesz);
160 memcpy(bp, volname, volnamesz);
161 if (padsz > 0)
162 memset((void *)bp + volnamesz, 0, padsz);
163
164 return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false);
165}
166
167/*
168 * Deliver reply data to a VL.GetAddrsU call.
169 *
170 * GetAddrsU(IN ListAddrByAttributes *inaddr,
171 * OUT afsUUID *uuidp1,
172 * OUT uint32_t *uniquifier,
173 * OUT uint32_t *nentries,
174 * OUT bulkaddrs *blkaddrs);
175 */
176static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
177{
178 struct afs_addr_list *alist;
179 __be32 *bp;
180 u32 uniquifier, nentries, count;
181 int i, ret;
182
183 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
184
185again:
186 switch (call->unmarshall) {
187 case 0:
188 call->offset = 0;
189 call->unmarshall++;
190
191 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
192 case 1:
193 ret = afs_extract_data(call, call->buffer,
194 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
195 true);
196 if (ret < 0)
197 return ret;
198
199 bp = call->buffer + sizeof(struct afs_uuid__xdr);
200 uniquifier = ntohl(*bp++);
201 nentries = ntohl(*bp++);
202 count = ntohl(*bp);
203
204 nentries = min(nentries, count);
205 alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
206 if (!alist)
207 return -ENOMEM;
208 alist->version = uniquifier;
209 call->reply[0] = alist;
210 call->count = count;
211 call->count2 = nentries;
212 call->offset = 0;
213 call->unmarshall++;
214
215 /* Extract entries */
216 case 2:
217 count = min(call->count, 4U);
218 ret = afs_extract_data(call, call->buffer,
219 count * sizeof(__be32),
220 call->count > 4);
221 if (ret < 0)
222 return ret;
223
224 alist = call->reply[0];
225 bp = call->buffer;
226 for (i = 0; i < count; i++)
227 if (alist->nr_addrs < call->count2)
David Howellsbf99a532017-11-02 15:27:51 +0000228 afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
David Howellsd2ddc772017-11-02 15:27:50 +0000229
230 call->count -= count;
231 if (call->count > 0)
232 goto again;
233 call->offset = 0;
234 call->unmarshall++;
235 break;
236 }
David Howells08e0e7c2007-04-26 15:55:03 -0700237
238 _leave(" = 0 [done]");
239 return 0;
David Howellsec268152007-04-26 15:49:28 -0700240}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
David Howellsd2ddc772017-11-02 15:27:50 +0000242static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
David Howellsd2ddc772017-11-02 15:27:50 +0000244 afs_put_server(call->net, (struct afs_server *)call->reply[0]);
245 kfree(call->reply[1]);
246 return afs_flat_call_destructor(call);
David Howellsec268152007-04-26 15:49:28 -0700247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249/*
David Howellsd2ddc772017-11-02 15:27:50 +0000250 * VL.GetAddrsU operation type.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 */
David Howellsd2ddc772017-11-02 15:27:50 +0000252static const struct afs_call_type afs_RXVLGetAddrsU = {
253 .name = "VL.GetAddrsU",
254 .deliver = afs_deliver_vl_get_addrs_u,
255 .destructor = afs_vl_get_addrs_u_destructor,
256};
257
258/*
259 * Dispatch an operation to get the addresses for a server, where the server is
260 * nominated by UUID.
261 */
262struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
263 struct afs_addr_cursor *ac,
264 struct key *key,
265 const uuid_t *uuid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
David Howellsd2ddc772017-11-02 15:27:50 +0000267 struct afs_ListAddrByAttributes__xdr *r;
268 const struct afs_uuid *u = (const struct afs_uuid *)uuid;
David Howells08e0e7c2007-04-26 15:55:03 -0700269 struct afs_call *call;
270 __be32 *bp;
David Howellsd2ddc772017-11-02 15:27:50 +0000271 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
David Howells08e0e7c2007-04-26 15:55:03 -0700273 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
David Howellsd2ddc772017-11-02 15:27:50 +0000275 call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
276 sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
277 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
David Howells08e0e7c2007-04-26 15:55:03 -0700278 if (!call)
David Howellsd2ddc772017-11-02 15:27:50 +0000279 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
David Howells00d3b7a2007-04-26 15:57:07 -0700281 call->key = key;
David Howellsd2ddc772017-11-02 15:27:50 +0000282 call->reply[0] = NULL;
283 call->ret_reply0 = true;
David Howells08e0e7c2007-04-26 15:55:03 -0700284
David Howellsd2ddc772017-11-02 15:27:50 +0000285 /* Marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700286 bp = call->request;
David Howellsd2ddc772017-11-02 15:27:50 +0000287 *bp++ = htonl(VLGETADDRSU);
288 r = (struct afs_ListAddrByAttributes__xdr *)bp;
289 r->Mask = htonl(AFS_VLADDR_UUID);
290 r->ipaddr = 0;
291 r->index = 0;
292 r->spare = 0;
293 r->uuid.time_low = u->time_low;
294 r->uuid.time_mid = htonl(ntohs(u->time_mid));
295 r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version));
296 r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
297 r->uuid.clock_seq_low = htonl(u->clock_seq_low);
298 for (i = 0; i < 6; i++)
299 r->uuid.node[i] = ntohl(u->node[i]);
David Howells08e0e7c2007-04-26 15:55:03 -0700300
David Howellsd2ddc772017-11-02 15:27:50 +0000301 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
David Howellsec268152007-04-26 15:49:28 -0700302}
David Howellsbf99a532017-11-02 15:27:51 +0000303
304/*
305 * Deliver reply data to an VL.GetCapabilities operation.
306 */
307static int afs_deliver_vl_get_capabilities(struct afs_call *call)
308{
309 u32 count;
310 int ret;
311
312 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
313
314again:
315 switch (call->unmarshall) {
316 case 0:
317 call->offset = 0;
318 call->unmarshall++;
319
320 /* Extract the capabilities word count */
321 case 1:
322 ret = afs_extract_data(call, &call->tmp,
323 1 * sizeof(__be32),
324 true);
325 if (ret < 0)
326 return ret;
327
328 count = ntohl(call->tmp);
329
330 call->count = count;
331 call->count2 = count;
332 call->offset = 0;
333 call->unmarshall++;
334
335 /* Extract capabilities words */
336 case 2:
337 count = min(call->count, 16U);
338 ret = afs_extract_data(call, call->buffer,
339 count * sizeof(__be32),
340 call->count > 16);
341 if (ret < 0)
342 return ret;
343
344 /* TODO: Examine capabilities */
345
346 call->count -= count;
347 if (call->count > 0)
348 goto again;
349 call->offset = 0;
350 call->unmarshall++;
351 break;
352 }
353
354 call->reply[0] = (void *)(unsigned long)call->service_id;
355
356 _leave(" = 0 [done]");
357 return 0;
358}
359
360/*
361 * VL.GetCapabilities operation type
362 */
363static const struct afs_call_type afs_RXVLGetCapabilities = {
364 .name = "VL.GetCapabilities",
365 .deliver = afs_deliver_vl_get_capabilities,
366 .destructor = afs_flat_call_destructor,
367};
368
369/*
370 * Probe a fileserver for the capabilities that it supports. This can
371 * return up to 196 words.
372 *
373 * We use this to probe for service upgrade to determine what the server at the
374 * other end supports.
375 */
376int afs_vl_get_capabilities(struct afs_net *net,
377 struct afs_addr_cursor *ac,
378 struct key *key)
379{
380 struct afs_call *call;
381 __be32 *bp;
382
383 _enter("");
384
385 call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
386 if (!call)
387 return -ENOMEM;
388
389 call->key = key;
390 call->upgrade = true; /* Let's see if this is a YFS server */
391 call->reply[0] = (void *)VLGETCAPABILITIES;
392 call->ret_reply0 = true;
393
394 /* marshall the parameters */
395 bp = call->request;
396 *bp++ = htonl(VLGETCAPABILITIES);
397
398 /* Can't take a ref on server */
399 return afs_make_call(ac, call, GFP_KERNEL, false);
400}
401
402/*
403 * Deliver reply data to a YFSVL.GetEndpoints call.
404 *
405 * GetEndpoints(IN yfsServerAttributes *attr,
406 * OUT opr_uuid *uuid,
407 * OUT afs_int32 *uniquifier,
408 * OUT endpoints *fsEndpoints,
409 * OUT endpoints *volEndpoints)
410 */
411static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
412{
413 struct afs_addr_list *alist;
414 __be32 *bp;
415 u32 uniquifier, size;
416 int ret;
417
418 _enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2);
419
420again:
421 switch (call->unmarshall) {
422 case 0:
423 call->offset = 0;
424 call->unmarshall = 1;
425
426 /* Extract the returned uuid, uniquifier, fsEndpoints count and
427 * either the first fsEndpoint type or the volEndpoints
428 * count if there are no fsEndpoints. */
429 case 1:
430 ret = afs_extract_data(call, call->buffer,
431 sizeof(uuid_t) +
432 3 * sizeof(__be32),
433 true);
434 if (ret < 0)
435 return ret;
436
437 bp = call->buffer + sizeof(uuid_t);
438 uniquifier = ntohl(*bp++);
439 call->count = ntohl(*bp++);
440 call->count2 = ntohl(*bp); /* Type or next count */
441
442 if (call->count > YFS_MAXENDPOINTS)
443 return -EBADMSG;
444
445 alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
446 if (!alist)
447 return -ENOMEM;
448 alist->version = uniquifier;
449 call->reply[0] = alist;
450 call->offset = 0;
451
452 if (call->count == 0)
453 goto extract_volendpoints;
454
455 call->unmarshall = 2;
456
457 /* Extract fsEndpoints[] entries */
458 case 2:
459 switch (call->count2) {
460 case YFS_ENDPOINT_IPV4:
461 size = sizeof(__be32) * (1 + 1 + 1);
462 break;
463 case YFS_ENDPOINT_IPV6:
464 size = sizeof(__be32) * (1 + 4 + 1);
465 break;
466 default:
467 return -EBADMSG;
468 }
469
470 size += sizeof(__be32);
471 ret = afs_extract_data(call, call->buffer, size, true);
472 if (ret < 0)
473 return ret;
474
475 alist = call->reply[0];
476 bp = call->buffer;
477 switch (call->count2) {
478 case YFS_ENDPOINT_IPV4:
479 if (ntohl(bp[0]) != sizeof(__be32) * 2)
480 return -EBADMSG;
481 afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
482 bp += 3;
483 break;
484 case YFS_ENDPOINT_IPV6:
485 if (ntohl(bp[0]) != sizeof(__be32) * 5)
486 return -EBADMSG;
487 afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
488 bp += 6;
489 break;
490 default:
491 return -EBADMSG;
492 }
493
494 /* Got either the type of the next entry or the count of
495 * volEndpoints if no more fsEndpoints.
496 */
497 call->count2 = htonl(*bp++);
498
499 call->offset = 0;
500 call->count--;
501 if (call->count > 0)
502 goto again;
503
504 extract_volendpoints:
505 /* Extract the list of volEndpoints. */
506 call->count = call->count2;
507 if (!call->count)
508 goto end;
509 if (call->count > YFS_MAXENDPOINTS)
510 return -EBADMSG;
511
512 call->unmarshall = 3;
513
514 /* Extract the type of volEndpoints[0]. Normally we would
515 * extract the type of the next endpoint when we extract the
516 * data of the current one, but this is the first...
517 */
518 case 3:
519 ret = afs_extract_data(call, call->buffer, sizeof(__be32), true);
520 if (ret < 0)
521 return ret;
522
523 bp = call->buffer;
524 call->count2 = htonl(*bp++);
525 call->offset = 0;
526 call->unmarshall = 4;
527
528 /* Extract volEndpoints[] entries */
529 case 4:
530 switch (call->count2) {
531 case YFS_ENDPOINT_IPV4:
532 size = sizeof(__be32) * (1 + 1 + 1);
533 break;
534 case YFS_ENDPOINT_IPV6:
535 size = sizeof(__be32) * (1 + 4 + 1);
536 break;
537 default:
538 return -EBADMSG;
539 }
540
541 if (call->count > 1)
542 size += sizeof(__be32);
543 ret = afs_extract_data(call, call->buffer, size, true);
544 if (ret < 0)
545 return ret;
546
547 bp = call->buffer;
548 switch (call->count2) {
549 case YFS_ENDPOINT_IPV4:
550 if (ntohl(bp[0]) != sizeof(__be32) * 2)
551 return -EBADMSG;
552 bp += 3;
553 break;
554 case YFS_ENDPOINT_IPV6:
555 if (ntohl(bp[0]) != sizeof(__be32) * 5)
556 return -EBADMSG;
557 bp += 6;
558 break;
559 default:
560 return -EBADMSG;
561 }
562
563 /* Got either the type of the next entry or the count of
564 * volEndpoints if no more fsEndpoints.
565 */
566 call->offset = 0;
567 call->count--;
568 if (call->count > 0) {
569 call->count2 = htonl(*bp++);
570 goto again;
571 }
572
573 end:
574 call->unmarshall = 5;
575
576 /* Done */
577 case 5:
578 ret = afs_extract_data(call, call->buffer, 0, false);
579 if (ret < 0)
580 return ret;
581 call->unmarshall = 6;
582
583 case 6:
584 break;
585 }
586
587 alist = call->reply[0];
588
589 /* Start with IPv6 if available. */
590 if (alist->nr_ipv4 < alist->nr_addrs)
591 alist->index = alist->nr_ipv4;
592
593 _leave(" = 0 [done]");
594 return 0;
595}
596
597/*
598 * YFSVL.GetEndpoints operation type.
599 */
600static const struct afs_call_type afs_YFSVLGetEndpoints = {
601 .name = "VL.GetEndpoints",
602 .deliver = afs_deliver_yfsvl_get_endpoints,
603 .destructor = afs_vl_get_addrs_u_destructor,
604};
605
606/*
607 * Dispatch an operation to get the addresses for a server, where the server is
608 * nominated by UUID.
609 */
610struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
611 struct afs_addr_cursor *ac,
612 struct key *key,
613 const uuid_t *uuid)
614{
615 struct afs_call *call;
616 __be32 *bp;
617
618 _enter("");
619
620 call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
621 sizeof(__be32) * 2 + sizeof(*uuid),
622 sizeof(struct in6_addr) + sizeof(__be32) * 3);
623 if (!call)
624 return ERR_PTR(-ENOMEM);
625
626 call->key = key;
627 call->reply[0] = NULL;
628 call->ret_reply0 = true;
629
630 /* Marshall the parameters */
631 bp = call->request;
632 *bp++ = htonl(YVLGETENDPOINTS);
633 *bp++ = htonl(YFS_SERVER_UUID);
634 memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
635
636 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
637}