diff options
Diffstat (limited to 'net/rxrpc/ar-skbuff.c')
-rw-r--r-- | net/rxrpc/ar-skbuff.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/net/rxrpc/ar-skbuff.c b/net/rxrpc/ar-skbuff.c new file mode 100644 index 000000000000..d73f6fc76011 --- /dev/null +++ b/net/rxrpc/ar-skbuff.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* ar-skbuff.c: socket buffer destruction handling | ||
2 | * | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/net.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <net/sock.h> | ||
16 | #include <net/af_rxrpc.h> | ||
17 | #include "ar-internal.h" | ||
18 | |||
19 | /* | ||
20 | * set up for the ACK at the end of the receive phase when we discard the final | ||
21 | * receive phase data packet | ||
22 | * - called with softirqs disabled | ||
23 | */ | ||
24 | static void rxrpc_request_final_ACK(struct rxrpc_call *call) | ||
25 | { | ||
26 | /* the call may be aborted before we have a chance to ACK it */ | ||
27 | write_lock(&call->state_lock); | ||
28 | |||
29 | switch (call->state) { | ||
30 | case RXRPC_CALL_CLIENT_RECV_REPLY: | ||
31 | call->state = RXRPC_CALL_CLIENT_FINAL_ACK; | ||
32 | _debug("request final ACK"); | ||
33 | |||
34 | /* get an extra ref on the call for the final-ACK generator to | ||
35 | * release */ | ||
36 | rxrpc_get_call(call); | ||
37 | set_bit(RXRPC_CALL_ACK_FINAL, &call->events); | ||
38 | if (try_to_del_timer_sync(&call->ack_timer) >= 0) | ||
39 | schedule_work(&call->processor); | ||
40 | break; | ||
41 | |||
42 | case RXRPC_CALL_SERVER_RECV_REQUEST: | ||
43 | call->state = RXRPC_CALL_SERVER_ACK_REQUEST; | ||
44 | default: | ||
45 | break; | ||
46 | } | ||
47 | |||
48 | write_unlock(&call->state_lock); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * drop the bottom ACK off of the call ACK window and advance the window | ||
53 | */ | ||
54 | static void rxrpc_hard_ACK_data(struct rxrpc_call *call, | ||
55 | struct rxrpc_skb_priv *sp) | ||
56 | { | ||
57 | int loop; | ||
58 | u32 seq; | ||
59 | |||
60 | spin_lock_bh(&call->lock); | ||
61 | |||
62 | _debug("hard ACK #%u", ntohl(sp->hdr.seq)); | ||
63 | |||
64 | for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) { | ||
65 | call->ackr_window[loop] >>= 1; | ||
66 | call->ackr_window[loop] |= | ||
67 | call->ackr_window[loop + 1] << (BITS_PER_LONG - 1); | ||
68 | } | ||
69 | |||
70 | seq = ntohl(sp->hdr.seq); | ||
71 | ASSERTCMP(seq, ==, call->rx_data_eaten + 1); | ||
72 | call->rx_data_eaten = seq; | ||
73 | |||
74 | if (call->ackr_win_top < UINT_MAX) | ||
75 | call->ackr_win_top++; | ||
76 | |||
77 | ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE, | ||
78 | call->rx_data_post, >=, call->rx_data_recv); | ||
79 | ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE, | ||
80 | call->rx_data_recv, >=, call->rx_data_eaten); | ||
81 | |||
82 | if (sp->hdr.flags & RXRPC_LAST_PACKET) { | ||
83 | rxrpc_request_final_ACK(call); | ||
84 | } else if (atomic_dec_and_test(&call->ackr_not_idle) && | ||
85 | test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) { | ||
86 | _debug("send Rx idle ACK"); | ||
87 | __rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial, | ||
88 | true); | ||
89 | } | ||
90 | |||
91 | spin_unlock_bh(&call->lock); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * destroy a packet that has an RxRPC control buffer | ||
96 | * - advance the hard-ACK state of the parent call (done here in case something | ||
97 | * in the kernel bypasses recvmsg() and steals the packet directly off of the | ||
98 | * socket receive queue) | ||
99 | */ | ||
100 | void rxrpc_packet_destructor(struct sk_buff *skb) | ||
101 | { | ||
102 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | ||
103 | struct rxrpc_call *call = sp->call; | ||
104 | |||
105 | _enter("%p{%p}", skb, call); | ||
106 | |||
107 | if (call) { | ||
108 | /* send the final ACK on a client call */ | ||
109 | if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA) | ||
110 | rxrpc_hard_ACK_data(call, sp); | ||
111 | rxrpc_put_call(call); | ||
112 | sp->call = NULL; | ||
113 | } | ||
114 | |||
115 | if (skb->sk) | ||
116 | sock_rfree(skb); | ||
117 | _leave(""); | ||
118 | } | ||