blob: e372f89fd36a23867e73af30d6c0a8e85a728f19 [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",
David Howells025db802017-11-02 15:27:51 +0000117 .op = afs_VL_GetEntryByNameU,
David Howellsd2ddc772017-11-02 15:27:50 +0000118 .deliver = afs_deliver_vl_get_entry_by_name_u,
119 .destructor = afs_destroy_vl_get_entry_by_name_u,
120};
121
122/*
123 * Dispatch a get volume entry by name or ID operation (uuid variant). If the
124 * volname is a decimal number then it's a volume ID not a volume name.
125 */
126struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
127 struct afs_addr_cursor *ac,
128 struct key *key,
129 const char *volname,
130 int volnamesz)
131{
132 struct afs_vldb_entry *entry;
133 struct afs_call *call;
134 size_t reqsz, padsz;
135 __be32 *bp;
136
137 _enter("");
138
139 padsz = (4 - (volnamesz & 3)) & 3;
140 reqsz = 8 + volnamesz + padsz;
141
142 entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
143 if (!entry)
144 return ERR_PTR(-ENOMEM);
145
146 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
147 sizeof(struct afs_uvldbentry__xdr));
148 if (!call) {
149 kfree(entry);
150 return ERR_PTR(-ENOMEM);
151 }
152
153 call->key = key;
154 call->reply[0] = entry;
155 call->ret_reply0 = true;
156
157 /* Marshall the parameters */
158 bp = call->request;
159 *bp++ = htonl(VLGETENTRYBYNAMEU);
160 *bp++ = htonl(volnamesz);
161 memcpy(bp, volname, volnamesz);
162 if (padsz > 0)
163 memset((void *)bp + volnamesz, 0, padsz);
164
David Howells025db802017-11-02 15:27:51 +0000165 trace_afs_make_vl_call(call);
David Howellsd2ddc772017-11-02 15:27:50 +0000166 return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false);
167}
168
169/*
170 * Deliver reply data to a VL.GetAddrsU call.
171 *
172 * GetAddrsU(IN ListAddrByAttributes *inaddr,
173 * OUT afsUUID *uuidp1,
174 * OUT uint32_t *uniquifier,
175 * OUT uint32_t *nentries,
176 * OUT bulkaddrs *blkaddrs);
177 */
178static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
179{
180 struct afs_addr_list *alist;
181 __be32 *bp;
182 u32 uniquifier, nentries, count;
183 int i, ret;
184
185 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
186
187again:
188 switch (call->unmarshall) {
189 case 0:
190 call->offset = 0;
191 call->unmarshall++;
192
193 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
194 case 1:
195 ret = afs_extract_data(call, call->buffer,
196 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
197 true);
198 if (ret < 0)
199 return ret;
200
201 bp = call->buffer + sizeof(struct afs_uuid__xdr);
202 uniquifier = ntohl(*bp++);
203 nentries = ntohl(*bp++);
204 count = ntohl(*bp);
205
206 nentries = min(nentries, count);
207 alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
208 if (!alist)
209 return -ENOMEM;
210 alist->version = uniquifier;
211 call->reply[0] = alist;
212 call->count = count;
213 call->count2 = nentries;
214 call->offset = 0;
215 call->unmarshall++;
216
217 /* Extract entries */
218 case 2:
219 count = min(call->count, 4U);
220 ret = afs_extract_data(call, call->buffer,
221 count * sizeof(__be32),
222 call->count > 4);
223 if (ret < 0)
224 return ret;
225
226 alist = call->reply[0];
227 bp = call->buffer;
228 for (i = 0; i < count; i++)
229 if (alist->nr_addrs < call->count2)
David Howellsbf99a532017-11-02 15:27:51 +0000230 afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
David Howellsd2ddc772017-11-02 15:27:50 +0000231
232 call->count -= count;
233 if (call->count > 0)
234 goto again;
235 call->offset = 0;
236 call->unmarshall++;
237 break;
238 }
David Howells08e0e7c2007-04-26 15:55:03 -0700239
240 _leave(" = 0 [done]");
241 return 0;
David Howellsec268152007-04-26 15:49:28 -0700242}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
David Howellsd2ddc772017-11-02 15:27:50 +0000244static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
David Howellsd2ddc772017-11-02 15:27:50 +0000246 afs_put_server(call->net, (struct afs_server *)call->reply[0]);
247 kfree(call->reply[1]);
248 return afs_flat_call_destructor(call);
David Howellsec268152007-04-26 15:49:28 -0700249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251/*
David Howellsd2ddc772017-11-02 15:27:50 +0000252 * VL.GetAddrsU operation type.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 */
David Howellsd2ddc772017-11-02 15:27:50 +0000254static const struct afs_call_type afs_RXVLGetAddrsU = {
255 .name = "VL.GetAddrsU",
David Howells025db802017-11-02 15:27:51 +0000256 .op = afs_VL_GetAddrsU,
David Howellsd2ddc772017-11-02 15:27:50 +0000257 .deliver = afs_deliver_vl_get_addrs_u,
258 .destructor = afs_vl_get_addrs_u_destructor,
259};
260
261/*
262 * Dispatch an operation to get the addresses for a server, where the server is
263 * nominated by UUID.
264 */
265struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
266 struct afs_addr_cursor *ac,
267 struct key *key,
268 const uuid_t *uuid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
David Howellsd2ddc772017-11-02 15:27:50 +0000270 struct afs_ListAddrByAttributes__xdr *r;
271 const struct afs_uuid *u = (const struct afs_uuid *)uuid;
David Howells08e0e7c2007-04-26 15:55:03 -0700272 struct afs_call *call;
273 __be32 *bp;
David Howellsd2ddc772017-11-02 15:27:50 +0000274 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
David Howells08e0e7c2007-04-26 15:55:03 -0700276 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
David Howellsd2ddc772017-11-02 15:27:50 +0000278 call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
279 sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
280 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
David Howells08e0e7c2007-04-26 15:55:03 -0700281 if (!call)
David Howellsd2ddc772017-11-02 15:27:50 +0000282 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
David Howells00d3b7a2007-04-26 15:57:07 -0700284 call->key = key;
David Howellsd2ddc772017-11-02 15:27:50 +0000285 call->reply[0] = NULL;
286 call->ret_reply0 = true;
David Howells08e0e7c2007-04-26 15:55:03 -0700287
David Howellsd2ddc772017-11-02 15:27:50 +0000288 /* Marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700289 bp = call->request;
David Howellsd2ddc772017-11-02 15:27:50 +0000290 *bp++ = htonl(VLGETADDRSU);
291 r = (struct afs_ListAddrByAttributes__xdr *)bp;
292 r->Mask = htonl(AFS_VLADDR_UUID);
293 r->ipaddr = 0;
294 r->index = 0;
295 r->spare = 0;
296 r->uuid.time_low = u->time_low;
297 r->uuid.time_mid = htonl(ntohs(u->time_mid));
298 r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version));
299 r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
300 r->uuid.clock_seq_low = htonl(u->clock_seq_low);
301 for (i = 0; i < 6; i++)
302 r->uuid.node[i] = ntohl(u->node[i]);
David Howells08e0e7c2007-04-26 15:55:03 -0700303
David Howells025db802017-11-02 15:27:51 +0000304 trace_afs_make_vl_call(call);
David Howellsd2ddc772017-11-02 15:27:50 +0000305 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
David Howellsec268152007-04-26 15:49:28 -0700306}
David Howellsbf99a532017-11-02 15:27:51 +0000307
308/*
309 * Deliver reply data to an VL.GetCapabilities operation.
310 */
311static int afs_deliver_vl_get_capabilities(struct afs_call *call)
312{
313 u32 count;
314 int ret;
315
316 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
317
318again:
319 switch (call->unmarshall) {
320 case 0:
321 call->offset = 0;
322 call->unmarshall++;
323
324 /* Extract the capabilities word count */
325 case 1:
326 ret = afs_extract_data(call, &call->tmp,
327 1 * sizeof(__be32),
328 true);
329 if (ret < 0)
330 return ret;
331
332 count = ntohl(call->tmp);
333
334 call->count = count;
335 call->count2 = count;
336 call->offset = 0;
337 call->unmarshall++;
338
339 /* Extract capabilities words */
340 case 2:
341 count = min(call->count, 16U);
342 ret = afs_extract_data(call, call->buffer,
343 count * sizeof(__be32),
344 call->count > 16);
345 if (ret < 0)
346 return ret;
347
348 /* TODO: Examine capabilities */
349
350 call->count -= count;
351 if (call->count > 0)
352 goto again;
353 call->offset = 0;
354 call->unmarshall++;
355 break;
356 }
357
358 call->reply[0] = (void *)(unsigned long)call->service_id;
359
360 _leave(" = 0 [done]");
361 return 0;
362}
363
364/*
365 * VL.GetCapabilities operation type
366 */
367static const struct afs_call_type afs_RXVLGetCapabilities = {
368 .name = "VL.GetCapabilities",
David Howells025db802017-11-02 15:27:51 +0000369 .op = afs_VL_GetCapabilities,
David Howellsbf99a532017-11-02 15:27:51 +0000370 .deliver = afs_deliver_vl_get_capabilities,
371 .destructor = afs_flat_call_destructor,
372};
373
374/*
375 * Probe a fileserver for the capabilities that it supports. This can
376 * return up to 196 words.
377 *
378 * We use this to probe for service upgrade to determine what the server at the
379 * other end supports.
380 */
381int afs_vl_get_capabilities(struct afs_net *net,
382 struct afs_addr_cursor *ac,
383 struct key *key)
384{
385 struct afs_call *call;
386 __be32 *bp;
387
388 _enter("");
389
390 call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
391 if (!call)
392 return -ENOMEM;
393
394 call->key = key;
395 call->upgrade = true; /* Let's see if this is a YFS server */
396 call->reply[0] = (void *)VLGETCAPABILITIES;
397 call->ret_reply0 = true;
398
399 /* marshall the parameters */
400 bp = call->request;
401 *bp++ = htonl(VLGETCAPABILITIES);
402
403 /* Can't take a ref on server */
David Howells025db802017-11-02 15:27:51 +0000404 trace_afs_make_vl_call(call);
David Howellsbf99a532017-11-02 15:27:51 +0000405 return afs_make_call(ac, call, GFP_KERNEL, false);
406}
407
408/*
409 * Deliver reply data to a YFSVL.GetEndpoints call.
410 *
411 * GetEndpoints(IN yfsServerAttributes *attr,
412 * OUT opr_uuid *uuid,
413 * OUT afs_int32 *uniquifier,
414 * OUT endpoints *fsEndpoints,
415 * OUT endpoints *volEndpoints)
416 */
417static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
418{
419 struct afs_addr_list *alist;
420 __be32 *bp;
421 u32 uniquifier, size;
422 int ret;
423
424 _enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2);
425
426again:
427 switch (call->unmarshall) {
428 case 0:
429 call->offset = 0;
430 call->unmarshall = 1;
431
432 /* Extract the returned uuid, uniquifier, fsEndpoints count and
433 * either the first fsEndpoint type or the volEndpoints
434 * count if there are no fsEndpoints. */
435 case 1:
436 ret = afs_extract_data(call, call->buffer,
437 sizeof(uuid_t) +
438 3 * sizeof(__be32),
439 true);
440 if (ret < 0)
441 return ret;
442
443 bp = call->buffer + sizeof(uuid_t);
444 uniquifier = ntohl(*bp++);
445 call->count = ntohl(*bp++);
446 call->count2 = ntohl(*bp); /* Type or next count */
447
448 if (call->count > YFS_MAXENDPOINTS)
449 return -EBADMSG;
450
451 alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
452 if (!alist)
453 return -ENOMEM;
454 alist->version = uniquifier;
455 call->reply[0] = alist;
456 call->offset = 0;
457
458 if (call->count == 0)
459 goto extract_volendpoints;
460
461 call->unmarshall = 2;
462
463 /* Extract fsEndpoints[] entries */
464 case 2:
465 switch (call->count2) {
466 case YFS_ENDPOINT_IPV4:
467 size = sizeof(__be32) * (1 + 1 + 1);
468 break;
469 case YFS_ENDPOINT_IPV6:
470 size = sizeof(__be32) * (1 + 4 + 1);
471 break;
472 default:
473 return -EBADMSG;
474 }
475
476 size += sizeof(__be32);
477 ret = afs_extract_data(call, call->buffer, size, true);
478 if (ret < 0)
479 return ret;
480
481 alist = call->reply[0];
482 bp = call->buffer;
483 switch (call->count2) {
484 case YFS_ENDPOINT_IPV4:
485 if (ntohl(bp[0]) != sizeof(__be32) * 2)
486 return -EBADMSG;
487 afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
488 bp += 3;
489 break;
490 case YFS_ENDPOINT_IPV6:
491 if (ntohl(bp[0]) != sizeof(__be32) * 5)
492 return -EBADMSG;
493 afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
494 bp += 6;
495 break;
496 default:
497 return -EBADMSG;
498 }
499
500 /* Got either the type of the next entry or the count of
501 * volEndpoints if no more fsEndpoints.
502 */
503 call->count2 = htonl(*bp++);
504
505 call->offset = 0;
506 call->count--;
507 if (call->count > 0)
508 goto again;
509
510 extract_volendpoints:
511 /* Extract the list of volEndpoints. */
512 call->count = call->count2;
513 if (!call->count)
514 goto end;
515 if (call->count > YFS_MAXENDPOINTS)
516 return -EBADMSG;
517
518 call->unmarshall = 3;
519
520 /* Extract the type of volEndpoints[0]. Normally we would
521 * extract the type of the next endpoint when we extract the
522 * data of the current one, but this is the first...
523 */
524 case 3:
525 ret = afs_extract_data(call, call->buffer, sizeof(__be32), true);
526 if (ret < 0)
527 return ret;
528
529 bp = call->buffer;
530 call->count2 = htonl(*bp++);
531 call->offset = 0;
532 call->unmarshall = 4;
533
534 /* Extract volEndpoints[] entries */
535 case 4:
536 switch (call->count2) {
537 case YFS_ENDPOINT_IPV4:
538 size = sizeof(__be32) * (1 + 1 + 1);
539 break;
540 case YFS_ENDPOINT_IPV6:
541 size = sizeof(__be32) * (1 + 4 + 1);
542 break;
543 default:
544 return -EBADMSG;
545 }
546
547 if (call->count > 1)
548 size += sizeof(__be32);
549 ret = afs_extract_data(call, call->buffer, size, true);
550 if (ret < 0)
551 return ret;
552
553 bp = call->buffer;
554 switch (call->count2) {
555 case YFS_ENDPOINT_IPV4:
556 if (ntohl(bp[0]) != sizeof(__be32) * 2)
557 return -EBADMSG;
558 bp += 3;
559 break;
560 case YFS_ENDPOINT_IPV6:
561 if (ntohl(bp[0]) != sizeof(__be32) * 5)
562 return -EBADMSG;
563 bp += 6;
564 break;
565 default:
566 return -EBADMSG;
567 }
568
569 /* Got either the type of the next entry or the count of
570 * volEndpoints if no more fsEndpoints.
571 */
572 call->offset = 0;
573 call->count--;
574 if (call->count > 0) {
575 call->count2 = htonl(*bp++);
576 goto again;
577 }
578
579 end:
580 call->unmarshall = 5;
581
582 /* Done */
583 case 5:
584 ret = afs_extract_data(call, call->buffer, 0, false);
585 if (ret < 0)
586 return ret;
587 call->unmarshall = 6;
588
589 case 6:
590 break;
591 }
592
593 alist = call->reply[0];
594
595 /* Start with IPv6 if available. */
596 if (alist->nr_ipv4 < alist->nr_addrs)
597 alist->index = alist->nr_ipv4;
598
599 _leave(" = 0 [done]");
600 return 0;
601}
602
603/*
604 * YFSVL.GetEndpoints operation type.
605 */
606static const struct afs_call_type afs_YFSVLGetEndpoints = {
David Howells025db802017-11-02 15:27:51 +0000607 .name = "YFSVL.GetEndpoints",
608 .op = afs_YFSVL_GetEndpoints,
David Howellsbf99a532017-11-02 15:27:51 +0000609 .deliver = afs_deliver_yfsvl_get_endpoints,
610 .destructor = afs_vl_get_addrs_u_destructor,
611};
612
613/*
614 * Dispatch an operation to get the addresses for a server, where the server is
615 * nominated by UUID.
616 */
617struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
618 struct afs_addr_cursor *ac,
619 struct key *key,
620 const uuid_t *uuid)
621{
622 struct afs_call *call;
623 __be32 *bp;
624
625 _enter("");
626
627 call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
628 sizeof(__be32) * 2 + sizeof(*uuid),
629 sizeof(struct in6_addr) + sizeof(__be32) * 3);
630 if (!call)
631 return ERR_PTR(-ENOMEM);
632
633 call->key = key;
634 call->reply[0] = NULL;
635 call->ret_reply0 = true;
636
637 /* Marshall the parameters */
638 bp = call->request;
639 *bp++ = htonl(YVLGETENDPOINTS);
640 *bp++ = htonl(YFS_SERVER_UUID);
641 memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
642
David Howells025db802017-11-02 15:27:51 +0000643 trace_afs_make_vl_call(call);
David Howellsbf99a532017-11-02 15:27:51 +0000644 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
645}