Commit fa5f4aaf authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-rewrite-20160908' of...

Merge tag 'rxrpc-rewrite-20160908' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Rewrite data and ack handling

This patch set constitutes the main portion of the AF_RXRPC rewrite.  It
consists of five fix/helper patches:

 (1) Fix ASSERTCMP's and ASSERTIFCMP's handling of signed values.

 (2) Update some protocol definitions slightly.

 (3) Use of an hlist for RCU purposes.

 (4) Removal of per-call sk_buff accounting (not really needed when skbs
     aren't being queued on the main queue).

 (5) Addition of a tracepoint to log incoming packets in the data_ready
     callback and to log the end of the data_ready callback.

And then there are two patches that form the main part:

 (6) Preallocation of resources for incoming calls so that in patch (7) the
     data_ready handler can be made to fully instantiate an incoming call
     and make it live.  This extends through into AFS so that AFS can
     preallocate its own incoming call resources.

     The preallocation size is capped at the listen() backlog setting - and
     that is capped at a sysctl limit which can be set between 4 and 32.

     The preallocation is (re)charged either by accepting/rejecting pending
     calls or, in the case of AFS, manually.  If insufficient preallocation
     resources exist, a BUSY packet will be transmitted.

     The advantage of using this preallocation is that once a call is set
     up in the data_ready handler, DATA packets can be queued on it
     immediately rather than the DATA packets being queued for a background
     work item to do all the allocation and then try and sort out the DATA
     packets whilst other DATA packets may still be coming in and going
     either to the background thread or the new call.

 (7) Rewrite the handling of DATA, ACK and ABORT packets.

     In the receive phase, DATA packets are now held in per-call circular
     buffers with deduplication, out of sequence detection and suchlike
     being done in data_ready.  Since there is only one producer and only
     once consumer, no locks need be used on the receive queue.

     Received ACK and ABORT packets are now parsed and discarded in
     data_ready to recycle resources as fast as possible.

     sk_buffs are no longer pulled, trimmed or cloned, but rather the
     offset and size of the content is tracked.  This particularly affects
     jumbo DATA packets which need insertion into the receive buffer in
     multiple places.  Annotations are kept to track which bit is which.

     Packets are no longer queued on the socket receive queue; rather,
     calls are queued.  Dummy packets to convey events therefore no longer
     need to be invented and metadata packets can be discarded as soon as
     parsed rather then being pushed onto the socket receive queue to
     indicate terminal events.

     The preallocation facility added in (6) is now used to set up incoming
     calls with very little locking required and no calls to the allocator
     in data_ready.

     Decryption and verification is now handled in recvmsg() rather than in
     a background thread.  This allows for the future possibility of
     decrypting directly into the user buffer.

     With this patch, the code is a lot simpler and most of the mass of
     call event and state wangling code in call_event.c is gone.

With this, the majority of the AF_RXRPC rewrite is complete.  However,
there are still things to be done, including:

 (*) Limit the number of active service calls to prevent an attacker from
     filling up a server's memory.

 (*) Limit the number of calls on the rebuff-with-BUSY queue.

 (*) Transmit delayed/deferred ACKs from recvmsg() if possible, rather than
     punting to the background thread.  Ideally, the background thread
     shouldn't run at all, but data_ready can't call kernel_sendmsg() and
     we can't rely on recvmsg() attending to the call in a timely fashion.

 (*) Prevent the call at the front of the socket queue from hogging
     recvmsg()'s attention if there's a sufficiently continuous supply of
     data.

 (*) Distribute ICMP errors by connection rather than by call.  Possibly
     parse the ICMP packet to try and pin down the exact connection and
     call.

 (*) Encrypt/decrypt directly between user buffers and socket buffers where
     possible.

 (*) IPv6.

 (*) Service ID upgrade.  This is a facility whereby a special flag bit is
     set in the DATA packet header when making a call that tells the server
     that it is allowed to change the service ID to an upgraded one and
     reply with an equivalent call from the upgraded service.

     This is used, for example, to override certain AFS calls so that IPv6
     addresses can be returned.

 (*) Allow userspace to preallocate call user IDs for incoming calls.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46dfc23e 248f219c
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
struct socket *afs_socket; /* my RxRPC socket */ struct socket *afs_socket; /* my RxRPC socket */
static struct workqueue_struct *afs_async_calls; static struct workqueue_struct *afs_async_calls;
static struct afs_call *afs_spare_incoming_call;
static atomic_t afs_outstanding_calls; static atomic_t afs_outstanding_calls;
static void afs_free_call(struct afs_call *); static void afs_free_call(struct afs_call *);
...@@ -26,7 +27,8 @@ static int afs_wait_for_call_to_complete(struct afs_call *); ...@@ -26,7 +27,8 @@ static int afs_wait_for_call_to_complete(struct afs_call *);
static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
static int afs_dont_wait_for_call_to_complete(struct afs_call *); static int afs_dont_wait_for_call_to_complete(struct afs_call *);
static void afs_process_async_call(struct work_struct *); static void afs_process_async_call(struct work_struct *);
static void afs_rx_new_call(struct sock *); static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
static int afs_deliver_cm_op_id(struct afs_call *); static int afs_deliver_cm_op_id(struct afs_call *);
/* synchronous call management */ /* synchronous call management */
...@@ -53,9 +55,9 @@ static const struct afs_call_type afs_RXCMxxxx = { ...@@ -53,9 +55,9 @@ static const struct afs_call_type afs_RXCMxxxx = {
.abort_to_error = afs_abort_to_error, .abort_to_error = afs_abort_to_error,
}; };
static void afs_collect_incoming_call(struct work_struct *); static void afs_charge_preallocation(struct work_struct *);
static DECLARE_WORK(afs_collect_incoming_call_work, afs_collect_incoming_call); static DECLARE_WORK(afs_charge_preallocation_work, afs_charge_preallocation);
static int afs_wait_atomic_t(atomic_t *p) static int afs_wait_atomic_t(atomic_t *p)
{ {
...@@ -100,13 +102,15 @@ int afs_open_socket(void) ...@@ -100,13 +102,15 @@ int afs_open_socket(void)
if (ret < 0) if (ret < 0)
goto error_2; goto error_2;
rxrpc_kernel_new_call_notification(socket, afs_rx_new_call); rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
afs_rx_discard_new_call);
ret = kernel_listen(socket, INT_MAX); ret = kernel_listen(socket, INT_MAX);
if (ret < 0) if (ret < 0)
goto error_2; goto error_2;
afs_socket = socket; afs_socket = socket;
afs_charge_preallocation(NULL);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -126,11 +130,19 @@ void afs_close_socket(void) ...@@ -126,11 +130,19 @@ void afs_close_socket(void)
{ {
_enter(""); _enter("");
if (afs_spare_incoming_call) {
atomic_inc(&afs_outstanding_calls);
afs_free_call(afs_spare_incoming_call);
afs_spare_incoming_call = NULL;
}
_debug("outstanding %u", atomic_read(&afs_outstanding_calls)); _debug("outstanding %u", atomic_read(&afs_outstanding_calls));
wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t, wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
_debug("no outstanding calls"); _debug("no outstanding calls");
flush_workqueue(afs_async_calls);
kernel_sock_shutdown(afs_socket, SHUT_RDWR);
flush_workqueue(afs_async_calls); flush_workqueue(afs_async_calls);
sock_release(afs_socket); sock_release(afs_socket);
...@@ -590,57 +602,65 @@ static void afs_process_async_call(struct work_struct *work) ...@@ -590,57 +602,65 @@ static void afs_process_async_call(struct work_struct *work)
_leave(""); _leave("");
} }
static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID)
{
struct afs_call *call = (struct afs_call *)user_call_ID;
call->rxcall = rxcall;
}
/* /*
* accept the backlog of incoming calls * Charge the incoming call preallocation.
*/ */
static void afs_collect_incoming_call(struct work_struct *work) static void afs_charge_preallocation(struct work_struct *work)
{ {
struct rxrpc_call *rxcall; struct afs_call *call = afs_spare_incoming_call;
struct afs_call *call = NULL;
_enter("");
do { for (;;) {
if (!call) { if (!call) {
call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); call = kzalloc(sizeof(struct afs_call), GFP_KERNEL);
if (!call) { if (!call)
rxrpc_kernel_reject_call(afs_socket); break;
return;
}
INIT_WORK(&call->async_work, afs_process_async_call); INIT_WORK(&call->async_work, afs_process_async_call);
call->wait_mode = &afs_async_incoming_call; call->wait_mode = &afs_async_incoming_call;
call->type = &afs_RXCMxxxx; call->type = &afs_RXCMxxxx;
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
call->state = AFS_CALL_AWAIT_OP_ID; call->state = AFS_CALL_AWAIT_OP_ID;
_debug("CALL %p{%s} [%d]",
call, call->type->name,
atomic_read(&afs_outstanding_calls));
atomic_inc(&afs_outstanding_calls);
} }
rxcall = rxrpc_kernel_accept_call(afs_socket, if (rxrpc_kernel_charge_accept(afs_socket,
afs_wake_up_async_call,
afs_rx_attach,
(unsigned long)call, (unsigned long)call,
afs_wake_up_async_call); GFP_KERNEL) < 0)
if (!IS_ERR(rxcall)) { break;
call->rxcall = rxcall;
call->need_attention = true;
queue_work(afs_async_calls, &call->async_work);
call = NULL; call = NULL;
} }
} while (!call); afs_spare_incoming_call = call;
}
/*
* Discard a preallocated call when a socket is shut down.
*/
static void afs_rx_discard_new_call(struct rxrpc_call *rxcall,
unsigned long user_call_ID)
{
struct afs_call *call = (struct afs_call *)user_call_ID;
if (call) atomic_inc(&afs_outstanding_calls);
call->rxcall = NULL;
afs_free_call(call); afs_free_call(call);
} }
/* /*
* Notification of an incoming call. * Notification of an incoming call.
*/ */
static void afs_rx_new_call(struct sock *sk) static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall,
unsigned long user_call_ID)
{ {
queue_work(afs_wq, &afs_collect_incoming_call_work); atomic_inc(&afs_outstanding_calls);
queue_work(afs_wq, &afs_charge_preallocation_work);
} }
/* /*
......
...@@ -21,10 +21,14 @@ struct rxrpc_call; ...@@ -21,10 +21,14 @@ struct rxrpc_call;
typedef void (*rxrpc_notify_rx_t)(struct sock *, struct rxrpc_call *, typedef void (*rxrpc_notify_rx_t)(struct sock *, struct rxrpc_call *,
unsigned long); unsigned long);
typedef void (*rxrpc_notify_new_call_t)(struct sock *); typedef void (*rxrpc_notify_new_call_t)(struct sock *, struct rxrpc_call *,
unsigned long);
typedef void (*rxrpc_discard_new_call_t)(struct rxrpc_call *, unsigned long);
typedef void (*rxrpc_user_attach_call_t)(struct rxrpc_call *, unsigned long);
void rxrpc_kernel_new_call_notification(struct socket *, void rxrpc_kernel_new_call_notification(struct socket *,
rxrpc_notify_new_call_t); rxrpc_notify_new_call_t,
rxrpc_discard_new_call_t);
struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *, struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
struct sockaddr_rxrpc *, struct sockaddr_rxrpc *,
struct key *, struct key *,
...@@ -38,10 +42,9 @@ int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *, ...@@ -38,10 +42,9 @@ int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
void rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, void rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
u32, int, const char *); u32, int, const char *);
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *); void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, unsigned long,
rxrpc_notify_rx_t);
int rxrpc_kernel_reject_call(struct socket *);
void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *, void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
struct sockaddr_rxrpc *); struct sockaddr_rxrpc *);
int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
rxrpc_user_attach_call_t, unsigned long, gfp_t);
#endif /* _NET_RXRPC_H */ #endif /* _NET_RXRPC_H */
...@@ -34,8 +34,6 @@ struct rxrpc_wire_header { ...@@ -34,8 +34,6 @@ struct rxrpc_wire_header {
#define RXRPC_CID_INC (1 << RXRPC_CIDSHIFT) /* connection ID increment */ #define RXRPC_CID_INC (1 << RXRPC_CIDSHIFT) /* connection ID increment */
__be32 callNumber; /* call ID (0 for connection-level packets) */ __be32 callNumber; /* call ID (0 for connection-level packets) */
#define RXRPC_PROCESS_MAXCALLS (1<<2) /* maximum number of active calls per conn (power of 2) */
__be32 seq; /* sequence number of pkt in call stream */ __be32 seq; /* sequence number of pkt in call stream */
__be32 serial; /* serial number of pkt sent to network */ __be32 serial; /* serial number of pkt sent to network */
...@@ -93,10 +91,14 @@ struct rxrpc_wire_header { ...@@ -93,10 +91,14 @@ struct rxrpc_wire_header {
struct rxrpc_jumbo_header { struct rxrpc_jumbo_header {
uint8_t flags; /* packet flags (as per rxrpc_header) */ uint8_t flags; /* packet flags (as per rxrpc_header) */
uint8_t pad; uint8_t pad;
__be16 _rsvd; /* reserved (used by kerberos security as cksum) */ union {
__be16 _rsvd; /* reserved */
__be16 cksum; /* kerberos security checksum */
};
}; };
#define RXRPC_JUMBO_DATALEN 1412 /* non-terminal jumbo packet data length */ #define RXRPC_JUMBO_DATALEN 1412 /* non-terminal jumbo packet data length */
#define RXRPC_JUMBO_SUBPKTLEN (RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header))
/*****************************************************************************/ /*****************************************************************************/
/* /*
...@@ -131,6 +133,13 @@ struct rxrpc_ackpacket { ...@@ -131,6 +133,13 @@ struct rxrpc_ackpacket {
} __packed; } __packed;
/* Some ACKs refer to specific packets and some are general and can be updated. */
#define RXRPC_ACK_UPDATEABLE ((1 << RXRPC_ACK_REQUESTED) | \
(1 << RXRPC_ACK_PING_RESPONSE) | \
(1 << RXRPC_ACK_DELAY) | \
(1 << RXRPC_ACK_IDLE))
/* /*
* ACK packets can have a further piece of information tagged on the end * ACK packets can have a further piece of information tagged on the end
*/ */
......
...@@ -18,16 +18,14 @@ ...@@ -18,16 +18,14 @@
TRACE_EVENT(rxrpc_call, TRACE_EVENT(rxrpc_call,
TP_PROTO(struct rxrpc_call *call, enum rxrpc_call_trace op, TP_PROTO(struct rxrpc_call *call, enum rxrpc_call_trace op,
int usage, int nskb, int usage, const void *where, const void *aux),
const void *where, const void *aux),
TP_ARGS(call, op, usage, nskb, where, aux), TP_ARGS(call, op, usage, where, aux),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(struct rxrpc_call *, call ) __field(struct rxrpc_call *, call )
__field(int, op ) __field(int, op )
__field(int, usage ) __field(int, usage )
__field(int, nskb )
__field(const void *, where ) __field(const void *, where )
__field(const void *, aux ) __field(const void *, aux )
), ),
...@@ -36,16 +34,14 @@ TRACE_EVENT(rxrpc_call, ...@@ -36,16 +34,14 @@ TRACE_EVENT(rxrpc_call,
__entry->call = call; __entry->call = call;
__entry->op = op; __entry->op = op;
__entry->usage = usage; __entry->usage = usage;
__entry->nskb = nskb;
__entry->where = where; __entry->where = where;
__entry->aux = aux; __entry->aux = aux;
), ),
TP_printk("c=%p %s u=%d s=%d p=%pSR a=%p", TP_printk("c=%p %s u=%d sp=%pSR a=%p",
__entry->call, __entry->call,
rxrpc_call_traces[__entry->op], rxrpc_call_traces[__entry->op],
__entry->usage, __entry->usage,
__entry->nskb,
__entry->where, __entry->where,
__entry->aux) __entry->aux)
); );
...@@ -84,6 +80,44 @@ TRACE_EVENT(rxrpc_skb, ...@@ -84,6 +80,44 @@ TRACE_EVENT(rxrpc_skb,
__entry->where) __entry->where)
); );
TRACE_EVENT(rxrpc_rx_packet,
TP_PROTO(struct rxrpc_skb_priv *sp),
TP_ARGS(sp),
TP_STRUCT__entry(
__field_struct(struct rxrpc_host_header, hdr )
),
TP_fast_assign(
memcpy(&__entry->hdr, &sp->hdr, sizeof(__entry->hdr));
),
TP_printk("%08x:%08x:%08x:%04x %08x %08x %02x %02x",
__entry->hdr.epoch, __entry->hdr.cid,
__entry->hdr.callNumber, __entry->hdr.serviceId,
__entry->hdr.serial, __entry->hdr.seq,
__entry->hdr.type, __entry->hdr.flags)
);
TRACE_EVENT(rxrpc_rx_done,
TP_PROTO(int result, int abort_code),
TP_ARGS(result, abort_code),
TP_STRUCT__entry(
__field(int, result )
__field(int, abort_code )
),
TP_fast_assign(
__entry->result = result;
__entry->abort_code = abort_code;
),
TP_printk("r=%d a=%d", __entry->result, __entry->abort_code)
);
TRACE_EVENT(rxrpc_abort, TRACE_EVENT(rxrpc_abort,
TP_PROTO(const char *why, u32 cid, u32 call_id, rxrpc_seq_t seq, TP_PROTO(const char *why, u32 cid, u32 call_id, rxrpc_seq_t seq,
int abort_code, int error), int abort_code, int error),
......
...@@ -155,15 +155,15 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) ...@@ -155,15 +155,15 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
} }
if (rx->srx.srx_service) { if (rx->srx.srx_service) {
write_lock_bh(&local->services_lock); write_lock(&local->services_lock);
list_for_each_entry(prx, &local->services, listen_link) { hlist_for_each_entry(prx, &local->services, listen_link) {
if (prx->srx.srx_service == rx->srx.srx_service) if (prx->srx.srx_service == rx->srx.srx_service)
goto service_in_use; goto service_in_use;
} }
rx->local = local; rx->local = local;
list_add_tail(&rx->listen_link, &local->services); hlist_add_head_rcu(&rx->listen_link, &local->services);
write_unlock_bh(&local->services_lock); write_unlock(&local->services_lock);
rx->sk.sk_state = RXRPC_SERVER_BOUND; rx->sk.sk_state = RXRPC_SERVER_BOUND;
} else { } else {
...@@ -176,7 +176,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) ...@@ -176,7 +176,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
return 0; return 0;
service_in_use: service_in_use:
write_unlock_bh(&local->services_lock); write_unlock(&local->services_lock);
rxrpc_put_local(local); rxrpc_put_local(local);
ret = -EADDRINUSE; ret = -EADDRINUSE;
error_unlock: error_unlock:
...@@ -193,7 +193,7 @@ static int rxrpc_listen(struct socket *sock, int backlog) ...@@ -193,7 +193,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct rxrpc_sock *rx = rxrpc_sk(sk); struct rxrpc_sock *rx = rxrpc_sk(sk);
unsigned int max; unsigned int max, old;
int ret; int ret;
_enter("%p,%d", rx, backlog); _enter("%p,%d", rx, backlog);
...@@ -212,9 +212,13 @@ static int rxrpc_listen(struct socket *sock, int backlog) ...@@ -212,9 +212,13 @@ static int rxrpc_listen(struct socket *sock, int backlog)
backlog = max; backlog = max;
else if (backlog < 0 || backlog > max) else if (backlog < 0 || backlog > max)
break; break;
old = sk->sk_max_ack_backlog;
sk->sk_max_ack_backlog = backlog; sk->sk_max_ack_backlog = backlog;
ret = rxrpc_service_prealloc(rx, GFP_KERNEL);
if (ret == 0)
rx->sk.sk_state = RXRPC_SERVER_LISTENING; rx->sk.sk_state = RXRPC_SERVER_LISTENING;
ret = 0; else
sk->sk_max_ack_backlog = old;
break; break;
default: default:
ret = -EBUSY; ret = -EBUSY;
...@@ -303,16 +307,19 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call); ...@@ -303,16 +307,19 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
* rxrpc_kernel_new_call_notification - Get notifications of new calls * rxrpc_kernel_new_call_notification - Get notifications of new calls
* @sock: The socket to intercept received messages on * @sock: The socket to intercept received messages on
* @notify_new_call: Function to be called when new calls appear * @notify_new_call: Function to be called when new calls appear
* @discard_new_call: Function to discard preallocated calls
* *
* Allow a kernel service to be given notifications about new calls. * Allow a kernel service to be given notifications about new calls.
*/ */
void rxrpc_kernel_new_call_notification( void rxrpc_kernel_new_call_notification(
struct socket *sock, struct socket *sock,
rxrpc_notify_new_call_t notify_new_call) rxrpc_notify_new_call_t notify_new_call,
rxrpc_discard_new_call_t discard_new_call)
{ {
struct rxrpc_sock *rx = rxrpc_sk(sock->sk); struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
rx->notify_new_call = notify_new_call; rx->notify_new_call = notify_new_call;
rx->discard_new_call = discard_new_call;
} }
EXPORT_SYMBOL(rxrpc_kernel_new_call_notification); EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
...@@ -508,15 +515,16 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, ...@@ -508,15 +515,16 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
static unsigned int rxrpc_poll(struct file *file, struct socket *sock, static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
poll_table *wait) poll_table *wait)
{ {
unsigned int mask;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct rxrpc_sock *rx = rxrpc_sk(sk);
unsigned int mask;
sock_poll_wait(file, sk_sleep(sk), wait); sock_poll_wait(file, sk_sleep(sk), wait);
mask = 0; mask = 0;
/* the socket is readable if there are any messages waiting on the Rx /* the socket is readable if there are any messages waiting on the Rx
* queue */ * queue */
if (!skb_queue_empty(&sk->sk_receive_queue)) if (!list_empty(&rx->recvmsg_q))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
/* the socket is writable if there is space to add new data to the /* the socket is writable if there is space to add new data to the
...@@ -567,9 +575,12 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, ...@@ -567,9 +575,12 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
rx->family = protocol; rx->family = protocol;
rx->calls = RB_ROOT; rx->calls = RB_ROOT;
INIT_LIST_HEAD(&rx->listen_link); INIT_HLIST_NODE(&rx->listen_link);
INIT_LIST_HEAD(&rx->secureq); spin_lock_init(&rx->incoming_lock);
INIT_LIST_HEAD(&rx->acceptq); INIT_LIST_HEAD(&rx->sock_calls);
INIT_LIST_HEAD(&rx->to_be_accepted);
INIT_LIST_HEAD(&rx->recvmsg_q);
rwlock_init(&rx->recvmsg_lock);
rwlock_init(&rx->call_lock); rwlock_init(&rx->call_lock);
memset(&rx->srx, 0, sizeof(rx->srx)); memset(&rx->srx, 0, sizeof(rx->srx));
...@@ -577,6 +588,39 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, ...@@ -577,6 +588,39 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
return 0; return 0;
} }
/*
* Kill all the calls on a socket and shut it down.
*/
static int rxrpc_shutdown(struct socket *sock, int flags)
{
struct sock *sk = sock->sk;
struct rxrpc_sock *rx = rxrpc_sk(sk);
int ret = 0;
_enter("%p,%d", sk, flags);
if (flags != SHUT_RDWR)
return -EOPNOTSUPP;
if (sk->sk_state == RXRPC_CLOSE)
return -ESHUTDOWN;
lock_sock(sk);
spin_lock_bh(&sk->sk_receive_queue.lock);
if (sk->sk_state < RXRPC_CLOSE) {
sk->sk_state = RXRPC_CLOSE;
sk->sk_shutdown = SHUTDOWN_MASK;
} else {
ret = -ESHUTDOWN;
}
spin_unlock_bh(&sk->sk_receive_queue.lock);
rxrpc_discard_prealloc(rx);
release_sock(sk);
return ret;
}
/* /*
* RxRPC socket destructor * RxRPC socket destructor
*/ */
...@@ -615,13 +659,14 @@ static int rxrpc_release_sock(struct sock *sk) ...@@ -615,13 +659,14 @@ static int rxrpc_release_sock(struct sock *sk)
ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1); ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);
if (!list_empty(&rx->listen_link)) { if (!hlist_unhashed(&rx->listen_link)) {
write_lock_bh(&rx->local->services_lock); write_lock(&rx->local->services_lock);
list_del(&rx->listen_link); hlist_del_rcu(&rx->listen_link);
write_unlock_bh(&rx->local->services_lock); write_unlock(&rx->local->services_lock);
} }
/* try to flush out this socket */ /* try to flush out this socket */
rxrpc_discard_prealloc(rx);
rxrpc_release_calls_on_socket(rx); rxrpc_release_calls_on_socket(rx);
flush_workqueue(rxrpc_workqueue); flush_workqueue(rxrpc_workqueue);
rxrpc_purge_queue(&sk->sk_receive_queue); rxrpc_purge_queue(&sk->sk_receive_queue);
...@@ -670,7 +715,7 @@ static const struct proto_ops rxrpc_rpc_ops = { ...@@ -670,7 +715,7 @@ static const struct proto_ops rxrpc_rpc_ops = {
.poll = rxrpc_poll, .poll = rxrpc_poll,
.ioctl = sock_no_ioctl, .ioctl = sock_no_ioctl,
.listen = rxrpc_listen, .listen = rxrpc_listen,
.shutdown = sock_no_shutdown, .shutdown = rxrpc_shutdown,
.setsockopt = rxrpc_setsockopt, .setsockopt = rxrpc_setsockopt,
.getsockopt = sock_no_getsockopt, .getsockopt = sock_no_getsockopt,
.sendmsg = rxrpc_sendmsg, .sendmsg = rxrpc_sendmsg,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -15,10 +15,6 @@ ...@@ -15,10 +15,6 @@
#include <linux/net.h> #include <linux/net.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/icmp.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -140,16 +136,10 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, ...@@ -140,16 +136,10 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
u32 abort_code, int error) u32 abort_code, int error)
{ {
struct rxrpc_call *call; struct rxrpc_call *call;
bool queue; int i;
int i, bit;
_enter("{%d},%x", conn->debug_id, abort_code); _enter("{%d},%x", conn->debug_id, abort_code);
if (compl == RXRPC_CALL_LOCALLY_ABORTED)
bit = RXRPC_CALL_EV_CONN_ABORT;
else
bit = RXRPC_CALL_EV_RCVD_ABORT;
spin_lock(&conn->channel_lock); spin_lock(&conn->channel_lock);
for (i = 0; i < RXRPC_MAXCALLS; i++) { for (i = 0; i < RXRPC_MAXCALLS; i++) {
...@@ -157,22 +147,13 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, ...@@ -157,22 +147,13 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
conn->channels[i].call, conn->channels[i].call,
lockdep_is_held(&conn->channel_lock)); lockdep_is_held(&conn->channel_lock));
if (call) { if (call) {
rxrpc_see_call(call);
if (compl == RXRPC_CALL_LOCALLY_ABORTED) if (compl == RXRPC_CALL_LOCALLY_ABORTED)
trace_rxrpc_abort("CON", call->cid, trace_rxrpc_abort("CON", call->cid,
call->call_id, 0, call->call_id, 0,
abort_code, error); abort_code, error);
if (rxrpc_set_call_completion(call, compl,
write_lock_bh(&call->state_lock); abort_code, error))
if (rxrpc_set_call_completion(call, compl, abort_code, rxrpc_notify_socket(call);
error)) {
set_bit(bit, &call->events);
queue = true;
}
write_unlock_bh(&call->state_lock);
if (queue)
rxrpc_queue_call(call);
} }
} }
...@@ -251,17 +232,18 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn, ...@@ -251,17 +232,18 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
/* /*
* mark a call as being on a now-secured channel * mark a call as being on a now-secured channel
* - must be called with softirqs disabled * - must be called with BH's disabled.
*/ */
static void rxrpc_call_is_secure(struct rxrpc_call *call) static void rxrpc_call_is_secure(struct rxrpc_call *call)
{ {
_enter("%p", call); _enter("%p", call);
if (call) { if (call) {
read_lock(&call->state_lock); write_lock_bh(&call->state_lock);
if (call->state < RXRPC_CALL_COMPLETE && if (call->state == RXRPC_CALL_SERVER_SECURING) {
!test_and_set_bit(RXRPC_CALL_EV_SECURED, &call->events)) call->state = RXRPC_CALL_SERVER_ACCEPTING;
rxrpc_queue_call(call); rxrpc_notify_socket(call);
read_unlock(&call->state_lock); }
write_unlock_bh(&call->state_lock);
} }
} }
...@@ -278,7 +260,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -278,7 +260,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
int loop, ret; int loop, ret;
if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
kleave(" = -ECONNABORTED [%u]", conn->state); _leave(" = -ECONNABORTED [%u]", conn->state);
return -ECONNABORTED; return -ECONNABORTED;
} }
...@@ -291,14 +273,14 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -291,14 +273,14 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return 0; return 0;
case RXRPC_PACKET_TYPE_ABORT: case RXRPC_PACKET_TYPE_ABORT:
if (skb_copy_bits(skb, 0, &wtmp, sizeof(wtmp)) < 0) if (skb_copy_bits(skb, sp->offset, &wtmp, sizeof(wtmp)) < 0)
return -EPROTO; return -EPROTO;
abort_code = ntohl(wtmp); abort_code = ntohl(wtmp);
_proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code); _proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);
conn->state = RXRPC_CONN_REMOTELY_ABORTED; conn->state = RXRPC_CONN_REMOTELY_ABORTED;
rxrpc_abort_calls(conn, 0, RXRPC_CALL_REMOTELY_ABORTED, rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
abort_code); abort_code, ECONNABORTED);
return -ECONNABORTED; return -ECONNABORTED;
case RXRPC_PACKET_TYPE_CHALLENGE: case RXRPC_PACKET_TYPE_CHALLENGE:
...@@ -323,14 +305,16 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -323,14 +305,16 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) { if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE; conn->state = RXRPC_CONN_SERVICE;
spin_unlock(&conn->state_lock);
for (loop = 0; loop < RXRPC_MAXCALLS; loop++) for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
rxrpc_call_is_secure( rxrpc_call_is_secure(
rcu_dereference_protected( rcu_dereference_protected(
conn->channels[loop].call, conn->channels[loop].call,
lockdep_is_held(&conn->channel_lock))); lockdep_is_held(&conn->channel_lock)));
} else {
spin_unlock(&conn->state_lock);
} }
spin_unlock(&conn->state_lock);
spin_unlock(&conn->channel_lock); spin_unlock(&conn->channel_lock);
return 0; return 0;
...@@ -433,88 +417,3 @@ void rxrpc_process_connection(struct work_struct *work) ...@@ -433,88 +417,3 @@ void rxrpc_process_connection(struct work_struct *work)
_leave(" [EPROTO]"); _leave(" [EPROTO]");
goto out; goto out;
} }
/*
* put a packet up for transport-level abort
*/
void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
{
CHECK_SLAB_OKAY(&local->usage);
skb_queue_tail(&local->reject_queue, skb);
rxrpc_queue_local(local);
}
/*
* reject packets through the local endpoint
*/
void rxrpc_reject_packets(struct rxrpc_local *local)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
} sa;
struct rxrpc_skb_priv *sp;
struct rxrpc_wire_header whdr;
struct sk_buff *skb;
struct msghdr msg;
struct kvec iov[2];
size_t size;
__be32 code;
_enter("%d", local->debug_id);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
iov[1].iov_base = &code;
iov[1].iov_len = sizeof(code);
size = sizeof(whdr) + sizeof(code);
msg.msg_name = &sa;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&sa, 0, sizeof(sa));
sa.sa.sa_family = local->srx.transport.family;
switch (sa.sa.sa_family) {
case AF_INET:
msg.msg_namelen = sizeof(sa.sin);
break;
default:
msg.msg_namelen = 0;
break;
}
memset(&whdr, 0, sizeof(whdr));
whdr.type = RXRPC_PACKET_TYPE_ABORT;
while ((skb = skb_dequeue(&local->reject_queue))) {
rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
switch (sa.sa.sa_family) {
case AF_INET:
sa.sin.sin_port = udp_hdr(skb)->source;
sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
code = htonl(skb->priority);
whdr.epoch = htonl(sp->hdr.epoch);
whdr.cid = htonl(sp->hdr.cid);
whdr.callNumber = htonl(sp->hdr.callNumber);
whdr.serviceId = htons(sp->hdr.serviceId);
whdr.flags = sp->hdr.flags;
whdr.flags ^= RXRPC_CLIENT_INITIATED;
whdr.flags &= RXRPC_CLIENT_INITIATED;
kernel_sendmsg(local->socket, &msg, iov, 2, size);
break;
default:
break;
}
rxrpc_free_skb(skb);
}
_leave("");
}
...@@ -169,7 +169,7 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn, ...@@ -169,7 +169,7 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
chan->last_abort = call->abort_code; chan->last_abort = call->abort_code;
chan->last_type = RXRPC_PACKET_TYPE_ABORT; chan->last_type = RXRPC_PACKET_TYPE_ABORT;
} else { } else {
chan->last_seq = call->rx_data_eaten; chan->last_seq = call->rx_hard_ack;
chan->last_type = RXRPC_PACKET_TYPE_ACK; chan->last_type = RXRPC_PACKET_TYPE_ACK;
} }
/* Sync with rxrpc_conn_retransmit(). */ /* Sync with rxrpc_conn_retransmit(). */
...@@ -191,6 +191,10 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) ...@@ -191,6 +191,10 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
{ {
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
spin_lock_bh(&conn->params.peer->lock);
hlist_del_init(&call->error_link);
spin_unlock_bh(&conn->params.peer->lock);
if (rxrpc_is_client_call(call)) if (rxrpc_is_client_call(call))
return rxrpc_disconnect_client_call(call); return rxrpc_disconnect_client_call(call);
...@@ -286,6 +290,8 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -286,6 +290,8 @@ static void rxrpc_connection_reaper(struct work_struct *work)
ASSERTCMP(atomic_read(&conn->usage), >, 0); ASSERTCMP(atomic_read(&conn->usage), >, 0);
if (likely(atomic_read(&conn->usage) > 1)) if (likely(atomic_read(&conn->usage) > 1))
continue; continue;
if (conn->state == RXRPC_CONN_SERVICE_PREALLOC)
continue;
idle_timestamp = READ_ONCE(conn->idle_timestamp); idle_timestamp = READ_ONCE(conn->idle_timestamp);
_debug("reap CONN %d { u=%d,t=%ld }", _debug("reap CONN %d { u=%d,t=%ld }",
......
...@@ -65,8 +65,7 @@ struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *peer, ...@@ -65,8 +65,7 @@ struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *peer,
* Insert a service connection into a peer's tree, thereby making it a target * Insert a service connection into a peer's tree, thereby making it a target
* for incoming packets. * for incoming packets.
*/ */
static struct rxrpc_connection * static void rxrpc_publish_service_conn(struct rxrpc_peer *peer,
rxrpc_publish_service_conn(struct rxrpc_peer *peer,
struct rxrpc_connection *conn) struct rxrpc_connection *conn)
{ {
struct rxrpc_connection *cursor = NULL; struct rxrpc_connection *cursor = NULL;
...@@ -96,7 +95,7 @@ rxrpc_publish_service_conn(struct rxrpc_peer *peer, ...@@ -96,7 +95,7 @@ rxrpc_publish_service_conn(struct rxrpc_peer *peer,
set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags); set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags);
write_sequnlock_bh(&peer->service_conn_lock); write_sequnlock_bh(&peer->service_conn_lock);
_leave(" = %d [new]", conn->debug_id); _leave(" = %d [new]", conn->debug_id);
return conn; return;
found_extant_conn: found_extant_conn:
if (atomic_read(&cursor->usage) == 0) if (atomic_read(&cursor->usage) == 0)
...@@ -119,106 +118,54 @@ rxrpc_publish_service_conn(struct rxrpc_peer *peer, ...@@ -119,106 +118,54 @@ rxrpc_publish_service_conn(struct rxrpc_peer *peer,
} }
/* /*
* get a record of an incoming connection * Preallocate a service connection. The connection is placed on the proc and
* reap lists so that we don't have to get the lock from BH context.
*/ */
struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local, struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp)
struct sockaddr_rxrpc *srx,
struct sk_buff *skb)
{ {
struct rxrpc_connection *conn; struct rxrpc_connection *conn = rxrpc_alloc_connection(gfp);
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_peer *peer;
const char *new = "old";
_enter("");
peer = rxrpc_lookup_peer(local, srx, GFP_NOIO);
if (!peer) {
_debug("no peer");
return ERR_PTR(-EBUSY);
}
ASSERT(sp->hdr.flags & RXRPC_CLIENT_INITIATED);
rcu_read_lock();
peer = rxrpc_lookup_peer_rcu(local, srx);
if (peer) {
conn = rxrpc_find_service_conn_rcu(peer, skb);
if (conn) { if (conn) {
if (sp->hdr.securityIndex != conn->security_ix)
goto security_mismatch_rcu;
if (rxrpc_get_connection_maybe(conn))
goto found_extant_connection_rcu;
/* The conn has expired but we can't remove it without
* the appropriate lock, so we attempt to replace it
* when we have a new candidate.
*/
}
if (!rxrpc_get_peer_maybe(peer))
peer = NULL;
}
rcu_read_unlock();
if (!peer) {
peer = rxrpc_lookup_peer(local, srx, GFP_NOIO);
if (!peer)
goto enomem;
}
/* We don't have a matching record yet. */
conn = rxrpc_alloc_connection(GFP_NOIO);
if (!conn)
goto enomem_peer;
conn->proto.epoch = sp->hdr.epoch;
conn->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
conn->params.local = local;
conn->params.peer = peer;
conn->params.service_id = sp->hdr.serviceId;
conn->security_ix = sp->hdr.securityIndex;
conn->out_clientflag = 0;
conn->state = RXRPC_CONN_SERVICE;
if (conn->params.service_id)
conn->state = RXRPC_CONN_SERVICE_UNSECURED;
rxrpc_get_local(local);
/* We maintain an extra ref on the connection whilst it is on /* We maintain an extra ref on the connection whilst it is on
* the rxrpc_connections list. * the rxrpc_connections list.
*/ */
conn->state = RXRPC_CONN_SERVICE_PREALLOC;
atomic_set(&conn->usage, 2); atomic_set(&conn->usage, 2);
write_lock(&rxrpc_connection_lock); write_lock(&rxrpc_connection_lock);
list_add_tail(&conn->link, &rxrpc_connections); list_add_tail(&conn->link, &rxrpc_connections);
list_add_tail(&conn->proc_link, &rxrpc_connection_proc_list); list_add_tail(&conn->proc_link, &rxrpc_connection_proc_list);
write_unlock(&rxrpc_connection_lock); write_unlock(&rxrpc_connection_lock);
}
/* Make the connection a target for incoming packets. */ return conn;
rxrpc_publish_service_conn(peer, conn); }
new = "new"; /*
* Set up an incoming connection. This is called in BH context with the RCU
* read lock held.
*/
void rxrpc_new_incoming_connection(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
success: _enter("");
_net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid);
_leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
return conn;
found_extant_connection_rcu: conn->proto.epoch = sp->hdr.epoch;
rcu_read_unlock(); conn->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
goto success; conn->params.service_id = sp->hdr.serviceId;
conn->security_ix = sp->hdr.securityIndex;
conn->out_clientflag = 0;
if (conn->security_ix)
conn->state = RXRPC_CONN_SERVICE_UNSECURED;
else
conn->state = RXRPC_CONN_SERVICE;
security_mismatch_rcu: /* Make the connection a target for incoming packets. */
rcu_read_unlock(); rxrpc_publish_service_conn(conn->params.peer, conn);
_leave(" = -EKEYREJECTED");
return ERR_PTR(-EKEYREJECTED);
enomem_peer: _net("CONNECTION new %d {%x}", conn->debug_id, conn->proto.cid);
rxrpc_put_peer(peer);
enomem:
_leave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
} }
/* /*
......
This diff is collapsed.
...@@ -30,14 +30,18 @@ static int none_secure_packet(struct rxrpc_call *call, ...@@ -30,14 +30,18 @@ static int none_secure_packet(struct rxrpc_call *call,
return 0; return 0;
} }
static int none_verify_packet(struct rxrpc_call *call, static int none_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
struct sk_buff *skb, unsigned int offset, unsigned int len,
rxrpc_seq_t seq, rxrpc_seq_t seq, u16 expected_cksum)
u16 expected_cksum)
{ {
return 0; return 0;
} }
static void none_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
unsigned int *_offset, unsigned int *_len)
{
}
static int none_respond_to_challenge(struct rxrpc_connection *conn, static int none_respond_to_challenge(struct rxrpc_connection *conn,
struct sk_buff *skb, struct sk_buff *skb,
u32 *_abort_code) u32 *_abort_code)
...@@ -79,6 +83,7 @@ const struct rxrpc_security rxrpc_no_security = { ...@@ -79,6 +83,7 @@ const struct rxrpc_security rxrpc_no_security = {
.prime_packet_security = none_prime_packet_security, .prime_packet_security = none_prime_packet_security,
.secure_packet = none_secure_packet, .secure_packet = none_secure_packet,
.verify_packet = none_verify_packet, .verify_packet = none_verify_packet,
.locate_data = none_locate_data,
.respond_to_challenge = none_respond_to_challenge, .respond_to_challenge = none_respond_to_challenge,
.verify_response = none_verify_response, .verify_response = none_verify_response,
.clear = none_clear, .clear = none_clear,
......
...@@ -98,7 +98,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local) ...@@ -98,7 +98,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
switch (sp->hdr.type) { switch (sp->hdr.type) {
case RXRPC_PACKET_TYPE_VERSION: case RXRPC_PACKET_TYPE_VERSION:
if (skb_copy_bits(skb, 0, &v, 1) < 0) if (skb_copy_bits(skb, sp->offset, &v, 1) < 0)
return; return;
_proto("Rx VERSION { %02x }", v); _proto("Rx VERSION { %02x }", v);
if (v == 0) if (v == 0)
......
...@@ -75,9 +75,8 @@ static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx) ...@@ -75,9 +75,8 @@ static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx)
atomic_set(&local->usage, 1); atomic_set(&local->usage, 1);
INIT_LIST_HEAD(&local->link); INIT_LIST_HEAD(&local->link);
INIT_WORK(&local->processor, rxrpc_local_processor); INIT_WORK(&local->processor, rxrpc_local_processor);
INIT_LIST_HEAD(&local->services); INIT_HLIST_HEAD(&local->services);
init_rwsem(&local->defrag_sem); init_rwsem(&local->defrag_sem);
skb_queue_head_init(&local->accept_queue);
skb_queue_head_init(&local->reject_queue); skb_queue_head_init(&local->reject_queue);
skb_queue_head_init(&local->event_queue); skb_queue_head_init(&local->event_queue);
local->client_conns = RB_ROOT; local->client_conns = RB_ROOT;
...@@ -296,7 +295,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local) ...@@ -296,7 +295,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxrpc_local_mutex);
ASSERT(RB_EMPTY_ROOT(&local->client_conns)); ASSERT(RB_EMPTY_ROOT(&local->client_conns));
ASSERT(list_empty(&local->services)); ASSERT(hlist_empty(&local->services));
if (socket) { if (socket) {
local->socket = NULL; local->socket = NULL;
...@@ -308,7 +307,6 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local) ...@@ -308,7 +307,6 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
/* At this point, there should be no more packets coming in to the /* At this point, there should be no more packets coming in to the
* local endpoint. * local endpoint.
*/ */
rxrpc_purge_queue(&local->accept_queue);
rxrpc_purge_queue(&local->reject_queue); rxrpc_purge_queue(&local->reject_queue);
rxrpc_purge_queue(&local->event_queue); rxrpc_purge_queue(&local->event_queue);
...@@ -332,11 +330,6 @@ static void rxrpc_local_processor(struct work_struct *work) ...@@ -332,11 +330,6 @@ static void rxrpc_local_processor(struct work_struct *work)
if (atomic_read(&local->usage) == 0) if (atomic_read(&local->usage) == 0)
return rxrpc_local_destroyer(local); return rxrpc_local_destroyer(local);
if (!skb_queue_empty(&local->accept_queue)) {
rxrpc_accept_incoming_calls(local);
again = true;
}
if (!skb_queue_empty(&local->reject_queue)) { if (!skb_queue_empty(&local->reject_queue)) {
rxrpc_reject_packets(local); rxrpc_reject_packets(local);
again = true; again = true;
......
...@@ -50,7 +50,7 @@ unsigned int rxrpc_idle_ack_delay = 0.5 * HZ; ...@@ -50,7 +50,7 @@ unsigned int rxrpc_idle_ack_delay = 0.5 * HZ;
* limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further * limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further
* packets. * packets.
*/ */
unsigned int rxrpc_rx_window_size = 32; unsigned int rxrpc_rx_window_size = RXRPC_RXTX_BUFF_SIZE - 46;
/* /*
* Maximum Rx MTU size. This indicates to the sender the size of jumbo packet * Maximum Rx MTU size. This indicates to the sender the size of jumbo packet
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include "ar-internal.h" #include "ar-internal.h"
...@@ -38,20 +40,38 @@ struct rxrpc_pkt_buffer { ...@@ -38,20 +40,38 @@ struct rxrpc_pkt_buffer {
static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, static size_t rxrpc_fill_out_ack(struct rxrpc_call *call,
struct rxrpc_pkt_buffer *pkt) struct rxrpc_pkt_buffer *pkt)
{ {
rxrpc_seq_t hard_ack, top, seq;
int ix;
u32 mtu, jmax; u32 mtu, jmax;
u8 *ackp = pkt->acks; u8 *ackp = pkt->acks;
/* Barrier against rxrpc_input_data(). */
hard_ack = READ_ONCE(call->rx_hard_ack);
top = smp_load_acquire(&call->rx_top);
pkt->ack.bufferSpace = htons(8); pkt->ack.bufferSpace = htons(8);
pkt->ack.maxSkew = htons(0); pkt->ack.maxSkew = htons(call->ackr_skew);
pkt->ack.firstPacket = htonl(call->rx_data_eaten + 1); pkt->ack.firstPacket = htonl(hard_ack + 1);
pkt->ack.previousPacket = htonl(call->ackr_prev_seq); pkt->ack.previousPacket = htonl(call->ackr_prev_seq);
pkt->ack.serial = htonl(call->ackr_serial); pkt->ack.serial = htonl(call->ackr_serial);
pkt->ack.reason = RXRPC_ACK_IDLE; pkt->ack.reason = call->ackr_reason;
pkt->ack.nAcks = 0; pkt->ack.nAcks = top - hard_ack;
if (after(top, hard_ack)) {
seq = hard_ack + 1;
do {
ix = seq & RXRPC_RXTX_BUFF_MASK;
if (call->rxtx_buffer[ix])
*ackp++ = RXRPC_ACK_TYPE_ACK;
else
*ackp++ = RXRPC_ACK_TYPE_NACK;
seq++;
} while (before_eq(seq, top));
}
mtu = call->peer->if_mtu; mtu = call->conn->params.peer->if_mtu;
mtu -= call->peer->hdrsize; mtu -= call->conn->params.peer->hdrsize;
jmax = rxrpc_rx_jumbo_max; jmax = (call->nr_jumbo_dup > 3) ? 1 : rxrpc_rx_jumbo_max;
pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu); pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu);
pkt->ackinfo.maxMTU = htonl(mtu); pkt->ackinfo.maxMTU = htonl(mtu);
pkt->ackinfo.rwind = htonl(rxrpc_rx_window_size); pkt->ackinfo.rwind = htonl(rxrpc_rx_window_size);
...@@ -60,11 +80,11 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, ...@@ -60,11 +80,11 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call,
*ackp++ = 0; *ackp++ = 0;
*ackp++ = 0; *ackp++ = 0;
*ackp++ = 0; *ackp++ = 0;
return 3; return top - hard_ack + 3;
} }
/* /*
* Send a final ACK or ABORT call packet. * Send an ACK or ABORT call packet.
*/ */
int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type) int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
{ {
...@@ -158,6 +178,19 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type) ...@@ -158,6 +178,19 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
ret = kernel_sendmsg(conn->params.local->socket, ret = kernel_sendmsg(conn->params.local->socket,
&msg, iov, ioc, len); &msg, iov, ioc, len);
if (ret < 0 && call->state < RXRPC_CALL_COMPLETE) {
switch (pkt->whdr.type) {
case RXRPC_PACKET_TYPE_ACK:
rxrpc_propose_ACK(call, pkt->ack.reason,
ntohs(pkt->ack.maxSkew),
ntohl(pkt->ack.serial),
true, true);
break;
case RXRPC_PACKET_TYPE_ABORT:
break;
}
}
out: out:
rxrpc_put_connection(conn); rxrpc_put_connection(conn);
kfree(pkt); kfree(pkt);
...@@ -233,3 +266,77 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb) ...@@ -233,3 +266,77 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
_leave(" = %d [frag %u]", ret, conn->params.peer->maxdata); _leave(" = %d [frag %u]", ret, conn->params.peer->maxdata);
return ret; return ret;
} }
/*
* reject packets through the local endpoint
*/
void rxrpc_reject_packets(struct rxrpc_local *local)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
} sa;
struct rxrpc_skb_priv *sp;
struct rxrpc_wire_header whdr;
struct sk_buff *skb;
struct msghdr msg;
struct kvec iov[2];
size_t size;
__be32 code;
_enter("%d", local->debug_id);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
iov[1].iov_base = &code;
iov[1].iov_len = sizeof(code);
size = sizeof(whdr) + sizeof(code);
msg.msg_name = &sa;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
memset(&sa, 0, sizeof(sa));
sa.sa.sa_family = local->srx.transport.family;
switch (sa.sa.sa_family) {
case AF_INET:
msg.msg_namelen = sizeof(sa.sin);
break;
default:
msg.msg_namelen = 0;
break;
}
memset(&whdr, 0, sizeof(whdr));
whdr.type = RXRPC_PACKET_TYPE_ABORT;
while ((skb = skb_dequeue(&local->reject_queue))) {
rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
switch (sa.sa.sa_family) {
case AF_INET:
sa.sin.sin_port = udp_hdr(skb)->source;
sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
code = htonl(skb->priority);
whdr.epoch = htonl(sp->hdr.epoch);
whdr.cid = htonl(sp->hdr.cid);
whdr.callNumber = htonl(sp->hdr.callNumber);
whdr.serviceId = htons(sp->hdr.serviceId);
whdr.flags = sp->hdr.flags;
whdr.flags ^= RXRPC_CLIENT_INITIATED;
whdr.flags &= RXRPC_CLIENT_INITIATED;
kernel_sendmsg(local->socket, &msg, iov, 2, size);
break;
default:
break;
}
rxrpc_free_skb(skb);
}
_leave("");
}
...@@ -129,15 +129,14 @@ void rxrpc_error_report(struct sock *sk) ...@@ -129,15 +129,14 @@ void rxrpc_error_report(struct sock *sk)
_leave("UDP socket errqueue empty"); _leave("UDP socket errqueue empty");
return; return;
} }
rxrpc_new_skb(skb);
serr = SKB_EXT_ERR(skb); serr = SKB_EXT_ERR(skb);
if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
_leave("UDP empty message"); _leave("UDP empty message");
kfree_skb(skb); rxrpc_free_skb(skb);
return; return;
} }
rxrpc_new_skb(skb);
rcu_read_lock(); rcu_read_lock();
peer = rxrpc_lookup_peer_icmp_rcu(local, skb); peer = rxrpc_lookup_peer_icmp_rcu(local, skb);
if (peer && !rxrpc_get_peer_maybe(peer)) if (peer && !rxrpc_get_peer_maybe(peer))
...@@ -249,7 +248,6 @@ void rxrpc_peer_error_distributor(struct work_struct *work) ...@@ -249,7 +248,6 @@ void rxrpc_peer_error_distributor(struct work_struct *work)
container_of(work, struct rxrpc_peer, error_distributor); container_of(work, struct rxrpc_peer, error_distributor);
struct rxrpc_call *call; struct rxrpc_call *call;
enum rxrpc_call_completion compl; enum rxrpc_call_completion compl;
bool queue;
int error; int error;
_enter(""); _enter("");
...@@ -272,15 +270,8 @@ void rxrpc_peer_error_distributor(struct work_struct *work) ...@@ -272,15 +270,8 @@ void rxrpc_peer_error_distributor(struct work_struct *work)
hlist_del_init(&call->error_link); hlist_del_init(&call->error_link);
rxrpc_see_call(call); rxrpc_see_call(call);
queue = false; if (rxrpc_set_call_completion(call, compl, 0, error))
write_lock(&call->state_lock); rxrpc_notify_socket(call);
if (__rxrpc_set_call_completion(call, compl, 0, error)) {
set_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events);
queue = true;
}
write_unlock(&call->state_lock);
if (queue)
rxrpc_queue_call(call);
} }
spin_unlock_bh(&peer->lock); spin_unlock_bh(&peer->lock);
......
...@@ -199,28 +199,16 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp) ...@@ -199,28 +199,16 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp)
} }
/* /*
* Set up a new peer. * Initialise peer record.
*/ */
static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local, static void rxrpc_init_peer(struct rxrpc_peer *peer, unsigned long hash_key)
struct sockaddr_rxrpc *srx,
unsigned long hash_key,
gfp_t gfp)
{ {
struct rxrpc_peer *peer;
_enter("");
peer = rxrpc_alloc_peer(local, gfp);
if (peer) {
peer->hash_key = hash_key;
memcpy(&peer->srx, srx, sizeof(*srx));
rxrpc_assess_MTU_size(peer); rxrpc_assess_MTU_size(peer);
peer->mtu = peer->if_mtu; peer->mtu = peer->if_mtu;
if (srx->transport.family == AF_INET) { if (peer->srx.transport.family == AF_INET) {
peer->hdrsize = sizeof(struct iphdr); peer->hdrsize = sizeof(struct iphdr);
switch (srx->transport_type) { switch (peer->srx.transport_type) {
case SOCK_DGRAM: case SOCK_DGRAM:
peer->hdrsize += sizeof(struct udphdr); peer->hdrsize += sizeof(struct udphdr);
break; break;
...@@ -234,12 +222,60 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local, ...@@ -234,12 +222,60 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
peer->hdrsize += sizeof(struct rxrpc_wire_header); peer->hdrsize += sizeof(struct rxrpc_wire_header);
peer->maxdata = peer->mtu - peer->hdrsize; peer->maxdata = peer->mtu - peer->hdrsize;
}
/*
* Set up a new peer.
*/
static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
struct sockaddr_rxrpc *srx,
unsigned long hash_key,
gfp_t gfp)
{
struct rxrpc_peer *peer;
_enter("");
peer = rxrpc_alloc_peer(local, gfp);
if (peer) {
peer->hash_key = hash_key;
memcpy(&peer->srx, srx, sizeof(*srx));
rxrpc_init_peer(peer, hash_key);
} }
_leave(" = %p", peer); _leave(" = %p", peer);
return peer; return peer;
} }
/*
* Set up a new incoming peer. The address is prestored in the preallocated
* peer.
*/
struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local,
struct rxrpc_peer *prealloc)
{
struct rxrpc_peer *peer;
unsigned long hash_key;
hash_key = rxrpc_peer_hash_key(local, &prealloc->srx);
prealloc->local = local;
rxrpc_init_peer(prealloc, hash_key);
spin_lock(&rxrpc_peer_hash_lock);
/* Need to check that we aren't racing with someone else */
peer = __rxrpc_lookup_peer_rcu(local, &prealloc->srx, hash_key);
if (peer && !rxrpc_get_peer_maybe(peer))
peer = NULL;
if (!peer) {
peer = prealloc;
hash_add_rcu(rxrpc_peer_hash, &peer->hash_link, hash_key);
}
spin_unlock(&rxrpc_peer_hash_lock);
return peer;
}
/* /*
* obtain a remote transport endpoint for the specified address * obtain a remote transport endpoint for the specified address
*/ */
...@@ -272,7 +308,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, ...@@ -272,7 +308,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
return NULL; return NULL;
} }
spin_lock(&rxrpc_peer_hash_lock); spin_lock_bh(&rxrpc_peer_hash_lock);
/* Need to check that we aren't racing with someone else */ /* Need to check that we aren't racing with someone else */
peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
...@@ -282,7 +318,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, ...@@ -282,7 +318,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
hash_add_rcu(rxrpc_peer_hash, hash_add_rcu(rxrpc_peer_hash,
&candidate->hash_link, hash_key); &candidate->hash_link, hash_key);
spin_unlock(&rxrpc_peer_hash_lock); spin_unlock_bh(&rxrpc_peer_hash_lock);
if (peer) if (peer)
kfree(candidate); kfree(candidate);
...@@ -307,9 +343,9 @@ void __rxrpc_put_peer(struct rxrpc_peer *peer) ...@@ -307,9 +343,9 @@ void __rxrpc_put_peer(struct rxrpc_peer *peer)
{ {
ASSERT(hlist_empty(&peer->error_targets)); ASSERT(hlist_empty(&peer->error_targets));
spin_lock(&rxrpc_peer_hash_lock); spin_lock_bh(&rxrpc_peer_hash_lock);
hash_del_rcu(&peer->hash_link); hash_del_rcu(&peer->hash_link);
spin_unlock(&rxrpc_peer_hash_lock); spin_unlock_bh(&rxrpc_peer_hash_lock);
kfree_rcu(peer, rcu); kfree_rcu(peer, rcu);
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = { static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
[RXRPC_CONN_UNUSED] = "Unused ", [RXRPC_CONN_UNUSED] = "Unused ",
[RXRPC_CONN_CLIENT] = "Client ", [RXRPC_CONN_CLIENT] = "Client ",
[RXRPC_CONN_SERVICE_PREALLOC] = "SvPrealc",
[RXRPC_CONN_SERVICE_UNSECURED] = "SvUnsec ", [RXRPC_CONN_SERVICE_UNSECURED] = "SvUnsec ",
[RXRPC_CONN_SERVICE_CHALLENGING] = "SvChall ", [RXRPC_CONN_SERVICE_CHALLENGING] = "SvChall ",
[RXRPC_CONN_SERVICE] = "SvSecure", [RXRPC_CONN_SERVICE] = "SvSecure",
...@@ -156,6 +157,11 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) ...@@ -156,6 +157,11 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
} }
conn = list_entry(v, struct rxrpc_connection, proc_link); conn = list_entry(v, struct rxrpc_connection, proc_link);
if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
strcpy(lbuff, "no_local");
strcpy(rbuff, "no_connection");
goto print;
}
sprintf(lbuff, "%pI4:%u", sprintf(lbuff, "%pI4:%u",
&conn->params.local->srx.transport.sin.sin_addr, &conn->params.local->srx.transport.sin.sin_addr,
...@@ -164,7 +170,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) ...@@ -164,7 +170,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
sprintf(rbuff, "%pI4:%u", sprintf(rbuff, "%pI4:%u",
&conn->params.peer->srx.transport.sin.sin_addr, &conn->params.peer->srx.transport.sin.sin_addr,
ntohs(conn->params.peer->srx.transport.sin.sin_port)); ntohs(conn->params.peer->srx.transport.sin.sin_port));
print:
seq_printf(seq, seq_printf(seq,
"UDP %-22.22s %-22.22s %4x %08x %s %3u" "UDP %-22.22s %-22.22s %4x %08x %s %3u"
" %s %08x %08x %08x\n", " %s %08x %08x %08x\n",
......
This diff is collapsed.
This diff is collapsed.
...@@ -130,20 +130,20 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn) ...@@ -130,20 +130,20 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
} }
/* find the service */ /* find the service */
read_lock_bh(&local->services_lock); read_lock(&local->services_lock);
list_for_each_entry(rx, &local->services, listen_link) { hlist_for_each_entry(rx, &local->services, listen_link) {
if (rx->srx.srx_service == conn->params.service_id) if (rx->srx.srx_service == conn->params.service_id)
goto found_service; goto found_service;
} }
/* the service appears to have died */ /* the service appears to have died */
read_unlock_bh(&local->services_lock); read_unlock(&local->services_lock);
_leave(" = -ENOENT"); _leave(" = -ENOENT");
return -ENOENT; return -ENOENT;
found_service: found_service:
if (!rx->securities) { if (!rx->securities) {
read_unlock_bh(&local->services_lock); read_unlock(&local->services_lock);
_leave(" = -ENOKEY"); _leave(" = -ENOKEY");
return -ENOKEY; return -ENOKEY;
} }
...@@ -152,13 +152,13 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn) ...@@ -152,13 +152,13 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
kref = keyring_search(make_key_ref(rx->securities, 1UL), kref = keyring_search(make_key_ref(rx->securities, 1UL),
&key_type_rxrpc_s, kdesc); &key_type_rxrpc_s, kdesc);
if (IS_ERR(kref)) { if (IS_ERR(kref)) {
read_unlock_bh(&local->services_lock); read_unlock(&local->services_lock);
_leave(" = %ld [search]", PTR_ERR(kref)); _leave(" = %ld [search]", PTR_ERR(kref));
return PTR_ERR(kref); return PTR_ERR(kref);
} }
key = key_ref_to_ptr(kref); key = key_ref_to_ptr(kref);
read_unlock_bh(&local->services_lock); read_unlock(&local->services_lock);
conn->server_key = key; conn->server_key = key;
conn->security = sec; conn->security = sec;
......
This diff is collapsed.
...@@ -18,133 +18,6 @@ ...@@ -18,133 +18,6 @@
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include "ar-internal.h" #include "ar-internal.h"
/*
* set up for the ACK at the end of the receive phase when we discard the final
* receive phase data packet
* - called with softirqs disabled
*/
static void rxrpc_request_final_ACK(struct rxrpc_call *call)
{
/* the call may be aborted before we have a chance to ACK it */
write_lock(&call->state_lock);
switch (call->state) {
case RXRPC_CALL_CLIENT_RECV_REPLY:
call->state = RXRPC_CALL_CLIENT_FINAL_ACK;
_debug("request final ACK");
set_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events);
if (try_to_del_timer_sync(&call->ack_timer) >= 0)
rxrpc_queue_call(call);
break;
case RXRPC_CALL_SERVER_RECV_REQUEST:
call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
default:
break;
}
write_unlock(&call->state_lock);
}
/*
* drop the bottom ACK off of the call ACK window and advance the window
*/
static void rxrpc_hard_ACK_data(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
int loop;
u32 seq;
spin_lock_bh(&call->lock);
_debug("hard ACK #%u", sp->hdr.seq);
for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) {
call->ackr_window[loop] >>= 1;
call->ackr_window[loop] |=
call->ackr_window[loop + 1] << (BITS_PER_LONG - 1);
}
seq = sp->hdr.seq;
ASSERTCMP(seq, ==, call->rx_data_eaten + 1);
call->rx_data_eaten = seq;
if (call->ackr_win_top < UINT_MAX)
call->ackr_win_top++;
ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE,
call->rx_data_post, >=, call->rx_data_recv);
ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE,
call->rx_data_recv, >=, call->rx_data_eaten);
if (sp->hdr.flags & RXRPC_LAST_PACKET) {
rxrpc_request_final_ACK(call);
} else if (atomic_dec_and_test(&call->ackr_not_idle) &&
test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) {
/* We previously soft-ACK'd some received packets that have now
* been consumed, so send a hard-ACK if no more packets are
* immediately forthcoming to allow the transmitter to free up
* its Tx bufferage.
*/
_debug("send Rx idle ACK");
__rxrpc_propose_ACK(call, RXRPC_ACK_IDLE,
skb->priority, sp->hdr.serial, false);
}
spin_unlock_bh(&call->lock);
}
/**
* rxrpc_kernel_data_consumed - Record consumption of data message
* @call: The call to which the message pertains.
* @skb: Message holding data
*
* Record the consumption of a data message and generate an ACK if appropriate.
* The call state is shifted if this was the final packet. The caller must be
* in process context with no spinlocks held.
*
* TODO: Actually generate the ACK here rather than punting this to the
* workqueue.
*/
void rxrpc_kernel_data_consumed(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
_enter("%d,%p{%u}", call->debug_id, skb, sp->hdr.seq);
ASSERTCMP(sp->call, ==, call);
ASSERTCMP(sp->hdr.type, ==, RXRPC_PACKET_TYPE_DATA);
/* TODO: Fix the sequence number tracking */
ASSERTCMP(sp->hdr.seq, >=, call->rx_data_recv);
ASSERTCMP(sp->hdr.seq, <=, call->rx_data_recv + 1);
ASSERTCMP(sp->hdr.seq, >, call->rx_data_eaten);
call->rx_data_recv = sp->hdr.seq;
rxrpc_hard_ACK_data(call, skb);
}
/*
* Destroy a packet that has an RxRPC control buffer
*/
void rxrpc_packet_destructor(struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_call *call = sp->call;
_enter("%p{%p}", skb, call);
if (call) {
rxrpc_put_call_for_skb(call, skb);
sp->call = NULL;
}
if (skb->sk)
sock_rfree(skb);
_leave("");
}
/* /*
* Note the existence of a new-to-us socket buffer (allocated or dequeued). * Note the existence of a new-to-us socket buffer (allocated or dequeued).
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment