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 | ||
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) | |
651350d1 | 39 | rxrpc_queue_call(call); |
17926a79 DH |
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)) { | |
5873c083 DH |
86 | /* We previously soft-ACK'd some received packets that have now |
87 | * been consumed, so send a hard-ACK if no more packets are | |
88 | * immediately forthcoming to allow the transmitter to free up | |
89 | * its Tx bufferage. | |
90 | */ | |
17926a79 DH |
91 | _debug("send Rx idle ACK"); |
92 | __rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial, | |
9823f39a | 93 | false); |
17926a79 DH |
94 | } |
95 | ||
96 | spin_unlock_bh(&call->lock); | |
97 | } | |
98 | ||
99 | /* | |
100 | * destroy a packet that has an RxRPC control buffer | |
101 | * - advance the hard-ACK state of the parent call (done here in case something | |
102 | * in the kernel bypasses recvmsg() and steals the packet directly off of the | |
103 | * socket receive queue) | |
104 | */ | |
105 | void rxrpc_packet_destructor(struct sk_buff *skb) | |
106 | { | |
107 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | |
108 | struct rxrpc_call *call = sp->call; | |
109 | ||
110 | _enter("%p{%p}", skb, call); | |
111 | ||
112 | if (call) { | |
113 | /* send the final ACK on a client call */ | |
114 | if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA) | |
115 | rxrpc_hard_ACK_data(call, sp); | |
116 | rxrpc_put_call(call); | |
117 | sp->call = NULL; | |
118 | } | |
119 | ||
120 | if (skb->sk) | |
121 | sock_rfree(skb); | |
122 | _leave(""); | |
123 | } | |
651350d1 DH |
124 | |
125 | /** | |
126 | * rxrpc_kernel_free_skb - Free an RxRPC socket buffer | |
127 | * @skb: The socket buffer to be freed | |
128 | * | |
129 | * Let RxRPC free its own socket buffer, permitting it to maintain debug | |
130 | * accounting. | |
131 | */ | |
132 | void rxrpc_kernel_free_skb(struct sk_buff *skb) | |
133 | { | |
134 | rxrpc_free_skb(skb); | |
135 | } | |
136 | ||
137 | EXPORT_SYMBOL(rxrpc_kernel_free_skb); |