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) }