18c3e34a4SDavid Howells /* connection-level event handling 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/module.h> 158c3e34a4SDavid Howells #include <linux/net.h> 168c3e34a4SDavid Howells #include <linux/skbuff.h> 178c3e34a4SDavid Howells #include <linux/errqueue.h> 188c3e34a4SDavid Howells #include <linux/udp.h> 198c3e34a4SDavid Howells #include <linux/in.h> 208c3e34a4SDavid Howells #include <linux/in6.h> 218c3e34a4SDavid Howells #include <linux/icmp.h> 228c3e34a4SDavid Howells #include <net/sock.h> 238c3e34a4SDavid Howells #include <net/af_rxrpc.h> 248c3e34a4SDavid Howells #include <net/ip.h> 258c3e34a4SDavid Howells #include "ar-internal.h" 268c3e34a4SDavid Howells 278c3e34a4SDavid Howells /* 2818bfeba5SDavid Howells * Retransmit terminal ACK or ABORT of the previous call. 2918bfeba5SDavid Howells */ 3018bfeba5SDavid Howells static void rxrpc_conn_retransmit(struct rxrpc_connection *conn, 3118bfeba5SDavid Howells struct sk_buff *skb) 3218bfeba5SDavid Howells { 3318bfeba5SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 3418bfeba5SDavid Howells struct rxrpc_channel *chan; 3518bfeba5SDavid Howells struct msghdr msg; 3618bfeba5SDavid Howells struct kvec iov; 3718bfeba5SDavid Howells struct { 3818bfeba5SDavid Howells struct rxrpc_wire_header whdr; 3918bfeba5SDavid Howells union { 4018bfeba5SDavid Howells struct { 4118bfeba5SDavid Howells __be32 code; 4218bfeba5SDavid Howells } abort; 4318bfeba5SDavid Howells struct { 4418bfeba5SDavid Howells struct rxrpc_ackpacket ack; 452266ffdeSDavid Howells u8 padding[3]; 4618bfeba5SDavid Howells struct rxrpc_ackinfo info; 4718bfeba5SDavid Howells }; 4818bfeba5SDavid Howells }; 4918bfeba5SDavid Howells } __attribute__((packed)) pkt; 5018bfeba5SDavid Howells size_t len; 5118bfeba5SDavid Howells u32 serial, mtu, call_id; 5218bfeba5SDavid Howells 5318bfeba5SDavid Howells _enter("%d", conn->debug_id); 5418bfeba5SDavid Howells 5518bfeba5SDavid Howells chan = &conn->channels[sp->hdr.cid & RXRPC_CHANNELMASK]; 5618bfeba5SDavid Howells 5718bfeba5SDavid Howells /* If the last call got moved on whilst we were waiting to run, just 5818bfeba5SDavid Howells * ignore this packet. 5918bfeba5SDavid Howells */ 6018bfeba5SDavid Howells call_id = READ_ONCE(chan->last_call); 6118bfeba5SDavid Howells /* Sync with __rxrpc_disconnect_call() */ 6218bfeba5SDavid Howells smp_rmb(); 6318bfeba5SDavid Howells if (call_id != sp->hdr.callNumber) 6418bfeba5SDavid Howells return; 6518bfeba5SDavid Howells 6618bfeba5SDavid Howells msg.msg_name = &conn->params.peer->srx.transport; 6718bfeba5SDavid Howells msg.msg_namelen = conn->params.peer->srx.transport_len; 6818bfeba5SDavid Howells msg.msg_control = NULL; 6918bfeba5SDavid Howells msg.msg_controllen = 0; 7018bfeba5SDavid Howells msg.msg_flags = 0; 7118bfeba5SDavid Howells 7218bfeba5SDavid Howells pkt.whdr.epoch = htonl(sp->hdr.epoch); 7318bfeba5SDavid Howells pkt.whdr.cid = htonl(sp->hdr.cid); 7418bfeba5SDavid Howells pkt.whdr.callNumber = htonl(sp->hdr.callNumber); 7518bfeba5SDavid Howells pkt.whdr.seq = 0; 7618bfeba5SDavid Howells pkt.whdr.type = chan->last_type; 7718bfeba5SDavid Howells pkt.whdr.flags = conn->out_clientflag; 7818bfeba5SDavid Howells pkt.whdr.userStatus = 0; 7918bfeba5SDavid Howells pkt.whdr.securityIndex = conn->security_ix; 8018bfeba5SDavid Howells pkt.whdr._rsvd = 0; 8118bfeba5SDavid Howells pkt.whdr.serviceId = htons(chan->last_service_id); 8218bfeba5SDavid Howells 8318bfeba5SDavid Howells len = sizeof(pkt.whdr); 8418bfeba5SDavid Howells switch (chan->last_type) { 8518bfeba5SDavid Howells case RXRPC_PACKET_TYPE_ABORT: 8618bfeba5SDavid Howells pkt.abort.code = htonl(chan->last_abort); 8718bfeba5SDavid Howells len += sizeof(pkt.abort); 8818bfeba5SDavid Howells break; 8918bfeba5SDavid Howells 9018bfeba5SDavid Howells case RXRPC_PACKET_TYPE_ACK: 9118bfeba5SDavid Howells mtu = conn->params.peer->if_mtu; 9218bfeba5SDavid Howells mtu -= conn->params.peer->hdrsize; 9318bfeba5SDavid Howells pkt.ack.bufferSpace = 0; 9418bfeba5SDavid Howells pkt.ack.maxSkew = htons(skb->priority); 9518bfeba5SDavid Howells pkt.ack.firstPacket = htonl(chan->last_seq); 9618bfeba5SDavid Howells pkt.ack.previousPacket = htonl(chan->last_seq - 1); 9718bfeba5SDavid Howells pkt.ack.serial = htonl(sp->hdr.serial); 9818bfeba5SDavid Howells pkt.ack.reason = RXRPC_ACK_DUPLICATE; 9918bfeba5SDavid Howells pkt.ack.nAcks = 0; 10018bfeba5SDavid Howells pkt.info.rxMTU = htonl(rxrpc_rx_mtu); 10118bfeba5SDavid Howells pkt.info.maxMTU = htonl(mtu); 10218bfeba5SDavid Howells pkt.info.rwind = htonl(rxrpc_rx_window_size); 10318bfeba5SDavid Howells pkt.info.jumbo_max = htonl(rxrpc_rx_jumbo_max); 10418bfeba5SDavid Howells len += sizeof(pkt.ack) + sizeof(pkt.info); 10518bfeba5SDavid Howells break; 10618bfeba5SDavid Howells } 10718bfeba5SDavid Howells 10818bfeba5SDavid Howells /* Resync with __rxrpc_disconnect_call() and check that the last call 10918bfeba5SDavid Howells * didn't get advanced whilst we were filling out the packets. 11018bfeba5SDavid Howells */ 11118bfeba5SDavid Howells smp_rmb(); 11218bfeba5SDavid Howells if (READ_ONCE(chan->last_call) != call_id) 11318bfeba5SDavid Howells return; 11418bfeba5SDavid Howells 11518bfeba5SDavid Howells iov.iov_base = &pkt; 11618bfeba5SDavid Howells iov.iov_len = len; 11718bfeba5SDavid Howells 11818bfeba5SDavid Howells serial = atomic_inc_return(&conn->serial); 11918bfeba5SDavid Howells pkt.whdr.serial = htonl(serial); 12018bfeba5SDavid Howells 12118bfeba5SDavid Howells switch (chan->last_type) { 12218bfeba5SDavid Howells case RXRPC_PACKET_TYPE_ABORT: 12318bfeba5SDavid Howells _proto("Tx ABORT %%%u { %d } [re]", serial, conn->local_abort); 12418bfeba5SDavid Howells break; 12518bfeba5SDavid Howells case RXRPC_PACKET_TYPE_ACK: 12618bfeba5SDavid Howells _proto("Tx ACK %%%u [re]", serial); 12718bfeba5SDavid Howells break; 12818bfeba5SDavid Howells } 12918bfeba5SDavid Howells 13018bfeba5SDavid Howells kernel_sendmsg(conn->params.local->socket, &msg, &iov, 1, len); 13118bfeba5SDavid Howells _leave(""); 13218bfeba5SDavid Howells return; 13318bfeba5SDavid Howells } 13418bfeba5SDavid Howells 13518bfeba5SDavid Howells /* 1368c3e34a4SDavid Howells * pass a connection-level abort onto all calls on that connection 1378c3e34a4SDavid Howells */ 1388c3e34a4SDavid Howells static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state, 1398c3e34a4SDavid Howells u32 abort_code) 1408c3e34a4SDavid Howells { 1418c3e34a4SDavid Howells struct rxrpc_call *call; 142a1399f8bSDavid Howells int i; 1438c3e34a4SDavid Howells 1448c3e34a4SDavid Howells _enter("{%d},%x", conn->debug_id, abort_code); 1458c3e34a4SDavid Howells 146a1399f8bSDavid Howells spin_lock(&conn->channel_lock); 1478c3e34a4SDavid Howells 148a1399f8bSDavid Howells for (i = 0; i < RXRPC_MAXCALLS; i++) { 149a1399f8bSDavid Howells call = rcu_dereference_protected( 150a1399f8bSDavid Howells conn->channels[i].call, 151a1399f8bSDavid Howells lockdep_is_held(&conn->channel_lock)); 152ccbd3dbeSDavid Howells if (call) { 153a1399f8bSDavid Howells write_lock_bh(&call->state_lock); 1548c3e34a4SDavid Howells if (call->state <= RXRPC_CALL_COMPLETE) { 1558c3e34a4SDavid Howells call->state = state; 1568c3e34a4SDavid Howells if (state == RXRPC_CALL_LOCALLY_ABORTED) { 1578c3e34a4SDavid Howells call->local_abort = conn->local_abort; 158ccbd3dbeSDavid Howells set_bit(RXRPC_CALL_EV_CONN_ABORT, 159ccbd3dbeSDavid Howells &call->events); 1608c3e34a4SDavid Howells } else { 1618c3e34a4SDavid Howells call->remote_abort = conn->remote_abort; 162ccbd3dbeSDavid Howells set_bit(RXRPC_CALL_EV_RCVD_ABORT, 163ccbd3dbeSDavid Howells &call->events); 1648c3e34a4SDavid Howells } 1658c3e34a4SDavid Howells rxrpc_queue_call(call); 1668c3e34a4SDavid Howells } 167a1399f8bSDavid Howells write_unlock_bh(&call->state_lock); 1688c3e34a4SDavid Howells } 169ccbd3dbeSDavid Howells } 1708c3e34a4SDavid Howells 171a1399f8bSDavid Howells spin_unlock(&conn->channel_lock); 1728c3e34a4SDavid Howells _leave(""); 1738c3e34a4SDavid Howells } 1748c3e34a4SDavid Howells 1758c3e34a4SDavid Howells /* 1768c3e34a4SDavid Howells * generate a connection-level abort 1778c3e34a4SDavid Howells */ 1788c3e34a4SDavid Howells static int rxrpc_abort_connection(struct rxrpc_connection *conn, 1798c3e34a4SDavid Howells u32 error, u32 abort_code) 1808c3e34a4SDavid Howells { 1818c3e34a4SDavid Howells struct rxrpc_wire_header whdr; 1828c3e34a4SDavid Howells struct msghdr msg; 1838c3e34a4SDavid Howells struct kvec iov[2]; 1848c3e34a4SDavid Howells __be32 word; 1858c3e34a4SDavid Howells size_t len; 1868c3e34a4SDavid Howells u32 serial; 1878c3e34a4SDavid Howells int ret; 1888c3e34a4SDavid Howells 1898c3e34a4SDavid Howells _enter("%d,,%u,%u", conn->debug_id, error, abort_code); 1908c3e34a4SDavid Howells 1918c3e34a4SDavid Howells /* generate a connection-level abort */ 1928c3e34a4SDavid Howells spin_lock_bh(&conn->state_lock); 1938c3e34a4SDavid Howells if (conn->state < RXRPC_CONN_REMOTELY_ABORTED) { 1948c3e34a4SDavid Howells conn->state = RXRPC_CONN_LOCALLY_ABORTED; 1958c3e34a4SDavid Howells conn->error = error; 1968c3e34a4SDavid Howells spin_unlock_bh(&conn->state_lock); 1978c3e34a4SDavid Howells } else { 1988c3e34a4SDavid Howells spin_unlock_bh(&conn->state_lock); 1998c3e34a4SDavid Howells _leave(" = 0 [already dead]"); 2008c3e34a4SDavid Howells return 0; 2018c3e34a4SDavid Howells } 2028c3e34a4SDavid Howells 2038c3e34a4SDavid Howells rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, abort_code); 2048c3e34a4SDavid Howells 20585f32278SDavid Howells msg.msg_name = &conn->params.peer->srx.transport; 20685f32278SDavid Howells msg.msg_namelen = conn->params.peer->srx.transport_len; 2078c3e34a4SDavid Howells msg.msg_control = NULL; 2088c3e34a4SDavid Howells msg.msg_controllen = 0; 2098c3e34a4SDavid Howells msg.msg_flags = 0; 2108c3e34a4SDavid Howells 21119ffa01cSDavid Howells whdr.epoch = htonl(conn->proto.epoch); 21219ffa01cSDavid Howells whdr.cid = htonl(conn->proto.cid); 2138c3e34a4SDavid Howells whdr.callNumber = 0; 2148c3e34a4SDavid Howells whdr.seq = 0; 2158c3e34a4SDavid Howells whdr.type = RXRPC_PACKET_TYPE_ABORT; 2168c3e34a4SDavid Howells whdr.flags = conn->out_clientflag; 2178c3e34a4SDavid Howells whdr.userStatus = 0; 2188c3e34a4SDavid Howells whdr.securityIndex = conn->security_ix; 2198c3e34a4SDavid Howells whdr._rsvd = 0; 22019ffa01cSDavid Howells whdr.serviceId = htons(conn->params.service_id); 2218c3e34a4SDavid Howells 2228c3e34a4SDavid Howells word = htonl(conn->local_abort); 2238c3e34a4SDavid Howells 2248c3e34a4SDavid Howells iov[0].iov_base = &whdr; 2258c3e34a4SDavid Howells iov[0].iov_len = sizeof(whdr); 2268c3e34a4SDavid Howells iov[1].iov_base = &word; 2278c3e34a4SDavid Howells iov[1].iov_len = sizeof(word); 2288c3e34a4SDavid Howells 2298c3e34a4SDavid Howells len = iov[0].iov_len + iov[1].iov_len; 2308c3e34a4SDavid Howells 2318c3e34a4SDavid Howells serial = atomic_inc_return(&conn->serial); 2328c3e34a4SDavid Howells whdr.serial = htonl(serial); 2338c3e34a4SDavid Howells _proto("Tx CONN ABORT %%%u { %d }", serial, conn->local_abort); 2348c3e34a4SDavid Howells 23585f32278SDavid Howells ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len); 2368c3e34a4SDavid Howells if (ret < 0) { 2378c3e34a4SDavid Howells _debug("sendmsg failed: %d", ret); 2388c3e34a4SDavid Howells return -EAGAIN; 2398c3e34a4SDavid Howells } 2408c3e34a4SDavid Howells 2418c3e34a4SDavid Howells _leave(" = 0"); 2428c3e34a4SDavid Howells return 0; 2438c3e34a4SDavid Howells } 2448c3e34a4SDavid Howells 2458c3e34a4SDavid Howells /* 2468c3e34a4SDavid Howells * mark a call as being on a now-secured channel 2478c3e34a4SDavid Howells * - must be called with softirqs disabled 2488c3e34a4SDavid Howells */ 2498c3e34a4SDavid Howells static void rxrpc_call_is_secure(struct rxrpc_call *call) 2508c3e34a4SDavid Howells { 2518c3e34a4SDavid Howells _enter("%p", call); 2528c3e34a4SDavid Howells if (call) { 2538c3e34a4SDavid Howells read_lock(&call->state_lock); 2548c3e34a4SDavid Howells if (call->state < RXRPC_CALL_COMPLETE && 2558c3e34a4SDavid Howells !test_and_set_bit(RXRPC_CALL_EV_SECURED, &call->events)) 2568c3e34a4SDavid Howells rxrpc_queue_call(call); 2578c3e34a4SDavid Howells read_unlock(&call->state_lock); 2588c3e34a4SDavid Howells } 2598c3e34a4SDavid Howells } 2608c3e34a4SDavid Howells 2618c3e34a4SDavid Howells /* 2628c3e34a4SDavid Howells * connection-level Rx packet processor 2638c3e34a4SDavid Howells */ 2648c3e34a4SDavid Howells static int rxrpc_process_event(struct rxrpc_connection *conn, 2658c3e34a4SDavid Howells struct sk_buff *skb, 2668c3e34a4SDavid Howells u32 *_abort_code) 2678c3e34a4SDavid Howells { 2688c3e34a4SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 2698c3e34a4SDavid Howells __be32 wtmp; 2708c3e34a4SDavid Howells u32 abort_code; 2718c3e34a4SDavid Howells int loop, ret; 2728c3e34a4SDavid Howells 2738c3e34a4SDavid Howells if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { 2748c3e34a4SDavid Howells kleave(" = -ECONNABORTED [%u]", conn->state); 2758c3e34a4SDavid Howells return -ECONNABORTED; 2768c3e34a4SDavid Howells } 2778c3e34a4SDavid Howells 2788c3e34a4SDavid Howells _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial); 2798c3e34a4SDavid Howells 2808c3e34a4SDavid Howells switch (sp->hdr.type) { 28118bfeba5SDavid Howells case RXRPC_PACKET_TYPE_DATA: 28218bfeba5SDavid Howells case RXRPC_PACKET_TYPE_ACK: 28318bfeba5SDavid Howells rxrpc_conn_retransmit(conn, skb); 28418bfeba5SDavid Howells rxrpc_free_skb(skb); 28518bfeba5SDavid Howells return 0; 28618bfeba5SDavid Howells 2878c3e34a4SDavid Howells case RXRPC_PACKET_TYPE_ABORT: 2888c3e34a4SDavid Howells if (skb_copy_bits(skb, 0, &wtmp, sizeof(wtmp)) < 0) 2898c3e34a4SDavid Howells return -EPROTO; 2908c3e34a4SDavid Howells abort_code = ntohl(wtmp); 2918c3e34a4SDavid Howells _proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code); 2928c3e34a4SDavid Howells 2938c3e34a4SDavid Howells conn->state = RXRPC_CONN_REMOTELY_ABORTED; 2948c3e34a4SDavid Howells rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, 2958c3e34a4SDavid Howells abort_code); 2968c3e34a4SDavid Howells return -ECONNABORTED; 2978c3e34a4SDavid Howells 2988c3e34a4SDavid Howells case RXRPC_PACKET_TYPE_CHALLENGE: 2998c3e34a4SDavid Howells return conn->security->respond_to_challenge(conn, skb, 3008c3e34a4SDavid Howells _abort_code); 3018c3e34a4SDavid Howells 3028c3e34a4SDavid Howells case RXRPC_PACKET_TYPE_RESPONSE: 3038c3e34a4SDavid Howells ret = conn->security->verify_response(conn, skb, _abort_code); 3048c3e34a4SDavid Howells if (ret < 0) 3058c3e34a4SDavid Howells return ret; 3068c3e34a4SDavid Howells 3078c3e34a4SDavid Howells ret = conn->security->init_connection_security(conn); 3088c3e34a4SDavid Howells if (ret < 0) 3098c3e34a4SDavid Howells return ret; 3108c3e34a4SDavid Howells 311a263629dSHerbert Xu ret = conn->security->prime_packet_security(conn); 312a263629dSHerbert Xu if (ret < 0) 313a263629dSHerbert Xu return ret; 314a263629dSHerbert Xu 315a1399f8bSDavid Howells spin_lock(&conn->channel_lock); 3168c3e34a4SDavid Howells spin_lock(&conn->state_lock); 3178c3e34a4SDavid Howells 318bba304dbSDavid Howells if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) { 319bba304dbSDavid Howells conn->state = RXRPC_CONN_SERVICE; 3208c3e34a4SDavid Howells for (loop = 0; loop < RXRPC_MAXCALLS; loop++) 321dee46364SDavid Howells rxrpc_call_is_secure( 322dee46364SDavid Howells rcu_dereference_protected( 323a1399f8bSDavid Howells conn->channels[loop].call, 324a1399f8bSDavid Howells lockdep_is_held(&conn->channel_lock))); 3258c3e34a4SDavid Howells } 3268c3e34a4SDavid Howells 3278c3e34a4SDavid Howells spin_unlock(&conn->state_lock); 328a1399f8bSDavid Howells spin_unlock(&conn->channel_lock); 3298c3e34a4SDavid Howells return 0; 3308c3e34a4SDavid Howells 3318c3e34a4SDavid Howells default: 3328c3e34a4SDavid Howells _leave(" = -EPROTO [%u]", sp->hdr.type); 3338c3e34a4SDavid Howells return -EPROTO; 3348c3e34a4SDavid Howells } 3358c3e34a4SDavid Howells } 3368c3e34a4SDavid Howells 3378c3e34a4SDavid Howells /* 3388c3e34a4SDavid Howells * set up security and issue a challenge 3398c3e34a4SDavid Howells */ 3408c3e34a4SDavid Howells static void rxrpc_secure_connection(struct rxrpc_connection *conn) 3418c3e34a4SDavid Howells { 3428c3e34a4SDavid Howells u32 abort_code; 3438c3e34a4SDavid Howells int ret; 3448c3e34a4SDavid Howells 3458c3e34a4SDavid Howells _enter("{%d}", conn->debug_id); 3468c3e34a4SDavid Howells 3478c3e34a4SDavid Howells ASSERT(conn->security_ix != 0); 3488c3e34a4SDavid Howells 34919ffa01cSDavid Howells if (!conn->params.key) { 3508c3e34a4SDavid Howells _debug("set up security"); 3518c3e34a4SDavid Howells ret = rxrpc_init_server_conn_security(conn); 3528c3e34a4SDavid Howells switch (ret) { 3538c3e34a4SDavid Howells case 0: 3548c3e34a4SDavid Howells break; 3558c3e34a4SDavid Howells case -ENOENT: 3568c3e34a4SDavid Howells abort_code = RX_CALL_DEAD; 3578c3e34a4SDavid Howells goto abort; 3588c3e34a4SDavid Howells default: 3598c3e34a4SDavid Howells abort_code = RXKADNOAUTH; 3608c3e34a4SDavid Howells goto abort; 3618c3e34a4SDavid Howells } 3628c3e34a4SDavid Howells } 3638c3e34a4SDavid Howells 3648c3e34a4SDavid Howells if (conn->security->issue_challenge(conn) < 0) { 3658c3e34a4SDavid Howells abort_code = RX_CALL_DEAD; 3668c3e34a4SDavid Howells ret = -ENOMEM; 3678c3e34a4SDavid Howells goto abort; 3688c3e34a4SDavid Howells } 3698c3e34a4SDavid Howells 3708c3e34a4SDavid Howells _leave(""); 3718c3e34a4SDavid Howells return; 3728c3e34a4SDavid Howells 3738c3e34a4SDavid Howells abort: 3748c3e34a4SDavid Howells _debug("abort %d, %d", ret, abort_code); 3758c3e34a4SDavid Howells rxrpc_abort_connection(conn, -ret, abort_code); 3768c3e34a4SDavid Howells _leave(" [aborted]"); 3778c3e34a4SDavid Howells } 3788c3e34a4SDavid Howells 3798c3e34a4SDavid Howells /* 3808c3e34a4SDavid Howells * connection-level event processor 3818c3e34a4SDavid Howells */ 3828c3e34a4SDavid Howells void rxrpc_process_connection(struct work_struct *work) 3838c3e34a4SDavid Howells { 3848c3e34a4SDavid Howells struct rxrpc_connection *conn = 3858c3e34a4SDavid Howells container_of(work, struct rxrpc_connection, processor); 3868c3e34a4SDavid Howells struct sk_buff *skb; 3878c3e34a4SDavid Howells u32 abort_code = RX_PROTOCOL_ERROR; 3888c3e34a4SDavid Howells int ret; 3898c3e34a4SDavid Howells 3908c3e34a4SDavid Howells _enter("{%d}", conn->debug_id); 3918c3e34a4SDavid Howells 3922c4579e4SDavid Howells if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events)) 3938c3e34a4SDavid Howells rxrpc_secure_connection(conn); 3948c3e34a4SDavid Howells 3958c3e34a4SDavid Howells /* go through the conn-level event packets, releasing the ref on this 3968c3e34a4SDavid Howells * connection that each one has when we've finished with it */ 3978c3e34a4SDavid Howells while ((skb = skb_dequeue(&conn->rx_queue))) { 398df844fd4SDavid Howells rxrpc_see_skb(skb); 3998c3e34a4SDavid Howells ret = rxrpc_process_event(conn, skb, &abort_code); 4008c3e34a4SDavid Howells switch (ret) { 4018c3e34a4SDavid Howells case -EPROTO: 4028c3e34a4SDavid Howells case -EKEYEXPIRED: 4038c3e34a4SDavid Howells case -EKEYREJECTED: 4048c3e34a4SDavid Howells goto protocol_error; 4058c3e34a4SDavid Howells case -EAGAIN: 4068c3e34a4SDavid Howells goto requeue_and_leave; 4078c3e34a4SDavid Howells case -ECONNABORTED: 4088c3e34a4SDavid Howells default: 4098c3e34a4SDavid Howells rxrpc_free_skb(skb); 4108c3e34a4SDavid Howells break; 4118c3e34a4SDavid Howells } 4128c3e34a4SDavid Howells } 4138c3e34a4SDavid Howells 4148c3e34a4SDavid Howells out: 4158c3e34a4SDavid Howells rxrpc_put_connection(conn); 4168c3e34a4SDavid Howells _leave(""); 4178c3e34a4SDavid Howells return; 4188c3e34a4SDavid Howells 4198c3e34a4SDavid Howells requeue_and_leave: 4208c3e34a4SDavid Howells skb_queue_head(&conn->rx_queue, skb); 4218c3e34a4SDavid Howells goto out; 4228c3e34a4SDavid Howells 4238c3e34a4SDavid Howells protocol_error: 4248c3e34a4SDavid Howells if (rxrpc_abort_connection(conn, -ret, abort_code) < 0) 4258c3e34a4SDavid Howells goto requeue_and_leave; 4268c3e34a4SDavid Howells rxrpc_free_skb(skb); 4278c3e34a4SDavid Howells _leave(" [EPROTO]"); 4288c3e34a4SDavid Howells goto out; 4298c3e34a4SDavid Howells } 4308c3e34a4SDavid Howells 4318c3e34a4SDavid Howells /* 4328c3e34a4SDavid Howells * put a packet up for transport-level abort 4338c3e34a4SDavid Howells */ 4348c3e34a4SDavid Howells void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb) 4358c3e34a4SDavid Howells { 4368c3e34a4SDavid Howells CHECK_SLAB_OKAY(&local->usage); 4378c3e34a4SDavid Howells 4388c3e34a4SDavid Howells skb_queue_tail(&local->reject_queue, skb); 4395acbee46SDavid Howells rxrpc_queue_local(local); 4408c3e34a4SDavid Howells } 4418c3e34a4SDavid Howells 4428c3e34a4SDavid Howells /* 4438c3e34a4SDavid Howells * reject packets through the local endpoint 4448c3e34a4SDavid Howells */ 4454f95dd78SDavid Howells void rxrpc_reject_packets(struct rxrpc_local *local) 4468c3e34a4SDavid Howells { 4478c3e34a4SDavid Howells union { 4488c3e34a4SDavid Howells struct sockaddr sa; 4498c3e34a4SDavid Howells struct sockaddr_in sin; 4508c3e34a4SDavid Howells } sa; 4518c3e34a4SDavid Howells struct rxrpc_skb_priv *sp; 4528c3e34a4SDavid Howells struct rxrpc_wire_header whdr; 4538c3e34a4SDavid Howells struct sk_buff *skb; 4548c3e34a4SDavid Howells struct msghdr msg; 4558c3e34a4SDavid Howells struct kvec iov[2]; 4568c3e34a4SDavid Howells size_t size; 4578c3e34a4SDavid Howells __be32 code; 4588c3e34a4SDavid Howells 4598c3e34a4SDavid Howells _enter("%d", local->debug_id); 4608c3e34a4SDavid Howells 4618c3e34a4SDavid Howells iov[0].iov_base = &whdr; 4628c3e34a4SDavid Howells iov[0].iov_len = sizeof(whdr); 4638c3e34a4SDavid Howells iov[1].iov_base = &code; 4648c3e34a4SDavid Howells iov[1].iov_len = sizeof(code); 4658c3e34a4SDavid Howells size = sizeof(whdr) + sizeof(code); 4668c3e34a4SDavid Howells 4678c3e34a4SDavid Howells msg.msg_name = &sa; 4688c3e34a4SDavid Howells msg.msg_control = NULL; 4698c3e34a4SDavid Howells msg.msg_controllen = 0; 4708c3e34a4SDavid Howells msg.msg_flags = 0; 4718c3e34a4SDavid Howells 4728c3e34a4SDavid Howells memset(&sa, 0, sizeof(sa)); 4738c3e34a4SDavid Howells sa.sa.sa_family = local->srx.transport.family; 4748c3e34a4SDavid Howells switch (sa.sa.sa_family) { 4758c3e34a4SDavid Howells case AF_INET: 4768c3e34a4SDavid Howells msg.msg_namelen = sizeof(sa.sin); 4778c3e34a4SDavid Howells break; 4788c3e34a4SDavid Howells default: 4798c3e34a4SDavid Howells msg.msg_namelen = 0; 4808c3e34a4SDavid Howells break; 4818c3e34a4SDavid Howells } 4828c3e34a4SDavid Howells 4838c3e34a4SDavid Howells memset(&whdr, 0, sizeof(whdr)); 4848c3e34a4SDavid Howells whdr.type = RXRPC_PACKET_TYPE_ABORT; 4858c3e34a4SDavid Howells 4868c3e34a4SDavid Howells while ((skb = skb_dequeue(&local->reject_queue))) { 487df844fd4SDavid Howells rxrpc_see_skb(skb); 4888c3e34a4SDavid Howells sp = rxrpc_skb(skb); 4898c3e34a4SDavid Howells switch (sa.sa.sa_family) { 4908c3e34a4SDavid Howells case AF_INET: 4918c3e34a4SDavid Howells sa.sin.sin_port = udp_hdr(skb)->source; 4928c3e34a4SDavid Howells sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr; 4938c3e34a4SDavid Howells code = htonl(skb->priority); 4948c3e34a4SDavid Howells 4958c3e34a4SDavid Howells whdr.epoch = htonl(sp->hdr.epoch); 4968c3e34a4SDavid Howells whdr.cid = htonl(sp->hdr.cid); 4978c3e34a4SDavid Howells whdr.callNumber = htonl(sp->hdr.callNumber); 4988c3e34a4SDavid Howells whdr.serviceId = htons(sp->hdr.serviceId); 4998c3e34a4SDavid Howells whdr.flags = sp->hdr.flags; 5008c3e34a4SDavid Howells whdr.flags ^= RXRPC_CLIENT_INITIATED; 5018c3e34a4SDavid Howells whdr.flags &= RXRPC_CLIENT_INITIATED; 5028c3e34a4SDavid Howells 5038c3e34a4SDavid Howells kernel_sendmsg(local->socket, &msg, iov, 2, size); 5048c3e34a4SDavid Howells break; 5058c3e34a4SDavid Howells 5068c3e34a4SDavid Howells default: 5078c3e34a4SDavid Howells break; 5088c3e34a4SDavid Howells } 5098c3e34a4SDavid Howells 5108c3e34a4SDavid Howells rxrpc_free_skb(skb); 5118c3e34a4SDavid Howells } 5128c3e34a4SDavid Howells 5138c3e34a4SDavid Howells _leave(""); 5148c3e34a4SDavid Howells } 515