18c3e34a4SDavid Howells /* RxRPC packet transmission 28c3e34a4SDavid Howells * 38c3e34a4SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 48c3e34a4SDavid Howells * Written by David Howells (dhowells@redhat.com) 58c3e34a4SDavid Howells * 68c3e34a4SDavid Howells * This program is free software; you can redistribute it and/or 78c3e34a4SDavid Howells * modify it under the terms of the GNU General Public License 88c3e34a4SDavid Howells * as published by the Free Software Foundation; either version 98c3e34a4SDavid Howells * 2 of the License, or (at your option) any later version. 108c3e34a4SDavid Howells */ 118c3e34a4SDavid Howells 128c3e34a4SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c3e34a4SDavid Howells 148c3e34a4SDavid Howells #include <linux/net.h> 158c3e34a4SDavid Howells #include <linux/gfp.h> 168c3e34a4SDavid Howells #include <linux/skbuff.h> 178c3e34a4SDavid Howells #include <linux/export.h> 188c3e34a4SDavid Howells #include <net/sock.h> 198c3e34a4SDavid Howells #include <net/af_rxrpc.h> 208c3e34a4SDavid Howells #include "ar-internal.h" 218c3e34a4SDavid Howells 2226cb02aaSDavid Howells struct rxrpc_ack_buffer { 238d94aa38SDavid Howells struct rxrpc_wire_header whdr; 248d94aa38SDavid Howells struct rxrpc_ackpacket ack; 258d94aa38SDavid Howells u8 acks[255]; 268d94aa38SDavid Howells u8 pad[3]; 278d94aa38SDavid Howells struct rxrpc_ackinfo ackinfo; 288d94aa38SDavid Howells }; 298d94aa38SDavid Howells 3026cb02aaSDavid Howells struct rxrpc_abort_buffer { 3126cb02aaSDavid Howells struct rxrpc_wire_header whdr; 3226cb02aaSDavid Howells __be32 abort_code; 3326cb02aaSDavid Howells }; 3426cb02aaSDavid Howells 358d94aa38SDavid Howells /* 368d94aa38SDavid Howells * Fill out an ACK packet. 378d94aa38SDavid Howells */ 388d94aa38SDavid Howells static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, 3926cb02aaSDavid Howells struct rxrpc_ack_buffer *pkt, 40805b21b9SDavid Howells rxrpc_seq_t *_hard_ack, 41805b21b9SDavid Howells rxrpc_seq_t *_top) 428d94aa38SDavid Howells { 43f3639df2SDavid Howells rxrpc_serial_t serial; 44248f219cSDavid Howells rxrpc_seq_t hard_ack, top, seq; 45248f219cSDavid Howells int ix; 468d94aa38SDavid Howells u32 mtu, jmax; 478d94aa38SDavid Howells u8 *ackp = pkt->acks; 488d94aa38SDavid Howells 49248f219cSDavid Howells /* Barrier against rxrpc_input_data(). */ 50f3639df2SDavid Howells serial = call->ackr_serial; 51248f219cSDavid Howells hard_ack = READ_ONCE(call->rx_hard_ack); 52248f219cSDavid Howells top = smp_load_acquire(&call->rx_top); 53805b21b9SDavid Howells *_hard_ack = hard_ack; 54805b21b9SDavid Howells *_top = top; 55248f219cSDavid Howells 568d94aa38SDavid Howells pkt->ack.bufferSpace = htons(8); 57248f219cSDavid Howells pkt->ack.maxSkew = htons(call->ackr_skew); 58248f219cSDavid Howells pkt->ack.firstPacket = htonl(hard_ack + 1); 598d94aa38SDavid Howells pkt->ack.previousPacket = htonl(call->ackr_prev_seq); 60f3639df2SDavid Howells pkt->ack.serial = htonl(serial); 61248f219cSDavid Howells pkt->ack.reason = call->ackr_reason; 62248f219cSDavid Howells pkt->ack.nAcks = top - hard_ack; 638d94aa38SDavid Howells 648e83134dSDavid Howells if (pkt->ack.reason == RXRPC_ACK_PING) 658e83134dSDavid Howells pkt->whdr.flags |= RXRPC_REQUEST_ACK; 668e83134dSDavid Howells 67248f219cSDavid Howells if (after(top, hard_ack)) { 68248f219cSDavid Howells seq = hard_ack + 1; 69248f219cSDavid Howells do { 70248f219cSDavid Howells ix = seq & RXRPC_RXTX_BUFF_MASK; 71248f219cSDavid Howells if (call->rxtx_buffer[ix]) 72248f219cSDavid Howells *ackp++ = RXRPC_ACK_TYPE_ACK; 73248f219cSDavid Howells else 74248f219cSDavid Howells *ackp++ = RXRPC_ACK_TYPE_NACK; 75248f219cSDavid Howells seq++; 76248f219cSDavid Howells } while (before_eq(seq, top)); 77248f219cSDavid Howells } 78248f219cSDavid Howells 79248f219cSDavid Howells mtu = call->conn->params.peer->if_mtu; 80248f219cSDavid Howells mtu -= call->conn->params.peer->hdrsize; 8175e42126SDavid Howells jmax = (call->nr_jumbo_bad > 3) ? 1 : rxrpc_rx_jumbo_max; 828d94aa38SDavid Howells pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu); 838d94aa38SDavid Howells pkt->ackinfo.maxMTU = htonl(mtu); 8475e42126SDavid Howells pkt->ackinfo.rwind = htonl(call->rx_winsize); 858d94aa38SDavid Howells pkt->ackinfo.jumbo_max = htonl(jmax); 868d94aa38SDavid Howells 878d94aa38SDavid Howells *ackp++ = 0; 888d94aa38SDavid Howells *ackp++ = 0; 898d94aa38SDavid Howells *ackp++ = 0; 90248f219cSDavid Howells return top - hard_ack + 3; 918d94aa38SDavid Howells } 928d94aa38SDavid Howells 938d94aa38SDavid Howells /* 9426cb02aaSDavid Howells * Send an ACK call packet. 958d94aa38SDavid Howells */ 9626cb02aaSDavid Howells int rxrpc_send_ack_packet(struct rxrpc_call *call) 978d94aa38SDavid Howells { 988d94aa38SDavid Howells struct rxrpc_connection *conn = NULL; 9926cb02aaSDavid Howells struct rxrpc_ack_buffer *pkt; 1008d94aa38SDavid Howells struct msghdr msg; 1018d94aa38SDavid Howells struct kvec iov[2]; 1028d94aa38SDavid Howells rxrpc_serial_t serial; 103805b21b9SDavid Howells rxrpc_seq_t hard_ack, top; 1048d94aa38SDavid Howells size_t len, n; 1058e83134dSDavid Howells bool ping = false; 10626cb02aaSDavid Howells int ret; 1078d94aa38SDavid Howells 1088d94aa38SDavid Howells spin_lock_bh(&call->lock); 1098d94aa38SDavid Howells if (call->conn) 1108d94aa38SDavid Howells conn = rxrpc_get_connection_maybe(call->conn); 1118d94aa38SDavid Howells spin_unlock_bh(&call->lock); 1128d94aa38SDavid Howells if (!conn) 1138d94aa38SDavid Howells return -ECONNRESET; 1148d94aa38SDavid Howells 1158d94aa38SDavid Howells pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); 1168d94aa38SDavid Howells if (!pkt) { 1178d94aa38SDavid Howells rxrpc_put_connection(conn); 1188d94aa38SDavid Howells return -ENOMEM; 1198d94aa38SDavid Howells } 1208d94aa38SDavid Howells 1218d94aa38SDavid Howells msg.msg_name = &call->peer->srx.transport; 1228d94aa38SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 1238d94aa38SDavid Howells msg.msg_control = NULL; 1248d94aa38SDavid Howells msg.msg_controllen = 0; 1258d94aa38SDavid Howells msg.msg_flags = 0; 1268d94aa38SDavid Howells 1278d94aa38SDavid Howells pkt->whdr.epoch = htonl(conn->proto.epoch); 1288d94aa38SDavid Howells pkt->whdr.cid = htonl(call->cid); 1298d94aa38SDavid Howells pkt->whdr.callNumber = htonl(call->call_id); 1308d94aa38SDavid Howells pkt->whdr.seq = 0; 13126cb02aaSDavid Howells pkt->whdr.type = RXRPC_PACKET_TYPE_ACK; 13226cb02aaSDavid Howells pkt->whdr.flags = RXRPC_SLOW_START_OK | conn->out_clientflag; 1338d94aa38SDavid Howells pkt->whdr.userStatus = 0; 1348d94aa38SDavid Howells pkt->whdr.securityIndex = call->security_ix; 1358d94aa38SDavid Howells pkt->whdr._rsvd = 0; 1368d94aa38SDavid Howells pkt->whdr.serviceId = htons(call->service_id); 1378d94aa38SDavid Howells 1388d94aa38SDavid Howells spin_lock_bh(&call->lock); 13927d0fc43SDavid Howells if (!call->ackr_reason) { 14027d0fc43SDavid Howells spin_unlock_bh(&call->lock); 14127d0fc43SDavid Howells ret = 0; 14227d0fc43SDavid Howells goto out; 14327d0fc43SDavid Howells } 1448e83134dSDavid Howells ping = (call->ackr_reason == RXRPC_ACK_PING); 145805b21b9SDavid Howells n = rxrpc_fill_out_ack(call, pkt, &hard_ack, &top); 1468d94aa38SDavid Howells call->ackr_reason = 0; 1478d94aa38SDavid Howells 1488d94aa38SDavid Howells spin_unlock_bh(&call->lock); 1498d94aa38SDavid Howells 15026cb02aaSDavid Howells iov[0].iov_base = pkt; 15126cb02aaSDavid Howells iov[0].iov_len = sizeof(pkt->whdr) + sizeof(pkt->ack) + n; 1528d94aa38SDavid Howells iov[1].iov_base = &pkt->ackinfo; 1538d94aa38SDavid Howells iov[1].iov_len = sizeof(pkt->ackinfo); 15426cb02aaSDavid Howells len = iov[0].iov_len + iov[1].iov_len; 1558d94aa38SDavid Howells 156b86e218eSDavid Howells serial = atomic_inc_return(&conn->serial); 157b86e218eSDavid Howells pkt->whdr.serial = htonl(serial); 158be832aecSDavid Howells trace_rxrpc_tx_ack(call, serial, 159b86e218eSDavid Howells ntohl(pkt->ack.firstPacket), 160b86e218eSDavid Howells ntohl(pkt->ack.serial), 161b86e218eSDavid Howells pkt->ack.reason, pkt->ack.nAcks); 162b86e218eSDavid Howells 1638e83134dSDavid Howells if (ping) { 1648e83134dSDavid Howells call->ackr_ping = serial; 1658e83134dSDavid Howells smp_wmb(); 1668e83134dSDavid Howells /* We need to stick a time in before we send the packet in case 1678e83134dSDavid Howells * the reply gets back before kernel_sendmsg() completes - but 1688e83134dSDavid Howells * asking UDP to send the packet can take a relatively long 1698e83134dSDavid Howells * time, so we update the time after, on the assumption that 1708e83134dSDavid Howells * the packet transmission is more likely to happen towards the 1718e83134dSDavid Howells * end of the kernel_sendmsg() call. 1728e83134dSDavid Howells */ 1738e83134dSDavid Howells call->ackr_ping_time = ktime_get_real(); 1748e83134dSDavid Howells set_bit(RXRPC_CALL_PINGING, &call->flags); 1758e83134dSDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_ping, serial); 1768e83134dSDavid Howells } 17726cb02aaSDavid Howells 17826cb02aaSDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len); 1798e83134dSDavid Howells if (ping) 1808e83134dSDavid Howells call->ackr_ping_time = ktime_get_real(); 1818d94aa38SDavid Howells 18226cb02aaSDavid Howells if (call->state < RXRPC_CALL_COMPLETE) { 183805b21b9SDavid Howells if (ret < 0) { 1848e83134dSDavid Howells clear_bit(RXRPC_CALL_PINGING, &call->flags); 185248f219cSDavid Howells rxrpc_propose_ACK(call, pkt->ack.reason, 186248f219cSDavid Howells ntohs(pkt->ack.maxSkew), 187248f219cSDavid Howells ntohl(pkt->ack.serial), 1889c7ad434SDavid Howells true, true, 1899c7ad434SDavid Howells rxrpc_propose_ack_retry_tx); 190805b21b9SDavid Howells } else { 191805b21b9SDavid Howells spin_lock_bh(&call->lock); 192805b21b9SDavid Howells if (after(hard_ack, call->ackr_consumed)) 193805b21b9SDavid Howells call->ackr_consumed = hard_ack; 194805b21b9SDavid Howells if (after(top, call->ackr_seen)) 195805b21b9SDavid Howells call->ackr_seen = top; 196805b21b9SDavid Howells spin_unlock_bh(&call->lock); 197248f219cSDavid Howells } 198248f219cSDavid Howells } 199248f219cSDavid Howells 2008d94aa38SDavid Howells out: 2018d94aa38SDavid Howells rxrpc_put_connection(conn); 2028d94aa38SDavid Howells kfree(pkt); 2038d94aa38SDavid Howells return ret; 2048d94aa38SDavid Howells } 2058d94aa38SDavid Howells 2068c3e34a4SDavid Howells /* 20726cb02aaSDavid Howells * Send an ABORT call packet. 20826cb02aaSDavid Howells */ 20926cb02aaSDavid Howells int rxrpc_send_abort_packet(struct rxrpc_call *call) 21026cb02aaSDavid Howells { 21126cb02aaSDavid Howells struct rxrpc_connection *conn = NULL; 21226cb02aaSDavid Howells struct rxrpc_abort_buffer pkt; 21326cb02aaSDavid Howells struct msghdr msg; 21426cb02aaSDavid Howells struct kvec iov[1]; 21526cb02aaSDavid Howells rxrpc_serial_t serial; 21626cb02aaSDavid Howells int ret; 21726cb02aaSDavid Howells 21826cb02aaSDavid Howells spin_lock_bh(&call->lock); 21926cb02aaSDavid Howells if (call->conn) 22026cb02aaSDavid Howells conn = rxrpc_get_connection_maybe(call->conn); 22126cb02aaSDavid Howells spin_unlock_bh(&call->lock); 22226cb02aaSDavid Howells if (!conn) 22326cb02aaSDavid Howells return -ECONNRESET; 22426cb02aaSDavid Howells 22526cb02aaSDavid Howells msg.msg_name = &call->peer->srx.transport; 22626cb02aaSDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 22726cb02aaSDavid Howells msg.msg_control = NULL; 22826cb02aaSDavid Howells msg.msg_controllen = 0; 22926cb02aaSDavid Howells msg.msg_flags = 0; 23026cb02aaSDavid Howells 23126cb02aaSDavid Howells pkt.whdr.epoch = htonl(conn->proto.epoch); 23226cb02aaSDavid Howells pkt.whdr.cid = htonl(call->cid); 23326cb02aaSDavid Howells pkt.whdr.callNumber = htonl(call->call_id); 23426cb02aaSDavid Howells pkt.whdr.seq = 0; 23526cb02aaSDavid Howells pkt.whdr.type = RXRPC_PACKET_TYPE_ABORT; 23626cb02aaSDavid Howells pkt.whdr.flags = conn->out_clientflag; 23726cb02aaSDavid Howells pkt.whdr.userStatus = 0; 23826cb02aaSDavid Howells pkt.whdr.securityIndex = call->security_ix; 23926cb02aaSDavid Howells pkt.whdr._rsvd = 0; 24026cb02aaSDavid Howells pkt.whdr.serviceId = htons(call->service_id); 24126cb02aaSDavid Howells pkt.abort_code = htonl(call->abort_code); 24226cb02aaSDavid Howells 24326cb02aaSDavid Howells iov[0].iov_base = &pkt; 24426cb02aaSDavid Howells iov[0].iov_len = sizeof(pkt); 24526cb02aaSDavid Howells 24626cb02aaSDavid Howells serial = atomic_inc_return(&conn->serial); 24726cb02aaSDavid Howells pkt.whdr.serial = htonl(serial); 24826cb02aaSDavid Howells 24926cb02aaSDavid Howells ret = kernel_sendmsg(conn->params.local->socket, 25026cb02aaSDavid Howells &msg, iov, 1, sizeof(pkt)); 25126cb02aaSDavid Howells 25226cb02aaSDavid Howells rxrpc_put_connection(conn); 25326cb02aaSDavid Howells return ret; 25426cb02aaSDavid Howells } 25526cb02aaSDavid Howells 25626cb02aaSDavid Howells /* 2578c3e34a4SDavid Howells * send a packet through the transport endpoint 2588c3e34a4SDavid Howells */ 259a1767077SDavid Howells int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, 260a1767077SDavid Howells bool retrans) 2618c3e34a4SDavid Howells { 2625a924b89SDavid Howells struct rxrpc_connection *conn = call->conn; 2635a924b89SDavid Howells struct rxrpc_wire_header whdr; 2645a924b89SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 2658c3e34a4SDavid Howells struct msghdr msg; 2665a924b89SDavid Howells struct kvec iov[2]; 2675a924b89SDavid Howells rxrpc_serial_t serial; 2685a924b89SDavid Howells size_t len; 269a1767077SDavid Howells bool lost = false; 2708c3e34a4SDavid Howells int ret, opt; 2718c3e34a4SDavid Howells 2728c3e34a4SDavid Howells _enter(",{%d}", skb->len); 2738c3e34a4SDavid Howells 2745a924b89SDavid Howells /* Each transmission of a Tx packet needs a new serial number */ 2755a924b89SDavid Howells serial = atomic_inc_return(&conn->serial); 2768c3e34a4SDavid Howells 2775a924b89SDavid Howells whdr.epoch = htonl(conn->proto.epoch); 2785a924b89SDavid Howells whdr.cid = htonl(call->cid); 2795a924b89SDavid Howells whdr.callNumber = htonl(call->call_id); 2805a924b89SDavid Howells whdr.seq = htonl(sp->hdr.seq); 2815a924b89SDavid Howells whdr.serial = htonl(serial); 2825a924b89SDavid Howells whdr.type = RXRPC_PACKET_TYPE_DATA; 2835a924b89SDavid Howells whdr.flags = sp->hdr.flags; 2845a924b89SDavid Howells whdr.userStatus = 0; 2855a924b89SDavid Howells whdr.securityIndex = call->security_ix; 2865a924b89SDavid Howells whdr._rsvd = htons(sp->hdr._rsvd); 2875a924b89SDavid Howells whdr.serviceId = htons(call->service_id); 2885a924b89SDavid Howells 2895a924b89SDavid Howells iov[0].iov_base = &whdr; 2905a924b89SDavid Howells iov[0].iov_len = sizeof(whdr); 2915a924b89SDavid Howells iov[1].iov_base = skb->head; 2925a924b89SDavid Howells iov[1].iov_len = skb->len; 2935a924b89SDavid Howells len = iov[0].iov_len + iov[1].iov_len; 2945a924b89SDavid Howells 2955a924b89SDavid Howells msg.msg_name = &call->peer->srx.transport; 2965a924b89SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 2978c3e34a4SDavid Howells msg.msg_control = NULL; 2988c3e34a4SDavid Howells msg.msg_controllen = 0; 2998c3e34a4SDavid Howells msg.msg_flags = 0; 3008c3e34a4SDavid Howells 30157494343SDavid Howells /* If our RTT cache needs working on, request an ACK. Also request 30257494343SDavid Howells * ACKs if a DATA packet appears to have been lost. 30357494343SDavid Howells */ 304a1767077SDavid Howells if (retrans || 305b112a670SDavid Howells call->cong_mode == RXRPC_CALL_SLOW_START || 30657494343SDavid Howells (call->peer->rtt_usage < 3 && sp->hdr.seq & 1) || 3070d4b103cSDavid Howells ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), 3080d4b103cSDavid Howells ktime_get_real())) 3090d4b103cSDavid Howells whdr.flags |= RXRPC_REQUEST_ACK; 3100d4b103cSDavid Howells 3118a681c36SDavid Howells if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { 3128a681c36SDavid Howells static int lose; 3138a681c36SDavid Howells if ((lose++ & 7) == 7) { 314a1767077SDavid Howells ret = 0; 315a1767077SDavid Howells lost = true; 316a1767077SDavid Howells goto done; 3178a681c36SDavid Howells } 3188a681c36SDavid Howells } 3198a681c36SDavid Howells 3205a924b89SDavid Howells _proto("Tx DATA %%%u { #%u }", serial, sp->hdr.seq); 3215a924b89SDavid Howells 3228c3e34a4SDavid Howells /* send the packet with the don't fragment bit set if we currently 3238c3e34a4SDavid Howells * think it's small enough */ 3245a924b89SDavid Howells if (iov[1].iov_len >= call->peer->maxdata) 3255a924b89SDavid Howells goto send_fragmentable; 3265a924b89SDavid Howells 327985a5c82SDavid Howells down_read(&conn->params.local->defrag_sem); 3288c3e34a4SDavid Howells /* send the packet by UDP 3298c3e34a4SDavid Howells * - returns -EMSGSIZE if UDP would have to fragment the packet 3308c3e34a4SDavid Howells * to go out of the interface 3318c3e34a4SDavid Howells * - in which case, we'll have processed the ICMP error 3328c3e34a4SDavid Howells * message and update the peer record 3338c3e34a4SDavid Howells */ 3345a924b89SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len); 3358c3e34a4SDavid Howells 336985a5c82SDavid Howells up_read(&conn->params.local->defrag_sem); 3378c3e34a4SDavid Howells if (ret == -EMSGSIZE) 3388c3e34a4SDavid Howells goto send_fragmentable; 3398c3e34a4SDavid Howells 3405a924b89SDavid Howells done: 341a1767077SDavid Howells trace_rxrpc_tx_data(call, sp->hdr.seq, serial, whdr.flags, 342a1767077SDavid Howells retrans, lost); 34350235c4bSDavid Howells if (ret >= 0) { 3440d4b103cSDavid Howells ktime_t now = ktime_get_real(); 3450d4b103cSDavid Howells skb->tstamp = now; 34650235c4bSDavid Howells smp_wmb(); 3475a924b89SDavid Howells sp->hdr.serial = serial; 3480d4b103cSDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) { 3490d4b103cSDavid Howells call->peer->rtt_last_req = now; 35050235c4bSDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial); 3518c3e34a4SDavid Howells } 3520d4b103cSDavid Howells } 3535a924b89SDavid Howells _leave(" = %d [%u]", ret, call->peer->maxdata); 3545a924b89SDavid Howells return ret; 3558c3e34a4SDavid Howells 3568c3e34a4SDavid Howells send_fragmentable: 3578c3e34a4SDavid Howells /* attempt to send this message with fragmentation enabled */ 3588c3e34a4SDavid Howells _debug("send fragment"); 3598c3e34a4SDavid Howells 360985a5c82SDavid Howells down_write(&conn->params.local->defrag_sem); 361985a5c82SDavid Howells 362985a5c82SDavid Howells switch (conn->params.local->srx.transport.family) { 363985a5c82SDavid Howells case AF_INET: 3648c3e34a4SDavid Howells opt = IP_PMTUDISC_DONT; 365985a5c82SDavid Howells ret = kernel_setsockopt(conn->params.local->socket, 366985a5c82SDavid Howells SOL_IP, IP_MTU_DISCOVER, 3678c3e34a4SDavid Howells (char *)&opt, sizeof(opt)); 3688c3e34a4SDavid Howells if (ret == 0) { 3695a924b89SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, 3705a924b89SDavid Howells iov, 2, len); 3718c3e34a4SDavid Howells 3728c3e34a4SDavid Howells opt = IP_PMTUDISC_DO; 373985a5c82SDavid Howells kernel_setsockopt(conn->params.local->socket, SOL_IP, 374985a5c82SDavid Howells IP_MTU_DISCOVER, 375985a5c82SDavid Howells (char *)&opt, sizeof(opt)); 376985a5c82SDavid Howells } 377985a5c82SDavid Howells break; 37875b54cb5SDavid Howells 379d1912747SDavid Howells #ifdef CONFIG_AF_RXRPC_IPV6 38075b54cb5SDavid Howells case AF_INET6: 38175b54cb5SDavid Howells opt = IPV6_PMTUDISC_DONT; 38275b54cb5SDavid Howells ret = kernel_setsockopt(conn->params.local->socket, 38375b54cb5SDavid Howells SOL_IPV6, IPV6_MTU_DISCOVER, 38475b54cb5SDavid Howells (char *)&opt, sizeof(opt)); 38575b54cb5SDavid Howells if (ret == 0) { 38675b54cb5SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, 38775b54cb5SDavid Howells iov, 1, iov[0].iov_len); 38875b54cb5SDavid Howells 38975b54cb5SDavid Howells opt = IPV6_PMTUDISC_DO; 39075b54cb5SDavid Howells kernel_setsockopt(conn->params.local->socket, 39175b54cb5SDavid Howells SOL_IPV6, IPV6_MTU_DISCOVER, 39275b54cb5SDavid Howells (char *)&opt, sizeof(opt)); 39375b54cb5SDavid Howells } 39475b54cb5SDavid Howells break; 395d1912747SDavid Howells #endif 3968c3e34a4SDavid Howells } 3978c3e34a4SDavid Howells 398985a5c82SDavid Howells up_write(&conn->params.local->defrag_sem); 3995a924b89SDavid Howells goto done; 4008c3e34a4SDavid Howells } 401248f219cSDavid Howells 402248f219cSDavid Howells /* 403248f219cSDavid Howells * reject packets through the local endpoint 404248f219cSDavid Howells */ 405248f219cSDavid Howells void rxrpc_reject_packets(struct rxrpc_local *local) 406248f219cSDavid Howells { 4071c2bc7b9SDavid Howells struct sockaddr_rxrpc srx; 408248f219cSDavid Howells struct rxrpc_skb_priv *sp; 409248f219cSDavid Howells struct rxrpc_wire_header whdr; 410248f219cSDavid Howells struct sk_buff *skb; 411248f219cSDavid Howells struct msghdr msg; 412248f219cSDavid Howells struct kvec iov[2]; 413248f219cSDavid Howells size_t size; 414248f219cSDavid Howells __be32 code; 415248f219cSDavid Howells 416248f219cSDavid Howells _enter("%d", local->debug_id); 417248f219cSDavid Howells 418248f219cSDavid Howells iov[0].iov_base = &whdr; 419248f219cSDavid Howells iov[0].iov_len = sizeof(whdr); 420248f219cSDavid Howells iov[1].iov_base = &code; 421248f219cSDavid Howells iov[1].iov_len = sizeof(code); 422248f219cSDavid Howells size = sizeof(whdr) + sizeof(code); 423248f219cSDavid Howells 4241c2bc7b9SDavid Howells msg.msg_name = &srx.transport; 425248f219cSDavid Howells msg.msg_control = NULL; 426248f219cSDavid Howells msg.msg_controllen = 0; 427248f219cSDavid Howells msg.msg_flags = 0; 428248f219cSDavid Howells 429248f219cSDavid Howells memset(&whdr, 0, sizeof(whdr)); 430248f219cSDavid Howells whdr.type = RXRPC_PACKET_TYPE_ABORT; 431248f219cSDavid Howells 432248f219cSDavid Howells while ((skb = skb_dequeue(&local->reject_queue))) { 43371f3ca40SDavid Howells rxrpc_see_skb(skb, rxrpc_skb_rx_seen); 434248f219cSDavid Howells sp = rxrpc_skb(skb); 4351c2bc7b9SDavid Howells 4361c2bc7b9SDavid Howells if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) { 4371c2bc7b9SDavid Howells msg.msg_namelen = srx.transport_len; 4381c2bc7b9SDavid Howells 439248f219cSDavid Howells code = htonl(skb->priority); 440248f219cSDavid Howells 441248f219cSDavid Howells whdr.epoch = htonl(sp->hdr.epoch); 442248f219cSDavid Howells whdr.cid = htonl(sp->hdr.cid); 443248f219cSDavid Howells whdr.callNumber = htonl(sp->hdr.callNumber); 444248f219cSDavid Howells whdr.serviceId = htons(sp->hdr.serviceId); 445248f219cSDavid Howells whdr.flags = sp->hdr.flags; 446248f219cSDavid Howells whdr.flags ^= RXRPC_CLIENT_INITIATED; 447248f219cSDavid Howells whdr.flags &= RXRPC_CLIENT_INITIATED; 448248f219cSDavid Howells 449248f219cSDavid Howells kernel_sendmsg(local->socket, &msg, iov, 2, size); 450248f219cSDavid Howells } 451248f219cSDavid Howells 45271f3ca40SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_rx_freed); 453248f219cSDavid Howells } 454248f219cSDavid Howells 455248f219cSDavid Howells _leave(""); 456248f219cSDavid Howells } 457