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 228d94aa38SDavid Howells struct rxrpc_pkt_buffer { 238d94aa38SDavid Howells struct rxrpc_wire_header whdr; 248d94aa38SDavid Howells union { 258d94aa38SDavid Howells struct { 268d94aa38SDavid Howells struct rxrpc_ackpacket ack; 278d94aa38SDavid Howells u8 acks[255]; 288d94aa38SDavid Howells u8 pad[3]; 298d94aa38SDavid Howells }; 308d94aa38SDavid Howells __be32 abort_code; 318d94aa38SDavid Howells }; 328d94aa38SDavid Howells struct rxrpc_ackinfo ackinfo; 338d94aa38SDavid Howells }; 348d94aa38SDavid 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, 39805b21b9SDavid Howells struct rxrpc_pkt_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 /* 94248f219cSDavid Howells * Send an ACK or ABORT call packet. 958d94aa38SDavid Howells */ 968d94aa38SDavid Howells int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type) 978d94aa38SDavid Howells { 988d94aa38SDavid Howells struct rxrpc_connection *conn = NULL; 998d94aa38SDavid Howells struct rxrpc_pkt_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; 1068d94aa38SDavid Howells int ioc, ret; 1078d94aa38SDavid Howells u32 abort_code; 1088d94aa38SDavid Howells 1098d94aa38SDavid Howells _enter("%u,%s", call->debug_id, rxrpc_pkts[type]); 1108d94aa38SDavid Howells 1118d94aa38SDavid Howells spin_lock_bh(&call->lock); 1128d94aa38SDavid Howells if (call->conn) 1138d94aa38SDavid Howells conn = rxrpc_get_connection_maybe(call->conn); 1148d94aa38SDavid Howells spin_unlock_bh(&call->lock); 1158d94aa38SDavid Howells if (!conn) 1168d94aa38SDavid Howells return -ECONNRESET; 1178d94aa38SDavid Howells 1188d94aa38SDavid Howells pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); 1198d94aa38SDavid Howells if (!pkt) { 1208d94aa38SDavid Howells rxrpc_put_connection(conn); 1218d94aa38SDavid Howells return -ENOMEM; 1228d94aa38SDavid Howells } 1238d94aa38SDavid Howells 1248d94aa38SDavid Howells msg.msg_name = &call->peer->srx.transport; 1258d94aa38SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 1268d94aa38SDavid Howells msg.msg_control = NULL; 1278d94aa38SDavid Howells msg.msg_controllen = 0; 1288d94aa38SDavid Howells msg.msg_flags = 0; 1298d94aa38SDavid Howells 1308d94aa38SDavid Howells pkt->whdr.epoch = htonl(conn->proto.epoch); 1318d94aa38SDavid Howells pkt->whdr.cid = htonl(call->cid); 1328d94aa38SDavid Howells pkt->whdr.callNumber = htonl(call->call_id); 1338d94aa38SDavid Howells pkt->whdr.seq = 0; 1348d94aa38SDavid Howells pkt->whdr.type = type; 1358d94aa38SDavid Howells pkt->whdr.flags = conn->out_clientflag; 1368d94aa38SDavid Howells pkt->whdr.userStatus = 0; 1378d94aa38SDavid Howells pkt->whdr.securityIndex = call->security_ix; 1388d94aa38SDavid Howells pkt->whdr._rsvd = 0; 1398d94aa38SDavid Howells pkt->whdr.serviceId = htons(call->service_id); 1408d94aa38SDavid Howells 1418d94aa38SDavid Howells iov[0].iov_base = pkt; 1428d94aa38SDavid Howells iov[0].iov_len = sizeof(pkt->whdr); 1438d94aa38SDavid Howells len = sizeof(pkt->whdr); 1448d94aa38SDavid Howells 1458d94aa38SDavid Howells switch (type) { 1468d94aa38SDavid Howells case RXRPC_PACKET_TYPE_ACK: 1478d94aa38SDavid Howells spin_lock_bh(&call->lock); 14827d0fc43SDavid Howells if (!call->ackr_reason) { 14927d0fc43SDavid Howells spin_unlock_bh(&call->lock); 15027d0fc43SDavid Howells ret = 0; 15127d0fc43SDavid Howells goto out; 15227d0fc43SDavid Howells } 1538e83134dSDavid Howells ping = (call->ackr_reason == RXRPC_ACK_PING); 154805b21b9SDavid Howells n = rxrpc_fill_out_ack(call, pkt, &hard_ack, &top); 1558d94aa38SDavid Howells call->ackr_reason = 0; 1568d94aa38SDavid Howells 1578d94aa38SDavid Howells spin_unlock_bh(&call->lock); 1588d94aa38SDavid Howells 1598d94aa38SDavid Howells 16057494343SDavid Howells pkt->whdr.flags |= RXRPC_SLOW_START_OK; 16157494343SDavid Howells 1628d94aa38SDavid Howells iov[0].iov_len += sizeof(pkt->ack) + n; 1638d94aa38SDavid Howells iov[1].iov_base = &pkt->ackinfo; 1648d94aa38SDavid Howells iov[1].iov_len = sizeof(pkt->ackinfo); 1658d94aa38SDavid Howells len += sizeof(pkt->ack) + n + sizeof(pkt->ackinfo); 1668d94aa38SDavid Howells ioc = 2; 1678d94aa38SDavid Howells break; 1688d94aa38SDavid Howells 1698d94aa38SDavid Howells case RXRPC_PACKET_TYPE_ABORT: 1708d94aa38SDavid Howells abort_code = call->abort_code; 1718d94aa38SDavid Howells pkt->abort_code = htonl(abort_code); 1728d94aa38SDavid Howells iov[0].iov_len += sizeof(pkt->abort_code); 1738d94aa38SDavid Howells len += sizeof(pkt->abort_code); 1748d94aa38SDavid Howells ioc = 1; 1758d94aa38SDavid Howells break; 1768d94aa38SDavid Howells 1778d94aa38SDavid Howells default: 1788d94aa38SDavid Howells BUG(); 1798d94aa38SDavid Howells ret = -ENOANO; 1808d94aa38SDavid Howells goto out; 1818d94aa38SDavid Howells } 1828d94aa38SDavid Howells 183b86e218eSDavid Howells serial = atomic_inc_return(&conn->serial); 184b86e218eSDavid Howells pkt->whdr.serial = htonl(serial); 185b86e218eSDavid Howells switch (type) { 186b86e218eSDavid Howells case RXRPC_PACKET_TYPE_ACK: 187be832aecSDavid Howells trace_rxrpc_tx_ack(call, serial, 188b86e218eSDavid Howells ntohl(pkt->ack.firstPacket), 189b86e218eSDavid Howells ntohl(pkt->ack.serial), 190b86e218eSDavid Howells pkt->ack.reason, pkt->ack.nAcks); 191b86e218eSDavid Howells break; 192b86e218eSDavid Howells } 193b86e218eSDavid Howells 1948e83134dSDavid Howells if (ping) { 1958e83134dSDavid Howells call->ackr_ping = serial; 1968e83134dSDavid Howells smp_wmb(); 1978e83134dSDavid Howells /* We need to stick a time in before we send the packet in case 1988e83134dSDavid Howells * the reply gets back before kernel_sendmsg() completes - but 1998e83134dSDavid Howells * asking UDP to send the packet can take a relatively long 2008e83134dSDavid Howells * time, so we update the time after, on the assumption that 2018e83134dSDavid Howells * the packet transmission is more likely to happen towards the 2028e83134dSDavid Howells * end of the kernel_sendmsg() call. 2038e83134dSDavid Howells */ 2048e83134dSDavid Howells call->ackr_ping_time = ktime_get_real(); 2058e83134dSDavid Howells set_bit(RXRPC_CALL_PINGING, &call->flags); 2068e83134dSDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_ping, serial); 2078e83134dSDavid Howells } 2088d94aa38SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, 2098d94aa38SDavid Howells &msg, iov, ioc, len); 2108e83134dSDavid Howells if (ping) 2118e83134dSDavid Howells call->ackr_ping_time = ktime_get_real(); 2128d94aa38SDavid Howells 213805b21b9SDavid Howells if (type == RXRPC_PACKET_TYPE_ACK && 214805b21b9SDavid Howells call->state < RXRPC_CALL_COMPLETE) { 215805b21b9SDavid Howells if (ret < 0) { 2168e83134dSDavid Howells clear_bit(RXRPC_CALL_PINGING, &call->flags); 217248f219cSDavid Howells rxrpc_propose_ACK(call, pkt->ack.reason, 218248f219cSDavid Howells ntohs(pkt->ack.maxSkew), 219248f219cSDavid Howells ntohl(pkt->ack.serial), 2209c7ad434SDavid Howells true, true, 2219c7ad434SDavid Howells rxrpc_propose_ack_retry_tx); 222805b21b9SDavid Howells } else { 223805b21b9SDavid Howells spin_lock_bh(&call->lock); 224805b21b9SDavid Howells if (after(hard_ack, call->ackr_consumed)) 225805b21b9SDavid Howells call->ackr_consumed = hard_ack; 226805b21b9SDavid Howells if (after(top, call->ackr_seen)) 227805b21b9SDavid Howells call->ackr_seen = top; 228805b21b9SDavid Howells spin_unlock_bh(&call->lock); 229248f219cSDavid Howells } 230248f219cSDavid Howells } 231248f219cSDavid Howells 2328d94aa38SDavid Howells out: 2338d94aa38SDavid Howells rxrpc_put_connection(conn); 2348d94aa38SDavid Howells kfree(pkt); 2358d94aa38SDavid Howells return ret; 2368d94aa38SDavid Howells } 2378d94aa38SDavid Howells 2388c3e34a4SDavid Howells /* 2398c3e34a4SDavid Howells * send a packet through the transport endpoint 2408c3e34a4SDavid Howells */ 241a1767077SDavid Howells int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, 242a1767077SDavid Howells bool retrans) 2438c3e34a4SDavid Howells { 2445a924b89SDavid Howells struct rxrpc_connection *conn = call->conn; 2455a924b89SDavid Howells struct rxrpc_wire_header whdr; 2465a924b89SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 2478c3e34a4SDavid Howells struct msghdr msg; 2485a924b89SDavid Howells struct kvec iov[2]; 2495a924b89SDavid Howells rxrpc_serial_t serial; 2505a924b89SDavid Howells size_t len; 251a1767077SDavid Howells bool lost = false; 2528c3e34a4SDavid Howells int ret, opt; 2538c3e34a4SDavid Howells 2548c3e34a4SDavid Howells _enter(",{%d}", skb->len); 2558c3e34a4SDavid Howells 2565a924b89SDavid Howells /* Each transmission of a Tx packet needs a new serial number */ 2575a924b89SDavid Howells serial = atomic_inc_return(&conn->serial); 2588c3e34a4SDavid Howells 2595a924b89SDavid Howells whdr.epoch = htonl(conn->proto.epoch); 2605a924b89SDavid Howells whdr.cid = htonl(call->cid); 2615a924b89SDavid Howells whdr.callNumber = htonl(call->call_id); 2625a924b89SDavid Howells whdr.seq = htonl(sp->hdr.seq); 2635a924b89SDavid Howells whdr.serial = htonl(serial); 2645a924b89SDavid Howells whdr.type = RXRPC_PACKET_TYPE_DATA; 2655a924b89SDavid Howells whdr.flags = sp->hdr.flags; 2665a924b89SDavid Howells whdr.userStatus = 0; 2675a924b89SDavid Howells whdr.securityIndex = call->security_ix; 2685a924b89SDavid Howells whdr._rsvd = htons(sp->hdr._rsvd); 2695a924b89SDavid Howells whdr.serviceId = htons(call->service_id); 2705a924b89SDavid Howells 2715a924b89SDavid Howells iov[0].iov_base = &whdr; 2725a924b89SDavid Howells iov[0].iov_len = sizeof(whdr); 2735a924b89SDavid Howells iov[1].iov_base = skb->head; 2745a924b89SDavid Howells iov[1].iov_len = skb->len; 2755a924b89SDavid Howells len = iov[0].iov_len + iov[1].iov_len; 2765a924b89SDavid Howells 2775a924b89SDavid Howells msg.msg_name = &call->peer->srx.transport; 2785a924b89SDavid Howells msg.msg_namelen = call->peer->srx.transport_len; 2798c3e34a4SDavid Howells msg.msg_control = NULL; 2808c3e34a4SDavid Howells msg.msg_controllen = 0; 2818c3e34a4SDavid Howells msg.msg_flags = 0; 2828c3e34a4SDavid Howells 28357494343SDavid Howells /* If our RTT cache needs working on, request an ACK. Also request 28457494343SDavid Howells * ACKs if a DATA packet appears to have been lost. 28557494343SDavid Howells */ 286a1767077SDavid Howells if (retrans || 28757494343SDavid Howells (call->peer->rtt_usage < 3 && sp->hdr.seq & 1) || 2880d4b103cSDavid Howells ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), 2890d4b103cSDavid Howells ktime_get_real())) 2900d4b103cSDavid Howells whdr.flags |= RXRPC_REQUEST_ACK; 2910d4b103cSDavid Howells 2928a681c36SDavid Howells if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { 2938a681c36SDavid Howells static int lose; 2948a681c36SDavid Howells if ((lose++ & 7) == 7) { 295a1767077SDavid Howells ret = 0; 296a1767077SDavid Howells lost = true; 297a1767077SDavid Howells goto done; 2988a681c36SDavid Howells } 2998a681c36SDavid Howells } 3008a681c36SDavid Howells 3015a924b89SDavid Howells _proto("Tx DATA %%%u { #%u }", serial, sp->hdr.seq); 3025a924b89SDavid Howells 3038c3e34a4SDavid Howells /* send the packet with the don't fragment bit set if we currently 3048c3e34a4SDavid Howells * think it's small enough */ 3055a924b89SDavid Howells if (iov[1].iov_len >= call->peer->maxdata) 3065a924b89SDavid Howells goto send_fragmentable; 3075a924b89SDavid Howells 308985a5c82SDavid Howells down_read(&conn->params.local->defrag_sem); 3098c3e34a4SDavid Howells /* send the packet by UDP 3108c3e34a4SDavid Howells * - returns -EMSGSIZE if UDP would have to fragment the packet 3118c3e34a4SDavid Howells * to go out of the interface 3128c3e34a4SDavid Howells * - in which case, we'll have processed the ICMP error 3138c3e34a4SDavid Howells * message and update the peer record 3148c3e34a4SDavid Howells */ 3155a924b89SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len); 3168c3e34a4SDavid Howells 317985a5c82SDavid Howells up_read(&conn->params.local->defrag_sem); 3188c3e34a4SDavid Howells if (ret == -EMSGSIZE) 3198c3e34a4SDavid Howells goto send_fragmentable; 3208c3e34a4SDavid Howells 3215a924b89SDavid Howells done: 322a1767077SDavid Howells trace_rxrpc_tx_data(call, sp->hdr.seq, serial, whdr.flags, 323a1767077SDavid Howells retrans, lost); 32450235c4bSDavid Howells if (ret >= 0) { 3250d4b103cSDavid Howells ktime_t now = ktime_get_real(); 3260d4b103cSDavid Howells skb->tstamp = now; 32750235c4bSDavid Howells smp_wmb(); 3285a924b89SDavid Howells sp->hdr.serial = serial; 3290d4b103cSDavid Howells if (whdr.flags & RXRPC_REQUEST_ACK) { 3300d4b103cSDavid Howells call->peer->rtt_last_req = now; 33150235c4bSDavid Howells trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial); 3328c3e34a4SDavid Howells } 3330d4b103cSDavid Howells } 3345a924b89SDavid Howells _leave(" = %d [%u]", ret, call->peer->maxdata); 3355a924b89SDavid Howells return ret; 3368c3e34a4SDavid Howells 3378c3e34a4SDavid Howells send_fragmentable: 3388c3e34a4SDavid Howells /* attempt to send this message with fragmentation enabled */ 3398c3e34a4SDavid Howells _debug("send fragment"); 3408c3e34a4SDavid Howells 341985a5c82SDavid Howells down_write(&conn->params.local->defrag_sem); 342985a5c82SDavid Howells 343985a5c82SDavid Howells switch (conn->params.local->srx.transport.family) { 344985a5c82SDavid Howells case AF_INET: 3458c3e34a4SDavid Howells opt = IP_PMTUDISC_DONT; 346985a5c82SDavid Howells ret = kernel_setsockopt(conn->params.local->socket, 347985a5c82SDavid Howells SOL_IP, IP_MTU_DISCOVER, 3488c3e34a4SDavid Howells (char *)&opt, sizeof(opt)); 3498c3e34a4SDavid Howells if (ret == 0) { 3505a924b89SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, 3515a924b89SDavid Howells iov, 2, len); 3528c3e34a4SDavid Howells 3538c3e34a4SDavid Howells opt = IP_PMTUDISC_DO; 354985a5c82SDavid Howells kernel_setsockopt(conn->params.local->socket, SOL_IP, 355985a5c82SDavid Howells IP_MTU_DISCOVER, 356985a5c82SDavid Howells (char *)&opt, sizeof(opt)); 357985a5c82SDavid Howells } 358985a5c82SDavid Howells break; 35975b54cb5SDavid Howells 360d1912747SDavid Howells #ifdef CONFIG_AF_RXRPC_IPV6 36175b54cb5SDavid Howells case AF_INET6: 36275b54cb5SDavid Howells opt = IPV6_PMTUDISC_DONT; 36375b54cb5SDavid Howells ret = kernel_setsockopt(conn->params.local->socket, 36475b54cb5SDavid Howells SOL_IPV6, IPV6_MTU_DISCOVER, 36575b54cb5SDavid Howells (char *)&opt, sizeof(opt)); 36675b54cb5SDavid Howells if (ret == 0) { 36775b54cb5SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, 36875b54cb5SDavid Howells iov, 1, iov[0].iov_len); 36975b54cb5SDavid Howells 37075b54cb5SDavid Howells opt = IPV6_PMTUDISC_DO; 37175b54cb5SDavid Howells kernel_setsockopt(conn->params.local->socket, 37275b54cb5SDavid Howells SOL_IPV6, IPV6_MTU_DISCOVER, 37375b54cb5SDavid Howells (char *)&opt, sizeof(opt)); 37475b54cb5SDavid Howells } 37575b54cb5SDavid Howells break; 376d1912747SDavid Howells #endif 3778c3e34a4SDavid Howells } 3788c3e34a4SDavid Howells 379985a5c82SDavid Howells up_write(&conn->params.local->defrag_sem); 3805a924b89SDavid Howells goto done; 3818c3e34a4SDavid Howells } 382248f219cSDavid Howells 383248f219cSDavid Howells /* 384248f219cSDavid Howells * reject packets through the local endpoint 385248f219cSDavid Howells */ 386248f219cSDavid Howells void rxrpc_reject_packets(struct rxrpc_local *local) 387248f219cSDavid Howells { 3881c2bc7b9SDavid Howells struct sockaddr_rxrpc srx; 389248f219cSDavid Howells struct rxrpc_skb_priv *sp; 390248f219cSDavid Howells struct rxrpc_wire_header whdr; 391248f219cSDavid Howells struct sk_buff *skb; 392248f219cSDavid Howells struct msghdr msg; 393248f219cSDavid Howells struct kvec iov[2]; 394248f219cSDavid Howells size_t size; 395248f219cSDavid Howells __be32 code; 396248f219cSDavid Howells 397248f219cSDavid Howells _enter("%d", local->debug_id); 398248f219cSDavid Howells 399248f219cSDavid Howells iov[0].iov_base = &whdr; 400248f219cSDavid Howells iov[0].iov_len = sizeof(whdr); 401248f219cSDavid Howells iov[1].iov_base = &code; 402248f219cSDavid Howells iov[1].iov_len = sizeof(code); 403248f219cSDavid Howells size = sizeof(whdr) + sizeof(code); 404248f219cSDavid Howells 4051c2bc7b9SDavid Howells msg.msg_name = &srx.transport; 406248f219cSDavid Howells msg.msg_control = NULL; 407248f219cSDavid Howells msg.msg_controllen = 0; 408248f219cSDavid Howells msg.msg_flags = 0; 409248f219cSDavid Howells 410248f219cSDavid Howells memset(&whdr, 0, sizeof(whdr)); 411248f219cSDavid Howells whdr.type = RXRPC_PACKET_TYPE_ABORT; 412248f219cSDavid Howells 413248f219cSDavid Howells while ((skb = skb_dequeue(&local->reject_queue))) { 41471f3ca40SDavid Howells rxrpc_see_skb(skb, rxrpc_skb_rx_seen); 415248f219cSDavid Howells sp = rxrpc_skb(skb); 4161c2bc7b9SDavid Howells 4171c2bc7b9SDavid Howells if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) { 4181c2bc7b9SDavid Howells msg.msg_namelen = srx.transport_len; 4191c2bc7b9SDavid Howells 420248f219cSDavid Howells code = htonl(skb->priority); 421248f219cSDavid Howells 422248f219cSDavid Howells whdr.epoch = htonl(sp->hdr.epoch); 423248f219cSDavid Howells whdr.cid = htonl(sp->hdr.cid); 424248f219cSDavid Howells whdr.callNumber = htonl(sp->hdr.callNumber); 425248f219cSDavid Howells whdr.serviceId = htons(sp->hdr.serviceId); 426248f219cSDavid Howells whdr.flags = sp->hdr.flags; 427248f219cSDavid Howells whdr.flags ^= RXRPC_CLIENT_INITIATED; 428248f219cSDavid Howells whdr.flags &= RXRPC_CLIENT_INITIATED; 429248f219cSDavid Howells 430248f219cSDavid Howells kernel_sendmsg(local->socket, &msg, iov, 2, size); 431248f219cSDavid Howells } 432248f219cSDavid Howells 43371f3ca40SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_rx_freed); 434248f219cSDavid Howells } 435248f219cSDavid Howells 436248f219cSDavid Howells _leave(""); 437248f219cSDavid Howells } 438