162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* AFS Volume Location Service client
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/gfp.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/sched.h>
1162306a36Sopenharmony_ci#include "afs_fs.h"
1262306a36Sopenharmony_ci#include "internal.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * Deliver reply data to a VL.GetEntryByNameU call.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_cistatic int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	struct afs_uvldbentry__xdr *uvldb;
2062306a36Sopenharmony_ci	struct afs_vldb_entry *entry;
2162306a36Sopenharmony_ci	bool new_only = false;
2262306a36Sopenharmony_ci	u32 tmp, nr_servers, vlflags;
2362306a36Sopenharmony_ci	int i, ret;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	_enter("");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	ret = afs_transfer_reply(call);
2862306a36Sopenharmony_ci	if (ret < 0)
2962306a36Sopenharmony_ci		return ret;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
3262306a36Sopenharmony_ci	uvldb = call->buffer;
3362306a36Sopenharmony_ci	entry = call->ret_vldb;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	nr_servers = ntohl(uvldb->nServers);
3662306a36Sopenharmony_ci	if (nr_servers > AFS_NMAXNSERVERS)
3762306a36Sopenharmony_ci		nr_servers = AFS_NMAXNSERVERS;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
4062306a36Sopenharmony_ci		entry->name[i] = (u8)ntohl(uvldb->name[i]);
4162306a36Sopenharmony_ci	entry->name[i] = 0;
4262306a36Sopenharmony_ci	entry->name_len = strlen(entry->name);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* If there is a new replication site that we can use, ignore all the
4562306a36Sopenharmony_ci	 * sites that aren't marked as new.
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	for (i = 0; i < nr_servers; i++) {
4862306a36Sopenharmony_ci		tmp = ntohl(uvldb->serverFlags[i]);
4962306a36Sopenharmony_ci		if (!(tmp & AFS_VLSF_DONTUSE) &&
5062306a36Sopenharmony_ci		    (tmp & AFS_VLSF_NEWREPSITE))
5162306a36Sopenharmony_ci			new_only = true;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	vlflags = ntohl(uvldb->flags);
5562306a36Sopenharmony_ci	for (i = 0; i < nr_servers; i++) {
5662306a36Sopenharmony_ci		struct afs_uuid__xdr *xdr;
5762306a36Sopenharmony_ci		struct afs_uuid *uuid;
5862306a36Sopenharmony_ci		int j;
5962306a36Sopenharmony_ci		int n = entry->nr_servers;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		tmp = ntohl(uvldb->serverFlags[i]);
6262306a36Sopenharmony_ci		if (tmp & AFS_VLSF_DONTUSE ||
6362306a36Sopenharmony_ci		    (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
6462306a36Sopenharmony_ci			continue;
6562306a36Sopenharmony_ci		if (tmp & AFS_VLSF_RWVOL) {
6662306a36Sopenharmony_ci			entry->fs_mask[n] |= AFS_VOL_VTM_RW;
6762306a36Sopenharmony_ci			if (vlflags & AFS_VLF_BACKEXISTS)
6862306a36Sopenharmony_ci				entry->fs_mask[n] |= AFS_VOL_VTM_BAK;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci		if (tmp & AFS_VLSF_ROVOL)
7162306a36Sopenharmony_ci			entry->fs_mask[n] |= AFS_VOL_VTM_RO;
7262306a36Sopenharmony_ci		if (!entry->fs_mask[n])
7362306a36Sopenharmony_ci			continue;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		xdr = &uvldb->serverNumber[i];
7662306a36Sopenharmony_ci		uuid = (struct afs_uuid *)&entry->fs_server[n];
7762306a36Sopenharmony_ci		uuid->time_low			= xdr->time_low;
7862306a36Sopenharmony_ci		uuid->time_mid			= htons(ntohl(xdr->time_mid));
7962306a36Sopenharmony_ci		uuid->time_hi_and_version	= htons(ntohl(xdr->time_hi_and_version));
8062306a36Sopenharmony_ci		uuid->clock_seq_hi_and_reserved	= (u8)ntohl(xdr->clock_seq_hi_and_reserved);
8162306a36Sopenharmony_ci		uuid->clock_seq_low		= (u8)ntohl(xdr->clock_seq_low);
8262306a36Sopenharmony_ci		for (j = 0; j < 6; j++)
8362306a36Sopenharmony_ci			uuid->node[j] = (u8)ntohl(xdr->node[j]);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		entry->addr_version[n] = ntohl(uvldb->serverUnique[i]);
8662306a36Sopenharmony_ci		entry->nr_servers++;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	for (i = 0; i < AFS_MAXTYPES; i++)
9062306a36Sopenharmony_ci		entry->vid[i] = ntohl(uvldb->volumeId[i]);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (vlflags & AFS_VLF_RWEXISTS)
9362306a36Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_RW, &entry->flags);
9462306a36Sopenharmony_ci	if (vlflags & AFS_VLF_ROEXISTS)
9562306a36Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_RO, &entry->flags);
9662306a36Sopenharmony_ci	if (vlflags & AFS_VLF_BACKEXISTS)
9762306a36Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
10062306a36Sopenharmony_ci		entry->error = -ENOMEDIUM;
10162306a36Sopenharmony_ci		__set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	__set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
10562306a36Sopenharmony_ci	_leave(" = 0 [done]");
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	kfree(call->ret_vldb);
11262306a36Sopenharmony_ci	afs_flat_call_destructor(call);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * VL.GetEntryByNameU operation type.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetEntryByNameU = {
11962306a36Sopenharmony_ci	.name		= "VL.GetEntryByNameU",
12062306a36Sopenharmony_ci	.op		= afs_VL_GetEntryByNameU,
12162306a36Sopenharmony_ci	.deliver	= afs_deliver_vl_get_entry_by_name_u,
12262306a36Sopenharmony_ci	.destructor	= afs_destroy_vl_get_entry_by_name_u,
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * Dispatch a get volume entry by name or ID operation (uuid variant).  If the
12762306a36Sopenharmony_ci * volname is a decimal number then it's a volume ID not a volume name.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_cistruct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
13062306a36Sopenharmony_ci						  const char *volname,
13162306a36Sopenharmony_ci						  int volnamesz)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct afs_vldb_entry *entry;
13462306a36Sopenharmony_ci	struct afs_call *call;
13562306a36Sopenharmony_ci	struct afs_net *net = vc->cell->net;
13662306a36Sopenharmony_ci	size_t reqsz, padsz;
13762306a36Sopenharmony_ci	__be32 *bp;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	_enter("");
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	padsz = (4 - (volnamesz & 3)) & 3;
14262306a36Sopenharmony_ci	reqsz = 8 + volnamesz + padsz;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
14562306a36Sopenharmony_ci	if (!entry)
14662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
14962306a36Sopenharmony_ci				   sizeof(struct afs_uvldbentry__xdr));
15062306a36Sopenharmony_ci	if (!call) {
15162306a36Sopenharmony_ci		kfree(entry);
15262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	call->key = vc->key;
15662306a36Sopenharmony_ci	call->ret_vldb = entry;
15762306a36Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Marshall the parameters */
16062306a36Sopenharmony_ci	bp = call->request;
16162306a36Sopenharmony_ci	*bp++ = htonl(VLGETENTRYBYNAMEU);
16262306a36Sopenharmony_ci	*bp++ = htonl(volnamesz);
16362306a36Sopenharmony_ci	memcpy(bp, volname, volnamesz);
16462306a36Sopenharmony_ci	if (padsz > 0)
16562306a36Sopenharmony_ci		memset((void *)bp + volnamesz, 0, padsz);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	trace_afs_make_vl_call(call);
16862306a36Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
16962306a36Sopenharmony_ci	return (struct afs_vldb_entry *)afs_wait_for_call_to_complete(call, &vc->ac);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Deliver reply data to a VL.GetAddrsU call.
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci *	GetAddrsU(IN ListAddrByAttributes *inaddr,
17662306a36Sopenharmony_ci *		  OUT afsUUID *uuidp1,
17762306a36Sopenharmony_ci *		  OUT uint32_t *uniquifier,
17862306a36Sopenharmony_ci *		  OUT uint32_t *nentries,
17962306a36Sopenharmony_ci *		  OUT bulkaddrs *blkaddrs);
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic int afs_deliver_vl_get_addrs_u(struct afs_call *call)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct afs_addr_list *alist;
18462306a36Sopenharmony_ci	__be32 *bp;
18562306a36Sopenharmony_ci	u32 uniquifier, nentries, count;
18662306a36Sopenharmony_ci	int i, ret;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	_enter("{%u,%zu/%u}",
18962306a36Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	switch (call->unmarshall) {
19262306a36Sopenharmony_ci	case 0:
19362306a36Sopenharmony_ci		afs_extract_to_buf(call,
19462306a36Sopenharmony_ci				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
19562306a36Sopenharmony_ci		call->unmarshall++;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		/* Extract the returned uuid, uniquifier, nentries and
19862306a36Sopenharmony_ci		 * blkaddrs size */
19962306a36Sopenharmony_ci		fallthrough;
20062306a36Sopenharmony_ci	case 1:
20162306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
20262306a36Sopenharmony_ci		if (ret < 0)
20362306a36Sopenharmony_ci			return ret;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		bp = call->buffer + sizeof(struct afs_uuid__xdr);
20662306a36Sopenharmony_ci		uniquifier	= ntohl(*bp++);
20762306a36Sopenharmony_ci		nentries	= ntohl(*bp++);
20862306a36Sopenharmony_ci		count		= ntohl(*bp);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		nentries = min(nentries, count);
21162306a36Sopenharmony_ci		alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
21262306a36Sopenharmony_ci		if (!alist)
21362306a36Sopenharmony_ci			return -ENOMEM;
21462306a36Sopenharmony_ci		alist->version = uniquifier;
21562306a36Sopenharmony_ci		call->ret_alist = alist;
21662306a36Sopenharmony_ci		call->count = count;
21762306a36Sopenharmony_ci		call->count2 = nentries;
21862306a36Sopenharmony_ci		call->unmarshall++;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	more_entries:
22162306a36Sopenharmony_ci		count = min(call->count, 4U);
22262306a36Sopenharmony_ci		afs_extract_to_buf(call, count * sizeof(__be32));
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		fallthrough;	/* and extract entries */
22562306a36Sopenharmony_ci	case 2:
22662306a36Sopenharmony_ci		ret = afs_extract_data(call, call->count > 4);
22762306a36Sopenharmony_ci		if (ret < 0)
22862306a36Sopenharmony_ci			return ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		alist = call->ret_alist;
23162306a36Sopenharmony_ci		bp = call->buffer;
23262306a36Sopenharmony_ci		count = min(call->count, 4U);
23362306a36Sopenharmony_ci		for (i = 0; i < count; i++)
23462306a36Sopenharmony_ci			if (alist->nr_addrs < call->count2)
23562306a36Sopenharmony_ci				afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		call->count -= count;
23862306a36Sopenharmony_ci		if (call->count > 0)
23962306a36Sopenharmony_ci			goto more_entries;
24062306a36Sopenharmony_ci		call->unmarshall++;
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	_leave(" = 0 [done]");
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void afs_vl_get_addrs_u_destructor(struct afs_call *call)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	afs_put_addrlist(call->ret_alist);
25162306a36Sopenharmony_ci	return afs_flat_call_destructor(call);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/*
25562306a36Sopenharmony_ci * VL.GetAddrsU operation type.
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetAddrsU = {
25862306a36Sopenharmony_ci	.name		= "VL.GetAddrsU",
25962306a36Sopenharmony_ci	.op		= afs_VL_GetAddrsU,
26062306a36Sopenharmony_ci	.deliver	= afs_deliver_vl_get_addrs_u,
26162306a36Sopenharmony_ci	.destructor	= afs_vl_get_addrs_u_destructor,
26262306a36Sopenharmony_ci};
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/*
26562306a36Sopenharmony_ci * Dispatch an operation to get the addresses for a server, where the server is
26662306a36Sopenharmony_ci * nominated by UUID.
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_cistruct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
26962306a36Sopenharmony_ci					 const uuid_t *uuid)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct afs_ListAddrByAttributes__xdr *r;
27262306a36Sopenharmony_ci	const struct afs_uuid *u = (const struct afs_uuid *)uuid;
27362306a36Sopenharmony_ci	struct afs_call *call;
27462306a36Sopenharmony_ci	struct afs_net *net = vc->cell->net;
27562306a36Sopenharmony_ci	__be32 *bp;
27662306a36Sopenharmony_ci	int i;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	_enter("");
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
28162306a36Sopenharmony_ci				   sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
28262306a36Sopenharmony_ci				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
28362306a36Sopenharmony_ci	if (!call)
28462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	call->key = vc->key;
28762306a36Sopenharmony_ci	call->ret_alist = NULL;
28862306a36Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* Marshall the parameters */
29162306a36Sopenharmony_ci	bp = call->request;
29262306a36Sopenharmony_ci	*bp++ = htonl(VLGETADDRSU);
29362306a36Sopenharmony_ci	r = (struct afs_ListAddrByAttributes__xdr *)bp;
29462306a36Sopenharmony_ci	r->Mask		= htonl(AFS_VLADDR_UUID);
29562306a36Sopenharmony_ci	r->ipaddr	= 0;
29662306a36Sopenharmony_ci	r->index	= 0;
29762306a36Sopenharmony_ci	r->spare	= 0;
29862306a36Sopenharmony_ci	r->uuid.time_low			= u->time_low;
29962306a36Sopenharmony_ci	r->uuid.time_mid			= htonl(ntohs(u->time_mid));
30062306a36Sopenharmony_ci	r->uuid.time_hi_and_version		= htonl(ntohs(u->time_hi_and_version));
30162306a36Sopenharmony_ci	r->uuid.clock_seq_hi_and_reserved 	= htonl(u->clock_seq_hi_and_reserved);
30262306a36Sopenharmony_ci	r->uuid.clock_seq_low			= htonl(u->clock_seq_low);
30362306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
30462306a36Sopenharmony_ci		r->uuid.node[i] = htonl(u->node[i]);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	trace_afs_make_vl_call(call);
30762306a36Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
30862306a36Sopenharmony_ci	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/*
31262306a36Sopenharmony_ci * Deliver reply data to an VL.GetCapabilities operation.
31362306a36Sopenharmony_ci */
31462306a36Sopenharmony_cistatic int afs_deliver_vl_get_capabilities(struct afs_call *call)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	u32 count;
31762306a36Sopenharmony_ci	int ret;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	_enter("{%u,%zu/%u}",
32062306a36Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	switch (call->unmarshall) {
32362306a36Sopenharmony_ci	case 0:
32462306a36Sopenharmony_ci		afs_extract_to_tmp(call);
32562306a36Sopenharmony_ci		call->unmarshall++;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		fallthrough;	/* and extract the capabilities word count */
32862306a36Sopenharmony_ci	case 1:
32962306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
33062306a36Sopenharmony_ci		if (ret < 0)
33162306a36Sopenharmony_ci			return ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		count = ntohl(call->tmp);
33462306a36Sopenharmony_ci		call->count = count;
33562306a36Sopenharmony_ci		call->count2 = count;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		call->unmarshall++;
33862306a36Sopenharmony_ci		afs_extract_discard(call, count * sizeof(__be32));
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		fallthrough;	/* and extract capabilities words */
34162306a36Sopenharmony_ci	case 2:
34262306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
34362306a36Sopenharmony_ci		if (ret < 0)
34462306a36Sopenharmony_ci			return ret;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		/* TODO: Examine capabilities */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		call->unmarshall++;
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	_leave(" = 0 [done]");
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void afs_destroy_vl_get_capabilities(struct afs_call *call)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	afs_put_vlserver(call->net, call->vlserver);
35962306a36Sopenharmony_ci	afs_flat_call_destructor(call);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*
36362306a36Sopenharmony_ci * VL.GetCapabilities operation type
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetCapabilities = {
36662306a36Sopenharmony_ci	.name		= "VL.GetCapabilities",
36762306a36Sopenharmony_ci	.op		= afs_VL_GetCapabilities,
36862306a36Sopenharmony_ci	.deliver	= afs_deliver_vl_get_capabilities,
36962306a36Sopenharmony_ci	.done		= afs_vlserver_probe_result,
37062306a36Sopenharmony_ci	.destructor	= afs_destroy_vl_get_capabilities,
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/*
37462306a36Sopenharmony_ci * Probe a volume server for the capabilities that it supports.  This can
37562306a36Sopenharmony_ci * return up to 196 words.
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * We use this to probe for service upgrade to determine what the server at the
37862306a36Sopenharmony_ci * other end supports.
37962306a36Sopenharmony_ci */
38062306a36Sopenharmony_cistruct afs_call *afs_vl_get_capabilities(struct afs_net *net,
38162306a36Sopenharmony_ci					 struct afs_addr_cursor *ac,
38262306a36Sopenharmony_ci					 struct key *key,
38362306a36Sopenharmony_ci					 struct afs_vlserver *server,
38462306a36Sopenharmony_ci					 unsigned int server_index)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct afs_call *call;
38762306a36Sopenharmony_ci	__be32 *bp;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	_enter("");
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
39262306a36Sopenharmony_ci	if (!call)
39362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	call->key = key;
39662306a36Sopenharmony_ci	call->vlserver = afs_get_vlserver(server);
39762306a36Sopenharmony_ci	call->server_index = server_index;
39862306a36Sopenharmony_ci	call->upgrade = true;
39962306a36Sopenharmony_ci	call->async = true;
40062306a36Sopenharmony_ci	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* marshall the parameters */
40362306a36Sopenharmony_ci	bp = call->request;
40462306a36Sopenharmony_ci	*bp++ = htonl(VLGETCAPABILITIES);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Can't take a ref on server */
40762306a36Sopenharmony_ci	trace_afs_make_vl_call(call);
40862306a36Sopenharmony_ci	afs_make_call(ac, call, GFP_KERNEL);
40962306a36Sopenharmony_ci	return call;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/*
41362306a36Sopenharmony_ci * Deliver reply data to a YFSVL.GetEndpoints call.
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci *	GetEndpoints(IN yfsServerAttributes *attr,
41662306a36Sopenharmony_ci *		     OUT opr_uuid *uuid,
41762306a36Sopenharmony_ci *		     OUT afs_int32 *uniquifier,
41862306a36Sopenharmony_ci *		     OUT endpoints *fsEndpoints,
41962306a36Sopenharmony_ci *		     OUT endpoints *volEndpoints)
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct afs_addr_list *alist;
42462306a36Sopenharmony_ci	__be32 *bp;
42562306a36Sopenharmony_ci	u32 uniquifier, size;
42662306a36Sopenharmony_ci	int ret;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	_enter("{%u,%zu,%u}",
42962306a36Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count2);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	switch (call->unmarshall) {
43262306a36Sopenharmony_ci	case 0:
43362306a36Sopenharmony_ci		afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32));
43462306a36Sopenharmony_ci		call->unmarshall = 1;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		/* Extract the returned uuid, uniquifier, fsEndpoints count and
43762306a36Sopenharmony_ci		 * either the first fsEndpoint type or the volEndpoints
43862306a36Sopenharmony_ci		 * count if there are no fsEndpoints. */
43962306a36Sopenharmony_ci		fallthrough;
44062306a36Sopenharmony_ci	case 1:
44162306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
44262306a36Sopenharmony_ci		if (ret < 0)
44362306a36Sopenharmony_ci			return ret;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		bp = call->buffer + sizeof(uuid_t);
44662306a36Sopenharmony_ci		uniquifier	= ntohl(*bp++);
44762306a36Sopenharmony_ci		call->count	= ntohl(*bp++);
44862306a36Sopenharmony_ci		call->count2	= ntohl(*bp); /* Type or next count */
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		if (call->count > YFS_MAXENDPOINTS)
45162306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
45462306a36Sopenharmony_ci		if (!alist)
45562306a36Sopenharmony_ci			return -ENOMEM;
45662306a36Sopenharmony_ci		alist->version = uniquifier;
45762306a36Sopenharmony_ci		call->ret_alist = alist;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (call->count == 0)
46062306a36Sopenharmony_ci			goto extract_volendpoints;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	next_fsendpoint:
46362306a36Sopenharmony_ci		switch (call->count2) {
46462306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
46562306a36Sopenharmony_ci			size = sizeof(__be32) * (1 + 1 + 1);
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
46862306a36Sopenharmony_ci			size = sizeof(__be32) * (1 + 4 + 1);
46962306a36Sopenharmony_ci			break;
47062306a36Sopenharmony_ci		default:
47162306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		size += sizeof(__be32);
47562306a36Sopenharmony_ci		afs_extract_to_buf(call, size);
47662306a36Sopenharmony_ci		call->unmarshall = 2;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		fallthrough;	/* and extract fsEndpoints[] entries */
47962306a36Sopenharmony_ci	case 2:
48062306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
48162306a36Sopenharmony_ci		if (ret < 0)
48262306a36Sopenharmony_ci			return ret;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		alist = call->ret_alist;
48562306a36Sopenharmony_ci		bp = call->buffer;
48662306a36Sopenharmony_ci		switch (call->count2) {
48762306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
48862306a36Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 2)
48962306a36Sopenharmony_ci				return afs_protocol_error(
49062306a36Sopenharmony_ci					call, afs_eproto_yvl_fsendpt4_len);
49162306a36Sopenharmony_ci			afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
49262306a36Sopenharmony_ci			bp += 3;
49362306a36Sopenharmony_ci			break;
49462306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
49562306a36Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 5)
49662306a36Sopenharmony_ci				return afs_protocol_error(
49762306a36Sopenharmony_ci					call, afs_eproto_yvl_fsendpt6_len);
49862306a36Sopenharmony_ci			afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
49962306a36Sopenharmony_ci			bp += 6;
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		default:
50262306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
50362306a36Sopenharmony_ci		}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		/* Got either the type of the next entry or the count of
50662306a36Sopenharmony_ci		 * volEndpoints if no more fsEndpoints.
50762306a36Sopenharmony_ci		 */
50862306a36Sopenharmony_ci		call->count2 = ntohl(*bp++);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		call->count--;
51162306a36Sopenharmony_ci		if (call->count > 0)
51262306a36Sopenharmony_ci			goto next_fsendpoint;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	extract_volendpoints:
51562306a36Sopenharmony_ci		/* Extract the list of volEndpoints. */
51662306a36Sopenharmony_ci		call->count = call->count2;
51762306a36Sopenharmony_ci		if (!call->count)
51862306a36Sopenharmony_ci			goto end;
51962306a36Sopenharmony_ci		if (call->count > YFS_MAXENDPOINTS)
52062306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		afs_extract_to_buf(call, 1 * sizeof(__be32));
52362306a36Sopenharmony_ci		call->unmarshall = 3;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		/* Extract the type of volEndpoints[0].  Normally we would
52662306a36Sopenharmony_ci		 * extract the type of the next endpoint when we extract the
52762306a36Sopenharmony_ci		 * data of the current one, but this is the first...
52862306a36Sopenharmony_ci		 */
52962306a36Sopenharmony_ci		fallthrough;
53062306a36Sopenharmony_ci	case 3:
53162306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
53262306a36Sopenharmony_ci		if (ret < 0)
53362306a36Sopenharmony_ci			return ret;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		bp = call->buffer;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	next_volendpoint:
53862306a36Sopenharmony_ci		call->count2 = ntohl(*bp++);
53962306a36Sopenharmony_ci		switch (call->count2) {
54062306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
54162306a36Sopenharmony_ci			size = sizeof(__be32) * (1 + 1 + 1);
54262306a36Sopenharmony_ci			break;
54362306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
54462306a36Sopenharmony_ci			size = sizeof(__be32) * (1 + 4 + 1);
54562306a36Sopenharmony_ci			break;
54662306a36Sopenharmony_ci		default:
54762306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
54862306a36Sopenharmony_ci		}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		if (call->count > 1)
55162306a36Sopenharmony_ci			size += sizeof(__be32); /* Get next type too */
55262306a36Sopenharmony_ci		afs_extract_to_buf(call, size);
55362306a36Sopenharmony_ci		call->unmarshall = 4;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		fallthrough;	/* and extract volEndpoints[] entries */
55662306a36Sopenharmony_ci	case 4:
55762306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
55862306a36Sopenharmony_ci		if (ret < 0)
55962306a36Sopenharmony_ci			return ret;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		bp = call->buffer;
56262306a36Sopenharmony_ci		switch (call->count2) {
56362306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
56462306a36Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 2)
56562306a36Sopenharmony_ci				return afs_protocol_error(
56662306a36Sopenharmony_ci					call, afs_eproto_yvl_vlendpt4_len);
56762306a36Sopenharmony_ci			bp += 3;
56862306a36Sopenharmony_ci			break;
56962306a36Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
57062306a36Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 5)
57162306a36Sopenharmony_ci				return afs_protocol_error(
57262306a36Sopenharmony_ci					call, afs_eproto_yvl_vlendpt6_len);
57362306a36Sopenharmony_ci			bp += 6;
57462306a36Sopenharmony_ci			break;
57562306a36Sopenharmony_ci		default:
57662306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		/* Got either the type of the next entry or the count of
58062306a36Sopenharmony_ci		 * volEndpoints if no more fsEndpoints.
58162306a36Sopenharmony_ci		 */
58262306a36Sopenharmony_ci		call->count--;
58362306a36Sopenharmony_ci		if (call->count > 0)
58462306a36Sopenharmony_ci			goto next_volendpoint;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	end:
58762306a36Sopenharmony_ci		afs_extract_discard(call, 0);
58862306a36Sopenharmony_ci		call->unmarshall = 5;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		fallthrough;	/* Done */
59162306a36Sopenharmony_ci	case 5:
59262306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
59362306a36Sopenharmony_ci		if (ret < 0)
59462306a36Sopenharmony_ci			return ret;
59562306a36Sopenharmony_ci		call->unmarshall = 6;
59662306a36Sopenharmony_ci		fallthrough;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	case 6:
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	_leave(" = 0 [done]");
60362306a36Sopenharmony_ci	return 0;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci/*
60762306a36Sopenharmony_ci * YFSVL.GetEndpoints operation type.
60862306a36Sopenharmony_ci */
60962306a36Sopenharmony_cistatic const struct afs_call_type afs_YFSVLGetEndpoints = {
61062306a36Sopenharmony_ci	.name		= "YFSVL.GetEndpoints",
61162306a36Sopenharmony_ci	.op		= afs_YFSVL_GetEndpoints,
61262306a36Sopenharmony_ci	.deliver	= afs_deliver_yfsvl_get_endpoints,
61362306a36Sopenharmony_ci	.destructor	= afs_vl_get_addrs_u_destructor,
61462306a36Sopenharmony_ci};
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/*
61762306a36Sopenharmony_ci * Dispatch an operation to get the addresses for a server, where the server is
61862306a36Sopenharmony_ci * nominated by UUID.
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_cistruct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
62162306a36Sopenharmony_ci					      const uuid_t *uuid)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct afs_call *call;
62462306a36Sopenharmony_ci	struct afs_net *net = vc->cell->net;
62562306a36Sopenharmony_ci	__be32 *bp;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	_enter("");
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
63062306a36Sopenharmony_ci				   sizeof(__be32) * 2 + sizeof(*uuid),
63162306a36Sopenharmony_ci				   sizeof(struct in6_addr) + sizeof(__be32) * 3);
63262306a36Sopenharmony_ci	if (!call)
63362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	call->key = vc->key;
63662306a36Sopenharmony_ci	call->ret_alist = NULL;
63762306a36Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* Marshall the parameters */
64062306a36Sopenharmony_ci	bp = call->request;
64162306a36Sopenharmony_ci	*bp++ = htonl(YVLGETENDPOINTS);
64262306a36Sopenharmony_ci	*bp++ = htonl(YFS_SERVER_UUID);
64362306a36Sopenharmony_ci	memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	trace_afs_make_vl_call(call);
64662306a36Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
64762306a36Sopenharmony_ci	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci/*
65162306a36Sopenharmony_ci * Deliver reply data to a YFSVL.GetCellName operation.
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	char *cell_name;
65662306a36Sopenharmony_ci	u32 namesz, paddedsz;
65762306a36Sopenharmony_ci	int ret;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	_enter("{%u,%zu/%u}",
66062306a36Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	switch (call->unmarshall) {
66362306a36Sopenharmony_ci	case 0:
66462306a36Sopenharmony_ci		afs_extract_to_tmp(call);
66562306a36Sopenharmony_ci		call->unmarshall++;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		fallthrough;	/* and extract the cell name length */
66862306a36Sopenharmony_ci	case 1:
66962306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
67062306a36Sopenharmony_ci		if (ret < 0)
67162306a36Sopenharmony_ci			return ret;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		namesz = ntohl(call->tmp);
67462306a36Sopenharmony_ci		if (namesz > AFS_MAXCELLNAME)
67562306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_cellname_len);
67662306a36Sopenharmony_ci		paddedsz = (namesz + 3) & ~3;
67762306a36Sopenharmony_ci		call->count = namesz;
67862306a36Sopenharmony_ci		call->count2 = paddedsz - namesz;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		cell_name = kmalloc(namesz + 1, GFP_KERNEL);
68162306a36Sopenharmony_ci		if (!cell_name)
68262306a36Sopenharmony_ci			return -ENOMEM;
68362306a36Sopenharmony_ci		cell_name[namesz] = 0;
68462306a36Sopenharmony_ci		call->ret_str = cell_name;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		afs_extract_begin(call, cell_name, namesz);
68762306a36Sopenharmony_ci		call->unmarshall++;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		fallthrough;	/* and extract cell name */
69062306a36Sopenharmony_ci	case 2:
69162306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
69262306a36Sopenharmony_ci		if (ret < 0)
69362306a36Sopenharmony_ci			return ret;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		afs_extract_discard(call, call->count2);
69662306a36Sopenharmony_ci		call->unmarshall++;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		fallthrough;	/* and extract padding */
69962306a36Sopenharmony_ci	case 3:
70062306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
70162306a36Sopenharmony_ci		if (ret < 0)
70262306a36Sopenharmony_ci			return ret;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		call->unmarshall++;
70562306a36Sopenharmony_ci		break;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	_leave(" = 0 [done]");
70962306a36Sopenharmony_ci	return 0;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic void afs_destroy_yfsvl_get_cell_name(struct afs_call *call)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	kfree(call->ret_str);
71562306a36Sopenharmony_ci	afs_flat_call_destructor(call);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci/*
71962306a36Sopenharmony_ci * VL.GetCapabilities operation type
72062306a36Sopenharmony_ci */
72162306a36Sopenharmony_cistatic const struct afs_call_type afs_YFSVLGetCellName = {
72262306a36Sopenharmony_ci	.name		= "YFSVL.GetCellName",
72362306a36Sopenharmony_ci	.op		= afs_YFSVL_GetCellName,
72462306a36Sopenharmony_ci	.deliver	= afs_deliver_yfsvl_get_cell_name,
72562306a36Sopenharmony_ci	.destructor	= afs_destroy_yfsvl_get_cell_name,
72662306a36Sopenharmony_ci};
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/*
72962306a36Sopenharmony_ci * Probe a volume server for the capabilities that it supports.  This can
73062306a36Sopenharmony_ci * return up to 196 words.
73162306a36Sopenharmony_ci *
73262306a36Sopenharmony_ci * We use this to probe for service upgrade to determine what the server at the
73362306a36Sopenharmony_ci * other end supports.
73462306a36Sopenharmony_ci */
73562306a36Sopenharmony_cichar *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	struct afs_call *call;
73862306a36Sopenharmony_ci	struct afs_net *net = vc->cell->net;
73962306a36Sopenharmony_ci	__be32 *bp;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	_enter("");
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_YFSVLGetCellName, 1 * 4, 0);
74462306a36Sopenharmony_ci	if (!call)
74562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	call->key = vc->key;
74862306a36Sopenharmony_ci	call->ret_str = NULL;
74962306a36Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* marshall the parameters */
75262306a36Sopenharmony_ci	bp = call->request;
75362306a36Sopenharmony_ci	*bp++ = htonl(YVLGETCELLNAME);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* Can't take a ref on server */
75662306a36Sopenharmony_ci	trace_afs_make_vl_call(call);
75762306a36Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
75862306a36Sopenharmony_ci	return (char *)afs_wait_for_call_to_complete(call, &vc->ac);
75962306a36Sopenharmony_ci}
760