Commit | Line | Data |
---|---|---|
17926a79 DH |
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 | ||
9b6d5398 JP |
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
13 | ||
17926a79 DH |
14 | #include <linux/module.h> |
15 | #include <linux/net.h> | |
16 | #include <linux/skbuff.h> | |
17 | #include <net/sock.h> | |
18 | #include <net/af_rxrpc.h> | |
19 | #include "ar-internal.h" | |
20 | ||
21 | /* | |
22 | * set up for the ACK at the end of the receive phase when we discard the final | |
23 | * receive phase data packet | |
24 | * - called with softirqs disabled | |
25 | */ | |
26 | static void rxrpc_request_final_ACK(struct rxrpc_call *call) | |
27 | { | |
28 | /* the call may be aborted before we have a chance to ACK it */ | |
29 | write_lock(&call->state_lock); | |
30 | ||
31 | switch (call->state) { | |
32 | case RXRPC_CALL_CLIENT_RECV_REPLY: | |
33 | call->state = RXRPC_CALL_CLIENT_FINAL_ACK; | |
34 | _debug("request final ACK"); | |
35 | ||
36 | /* get an extra ref on the call for the final-ACK generator to | |
37 | * release */ | |
38 | rxrpc_get_call(call); | |
4c198ad1 | 39 | set_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events); |
17926a79 | 40 | if (try_to_del_timer_sync(&call->ack_timer) >= 0) |
651350d1 | 41 | rxrpc_queue_call(call); |
17926a79 DH |
42 | break; |
43 | ||
44 | case RXRPC_CALL_SERVER_RECV_REQUEST: | |
45 | call->state = RXRPC_CALL_SERVER_ACK_REQUEST; | |
46 | default: | |
47 | break; | |
48 | } | |
49 | ||
50 | write_unlock(&call->state_lock); | |
51 | } | |
52 | ||
53 | /* | |
54 | * drop the bottom ACK off of the call ACK window and advance the window | |
55 | */ | |
56 | static void rxrpc_hard_ACK_data(struct rxrpc_call *call, | |
57 | struct rxrpc_skb_priv *sp) | |
58 | { | |
59 | int loop; | |
60 | u32 seq; | |
61 | ||
62 | spin_lock_bh(&call->lock); | |
63 | ||
0d12f8a4 | 64 | _debug("hard ACK #%u", sp->hdr.seq); |
17926a79 DH |
65 | |
66 | for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) { | |
67 | call->ackr_window[loop] >>= 1; | |
68 | call->ackr_window[loop] |= | |
69 | call->ackr_window[loop + 1] << (BITS_PER_LONG - 1); | |
70 | } | |
71 | ||
0d12f8a4 | 72 | seq = sp->hdr.seq; |
17926a79 DH |
73 | ASSERTCMP(seq, ==, call->rx_data_eaten + 1); |
74 | call->rx_data_eaten = seq; | |
75 | ||
76 | if (call->ackr_win_top < UINT_MAX) | |
77 | call->ackr_win_top++; | |
78 | ||
79 | ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE, | |
80 | call->rx_data_post, >=, call->rx_data_recv); | |
81 | ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE, | |
82 | call->rx_data_recv, >=, call->rx_data_eaten); | |
83 | ||
84 | if (sp->hdr.flags & RXRPC_LAST_PACKET) { | |
85 | rxrpc_request_final_ACK(call); | |
86 | } else if (atomic_dec_and_test(&call->ackr_not_idle) && | |
87 | test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) { | |
5873c083 DH |
88 | /* We previously soft-ACK'd some received packets that have now |
89 | * been consumed, so send a hard-ACK if no more packets are | |
90 | * immediately forthcoming to allow the transmitter to free up | |
91 | * its Tx bufferage. | |
92 | */ | |
17926a79 DH |
93 | _debug("send Rx idle ACK"); |
94 | __rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial, | |
9823f39a | 95 | false); |
17926a79 DH |
96 | } |
97 | ||
98 | spin_unlock_bh(&call->lock); | |
99 | } | |
100 | ||
372ee163 DH |
101 | /** |
102 | * rxrpc_kernel_data_consumed - Record consumption of data message | |
103 | * @call: The call to which the message pertains. | |
104 | * @skb: Message holding data | |
105 | * | |
106 | * Record the consumption of a data message and generate an ACK if appropriate. | |
107 | * The call state is shifted if this was the final packet. The caller must be | |
108 | * in process context with no spinlocks held. | |
109 | * | |
110 | * TODO: Actually generate the ACK here rather than punting this to the | |
111 | * workqueue. | |
112 | */ | |
113 | void rxrpc_kernel_data_consumed(struct rxrpc_call *call, struct sk_buff *skb) | |
114 | { | |
115 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | |
116 | ||
117 | _enter("%d,%p{%u}", call->debug_id, skb, sp->hdr.seq); | |
118 | ||
119 | ASSERTCMP(sp->call, ==, call); | |
120 | ASSERTCMP(sp->hdr.type, ==, RXRPC_PACKET_TYPE_DATA); | |
121 | ||
122 | /* TODO: Fix the sequence number tracking */ | |
123 | ASSERTCMP(sp->hdr.seq, >=, call->rx_data_recv); | |
124 | ASSERTCMP(sp->hdr.seq, <=, call->rx_data_recv + 1); | |
125 | ASSERTCMP(sp->hdr.seq, >, call->rx_data_eaten); | |
126 | ||
127 | call->rx_data_recv = sp->hdr.seq; | |
128 | rxrpc_hard_ACK_data(call, sp); | |
129 | } | |
130 | EXPORT_SYMBOL(rxrpc_kernel_data_consumed); | |
131 | ||
17926a79 | 132 | /* |
372ee163 | 133 | * Destroy a packet that has an RxRPC control buffer |
17926a79 DH |
134 | */ |
135 | void rxrpc_packet_destructor(struct sk_buff *skb) | |
136 | { | |
137 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | |
138 | struct rxrpc_call *call = sp->call; | |
139 | ||
140 | _enter("%p{%p}", skb, call); | |
141 | ||
142 | if (call) { | |
372ee163 DH |
143 | if (atomic_dec_return(&call->skb_count) < 0) |
144 | BUG(); | |
17926a79 DH |
145 | rxrpc_put_call(call); |
146 | sp->call = NULL; | |
147 | } | |
148 | ||
149 | if (skb->sk) | |
150 | sock_rfree(skb); | |
151 | _leave(""); | |
152 | } | |
651350d1 DH |
153 | |
154 | /** | |
155 | * rxrpc_kernel_free_skb - Free an RxRPC socket buffer | |
156 | * @skb: The socket buffer to be freed | |
157 | * | |
158 | * Let RxRPC free its own socket buffer, permitting it to maintain debug | |
159 | * accounting. | |
160 | */ | |
161 | void rxrpc_kernel_free_skb(struct sk_buff *skb) | |
162 | { | |
163 | rxrpc_free_skb(skb); | |
164 | } | |
651350d1 | 165 | EXPORT_SYMBOL(rxrpc_kernel_free_skb); |