1 /* RxRPC remote transport endpoint record management 2 * 3 * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 14 #include <linux/module.h> 15 #include <linux/net.h> 16 #include <linux/skbuff.h> 17 #include <linux/udp.h> 18 #include <linux/in.h> 19 #include <linux/slab.h> 20 #include <linux/hashtable.h> 21 #include <net/sock.h> 22 #include <net/af_rxrpc.h> 23 #include <net/ip.h> 24 #include <net/route.h> 25 #include "ar-internal.h" 26 27 static DEFINE_HASHTABLE(rxrpc_peer_hash, 10); 28 static DEFINE_SPINLOCK(rxrpc_peer_hash_lock); 29 30 /* 31 * Hash a peer key. 32 */ 33 static unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local, 34 const struct sockaddr_rxrpc *srx) 35 { 36 const u16 *p; 37 unsigned int i, size; 38 unsigned long hash_key; 39 40 _enter(""); 41 42 hash_key = (unsigned long)local / __alignof__(*local); 43 hash_key += srx->transport_type; 44 hash_key += srx->transport_len; 45 hash_key += srx->transport.family; 46 47 switch (srx->transport.family) { 48 case AF_INET: 49 hash_key += (u16 __force)srx->transport.sin.sin_port; 50 size = sizeof(srx->transport.sin.sin_addr); 51 p = (u16 *)&srx->transport.sin.sin_addr; 52 break; 53 } 54 55 /* Step through the peer address in 16-bit portions for speed */ 56 for (i = 0; i < size; i += sizeof(*p), p++) 57 hash_key += *p; 58 59 _leave(" 0x%lx", hash_key); 60 return hash_key; 61 } 62 63 /* 64 * Compare a peer to a key. Return -ve, 0 or +ve to indicate less than, same 65 * or greater than. 66 * 67 * Unfortunately, the primitives in linux/hashtable.h don't allow for sorted 68 * buckets and mid-bucket insertion, so we don't make full use of this 69 * information at this point. 70 */ 71 static long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer, 72 struct rxrpc_local *local, 73 const struct sockaddr_rxrpc *srx, 74 unsigned long hash_key) 75 { 76 long diff; 77 78 diff = ((peer->hash_key - hash_key) ?: 79 ((unsigned long)peer->local - (unsigned long)local) ?: 80 (peer->srx.transport_type - srx->transport_type) ?: 81 (peer->srx.transport_len - srx->transport_len) ?: 82 (peer->srx.transport.family - srx->transport.family)); 83 if (diff != 0) 84 return diff; 85 86 switch (srx->transport.family) { 87 case AF_INET: 88 return ((u16 __force)peer->srx.transport.sin.sin_port - 89 (u16 __force)srx->transport.sin.sin_port) ?: 90 memcmp(&peer->srx.transport.sin.sin_addr, 91 &srx->transport.sin.sin_addr, 92 sizeof(struct in_addr)); 93 default: 94 BUG(); 95 } 96 } 97 98 /* 99 * Look up a remote transport endpoint for the specified address using RCU. 100 */ 101 static struct rxrpc_peer *__rxrpc_lookup_peer_rcu( 102 struct rxrpc_local *local, 103 const struct sockaddr_rxrpc *srx, 104 unsigned long hash_key) 105 { 106 struct rxrpc_peer *peer; 107 108 hash_for_each_possible_rcu(rxrpc_peer_hash, peer, hash_link, hash_key) { 109 if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0) { 110 if (atomic_read(&peer->usage) == 0) 111 return NULL; 112 return peer; 113 } 114 } 115 116 return NULL; 117 } 118 119 /* 120 * Look up a remote transport endpoint for the specified address using RCU. 121 */ 122 struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local, 123 const struct sockaddr_rxrpc *srx) 124 { 125 struct rxrpc_peer *peer; 126 unsigned long hash_key = rxrpc_peer_hash_key(local, srx); 127 128 peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 129 if (peer) { 130 switch (srx->transport.family) { 131 case AF_INET: 132 _net("PEER %d {%d,%u,%pI4+%hu}", 133 peer->debug_id, 134 peer->srx.transport_type, 135 peer->srx.transport.family, 136 &peer->srx.transport.sin.sin_addr, 137 ntohs(peer->srx.transport.sin.sin_port)); 138 break; 139 } 140 141 _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); 142 } 143 return peer; 144 } 145 146 /* 147 * assess the MTU size for the network interface through which this peer is 148 * reached 149 */ 150 static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) 151 { 152 struct rtable *rt; 153 struct flowi4 fl4; 154 155 peer->if_mtu = 1500; 156 157 rt = ip_route_output_ports(&init_net, &fl4, NULL, 158 peer->srx.transport.sin.sin_addr.s_addr, 0, 159 htons(7000), htons(7001), 160 IPPROTO_UDP, 0, 0); 161 if (IS_ERR(rt)) { 162 _leave(" [route err %ld]", PTR_ERR(rt)); 163 return; 164 } 165 166 peer->if_mtu = dst_mtu(&rt->dst); 167 dst_release(&rt->dst); 168 169 _leave(" [if_mtu %u]", peer->if_mtu); 170 } 171 172 /* 173 * Allocate a peer. 174 */ 175 struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp) 176 { 177 struct rxrpc_peer *peer; 178 179 _enter(""); 180 181 peer = kzalloc(sizeof(struct rxrpc_peer), gfp); 182 if (peer) { 183 atomic_set(&peer->usage, 1); 184 peer->local = local; 185 INIT_HLIST_HEAD(&peer->error_targets); 186 INIT_WORK(&peer->error_distributor, 187 &rxrpc_peer_error_distributor); 188 spin_lock_init(&peer->lock); 189 peer->debug_id = atomic_inc_return(&rxrpc_debug_id); 190 } 191 192 _leave(" = %p", peer); 193 return peer; 194 } 195 196 /* 197 * Set up a new peer. 198 */ 199 static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local, 200 struct sockaddr_rxrpc *srx, 201 unsigned long hash_key, 202 gfp_t gfp) 203 { 204 struct rxrpc_peer *peer; 205 206 _enter(""); 207 208 peer = rxrpc_alloc_peer(local, gfp); 209 if (peer) { 210 peer->hash_key = hash_key; 211 memcpy(&peer->srx, srx, sizeof(*srx)); 212 213 rxrpc_assess_MTU_size(peer); 214 peer->mtu = peer->if_mtu; 215 216 if (srx->transport.family == AF_INET) { 217 peer->hdrsize = sizeof(struct iphdr); 218 switch (srx->transport_type) { 219 case SOCK_DGRAM: 220 peer->hdrsize += sizeof(struct udphdr); 221 break; 222 default: 223 BUG(); 224 break; 225 } 226 } else { 227 BUG(); 228 } 229 230 peer->hdrsize += sizeof(struct rxrpc_wire_header); 231 peer->maxdata = peer->mtu - peer->hdrsize; 232 } 233 234 _leave(" = %p", peer); 235 return peer; 236 } 237 238 /* 239 * obtain a remote transport endpoint for the specified address 240 */ 241 struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, 242 struct sockaddr_rxrpc *srx, gfp_t gfp) 243 { 244 struct rxrpc_peer *peer, *candidate; 245 unsigned long hash_key = rxrpc_peer_hash_key(local, srx); 246 247 _enter("{%d,%d,%pI4+%hu}", 248 srx->transport_type, 249 srx->transport_len, 250 &srx->transport.sin.sin_addr, 251 ntohs(srx->transport.sin.sin_port)); 252 253 /* search the peer list first */ 254 rcu_read_lock(); 255 peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 256 if (peer && !rxrpc_get_peer_maybe(peer)) 257 peer = NULL; 258 rcu_read_unlock(); 259 260 if (!peer) { 261 /* The peer is not yet present in hash - create a candidate 262 * for a new record and then redo the search. 263 */ 264 candidate = rxrpc_create_peer(local, srx, hash_key, gfp); 265 if (!candidate) { 266 _leave(" = NULL [nomem]"); 267 return NULL; 268 } 269 270 spin_lock(&rxrpc_peer_hash_lock); 271 272 /* Need to check that we aren't racing with someone else */ 273 peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 274 if (peer && !rxrpc_get_peer_maybe(peer)) 275 peer = NULL; 276 if (!peer) 277 hash_add_rcu(rxrpc_peer_hash, 278 &candidate->hash_link, hash_key); 279 280 spin_unlock(&rxrpc_peer_hash_lock); 281 282 if (peer) 283 kfree(candidate); 284 else 285 peer = candidate; 286 } 287 288 _net("PEER %d {%d,%pI4+%hu}", 289 peer->debug_id, 290 peer->srx.transport_type, 291 &peer->srx.transport.sin.sin_addr, 292 ntohs(peer->srx.transport.sin.sin_port)); 293 294 _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); 295 return peer; 296 } 297 298 /* 299 * Discard a ref on a remote peer record. 300 */ 301 void __rxrpc_put_peer(struct rxrpc_peer *peer) 302 { 303 ASSERT(hlist_empty(&peer->error_targets)); 304 305 spin_lock(&rxrpc_peer_hash_lock); 306 hash_del_rcu(&peer->hash_link); 307 spin_unlock(&rxrpc_peer_hash_lock); 308 309 kfree_rcu(peer, rcu); 310 } 311