| David Howells | 17926a7 | 2007-04-26 15:48:28 -0700 | [diff] [blame] | 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) | 
| David Howells | 651350d | 2007-04-26 15:50:17 -0700 | [diff] [blame] | 39 | rxrpc_queue_call(call); | 
| David Howells | 17926a7 | 2007-04-26 15:48:28 -0700 | [diff] [blame] | 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 | } | 
| David Howells | 651350d | 2007-04-26 15:50:17 -0700 | [diff] [blame] | 119 |  | 
|  | 120 | /** | 
|  | 121 | * rxrpc_kernel_free_skb - Free an RxRPC socket buffer | 
|  | 122 | * @skb: The socket buffer to be freed | 
|  | 123 | * | 
|  | 124 | * Let RxRPC free its own socket buffer, permitting it to maintain debug | 
|  | 125 | * accounting. | 
|  | 126 | */ | 
|  | 127 | void rxrpc_kernel_free_skb(struct sk_buff *skb) | 
|  | 128 | { | 
|  | 129 | rxrpc_free_skb(skb); | 
|  | 130 | } | 
|  | 131 |  | 
|  | 132 | EXPORT_SYMBOL(rxrpc_kernel_free_skb); |