| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* Peer event handling, typically ICMP messages. |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
|---|
| 4 | 5 | * 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 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 47 | 43 | */ |
|---|
| 48 | 44 | switch (srx->transport.family) { |
|---|
| 49 | 45 | case AF_INET: |
|---|
| 46 | + srx->transport_len = sizeof(srx->transport.sin); |
|---|
| 47 | + srx->transport.family = AF_INET; |
|---|
| 50 | 48 | srx->transport.sin.sin_port = serr->port; |
|---|
| 51 | 49 | switch (serr->ee.ee_origin) { |
|---|
| 52 | 50 | case SO_EE_ORIGIN_ICMP: |
|---|
| .. | .. |
|---|
| 70 | 68 | |
|---|
| 71 | 69 | #ifdef CONFIG_AF_RXRPC_IPV6 |
|---|
| 72 | 70 | case AF_INET6: |
|---|
| 73 | | - srx->transport.sin6.sin6_port = serr->port; |
|---|
| 74 | 71 | switch (serr->ee.ee_origin) { |
|---|
| 75 | 72 | case SO_EE_ORIGIN_ICMP6: |
|---|
| 76 | 73 | _net("Rx ICMP6"); |
|---|
| 74 | + srx->transport.sin6.sin6_port = serr->port; |
|---|
| 77 | 75 | memcpy(&srx->transport.sin6.sin6_addr, |
|---|
| 78 | 76 | skb_network_header(skb) + serr->addr_offset, |
|---|
| 79 | 77 | sizeof(struct in6_addr)); |
|---|
| 80 | 78 | break; |
|---|
| 81 | 79 | case SO_EE_ORIGIN_ICMP: |
|---|
| 82 | 80 | _net("Rx ICMP on v6 sock"); |
|---|
| 83 | | - srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; |
|---|
| 84 | | - srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; |
|---|
| 85 | | - srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); |
|---|
| 86 | | - memcpy(srx->transport.sin6.sin6_addr.s6_addr + 12, |
|---|
| 81 | + srx->transport_len = sizeof(srx->transport.sin); |
|---|
| 82 | + srx->transport.family = AF_INET; |
|---|
| 83 | + srx->transport.sin.sin_port = serr->port; |
|---|
| 84 | + memcpy(&srx->transport.sin.sin_addr, |
|---|
| 87 | 85 | skb_network_header(skb) + serr->addr_offset, |
|---|
| 88 | 86 | sizeof(struct in_addr)); |
|---|
| 89 | 87 | break; |
|---|
| .. | .. |
|---|
| 149 | 147 | { |
|---|
| 150 | 148 | struct sock_exterr_skb *serr; |
|---|
| 151 | 149 | struct sockaddr_rxrpc srx; |
|---|
| 152 | | - struct rxrpc_local *local = sk->sk_user_data; |
|---|
| 150 | + struct rxrpc_local *local; |
|---|
| 153 | 151 | struct rxrpc_peer *peer; |
|---|
| 154 | 152 | struct sk_buff *skb; |
|---|
| 155 | 153 | |
|---|
| 156 | | - if (unlikely(!local)) |
|---|
| 154 | + rcu_read_lock(); |
|---|
| 155 | + local = rcu_dereference_sk_user_data(sk); |
|---|
| 156 | + if (unlikely(!local)) { |
|---|
| 157 | + rcu_read_unlock(); |
|---|
| 157 | 158 | return; |
|---|
| 158 | | - |
|---|
| 159 | + } |
|---|
| 159 | 160 | _enter("%p{%d}", sk, local->debug_id); |
|---|
| 161 | + |
|---|
| 162 | + /* Clear the outstanding error value on the socket so that it doesn't |
|---|
| 163 | + * cause kernel_sendmsg() to return it later. |
|---|
| 164 | + */ |
|---|
| 165 | + sock_error(sk); |
|---|
| 160 | 166 | |
|---|
| 161 | 167 | skb = sock_dequeue_err_skb(sk); |
|---|
| 162 | 168 | if (!skb) { |
|---|
| 169 | + rcu_read_unlock(); |
|---|
| 163 | 170 | _leave("UDP socket errqueue empty"); |
|---|
| 164 | 171 | return; |
|---|
| 165 | 172 | } |
|---|
| 166 | | - rxrpc_new_skb(skb, rxrpc_skb_rx_received); |
|---|
| 173 | + rxrpc_new_skb(skb, rxrpc_skb_received); |
|---|
| 167 | 174 | serr = SKB_EXT_ERR(skb); |
|---|
| 168 | 175 | if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { |
|---|
| 169 | 176 | _leave("UDP empty message"); |
|---|
| 170 | | - rxrpc_free_skb(skb, rxrpc_skb_rx_freed); |
|---|
| 177 | + rcu_read_unlock(); |
|---|
| 178 | + rxrpc_free_skb(skb, rxrpc_skb_freed); |
|---|
| 171 | 179 | return; |
|---|
| 172 | 180 | } |
|---|
| 173 | 181 | |
|---|
| 174 | | - rcu_read_lock(); |
|---|
| 175 | 182 | peer = rxrpc_lookup_peer_icmp_rcu(local, skb, &srx); |
|---|
| 176 | 183 | if (peer && !rxrpc_get_peer_maybe(peer)) |
|---|
| 177 | 184 | peer = NULL; |
|---|
| 178 | 185 | if (!peer) { |
|---|
| 179 | 186 | rcu_read_unlock(); |
|---|
| 180 | | - rxrpc_free_skb(skb, rxrpc_skb_rx_freed); |
|---|
| 187 | + rxrpc_free_skb(skb, rxrpc_skb_freed); |
|---|
| 181 | 188 | _leave(" [no peer]"); |
|---|
| 182 | 189 | return; |
|---|
| 183 | 190 | } |
|---|
| .. | .. |
|---|
| 189 | 196 | serr->ee.ee_code == ICMP_FRAG_NEEDED)) { |
|---|
| 190 | 197 | rxrpc_adjust_mtu(peer, serr); |
|---|
| 191 | 198 | rcu_read_unlock(); |
|---|
| 192 | | - rxrpc_free_skb(skb, rxrpc_skb_rx_freed); |
|---|
| 199 | + rxrpc_free_skb(skb, rxrpc_skb_freed); |
|---|
| 193 | 200 | rxrpc_put_peer(peer); |
|---|
| 194 | 201 | _leave(" [MTU update]"); |
|---|
| 195 | 202 | return; |
|---|
| .. | .. |
|---|
| 197 | 204 | |
|---|
| 198 | 205 | rxrpc_store_error(peer, serr); |
|---|
| 199 | 206 | rcu_read_unlock(); |
|---|
| 200 | | - rxrpc_free_skb(skb, rxrpc_skb_rx_freed); |
|---|
| 207 | + rxrpc_free_skb(skb, rxrpc_skb_freed); |
|---|
| 201 | 208 | rxrpc_put_peer(peer); |
|---|
| 202 | 209 | |
|---|
| 203 | 210 | _leave(""); |
|---|
| .. | .. |
|---|
| 264 | 271 | break; |
|---|
| 265 | 272 | |
|---|
| 266 | 273 | case SO_EE_ORIGIN_ICMP6: |
|---|
| 274 | + if (err == EACCES) |
|---|
| 275 | + err = EHOSTUNREACH; |
|---|
| 276 | + fallthrough; |
|---|
| 267 | 277 | default: |
|---|
| 268 | 278 | _proto("Rx Received error report { orig=%u }", ee->ee_origin); |
|---|
| 269 | 279 | break; |
|---|
| .. | .. |
|---|
| 282 | 292 | |
|---|
| 283 | 293 | hlist_for_each_entry_rcu(call, &peer->error_targets, error_link) { |
|---|
| 284 | 294 | rxrpc_see_call(call); |
|---|
| 285 | | - if (call->state < RXRPC_CALL_COMPLETE && |
|---|
| 286 | | - rxrpc_set_call_completion(call, compl, 0, -error)) |
|---|
| 287 | | - rxrpc_notify_socket(call); |
|---|
| 295 | + rxrpc_set_call_completion(call, compl, 0, -error); |
|---|
| 288 | 296 | } |
|---|
| 289 | | -} |
|---|
| 290 | | - |
|---|
| 291 | | -/* |
|---|
| 292 | | - * Add RTT information to cache. This is called in softirq mode and has |
|---|
| 293 | | - * exclusive access to the peer RTT data. |
|---|
| 294 | | - */ |
|---|
| 295 | | -void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why, |
|---|
| 296 | | - rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial, |
|---|
| 297 | | - ktime_t send_time, ktime_t resp_time) |
|---|
| 298 | | -{ |
|---|
| 299 | | - struct rxrpc_peer *peer = call->peer; |
|---|
| 300 | | - s64 rtt; |
|---|
| 301 | | - u64 sum = peer->rtt_sum, avg; |
|---|
| 302 | | - u8 cursor = peer->rtt_cursor, usage = peer->rtt_usage; |
|---|
| 303 | | - |
|---|
| 304 | | - rtt = ktime_to_ns(ktime_sub(resp_time, send_time)); |
|---|
| 305 | | - if (rtt < 0) |
|---|
| 306 | | - return; |
|---|
| 307 | | - |
|---|
| 308 | | - spin_lock(&peer->rtt_input_lock); |
|---|
| 309 | | - |
|---|
| 310 | | - /* Replace the oldest datum in the RTT buffer */ |
|---|
| 311 | | - sum -= peer->rtt_cache[cursor]; |
|---|
| 312 | | - sum += rtt; |
|---|
| 313 | | - peer->rtt_cache[cursor] = rtt; |
|---|
| 314 | | - peer->rtt_cursor = (cursor + 1) & (RXRPC_RTT_CACHE_SIZE - 1); |
|---|
| 315 | | - peer->rtt_sum = sum; |
|---|
| 316 | | - if (usage < RXRPC_RTT_CACHE_SIZE) { |
|---|
| 317 | | - usage++; |
|---|
| 318 | | - peer->rtt_usage = usage; |
|---|
| 319 | | - } |
|---|
| 320 | | - |
|---|
| 321 | | - spin_unlock(&peer->rtt_input_lock); |
|---|
| 322 | | - |
|---|
| 323 | | - /* Now recalculate the average */ |
|---|
| 324 | | - if (usage == RXRPC_RTT_CACHE_SIZE) { |
|---|
| 325 | | - avg = sum / RXRPC_RTT_CACHE_SIZE; |
|---|
| 326 | | - } else { |
|---|
| 327 | | - avg = sum; |
|---|
| 328 | | - do_div(avg, usage); |
|---|
| 329 | | - } |
|---|
| 330 | | - |
|---|
| 331 | | - /* Don't need to update this under lock */ |
|---|
| 332 | | - peer->rtt = avg; |
|---|
| 333 | | - trace_rxrpc_rtt_rx(call, why, send_serial, resp_serial, rtt, |
|---|
| 334 | | - usage, avg); |
|---|
| 335 | 297 | } |
|---|
| 336 | 298 | |
|---|
| 337 | 299 | /* |
|---|