VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
2874c5fd28426 (Thomas Gleixner  2019-05-27 08:55:01 +0200   1) // SPDX-License-Identifier: GPL-2.0-or-later
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   2) /* AFS vlserver list management.
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   3)  *
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   4)  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   5)  * Written by David Howells (dhowells@redhat.com)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   6)  */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   7) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   8) #include <linux/kernel.h>
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100   9) #include <linux/slab.h>
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  10) #include "internal.h"
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  11) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  12) struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  13) 					unsigned short port)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  14) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  15) 	struct afs_vlserver *vlserver;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  16) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  17) 	vlserver = kzalloc(struct_size(vlserver, name, name_len + 1),
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  18) 			   GFP_KERNEL);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  19) 	if (vlserver) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  20) 		atomic_set(&vlserver->usage, 1);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  21) 		rwlock_init(&vlserver->lock);
3bf0fb6f33dd5 (David Howells    2018-10-20 00:57:59 +0100  22) 		init_waitqueue_head(&vlserver->probe_wq);
3bf0fb6f33dd5 (David Howells    2018-10-20 00:57:59 +0100  23) 		spin_lock_init(&vlserver->probe_lock);
b95b30940ee46 (David Howells    2020-08-19 15:27:17 +0100  24) 		vlserver->rtt = UINT_MAX;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  25) 		vlserver->name_len = name_len;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  26) 		vlserver->port = port;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  27) 		memcpy(vlserver->name, name, name_len);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  28) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  29) 	return vlserver;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  30) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  31) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  32) static void afs_vlserver_rcu(struct rcu_head *rcu)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  33) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  34) 	struct afs_vlserver *vlserver = container_of(rcu, struct afs_vlserver, rcu);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  35) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  36) 	afs_put_addrlist(rcu_access_pointer(vlserver->addresses));
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  37) 	kfree_rcu(vlserver, rcu);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  38) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  39) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  40) void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  41) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  42) 	if (vlserver) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  43) 		unsigned int u = atomic_dec_return(&vlserver->usage);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  44) 		//_debug("VL PUT %p{%u}", vlserver, u);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  45) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  46) 		if (u == 0)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  47) 			call_rcu(&vlserver->rcu, afs_vlserver_rcu);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  48) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  49) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  50) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  51) struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  52) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  53) 	struct afs_vlserver_list *vllist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  54) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  55) 	vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  56) 	if (vllist) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  57) 		atomic_set(&vllist->usage, 1);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  58) 		rwlock_init(&vllist->lock);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  59) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  60) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  61) 	return vllist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  62) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  63) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  64) void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  65) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  66) 	if (vllist) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  67) 		unsigned int u = atomic_dec_return(&vllist->usage);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  68) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  69) 		//_debug("VLLS PUT %p{%u}", vllist, u);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  70) 		if (u == 0) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  71) 			int i;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  72) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  73) 			for (i = 0; i < vllist->nr_servers; i++) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  74) 				afs_put_vlserver(net, vllist->servers[i].server);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  75) 			}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  76) 			kfree_rcu(vllist, rcu);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  77) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  78) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  79) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  80) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  81) static u16 afs_extract_le16(const u8 **_b)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  82) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  83) 	u16 val;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  84) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  85) 	val  = (u16)*(*_b)++ << 0;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  86) 	val |= (u16)*(*_b)++ << 8;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  87) 	return val;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  88) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  89) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  90) /*
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  91)  * Build a VL server address list from a DNS queried server list.
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  92)  */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  93) static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  94) 						  u8 nr_addrs, u16 port)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  95) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  96) 	struct afs_addr_list *alist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  97) 	const u8 *b = *_b;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  98) 	int ret = -EINVAL;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100  99) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 100) 	alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE, port);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 101) 	if (!alist)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 102) 		return ERR_PTR(-ENOMEM);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 103) 	if (nr_addrs == 0)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 104) 		return alist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 105) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 106) 	for (; nr_addrs > 0 && end - b >= nr_addrs; nr_addrs--) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 107) 		struct dns_server_list_v1_address hdr;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 108) 		__be32 x[4];
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 109) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 110) 		hdr.address_type = *b++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 111) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 112) 		switch (hdr.address_type) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 113) 		case DNS_ADDRESS_IS_IPV4:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 114) 			if (end - b < 4) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 115) 				_leave(" = -EINVAL [short inet]");
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 116) 				goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 117) 			}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 118) 			memcpy(x, b, 4);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 119) 			afs_merge_fs_addr4(alist, x[0], port);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 120) 			b += 4;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 121) 			break;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 122) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 123) 		case DNS_ADDRESS_IS_IPV6:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 124) 			if (end - b < 16) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 125) 				_leave(" = -EINVAL [short inet6]");
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 126) 				goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 127) 			}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 128) 			memcpy(x, b, 16);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 129) 			afs_merge_fs_addr6(alist, x, port);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 130) 			b += 16;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 131) 			break;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 132) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 133) 		default:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 134) 			_leave(" = -EADDRNOTAVAIL [unknown af %u]",
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 135) 			       hdr.address_type);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 136) 			ret = -EADDRNOTAVAIL;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 137) 			goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 138) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 139) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 140) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 141) 	/* Start with IPv6 if available. */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 142) 	if (alist->nr_ipv4 < alist->nr_addrs)
3bf0fb6f33dd5 (David Howells    2018-10-20 00:57:59 +0100 143) 		alist->preferred = alist->nr_ipv4;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 144) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 145) 	*_b = b;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 146) 	return alist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 147) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 148) error:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 149) 	*_b = b;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 150) 	afs_put_addrlist(alist);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 151) 	return ERR_PTR(ret);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 152) }
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 153) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 154) /*
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 155)  * Build a VL server list from a DNS queried server list.
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 156)  */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 157) struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 158) 						    const void *buffer,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 159) 						    size_t buffer_size)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 160) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 161) 	const struct dns_server_list_v1_header *hdr = buffer;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 162) 	struct dns_server_list_v1_server bs;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 163) 	struct afs_vlserver_list *vllist, *previous;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 164) 	struct afs_addr_list *addrs;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 165) 	struct afs_vlserver *server;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 166) 	const u8 *b = buffer, *end = buffer + buffer_size;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 167) 	int ret = -ENOMEM, nr_servers, i, j;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 168) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 169) 	_enter("");
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 170) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 171) 	/* Check that it's a server list, v1 */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 172) 	if (end - b < sizeof(*hdr) ||
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 173) 	    hdr->hdr.content != DNS_PAYLOAD_IS_SERVER_LIST ||
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 174) 	    hdr->hdr.version != 1) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 175) 		pr_notice("kAFS: Got DNS record [%u,%u] len %zu\n",
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 176) 			  hdr->hdr.content, hdr->hdr.version, end - b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 177) 		ret = -EDESTADDRREQ;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 178) 		goto dump;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 179) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 180) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 181) 	nr_servers = hdr->nr_servers;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 182) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 183) 	vllist = afs_alloc_vlserver_list(nr_servers);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 184) 	if (!vllist)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 185) 		return ERR_PTR(-ENOMEM);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 186) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 187) 	vllist->source = (hdr->source < NR__dns_record_source) ?
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 188) 		hdr->source : NR__dns_record_source;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 189) 	vllist->status = (hdr->status < NR__dns_lookup_status) ?
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 190) 		hdr->status : NR__dns_lookup_status;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 191) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 192) 	read_lock(&cell->vl_servers_lock);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 193) 	previous = afs_get_vlserverlist(
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 194) 		rcu_dereference_protected(cell->vl_servers,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 195) 					  lockdep_is_held(&cell->vl_servers_lock)));
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 196) 	read_unlock(&cell->vl_servers_lock);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 197) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 198) 	b += sizeof(*hdr);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 199) 	while (end - b >= sizeof(bs)) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 200) 		bs.name_len	= afs_extract_le16(&b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 201) 		bs.priority	= afs_extract_le16(&b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 202) 		bs.weight	= afs_extract_le16(&b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 203) 		bs.port		= afs_extract_le16(&b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 204) 		bs.source	= *b++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 205) 		bs.status	= *b++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 206) 		bs.protocol	= *b++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 207) 		bs.nr_addrs	= *b++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 208) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 209) 		_debug("extract %u %u %u %u %u %u %*.*s",
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 210) 		       bs.name_len, bs.priority, bs.weight,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 211) 		       bs.port, bs.protocol, bs.nr_addrs,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 212) 		       bs.name_len, bs.name_len, b);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 213) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 214) 		if (end - b < bs.name_len)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 215) 			break;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 216) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 217) 		ret = -EPROTONOSUPPORT;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 218) 		if (bs.protocol == DNS_SERVER_PROTOCOL_UNSPECIFIED) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 219) 			bs.protocol = DNS_SERVER_PROTOCOL_UDP;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 220) 		} else if (bs.protocol != DNS_SERVER_PROTOCOL_UDP) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 221) 			_leave(" = [proto %u]", bs.protocol);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 222) 			goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 223) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 224) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 225) 		if (bs.port == 0)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 226) 			bs.port = AFS_VL_PORT;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 227) 		if (bs.source > NR__dns_record_source)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 228) 			bs.source = NR__dns_record_source;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 229) 		if (bs.status > NR__dns_lookup_status)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 230) 			bs.status = NR__dns_lookup_status;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 231) 
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 232) 		/* See if we can update an old server record */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 233) 		server = NULL;
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 234) 		for (i = 0; i < previous->nr_servers; i++) {
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 235) 			struct afs_vlserver *p = previous->servers[i].server;
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 236) 
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 237) 			if (p->name_len == bs.name_len &&
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 238) 			    p->port == bs.port &&
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 239) 			    strncasecmp(b, p->name, bs.name_len) == 0) {
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 240) 				server = afs_get_vlserver(p);
ca1cbbdce92bc (David Howells    2019-05-07 15:30:34 +0100 241) 				break;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 242) 			}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 243) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 244) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 245) 		if (!server) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 246) 			ret = -ENOMEM;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 247) 			server = afs_alloc_vlserver(b, bs.name_len, bs.port);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 248) 			if (!server)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 249) 				goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 250) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 251) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 252) 		b += bs.name_len;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 253) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 254) 		/* Extract the addresses - note that we can't skip this as we
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 255) 		 * have to advance the payload pointer.
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 256) 		 */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 257) 		addrs = afs_extract_vl_addrs(&b, end, bs.nr_addrs, bs.port);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 258) 		if (IS_ERR(addrs)) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 259) 			ret = PTR_ERR(addrs);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 260) 			goto error_2;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 261) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 262) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 263) 		if (vllist->nr_servers >= nr_servers) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 264) 			_debug("skip %u >= %u", vllist->nr_servers, nr_servers);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 265) 			afs_put_addrlist(addrs);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 266) 			afs_put_vlserver(cell->net, server);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 267) 			continue;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 268) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 269) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 270) 		addrs->source = bs.source;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 271) 		addrs->status = bs.status;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 272) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 273) 		if (addrs->nr_addrs == 0) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 274) 			afs_put_addrlist(addrs);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 275) 			if (!rcu_access_pointer(server->addresses)) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 276) 				afs_put_vlserver(cell->net, server);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 277) 				continue;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 278) 			}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 279) 		} else {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 280) 			struct afs_addr_list *old = addrs;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 281) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 282) 			write_lock(&server->lock);
62860da7082e4 (Paul E. McKenney 2019-09-23 15:28:28 -0700 283) 			old = rcu_replace_pointer(server->addresses, old,
62860da7082e4 (Paul E. McKenney 2019-09-23 15:28:28 -0700 284) 						  lockdep_is_held(&server->lock));
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 285) 			write_unlock(&server->lock);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 286) 			afs_put_addrlist(old);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 287) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 288) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 289) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 290) 		/* TODO: Might want to check for duplicates */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 291) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 292) 		/* Insertion-sort by priority and weight */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 293) 		for (j = 0; j < vllist->nr_servers; j++) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 294) 			if (bs.priority < vllist->servers[j].priority)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 295) 				break; /* Lower preferable */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 296) 			if (bs.priority == vllist->servers[j].priority &&
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 297) 			    bs.weight > vllist->servers[j].weight)
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 298) 				break; /* Higher preferable */
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 299) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 300) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 301) 		if (j < vllist->nr_servers) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 302) 			memmove(vllist->servers + j + 1,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 303) 				vllist->servers + j,
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 304) 				(vllist->nr_servers - j) * sizeof(struct afs_vlserver_entry));
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 305) 		}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 306) 
3bf0fb6f33dd5 (David Howells    2018-10-20 00:57:59 +0100 307) 		clear_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
3bf0fb6f33dd5 (David Howells    2018-10-20 00:57:59 +0100 308) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 309) 		vllist->servers[j].priority = bs.priority;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 310) 		vllist->servers[j].weight = bs.weight;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 311) 		vllist->servers[j].server = server;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 312) 		vllist->nr_servers++;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 313) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 314) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 315) 	if (b != end) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 316) 		_debug("parse error %zd", b - end);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 317) 		goto error;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 318) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 319) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 320) 	afs_put_vlserverlist(cell->net, previous);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 321) 	_leave(" = ok [%u]", vllist->nr_servers);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 322) 	return vllist;
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 323) 
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 324) error_2:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 325) 	afs_put_vlserver(cell->net, server);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 326) error:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 327) 	afs_put_vlserverlist(cell->net, vllist);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 328) 	afs_put_vlserverlist(cell->net, previous);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 329) dump:
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 330) 	if (ret != -ENOMEM) {
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 331) 		printk(KERN_DEBUG "DNS: at %zu\n", (const void *)b - buffer);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 332) 		print_hex_dump_bytes("DNS: ", DUMP_PREFIX_NONE, buffer, buffer_size);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 333) 	}
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 334) 	return ERR_PTR(ret);
0a5143f2f89cc (David Howells    2018-10-20 00:57:57 +0100 335) }