12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 28c3e34a4SDavid Howells /* RxRPC packet transmission 38c3e34a4SDavid Howells * 48c3e34a4SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 58c3e34a4SDavid Howells * Written by David Howells (dhowells@redhat.com) 68c3e34a4SDavid Howells */ 78c3e34a4SDavid Howells 88c3e34a4SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c3e34a4SDavid Howells 108c3e34a4SDavid Howells #include <linux/net.h> 118c3e34a4SDavid Howells #include <linux/gfp.h> 128c3e34a4SDavid Howells #include <linux/skbuff.h> 138c3e34a4SDavid Howells #include <linux/export.h> 148c3e34a4SDavid Howells #include <net/sock.h> 158c3e34a4SDavid Howells #include <net/af_rxrpc.h> 16ed472b0cSDavid Howells #include <net/udp.h> 178c3e34a4SDavid Howells #include "ar-internal.h" 188c3e34a4SDavid Howells 19ed472b0cSDavid Howells extern int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); 20ed472b0cSDavid Howells 21ed472b0cSDavid Howells static ssize_t do_udp_sendmsg(struct socket *sk, struct msghdr *msg, size_t len) 22ed472b0cSDavid Howells { 23ed472b0cSDavid Howells #if IS_ENABLED(CONFIG_AF_RXRPC_IPV6) 24ed472b0cSDavid Howells struct sockaddr *sa = msg->msg_name; 25ed472b0cSDavid Howells 26ed472b0cSDavid Howells if (sa->sa_family == AF_INET6) 27ed472b0cSDavid Howells return udpv6_sendmsg(sk->sk, msg, len); 28ed472b0cSDavid Howells #endif 29ed472b0cSDavid Howells return udp_sendmsg(sk->sk, msg, len); 30ed472b0cSDavid Howells } 31ed472b0cSDavid Howells 3226cb02aaSDavid Howells struct rxrpc_abort_buffer { 3326cb02aaSDavid Howells struct rxrpc_wire_header whdr; 3426cb02aaSDavid Howells __be32 abort_code; 3526cb02aaSDavid Howells }; 3626cb02aaSDavid Howells 37ace45becSDavid Howells static const char rxrpc_keepalive_string[] = ""; 38ace45becSDavid Howells 398d94aa38SDavid Howells /* 40c7e86acfSDavid Howells * Increase Tx backoff on transmission failure and clear it on success. 41c7e86acfSDavid Howells */ 42c7e86acfSDavid Howells static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret) 43c7e86acfSDavid Howells { 44c7e86acfSDavid Howells if (ret < 0) { 45c7e86acfSDavid Howells u16 tx_backoff = READ_ONCE(call->tx_backoff); 46c7e86acfSDavid Howells 47c7e86acfSDavid Howells if (tx_backoff < HZ) 48c7e86acfSDavid Howells WRITE_ONCE(call->tx_backoff, tx_backoff + 1); 49c7e86acfSDavid Howells } else { 50c7e86acfSDavid Howells WRITE_ONCE(call->tx_backoff, 0); 51c7e86acfSDavid Howells } 52c7e86acfSDavid Howells } 53c7e86acfSDavid Howells 54c7e86acfSDavid Howells /* 55415f44e4SDavid Howells * Arrange for a keepalive ping a certain time after we last transmitted. This 56415f44e4SDavid Howells * lets the far side know we're still interested in this call and helps keep 57415f44e4SDavid Howells * the route through any intervening firewall open. 58415f44e4SDavid Howells * 59415f44e4SDavid Howells * Receiving a response to the ping will prevent the ->expect_rx_by timer from 60415f44e4SDavid Howells * expiring. 61415f44e4SDavid Howells */ 62415f44e4SDavid Howells static void rxrpc_set_keepalive(struct rxrpc_call *call) 63415f44e4SDavid Howells { 64415f44e4SDavid Howells unsigned long now = jiffies, keepalive_at = call->next_rx_timo / 6; 65415f44e4SDavid Howells 66415f44e4SDavid Howells keepalive_at += now; 67415f44e4SDavid Howells WRITE_ONCE(call->keepalive_at, keepalive_at); 68415f44e4SDavid Howells rxrpc_reduce_call_timer(call, keepalive_at, now, 69415f44e4SDavid Howells rxrpc_timer_set_for_keepalive); 70415f44e4SDavid Howells } 71415f44e4SDavid Howells 72415f44e4SDavid Howells /* 738d94aa38SDavid Howells * Fill out an ACK packet. 748d94aa38SDavid Howells */ 751457cc4cSDavid Howells static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, 761457cc4cSDavid Howells struct rxrpc_call *call, 77*5d7edbc9SDavid Howells struct rxrpc_txbuf *txb) 788d94aa38SDavid Howells { 7972f0c6fbSDavid Howells struct rxrpc_ackinfo ackinfo; 80*5d7edbc9SDavid Howells unsigned int qsize; 81*5d7edbc9SDavid Howells rxrpc_seq_t window, wtop, wrap_point, ix, first; 82*5d7edbc9SDavid Howells int rsize; 83*5d7edbc9SDavid Howells u64 wtmp; 848d94aa38SDavid Howells u32 mtu, jmax; 8572f0c6fbSDavid Howells u8 *ackp = txb->acks; 86*5d7edbc9SDavid Howells u8 sack_buffer[sizeof(call->ackr_sack_table)] __aligned(8); 878d94aa38SDavid Howells 88*5d7edbc9SDavid Howells atomic_set(&call->ackr_nr_unacked, 0); 89*5d7edbc9SDavid Howells atomic_set(&call->ackr_nr_consumed, 0); 90f2a676d1SDavid Howells rxrpc_inc_stat(call->rxnet, stat_tx_ack_fill); 919a3dedcfSDavid Howells 92248f219cSDavid Howells /* Barrier against rxrpc_input_data(). */ 93*5d7edbc9SDavid Howells retry: 94*5d7edbc9SDavid Howells wtmp = atomic64_read_acquire(&call->ackr_window); 95*5d7edbc9SDavid Howells window = lower_32_bits(wtmp); 96*5d7edbc9SDavid Howells wtop = upper_32_bits(wtmp); 97*5d7edbc9SDavid Howells txb->ack.firstPacket = htonl(window); 98*5d7edbc9SDavid Howells txb->ack.nAcks = 0; 99248f219cSDavid Howells 100*5d7edbc9SDavid Howells if (after(wtop, window)) { 101*5d7edbc9SDavid Howells /* Try to copy the SACK ring locklessly. We can use the copy, 102*5d7edbc9SDavid Howells * only if the now-current top of the window didn't go past the 103*5d7edbc9SDavid Howells * previously read base - otherwise we can't know whether we 104*5d7edbc9SDavid Howells * have old data or new data. 105*5d7edbc9SDavid Howells */ 106*5d7edbc9SDavid Howells memcpy(sack_buffer, call->ackr_sack_table, sizeof(sack_buffer)); 107*5d7edbc9SDavid Howells wrap_point = window + RXRPC_SACK_SIZE - 1; 108*5d7edbc9SDavid Howells wtmp = atomic64_read_acquire(&call->ackr_window); 109*5d7edbc9SDavid Howells window = lower_32_bits(wtmp); 110*5d7edbc9SDavid Howells wtop = upper_32_bits(wtmp); 111*5d7edbc9SDavid Howells if (after(wtop, wrap_point)) { 112*5d7edbc9SDavid Howells cond_resched(); 113*5d7edbc9SDavid Howells goto retry; 114*5d7edbc9SDavid Howells } 1158d94aa38SDavid Howells 116*5d7edbc9SDavid Howells /* The buffer is maintained as a ring with an invariant mapping 117*5d7edbc9SDavid Howells * between bit position and sequence number, so we'll probably 118*5d7edbc9SDavid Howells * need to rotate it. 119*5d7edbc9SDavid Howells */ 120*5d7edbc9SDavid Howells txb->ack.nAcks = wtop - window; 121*5d7edbc9SDavid Howells ix = window % RXRPC_SACK_SIZE; 122*5d7edbc9SDavid Howells first = sizeof(sack_buffer) - ix; 123*5d7edbc9SDavid Howells 124*5d7edbc9SDavid Howells if (ix + txb->ack.nAcks <= RXRPC_SACK_SIZE) { 125*5d7edbc9SDavid Howells memcpy(txb->acks, sack_buffer + ix, txb->ack.nAcks); 126*5d7edbc9SDavid Howells } else { 127*5d7edbc9SDavid Howells memcpy(txb->acks, sack_buffer + ix, first); 128*5d7edbc9SDavid Howells memcpy(txb->acks + first, sack_buffer, 129*5d7edbc9SDavid Howells txb->ack.nAcks - first); 130*5d7edbc9SDavid Howells } 131*5d7edbc9SDavid Howells 132*5d7edbc9SDavid Howells ackp += txb->ack.nAcks; 133*5d7edbc9SDavid Howells } else if (before(wtop, window)) { 134*5d7edbc9SDavid Howells pr_warn("ack window backward %x %x", window, wtop); 135530403d9SDavid Howells } else if (txb->ack.reason == RXRPC_ACK_DELAY) { 136530403d9SDavid Howells txb->ack.reason = RXRPC_ACK_IDLE; 137248f219cSDavid Howells } 138248f219cSDavid Howells 1391457cc4cSDavid Howells mtu = conn->params.peer->if_mtu; 1401457cc4cSDavid Howells mtu -= conn->params.peer->hdrsize; 141d4d02d8bSDavid Howells jmax = rxrpc_rx_jumbo_max; 142*5d7edbc9SDavid Howells qsize = (window - 1) - call->rx_consumed; 143*5d7edbc9SDavid Howells rsize = max_t(int, call->rx_winsize - qsize, 0); 14472f0c6fbSDavid Howells ackinfo.rxMTU = htonl(rxrpc_rx_mtu); 14572f0c6fbSDavid Howells ackinfo.maxMTU = htonl(mtu); 146*5d7edbc9SDavid Howells ackinfo.rwind = htonl(rsize); 14772f0c6fbSDavid Howells ackinfo.jumbo_max = htonl(jmax); 1488d94aa38SDavid Howells 1498d94aa38SDavid Howells *ackp++ = 0; 1508d94aa38SDavid Howells *ackp++ = 0; 1518d94aa38SDavid Howells *ackp++ = 0; 15272f0c6fbSDavid Howells memcpy(ackp, &ackinfo, sizeof(ackinfo)); 153*5d7edbc9SDavid Howells return txb->ack.nAcks + 3 + sizeof(ackinfo); 1548d94aa38SDavid Howells } 1558d94aa38SDavid Howells 1568d94aa38SDavid Howells /* 1574700c4d8SDavid Howells * Record the beginning of an RTT probe. 1584700c4d8SDavid Howells */ 1594700c4d8SDavid Howells static int rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial, 1604700c4d8SDavid Howells enum rxrpc_rtt_tx_trace why) 1614700c4d8SDavid Howells { 1624700c4d8SDavid Howells unsigned long avail = call->rtt_avail; 1634700c4d8SDavid Howells int rtt_slot = 9; 1644700c4d8SDavid Howells 1654700c4d8SDavid Howells if (!(avail & RXRPC_CALL_RTT_AVAIL_MASK)) 1664700c4d8SDavid Howells goto no_slot; 1674700c4d8SDavid Howells 1684700c4d8SDavid Howells rtt_slot = __ffs(avail & RXRPC_CALL_RTT_AVAIL_MASK); 1694700c4d8SDavid Howells if (!test_and_clear_bit(rtt_slot, &call->rtt_avail)) 1704700c4d8SDavid Howells goto no_slot; 1714700c4d8SDavid Howells 1724700c4d8SDavid Howells call->rtt_serial[rtt_slot] = serial; 1734700c4d8SDavid Howells call->rtt_sent_at[rtt_slot] = ktime_get_real(); 1744700c4d8SDavid Howells smp_wmb(); /* Write data before avail bit */ 1754700c4d8SDavid Howells set_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail); 1764700c4d8SDavid Howells 1774700c4d8SDavid Howells trace_rxrpc_rtt_tx(call, why, rtt_slot, serial); 1784700c4d8SDavid Howells return rtt_slot; 1794700c4d8SDavid Howells 1804700c4d8SDavid Howells no_slot: 1814700c4d8SDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_no_slot, rtt_slot, serial); 1824700c4d8SDavid Howells return -1; 1834700c4d8SDavid Howells } 1844700c4d8SDavid Howells 1854700c4d8SDavid Howells /* 1864700c4d8SDavid Howells * Cancel an RTT probe. 1874700c4d8SDavid Howells */ 1884700c4d8SDavid Howells static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, 1894700c4d8SDavid Howells rxrpc_serial_t serial, int rtt_slot) 1904700c4d8SDavid Howells { 1914700c4d8SDavid Howells if (rtt_slot != -1) { 1924700c4d8SDavid Howells clear_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail); 1934700c4d8SDavid Howells smp_wmb(); /* Clear pending bit before setting slot */ 1944700c4d8SDavid Howells set_bit(rtt_slot, &call->rtt_avail); 1954700c4d8SDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_cancel, rtt_slot, serial); 1964700c4d8SDavid Howells } 1974700c4d8SDavid Howells } 1984700c4d8SDavid Howells 1994700c4d8SDavid Howells /* 20026cb02aaSDavid Howells * Send an ACK call packet. 2018d94aa38SDavid Howells */ 20272f0c6fbSDavid Howells static int rxrpc_send_ack_packet(struct rxrpc_local *local, struct rxrpc_txbuf *txb) 2038d94aa38SDavid Howells { 2045273a191SDavid Howells struct rxrpc_connection *conn; 20526cb02aaSDavid Howells struct rxrpc_ack_buffer *pkt; 20672f0c6fbSDavid Howells struct rxrpc_call *call = txb->call; 2078d94aa38SDavid Howells struct msghdr msg; 20872f0c6fbSDavid Howells struct kvec iov[1]; 2098d94aa38SDavid Howells rxrpc_serial_t serial; 2108d94aa38SDavid Howells size_t len, n; 2114700c4d8SDavid Howells int ret, rtt_slot = -1; 2128d94aa38SDavid Howells 2135273a191SDavid Howells if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) 2148d94aa38SDavid Howells return -ECONNRESET; 2158d94aa38SDavid Howells 2165273a191SDavid Howells conn = call->conn; 2178d94aa38SDavid Howells 2188d94aa38SDavid Howells msg.msg_name = &call->peer->srx.transport; 2198d94aa38SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 2208d94aa38SDavid Howells msg.msg_control = NULL; 2218d94aa38SDavid Howells msg.msg_controllen = 0; 2228d94aa38SDavid Howells msg.msg_flags = 0; 2238d94aa38SDavid Howells 22472f0c6fbSDavid Howells if (txb->ack.reason == RXRPC_ACK_PING) 22572f0c6fbSDavid Howells txb->wire.flags |= RXRPC_REQUEST_ACK; 2268d94aa38SDavid Howells 227530403d9SDavid Howells if (txb->ack.reason == RXRPC_ACK_DELAY) 228530403d9SDavid Howells clear_bit(RXRPC_CALL_DELAY_ACK_PENDING, &call->flags); 229530403d9SDavid Howells if (txb->ack.reason == RXRPC_ACK_IDLE) 230530403d9SDavid Howells clear_bit(RXRPC_CALL_IDLE_ACK_PENDING, &call->flags); 231530403d9SDavid Howells 2328d94aa38SDavid Howells spin_lock_bh(&call->lock); 233*5d7edbc9SDavid Howells n = rxrpc_fill_out_ack(conn, call, txb); 2348d94aa38SDavid Howells spin_unlock_bh(&call->lock); 2359a3dedcfSDavid Howells if (n == 0) { 2369a3dedcfSDavid Howells kfree(pkt); 2379a3dedcfSDavid Howells return 0; 2389a3dedcfSDavid Howells } 2398d94aa38SDavid Howells 24072f0c6fbSDavid Howells iov[0].iov_base = &txb->wire; 24172f0c6fbSDavid Howells iov[0].iov_len = sizeof(txb->wire) + sizeof(txb->ack) + n; 24272f0c6fbSDavid Howells len = iov[0].iov_len; 2438d94aa38SDavid Howells 244b86e218eSDavid Howells serial = atomic_inc_return(&conn->serial); 24572f0c6fbSDavid Howells txb->wire.serial = htonl(serial); 2464764c0daSDavid Howells trace_rxrpc_tx_ack(call->debug_id, serial, 24772f0c6fbSDavid Howells ntohl(txb->ack.firstPacket), 24872f0c6fbSDavid Howells ntohl(txb->ack.serial), txb->ack.reason, txb->ack.nAcks); 24972f0c6fbSDavid Howells if (txb->ack_why == rxrpc_propose_ack_ping_for_lost_ack) 25072f0c6fbSDavid Howells call->acks_lost_ping = serial; 251b86e218eSDavid Howells 25272f0c6fbSDavid Howells if (txb->ack.reason == RXRPC_ACK_PING) 2534700c4d8SDavid Howells rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping); 25426cb02aaSDavid Howells 255f2a676d1SDavid Howells rxrpc_inc_stat(call->rxnet, stat_tx_ack_send); 256ed472b0cSDavid Howells 257*5d7edbc9SDavid Howells /* Grab the highest received seq as late as possible */ 258*5d7edbc9SDavid Howells txb->ack.previousPacket = htonl(call->rx_highest_seq); 259*5d7edbc9SDavid Howells 26072f0c6fbSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); 261ed472b0cSDavid Howells ret = do_udp_sendmsg(conn->params.local->socket, &msg, len); 262ed472b0cSDavid Howells call->peer->last_tx_at = ktime_get_seconds(); 2636b47fe1dSDavid Howells if (ret < 0) 2646b47fe1dSDavid Howells trace_rxrpc_tx_fail(call->debug_id, serial, ret, 2654764c0daSDavid Howells rxrpc_tx_point_call_ack); 2664764c0daSDavid Howells else 26772f0c6fbSDavid Howells trace_rxrpc_tx_packet(call->debug_id, &txb->wire, 2684764c0daSDavid Howells rxrpc_tx_point_call_ack); 269c7e86acfSDavid Howells rxrpc_tx_backoff(call, ret); 2708d94aa38SDavid Howells 27126cb02aaSDavid Howells if (call->state < RXRPC_CALL_COMPLETE) { 27272f0c6fbSDavid Howells if (ret < 0) 2734700c4d8SDavid Howells rxrpc_cancel_rtt_probe(call, serial, rtt_slot); 274415f44e4SDavid Howells rxrpc_set_keepalive(call); 275248f219cSDavid Howells } 276248f219cSDavid Howells 2778d94aa38SDavid Howells kfree(pkt); 2788d94aa38SDavid Howells return ret; 2798d94aa38SDavid Howells } 2808d94aa38SDavid Howells 2818c3e34a4SDavid Howells /* 28272f0c6fbSDavid Howells * ACK transmitter for a local endpoint. The UDP socket locks around each 28372f0c6fbSDavid Howells * transmission, so we can only transmit one packet at a time, ACK, DATA or 28472f0c6fbSDavid Howells * otherwise. 28572f0c6fbSDavid Howells */ 28672f0c6fbSDavid Howells void rxrpc_transmit_ack_packets(struct rxrpc_local *local) 28772f0c6fbSDavid Howells { 28872f0c6fbSDavid Howells LIST_HEAD(queue); 28972f0c6fbSDavid Howells int ret; 29072f0c6fbSDavid Howells 29172f0c6fbSDavid Howells trace_rxrpc_local(local->debug_id, rxrpc_local_tx_ack, 29272f0c6fbSDavid Howells refcount_read(&local->ref), NULL); 29372f0c6fbSDavid Howells 29472f0c6fbSDavid Howells if (list_empty(&local->ack_tx_queue)) 29572f0c6fbSDavid Howells return; 29672f0c6fbSDavid Howells 29772f0c6fbSDavid Howells spin_lock_bh(&local->ack_tx_lock); 29872f0c6fbSDavid Howells list_splice_tail_init(&local->ack_tx_queue, &queue); 29972f0c6fbSDavid Howells spin_unlock_bh(&local->ack_tx_lock); 30072f0c6fbSDavid Howells 30172f0c6fbSDavid Howells while (!list_empty(&queue)) { 30272f0c6fbSDavid Howells struct rxrpc_txbuf *txb = 30372f0c6fbSDavid Howells list_entry(queue.next, struct rxrpc_txbuf, tx_link); 30472f0c6fbSDavid Howells 30572f0c6fbSDavid Howells ret = rxrpc_send_ack_packet(local, txb); 30672f0c6fbSDavid Howells if (ret < 0 && ret != -ECONNRESET) { 30772f0c6fbSDavid Howells spin_lock_bh(&local->ack_tx_lock); 30872f0c6fbSDavid Howells list_splice_init(&queue, &local->ack_tx_queue); 30972f0c6fbSDavid Howells spin_unlock_bh(&local->ack_tx_lock); 31072f0c6fbSDavid Howells break; 31172f0c6fbSDavid Howells } 31272f0c6fbSDavid Howells 31372f0c6fbSDavid Howells list_del_init(&txb->tx_link); 31472f0c6fbSDavid Howells rxrpc_put_call(txb->call, rxrpc_call_put); 31572f0c6fbSDavid Howells rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx); 31672f0c6fbSDavid Howells } 31772f0c6fbSDavid Howells } 31872f0c6fbSDavid Howells 31972f0c6fbSDavid Howells /* 32026cb02aaSDavid Howells * Send an ABORT call packet. 32126cb02aaSDavid Howells */ 32226cb02aaSDavid Howells int rxrpc_send_abort_packet(struct rxrpc_call *call) 32326cb02aaSDavid Howells { 3245273a191SDavid Howells struct rxrpc_connection *conn; 32526cb02aaSDavid Howells struct rxrpc_abort_buffer pkt; 32626cb02aaSDavid Howells struct msghdr msg; 32726cb02aaSDavid Howells struct kvec iov[1]; 32826cb02aaSDavid Howells rxrpc_serial_t serial; 32926cb02aaSDavid Howells int ret; 33026cb02aaSDavid Howells 331dcbefc30SDavid Howells /* Don't bother sending aborts for a client call once the server has 332dcbefc30SDavid Howells * hard-ACK'd all of its request data. After that point, we're not 333dcbefc30SDavid Howells * going to stop the operation proceeding, and whilst we might limit 334dcbefc30SDavid Howells * the reply, it's not worth it if we can send a new call on the same 335dcbefc30SDavid Howells * channel instead, thereby closing off this call. 336dcbefc30SDavid Howells */ 337dcbefc30SDavid Howells if (rxrpc_is_client_call(call) && 338dcbefc30SDavid Howells test_bit(RXRPC_CALL_TX_LAST, &call->flags)) 339dcbefc30SDavid Howells return 0; 340dcbefc30SDavid Howells 3415273a191SDavid Howells if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) 34226cb02aaSDavid Howells return -ECONNRESET; 34326cb02aaSDavid Howells 3445273a191SDavid Howells conn = call->conn; 3455273a191SDavid Howells 34626cb02aaSDavid Howells msg.msg_name = &call->peer->srx.transport; 34726cb02aaSDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 34826cb02aaSDavid Howells msg.msg_control = NULL; 34926cb02aaSDavid Howells msg.msg_controllen = 0; 35026cb02aaSDavid Howells msg.msg_flags = 0; 35126cb02aaSDavid Howells 35226cb02aaSDavid Howells pkt.whdr.epoch = htonl(conn->proto.epoch); 35326cb02aaSDavid Howells pkt.whdr.cid = htonl(call->cid); 35426cb02aaSDavid Howells pkt.whdr.callNumber = htonl(call->call_id); 35526cb02aaSDavid Howells pkt.whdr.seq = 0; 35626cb02aaSDavid Howells pkt.whdr.type = RXRPC_PACKET_TYPE_ABORT; 35726cb02aaSDavid Howells pkt.whdr.flags = conn->out_clientflag; 35826cb02aaSDavid Howells pkt.whdr.userStatus = 0; 35926cb02aaSDavid Howells pkt.whdr.securityIndex = call->security_ix; 36026cb02aaSDavid Howells pkt.whdr._rsvd = 0; 36126cb02aaSDavid Howells pkt.whdr.serviceId = htons(call->service_id); 36226cb02aaSDavid Howells pkt.abort_code = htonl(call->abort_code); 36326cb02aaSDavid Howells 36426cb02aaSDavid Howells iov[0].iov_base = &pkt; 36526cb02aaSDavid Howells iov[0].iov_len = sizeof(pkt); 36626cb02aaSDavid Howells 36726cb02aaSDavid Howells serial = atomic_inc_return(&conn->serial); 36826cb02aaSDavid Howells pkt.whdr.serial = htonl(serial); 36926cb02aaSDavid Howells 370ed472b0cSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, sizeof(pkt)); 371ed472b0cSDavid Howells ret = do_udp_sendmsg(conn->params.local->socket, &msg, sizeof(pkt)); 372330bdcfaSDavid Howells conn->params.peer->last_tx_at = ktime_get_seconds(); 3736b47fe1dSDavid Howells if (ret < 0) 3746b47fe1dSDavid Howells trace_rxrpc_tx_fail(call->debug_id, serial, ret, 3754764c0daSDavid Howells rxrpc_tx_point_call_abort); 3764764c0daSDavid Howells else 3774764c0daSDavid Howells trace_rxrpc_tx_packet(call->debug_id, &pkt.whdr, 3784764c0daSDavid Howells rxrpc_tx_point_call_abort); 379c7e86acfSDavid Howells rxrpc_tx_backoff(call, ret); 38026cb02aaSDavid Howells return ret; 38126cb02aaSDavid Howells } 38226cb02aaSDavid Howells 38326cb02aaSDavid Howells /* 3848c3e34a4SDavid Howells * send a packet through the transport endpoint 3858c3e34a4SDavid Howells */ 386a1767077SDavid Howells int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, 387a1767077SDavid Howells bool retrans) 3888c3e34a4SDavid Howells { 3894d843be5SDavid Howells enum rxrpc_req_ack_trace why; 3905a924b89SDavid Howells struct rxrpc_connection *conn = call->conn; 3915a924b89SDavid Howells struct rxrpc_wire_header whdr; 3925a924b89SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 3938c3e34a4SDavid Howells struct msghdr msg; 3945a924b89SDavid Howells struct kvec iov[2]; 3955a924b89SDavid Howells rxrpc_serial_t serial; 3965a924b89SDavid Howells size_t len; 3974700c4d8SDavid Howells int ret, rtt_slot = -1; 3988c3e34a4SDavid Howells 3998c3e34a4SDavid Howells _enter(",{%d}", skb->len); 4008c3e34a4SDavid Howells 401245500d8SDavid Howells if (hlist_unhashed(&call->error_link)) { 402245500d8SDavid Howells spin_lock_bh(&call->peer->lock); 403245500d8SDavid Howells hlist_add_head_rcu(&call->error_link, &call->peer->error_targets); 404245500d8SDavid Howells spin_unlock_bh(&call->peer->lock); 405245500d8SDavid Howells } 406245500d8SDavid Howells 4075a924b89SDavid Howells /* Each transmission of a Tx packet needs a new serial number */ 4085a924b89SDavid Howells serial = atomic_inc_return(&conn->serial); 4098c3e34a4SDavid Howells 4105a924b89SDavid Howells whdr.epoch = htonl(conn->proto.epoch); 4115a924b89SDavid Howells whdr.cid = htonl(call->cid); 4125a924b89SDavid Howells whdr.callNumber = htonl(call->call_id); 4135a924b89SDavid Howells whdr.seq = htonl(sp->hdr.seq); 4145a924b89SDavid Howells whdr.serial = htonl(serial); 4155a924b89SDavid Howells whdr.type = RXRPC_PACKET_TYPE_DATA; 4165a924b89SDavid Howells whdr.flags = sp->hdr.flags; 4175a924b89SDavid Howells whdr.userStatus = 0; 4185a924b89SDavid Howells whdr.securityIndex = call->security_ix; 4195a924b89SDavid Howells whdr._rsvd = htons(sp->hdr._rsvd); 4205a924b89SDavid Howells whdr.serviceId = htons(call->service_id); 4215a924b89SDavid Howells 4224e255721SDavid Howells if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) && 4234e255721SDavid Howells sp->hdr.seq == 1) 4244e255721SDavid Howells whdr.userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE; 4254e255721SDavid Howells 4265a924b89SDavid Howells iov[0].iov_base = &whdr; 4275a924b89SDavid Howells iov[0].iov_len = sizeof(whdr); 4285a924b89SDavid Howells iov[1].iov_base = skb->head; 4295a924b89SDavid Howells iov[1].iov_len = skb->len; 4305a924b89SDavid Howells len = iov[0].iov_len + iov[1].iov_len; 431ed472b0cSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len); 4325a924b89SDavid Howells 4335a924b89SDavid Howells msg.msg_name = &call->peer->srx.transport; 4345a924b89SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 4358c3e34a4SDavid Howells msg.msg_control = NULL; 4368c3e34a4SDavid Howells msg.msg_controllen = 0; 4378c3e34a4SDavid Howells msg.msg_flags = 0; 4388c3e34a4SDavid Howells 43957494343SDavid Howells /* If our RTT cache needs working on, request an ACK. Also request 44057494343SDavid Howells * ACKs if a DATA packet appears to have been lost. 441b604dd98SDavid Howells * 442b604dd98SDavid Howells * However, we mustn't request an ACK on the last reply packet of a 443b604dd98SDavid Howells * service call, lest OpenAFS incorrectly send us an ACK with some 444b604dd98SDavid Howells * soft-ACKs in it and then never follow up with a proper hard ACK. 44557494343SDavid Howells */ 4464d843be5SDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) 4474d843be5SDavid Howells why = rxrpc_reqack_already_on; 4484d843be5SDavid Howells else if ((whdr.flags & RXRPC_LAST_PACKET) && rxrpc_to_client(sp)) 4494d843be5SDavid Howells why = rxrpc_reqack_no_srv_last; 4504d843be5SDavid Howells else if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) 4514d843be5SDavid Howells why = rxrpc_reqack_ack_lost; 4524d843be5SDavid Howells else if (retrans) 4534d843be5SDavid Howells why = rxrpc_reqack_retrans; 4544d843be5SDavid Howells else if (call->cong_mode == RXRPC_CALL_SLOW_START && call->cong_cwnd <= 2) 4554d843be5SDavid Howells why = rxrpc_reqack_slow_start; 4564d843be5SDavid Howells else if (call->tx_winsize <= 2) 4574d843be5SDavid Howells why = rxrpc_reqack_small_txwin; 4584d843be5SDavid Howells else if (call->peer->rtt_count < 3 && sp->hdr.seq & 1) 4594d843be5SDavid Howells why = rxrpc_reqack_more_rtt; 4604d843be5SDavid Howells else if (ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), ktime_get_real())) 4614d843be5SDavid Howells why = rxrpc_reqack_old_rtt; 4624d843be5SDavid Howells else 4634d843be5SDavid Howells goto dont_set_request_ack; 4644d843be5SDavid Howells 465f7fa5242SDavid Howells rxrpc_inc_stat(call->rxnet, stat_why_req_ack[why]); 4664d843be5SDavid Howells trace_rxrpc_req_ack(call->debug_id, sp->hdr.seq, why); 4674d843be5SDavid Howells if (why != rxrpc_reqack_no_srv_last) 4680d4b103cSDavid Howells whdr.flags |= RXRPC_REQUEST_ACK; 4694d843be5SDavid Howells dont_set_request_ack: 4700d4b103cSDavid Howells 4718a681c36SDavid Howells if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { 4728a681c36SDavid Howells static int lose; 4738a681c36SDavid Howells if ((lose++ & 7) == 7) { 474a1767077SDavid Howells ret = 0; 475526949e8SArnd Bergmann trace_rxrpc_tx_data(call, sp->hdr.seq, serial, 476526949e8SArnd Bergmann whdr.flags, retrans, true); 477526949e8SArnd Bergmann goto done; 4788a681c36SDavid Howells } 4798a681c36SDavid Howells } 4808a681c36SDavid Howells 481526949e8SArnd Bergmann trace_rxrpc_tx_data(call, sp->hdr.seq, serial, whdr.flags, retrans, 482526949e8SArnd Bergmann false); 4835a924b89SDavid Howells 4848c3e34a4SDavid Howells /* send the packet with the don't fragment bit set if we currently 4858c3e34a4SDavid Howells * think it's small enough */ 4865a924b89SDavid Howells if (iov[1].iov_len >= call->peer->maxdata) 4875a924b89SDavid Howells goto send_fragmentable; 4885a924b89SDavid Howells 489985a5c82SDavid Howells down_read(&conn->params.local->defrag_sem); 490b604dd98SDavid Howells 491b604dd98SDavid Howells sp->hdr.serial = serial; 492b604dd98SDavid Howells smp_wmb(); /* Set serial before timestamp */ 493b604dd98SDavid Howells skb->tstamp = ktime_get_real(); 4944700c4d8SDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) 4954700c4d8SDavid Howells rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data); 496b604dd98SDavid Howells 4978c3e34a4SDavid Howells /* send the packet by UDP 4988c3e34a4SDavid Howells * - returns -EMSGSIZE if UDP would have to fragment the packet 4998c3e34a4SDavid Howells * to go out of the interface 5008c3e34a4SDavid Howells * - in which case, we'll have processed the ICMP error 5018c3e34a4SDavid Howells * message and update the peer record 5028c3e34a4SDavid Howells */ 503b0154246SDavid Howells rxrpc_inc_stat(call->rxnet, stat_tx_data_send); 504ed472b0cSDavid Howells ret = do_udp_sendmsg(conn->params.local->socket, &msg, len); 505330bdcfaSDavid Howells conn->params.peer->last_tx_at = ktime_get_seconds(); 5068c3e34a4SDavid Howells 507985a5c82SDavid Howells up_read(&conn->params.local->defrag_sem); 5084700c4d8SDavid Howells if (ret < 0) { 5094700c4d8SDavid Howells rxrpc_cancel_rtt_probe(call, serial, rtt_slot); 5106b47fe1dSDavid Howells trace_rxrpc_tx_fail(call->debug_id, serial, ret, 5114764c0daSDavid Howells rxrpc_tx_point_call_data_nofrag); 5124700c4d8SDavid Howells } else { 5134764c0daSDavid Howells trace_rxrpc_tx_packet(call->debug_id, &whdr, 5144764c0daSDavid Howells rxrpc_tx_point_call_data_nofrag); 5154700c4d8SDavid Howells } 5164700c4d8SDavid Howells 517c7e86acfSDavid Howells rxrpc_tx_backoff(call, ret); 5188c3e34a4SDavid Howells if (ret == -EMSGSIZE) 5198c3e34a4SDavid Howells goto send_fragmentable; 5208c3e34a4SDavid Howells 5215a924b89SDavid Howells done: 52250235c4bSDavid Howells if (ret >= 0) { 5230d4b103cSDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) { 524b604dd98SDavid Howells call->peer->rtt_last_req = skb->tstamp; 525c410bf01SDavid Howells if (call->peer->rtt_count > 1) { 526bd1fdf8cSDavid Howells unsigned long nowj = jiffies, ack_lost_at; 527bd1fdf8cSDavid Howells 5282c13c05cSDavid Howells ack_lost_at = rxrpc_get_rto_backoff(call->peer, false); 529bd1fdf8cSDavid Howells ack_lost_at += nowj; 530bd1fdf8cSDavid Howells WRITE_ONCE(call->ack_lost_at, ack_lost_at); 531bd1fdf8cSDavid Howells rxrpc_reduce_call_timer(call, ack_lost_at, nowj, 532bd1fdf8cSDavid Howells rxrpc_timer_set_for_lost_ack); 533bd1fdf8cSDavid Howells } 5348c3e34a4SDavid Howells } 535c54e43d7SDavid Howells 536c54e43d7SDavid Howells if (sp->hdr.seq == 1 && 537c54e43d7SDavid Howells !test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, 538c54e43d7SDavid Howells &call->flags)) { 539c54e43d7SDavid Howells unsigned long nowj = jiffies, expect_rx_by; 540c54e43d7SDavid Howells 541c54e43d7SDavid Howells expect_rx_by = nowj + call->next_rx_timo; 542c54e43d7SDavid Howells WRITE_ONCE(call->expect_rx_by, expect_rx_by); 543c54e43d7SDavid Howells rxrpc_reduce_call_timer(call, expect_rx_by, nowj, 544c54e43d7SDavid Howells rxrpc_timer_set_for_normal); 545c54e43d7SDavid Howells } 546415f44e4SDavid Howells 547415f44e4SDavid Howells rxrpc_set_keepalive(call); 548c7e86acfSDavid Howells } else { 549c7e86acfSDavid Howells /* Cancel the call if the initial transmission fails, 550c7e86acfSDavid Howells * particularly if that's due to network routing issues that 551c7e86acfSDavid Howells * aren't going away anytime soon. The layer above can arrange 552c7e86acfSDavid Howells * the retransmission. 553c7e86acfSDavid Howells */ 554c7e86acfSDavid Howells if (!test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags)) 555c7e86acfSDavid Howells rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 556c7e86acfSDavid Howells RX_USER_ABORT, ret); 557c7e86acfSDavid Howells } 558415f44e4SDavid Howells 5595a924b89SDavid Howells _leave(" = %d [%u]", ret, call->peer->maxdata); 5605a924b89SDavid Howells return ret; 5618c3e34a4SDavid Howells 5628c3e34a4SDavid Howells send_fragmentable: 5638c3e34a4SDavid Howells /* attempt to send this message with fragmentation enabled */ 5648c3e34a4SDavid Howells _debug("send fragment"); 5658c3e34a4SDavid Howells 566985a5c82SDavid Howells down_write(&conn->params.local->defrag_sem); 567985a5c82SDavid Howells 568b604dd98SDavid Howells sp->hdr.serial = serial; 569b604dd98SDavid Howells smp_wmb(); /* Set serial before timestamp */ 570b604dd98SDavid Howells skb->tstamp = ktime_get_real(); 5714700c4d8SDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) 5724700c4d8SDavid Howells rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data); 573b604dd98SDavid Howells 574985a5c82SDavid Howells switch (conn->params.local->srx.transport.family) { 5750e631eeeSDavid Howells case AF_INET6: 576985a5c82SDavid Howells case AF_INET: 5772de569bdSChristoph Hellwig ip_sock_set_mtu_discover(conn->params.local->socket->sk, 5782de569bdSChristoph Hellwig IP_PMTUDISC_DONT); 579b0154246SDavid Howells rxrpc_inc_stat(call->rxnet, stat_tx_data_send_frag); 580ed472b0cSDavid Howells ret = do_udp_sendmsg(conn->params.local->socket, &msg, len); 581330bdcfaSDavid Howells conn->params.peer->last_tx_at = ktime_get_seconds(); 5828c3e34a4SDavid Howells 5832de569bdSChristoph Hellwig ip_sock_set_mtu_discover(conn->params.local->socket->sk, 5842de569bdSChristoph Hellwig IP_PMTUDISC_DO); 58575b54cb5SDavid Howells break; 5863427beb6SDavid Howells 5873427beb6SDavid Howells default: 5883427beb6SDavid Howells BUG(); 5898c3e34a4SDavid Howells } 5908c3e34a4SDavid Howells 5914700c4d8SDavid Howells if (ret < 0) { 5924700c4d8SDavid Howells rxrpc_cancel_rtt_probe(call, serial, rtt_slot); 5936b47fe1dSDavid Howells trace_rxrpc_tx_fail(call->debug_id, serial, ret, 5944764c0daSDavid Howells rxrpc_tx_point_call_data_frag); 5954700c4d8SDavid Howells } else { 5964764c0daSDavid Howells trace_rxrpc_tx_packet(call->debug_id, &whdr, 5974764c0daSDavid Howells rxrpc_tx_point_call_data_frag); 5984700c4d8SDavid Howells } 599c7e86acfSDavid Howells rxrpc_tx_backoff(call, ret); 6006b47fe1dSDavid Howells 601985a5c82SDavid Howells up_write(&conn->params.local->defrag_sem); 6025a924b89SDavid Howells goto done; 6038c3e34a4SDavid Howells } 604248f219cSDavid Howells 605248f219cSDavid Howells /* 606248f219cSDavid Howells * reject packets through the local endpoint 607248f219cSDavid Howells */ 608248f219cSDavid Howells void rxrpc_reject_packets(struct rxrpc_local *local) 609248f219cSDavid Howells { 6101c2bc7b9SDavid Howells struct sockaddr_rxrpc srx; 611248f219cSDavid Howells struct rxrpc_skb_priv *sp; 612248f219cSDavid Howells struct rxrpc_wire_header whdr; 613248f219cSDavid Howells struct sk_buff *skb; 614248f219cSDavid Howells struct msghdr msg; 615248f219cSDavid Howells struct kvec iov[2]; 616248f219cSDavid Howells size_t size; 617248f219cSDavid Howells __be32 code; 618ece64fecSDavid Howells int ret, ioc; 619248f219cSDavid Howells 620248f219cSDavid Howells _enter("%d", local->debug_id); 621248f219cSDavid Howells 622248f219cSDavid Howells iov[0].iov_base = &whdr; 623248f219cSDavid Howells iov[0].iov_len = sizeof(whdr); 624248f219cSDavid Howells iov[1].iov_base = &code; 625248f219cSDavid Howells iov[1].iov_len = sizeof(code); 626248f219cSDavid Howells 6271c2bc7b9SDavid Howells msg.msg_name = &srx.transport; 628248f219cSDavid Howells msg.msg_control = NULL; 629248f219cSDavid Howells msg.msg_controllen = 0; 630248f219cSDavid Howells msg.msg_flags = 0; 631248f219cSDavid Howells 632248f219cSDavid Howells memset(&whdr, 0, sizeof(whdr)); 633248f219cSDavid Howells 634248f219cSDavid Howells while ((skb = skb_dequeue(&local->reject_queue))) { 635987db9f7SDavid Howells rxrpc_see_skb(skb, rxrpc_skb_seen); 636248f219cSDavid Howells sp = rxrpc_skb(skb); 6371c2bc7b9SDavid Howells 638ece64fecSDavid Howells switch (skb->mark) { 639ece64fecSDavid Howells case RXRPC_SKB_MARK_REJECT_BUSY: 640ece64fecSDavid Howells whdr.type = RXRPC_PACKET_TYPE_BUSY; 641ece64fecSDavid Howells size = sizeof(whdr); 642ece64fecSDavid Howells ioc = 1; 643ece64fecSDavid Howells break; 644ece64fecSDavid Howells case RXRPC_SKB_MARK_REJECT_ABORT: 645ece64fecSDavid Howells whdr.type = RXRPC_PACKET_TYPE_ABORT; 646ece64fecSDavid Howells code = htonl(skb->priority); 647ece64fecSDavid Howells size = sizeof(whdr) + sizeof(code); 648ece64fecSDavid Howells ioc = 2; 649ece64fecSDavid Howells break; 650ece64fecSDavid Howells default: 651987db9f7SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_freed); 652ece64fecSDavid Howells continue; 653ece64fecSDavid Howells } 654ece64fecSDavid Howells 6555a790b73SDavid Howells if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) { 6561c2bc7b9SDavid Howells msg.msg_namelen = srx.transport_len; 6571c2bc7b9SDavid Howells 658248f219cSDavid Howells whdr.epoch = htonl(sp->hdr.epoch); 659248f219cSDavid Howells whdr.cid = htonl(sp->hdr.cid); 660248f219cSDavid Howells whdr.callNumber = htonl(sp->hdr.callNumber); 661248f219cSDavid Howells whdr.serviceId = htons(sp->hdr.serviceId); 662248f219cSDavid Howells whdr.flags = sp->hdr.flags; 663248f219cSDavid Howells whdr.flags ^= RXRPC_CLIENT_INITIATED; 664248f219cSDavid Howells whdr.flags &= RXRPC_CLIENT_INITIATED; 665248f219cSDavid Howells 666ed472b0cSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, ioc, size); 667ed472b0cSDavid Howells ret = do_udp_sendmsg(local->socket, &msg, size); 6686b47fe1dSDavid Howells if (ret < 0) 6696b47fe1dSDavid Howells trace_rxrpc_tx_fail(local->debug_id, 0, ret, 6704764c0daSDavid Howells rxrpc_tx_point_reject); 6714764c0daSDavid Howells else 6724764c0daSDavid Howells trace_rxrpc_tx_packet(local->debug_id, &whdr, 6734764c0daSDavid Howells rxrpc_tx_point_reject); 674248f219cSDavid Howells } 675248f219cSDavid Howells 676987db9f7SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_freed); 677248f219cSDavid Howells } 678248f219cSDavid Howells 679248f219cSDavid Howells _leave(""); 680248f219cSDavid Howells } 681ace45becSDavid Howells 682ace45becSDavid Howells /* 683ace45becSDavid Howells * Send a VERSION reply to a peer as a keepalive. 684ace45becSDavid Howells */ 685ace45becSDavid Howells void rxrpc_send_keepalive(struct rxrpc_peer *peer) 686ace45becSDavid Howells { 687ace45becSDavid Howells struct rxrpc_wire_header whdr; 688ace45becSDavid Howells struct msghdr msg; 689ace45becSDavid Howells struct kvec iov[2]; 690ace45becSDavid Howells size_t len; 691ace45becSDavid Howells int ret; 692ace45becSDavid Howells 693ace45becSDavid Howells _enter(""); 694ace45becSDavid Howells 695ace45becSDavid Howells msg.msg_name = &peer->srx.transport; 696ace45becSDavid Howells msg.msg_namelen = peer->srx.transport_len; 697ace45becSDavid Howells msg.msg_control = NULL; 698ace45becSDavid Howells msg.msg_controllen = 0; 699ace45becSDavid Howells msg.msg_flags = 0; 700ace45becSDavid Howells 701ace45becSDavid Howells whdr.epoch = htonl(peer->local->rxnet->epoch); 702ace45becSDavid Howells whdr.cid = 0; 703ace45becSDavid Howells whdr.callNumber = 0; 704ace45becSDavid Howells whdr.seq = 0; 705ace45becSDavid Howells whdr.serial = 0; 706ace45becSDavid Howells whdr.type = RXRPC_PACKET_TYPE_VERSION; /* Not client-initiated */ 707ace45becSDavid Howells whdr.flags = RXRPC_LAST_PACKET; 708ace45becSDavid Howells whdr.userStatus = 0; 709ace45becSDavid Howells whdr.securityIndex = 0; 710ace45becSDavid Howells whdr._rsvd = 0; 711ace45becSDavid Howells whdr.serviceId = 0; 712ace45becSDavid Howells 713ace45becSDavid Howells iov[0].iov_base = &whdr; 714ace45becSDavid Howells iov[0].iov_len = sizeof(whdr); 715ace45becSDavid Howells iov[1].iov_base = (char *)rxrpc_keepalive_string; 716ace45becSDavid Howells iov[1].iov_len = sizeof(rxrpc_keepalive_string); 717ace45becSDavid Howells 718ace45becSDavid Howells len = iov[0].iov_len + iov[1].iov_len; 719ace45becSDavid Howells 720ace45becSDavid Howells _proto("Tx VERSION (keepalive)"); 721ace45becSDavid Howells 722ed472b0cSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len); 723ed472b0cSDavid Howells ret = do_udp_sendmsg(peer->local->socket, &msg, len); 724ace45becSDavid Howells if (ret < 0) 7256b47fe1dSDavid Howells trace_rxrpc_tx_fail(peer->debug_id, 0, ret, 7264764c0daSDavid Howells rxrpc_tx_point_version_keepalive); 7274764c0daSDavid Howells else 7284764c0daSDavid Howells trace_rxrpc_tx_packet(peer->debug_id, &whdr, 7294764c0daSDavid Howells rxrpc_tx_point_version_keepalive); 730ace45becSDavid Howells 731330bdcfaSDavid Howells peer->last_tx_at = ktime_get_seconds(); 732ace45becSDavid Howells _leave(""); 733ace45becSDavid Howells } 734