1/* AF_RXRPC local endpoint management 2 * 3 * Copyright (C) 2007 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#include <linux/module.h> 13#include <linux/net.h> 14#include <linux/skbuff.h> 15#include <net/sock.h> 16#include <net/af_rxrpc.h> 17#include "ar-internal.h" 18 19static LIST_HEAD(rxrpc_locals); 20DEFINE_RWLOCK(rxrpc_local_lock); 21static DECLARE_RWSEM(rxrpc_local_sem); 22static DECLARE_WAIT_QUEUE_HEAD(rxrpc_local_wq); 23 24static void rxrpc_destroy_local(struct work_struct *work); 25 26/* 27 * allocate a new local 28 */ 29static 30struct rxrpc_local *rxrpc_alloc_local(struct sockaddr_rxrpc *srx) 31{ 32 struct rxrpc_local *local; 33 34 local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); 35 if (local) { 36 INIT_WORK(&local->destroyer, &rxrpc_destroy_local); 37 INIT_WORK(&local->acceptor, &rxrpc_accept_incoming_calls); 38 INIT_WORK(&local->rejecter, &rxrpc_reject_packets); 39 INIT_LIST_HEAD(&local->services); 40 INIT_LIST_HEAD(&local->link); 41 init_rwsem(&local->defrag_sem); 42 skb_queue_head_init(&local->accept_queue); 43 skb_queue_head_init(&local->reject_queue); 44 spin_lock_init(&local->lock); 45 rwlock_init(&local->services_lock); 46 atomic_set(&local->usage, 1); 47 local->debug_id = atomic_inc_return(&rxrpc_debug_id); 48 memcpy(&local->srx, srx, sizeof(*srx)); 49 } 50 51 _leave(" = %p", local); 52 return local; 53} 54 55/* 56 * create the local socket 57 * - must be called with rxrpc_local_sem writelocked 58 */ 59static int rxrpc_create_local(struct rxrpc_local *local) 60{ 61 struct sock *sock; 62 int ret, opt; 63 64 _enter("%p{%d}", local, local->srx.transport_type); 65 66 /* create a socket to represent the local endpoint */ 67 ret = sock_create_kern(PF_INET, local->srx.transport_type, IPPROTO_UDP, 68 &local->socket); 69 if (ret < 0) { 70 _leave(" = %d [socket]", ret); 71 return ret; 72 } 73 74 /* if a local address was supplied then bind it */ 75 if (local->srx.transport_len > sizeof(sa_family_t)) { 76 _debug("bind"); 77 ret = kernel_bind(local->socket, 78 (struct sockaddr *) &local->srx.transport, 79 local->srx.transport_len); 80 if (ret < 0) { 81 _debug("bind failed"); 82 goto error; 83 } 84 } 85 86 /* we want to receive ICMP errors */ 87 opt = 1; 88 ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, 89 (char *) &opt, sizeof(opt)); 90 if (ret < 0) { 91 _debug("setsockopt failed"); 92 goto error; 93 } 94 95 /* we want to set the don't fragment bit */ 96 opt = IP_PMTUDISC_DO; 97 ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, 98 (char *) &opt, sizeof(opt)); 99 if (ret < 0) { 100 _debug("setsockopt failed"); 101 goto error; 102 } 103 104 write_lock_bh(&rxrpc_local_lock); 105 list_add(&local->link, &rxrpc_locals); 106 write_unlock_bh(&rxrpc_local_lock); 107 108 /* set the socket up */ 109 sock = local->socket->sk; 110 sock->sk_user_data = local; 111 sock->sk_data_ready = rxrpc_data_ready; 112 sock->sk_error_report = rxrpc_UDP_error_report; 113 _leave(" = 0"); 114 return 0; 115 116error: 117 local->socket->ops->shutdown(local->socket, 2); 118 local->socket->sk->sk_user_data = NULL; 119 sock_release(local->socket); 120 local->socket = NULL; 121 122 _leave(" = %d", ret); 123 return ret; 124} 125 126/* 127 * create a new local endpoint using the specified UDP address 128 */ 129struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx) 130{ 131 struct rxrpc_local *local; 132 int ret; 133 134 _enter("{%d,%u,%u.%u.%u.%u+%hu}", 135 srx->transport_type, 136 srx->transport.family, 137 NIPQUAD(srx->transport.sin.sin_addr), 138 ntohs(srx->transport.sin.sin_port)); 139 140 down_write(&rxrpc_local_sem); 141 142 /* see if we have a suitable local local endpoint already */ 143 read_lock_bh(&rxrpc_local_lock); 144 145 list_for_each_entry(local, &rxrpc_locals, link) { 146 _debug("CMP {%d,%u,%u.%u.%u.%u+%hu}", 147 local->srx.transport_type, 148 local->srx.transport.family, 149 NIPQUAD(local->srx.transport.sin.sin_addr), 150 ntohs(local->srx.transport.sin.sin_port)); 151 152 if (local->srx.transport_type != srx->transport_type || 153 local->srx.transport.family != srx->transport.family) 154 continue; 155 156 switch (srx->transport.family) { 157 case AF_INET: 158 if (local->srx.transport.sin.sin_port != 159 srx->transport.sin.sin_port) 160 continue; 161 if (memcmp(&local->srx.transport.sin.sin_addr, 162 &srx->transport.sin.sin_addr, 163 sizeof(struct in_addr)) != 0) 164 continue; 165 goto found_local; 166 167 default: 168 BUG(); 169 } 170 } 171 172 read_unlock_bh(&rxrpc_local_lock); 173 174 /* we didn't find one, so we need to create one */ 175 local = rxrpc_alloc_local(srx); 176 if (!local) { 177 up_write(&rxrpc_local_sem); 178 return ERR_PTR(-ENOMEM); 179 } 180 181 ret = rxrpc_create_local(local); 182 if (ret < 0) { 183 up_write(&rxrpc_local_sem); 184 kfree(local); 185 _leave(" = %d", ret); 186 return ERR_PTR(ret); 187 } 188 189 up_write(&rxrpc_local_sem); 190 191 _net("LOCAL new %d {%d,%u,%u.%u.%u.%u+%hu}", 192 local->debug_id, 193 local->srx.transport_type, 194 local->srx.transport.family, 195 NIPQUAD(local->srx.transport.sin.sin_addr), 196 ntohs(local->srx.transport.sin.sin_port)); 197 198 _leave(" = %p [new]", local); 199 return local; 200 201found_local: 202 rxrpc_get_local(local); 203 read_unlock_bh(&rxrpc_local_lock); 204 up_write(&rxrpc_local_sem); 205 206 _net("LOCAL old %d {%d,%u,%u.%u.%u.%u+%hu}", 207 local->debug_id, 208 local->srx.transport_type, 209 local->srx.transport.family, 210 NIPQUAD(local->srx.transport.sin.sin_addr), 211 ntohs(local->srx.transport.sin.sin_port)); 212 213 _leave(" = %p [reuse]", local); 214 return local; 215} 216 217/* 218 * release a local endpoint 219 */ 220void rxrpc_put_local(struct rxrpc_local *local) 221{ 222 _enter("%p{u=%d}", local, atomic_read(&local->usage)); 223 224 ASSERTCMP(atomic_read(&local->usage), >, 0); 225 226 /* to prevent a race, the decrement and the dequeue must be effectively 227 * atomic */ 228 write_lock_bh(&rxrpc_local_lock); 229 if (unlikely(atomic_dec_and_test(&local->usage))) { 230 _debug("destroy local"); 231 rxrpc_queue_work(&local->destroyer); 232 } 233 write_unlock_bh(&rxrpc_local_lock); 234 _leave(""); 235} 236 237/* 238 * destroy a local endpoint 239 */ 240static void rxrpc_destroy_local(struct work_struct *work) 241{ 242 struct rxrpc_local *local = 243 container_of(work, struct rxrpc_local, destroyer); 244 245 _enter("%p{%d}", local, atomic_read(&local->usage)); 246 247 down_write(&rxrpc_local_sem); 248 249 write_lock_bh(&rxrpc_local_lock); 250 if (atomic_read(&local->usage) > 0) { 251 write_unlock_bh(&rxrpc_local_lock); 252 up_read(&rxrpc_local_sem); 253 _leave(" [resurrected]"); 254 return; 255 } 256 257 list_del(&local->link); 258 local->socket->sk->sk_user_data = NULL; 259 write_unlock_bh(&rxrpc_local_lock); 260 261 downgrade_write(&rxrpc_local_sem); 262 263 ASSERT(list_empty(&local->services)); 264 ASSERT(!work_pending(&local->acceptor)); 265 ASSERT(!work_pending(&local->rejecter)); 266 267 /* finish cleaning up the local descriptor */ 268 rxrpc_purge_queue(&local->accept_queue); 269 rxrpc_purge_queue(&local->reject_queue); 270 local->socket->ops->shutdown(local->socket, 2); 271 sock_release(local->socket); 272 273 up_read(&rxrpc_local_sem); 274 275 _net("DESTROY LOCAL %d", local->debug_id); 276 kfree(local); 277 278 if (list_empty(&rxrpc_locals)) 279 wake_up_all(&rxrpc_local_wq); 280 281 _leave(""); 282} 283 284/* 285 * preemptively destroy all local local endpoint rather than waiting for 286 * them to be destroyed 287 */ 288void __exit rxrpc_destroy_all_locals(void) 289{ 290 DECLARE_WAITQUEUE(myself,current); 291 292 _enter(""); 293 294 /* we simply have to wait for them to go away */ 295 if (!list_empty(&rxrpc_locals)) { 296 set_current_state(TASK_UNINTERRUPTIBLE); 297 add_wait_queue(&rxrpc_local_wq, &myself); 298 299 while (!list_empty(&rxrpc_locals)) { 300 schedule(); 301 set_current_state(TASK_UNINTERRUPTIBLE); 302 } 303 304 remove_wait_queue(&rxrpc_local_wq, &myself); 305 set_current_state(TASK_RUNNING); 306 } 307 308 _leave(""); 309} 310