merge sock_alloc_fd/sock_attach_fd into a new helper
[safe/jmp/linux-2.6] / net / rxrpc / ar-ack.c
index 8f7764e..b4a2209 100644 (file)
@@ -20,7 +20,7 @@
 
 static unsigned rxrpc_ack_defer = 1;
 
-static const char *rxrpc_acks[] = {
+static const char *const rxrpc_acks[] = {
        "---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL",
        "-?-"
 };
@@ -40,7 +40,7 @@ static const s8 rxrpc_ack_priority[] = {
 /*
  * propose an ACK be sent
  */
-void __rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason,
+void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                         __be32 serial, bool immediate)
 {
        unsigned long expiry;
@@ -113,14 +113,14 @@ cancel_timer:
        read_lock_bh(&call->state_lock);
        if (call->state <= RXRPC_CALL_COMPLETE &&
            !test_and_set_bit(RXRPC_CALL_ACK, &call->events))
-               schedule_work(&call->processor);
+               rxrpc_queue_call(call);
        read_unlock_bh(&call->state_lock);
 }
 
 /*
  * propose an ACK be sent, locking the call structure
  */
-void rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason,
+void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                       __be32 serial, bool immediate)
 {
        s8 prior = rxrpc_ack_priority[ack_reason];
@@ -520,7 +520,7 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)
        struct rxrpc_skb_priv *sp;
        struct sk_buff *skb;
        unsigned long _skb, *acks_window;
-       uint8_t winsz = call->acks_winsz;
+       u8 winsz = call->acks_winsz;
        int tail;
 
        acks_window = call->acks_window;
@@ -543,6 +543,38 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)
 }
 
 /*
+ * process the extra information that may be appended to an ACK packet
+ */
+static void rxrpc_extract_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
+                                 unsigned latest, int nAcks)
+{
+       struct rxrpc_ackinfo ackinfo;
+       struct rxrpc_peer *peer;
+       unsigned mtu;
+
+       if (skb_copy_bits(skb, nAcks + 3, &ackinfo, sizeof(ackinfo)) < 0) {
+               _leave(" [no ackinfo]");
+               return;
+       }
+
+       _proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }",
+              latest,
+              ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU),
+              ntohl(ackinfo.rwind), ntohl(ackinfo.jumbo_max));
+
+       mtu = min(ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU));
+
+       peer = call->conn->trans->peer;
+       if (mtu < peer->maxdata) {
+               spin_lock_bh(&peer->lock);
+               peer->maxdata = mtu;
+               peer->mtu = mtu + peer->hdrsize;
+               spin_unlock_bh(&peer->lock);
+               _net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata);
+       }
+}
+
+/*
  * process packets in the reception queue
  */
 static int rxrpc_process_rx_queue(struct rxrpc_call *call,
@@ -606,6 +638,8 @@ process_further:
                       rxrpc_acks[ack.reason],
                       ack.nAcks);
 
+               rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks);
+
                if (ack.reason == RXRPC_ACK_PING) {
                        _proto("Rx ACK %%%u PING Request", latest);
                        rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
@@ -780,8 +814,7 @@ static int rxrpc_post_message(struct rxrpc_call *call, u32 mark, u32 error,
                spin_lock_bh(&call->lock);
                ret = rxrpc_queue_rcv_skb(call, skb, true, fatal);
                spin_unlock_bh(&call->lock);
-               if (ret < 0)
-                       BUG();
+               BUG_ON(ret < 0);
        }
 
        return 0;
@@ -801,9 +834,9 @@ void rxrpc_process_call(struct work_struct *work)
        struct msghdr msg;
        struct kvec iov[5];
        unsigned long bits;
-       __be32 data;
+       __be32 data, pad;
        size_t len;
-       int genbit, loop, nbit, ioc, ret;
+       int genbit, loop, nbit, ioc, ret, mtu;
        u32 abort_code = RX_PROTOCOL_ERROR;
        u8 *acks = NULL;
 
@@ -899,9 +932,30 @@ void rxrpc_process_call(struct work_struct *work)
        }
 
        if (test_bit(RXRPC_CALL_ACK_FINAL, &call->events)) {
-               hdr.type = RXRPC_PACKET_TYPE_ACKALL;
                genbit = RXRPC_CALL_ACK_FINAL;
-               goto send_message;
+
+               ack.bufferSpace = htons(8);
+               ack.maxSkew     = 0;
+               ack.serial      = 0;
+               ack.reason      = RXRPC_ACK_IDLE;
+               ack.nAcks       = 0;
+               call->ackr_reason = 0;
+
+               spin_lock_bh(&call->lock);
+               ack.serial = call->ackr_serial;
+               ack.previousPacket = call->ackr_prev_seq;
+               ack.firstPacket = htonl(call->rx_data_eaten + 1);
+               spin_unlock_bh(&call->lock);
+
+               pad = 0;
+
+               iov[1].iov_base = &ack;
+               iov[1].iov_len  = sizeof(ack);
+               iov[2].iov_base = &pad;
+               iov[2].iov_len  = 3;
+               iov[3].iov_base = &ackinfo;
+               iov[3].iov_len  = sizeof(ackinfo);
+               goto send_ACK;
        }
 
        if (call->events & ((1 << RXRPC_CALL_RCVD_BUSY) |
@@ -971,8 +1025,6 @@ void rxrpc_process_call(struct work_struct *work)
 
        /* consider sending an ordinary ACK */
        if (test_bit(RXRPC_CALL_ACK, &call->events)) {
-               __be32 pad;
-
                _debug("send ACK: window: %d - %d { %lx }",
                       call->rx_data_eaten, call->ackr_win_top,
                       call->ackr_window[0]);
@@ -997,12 +1049,6 @@ void rxrpc_process_call(struct work_struct *work)
                ack.serial      = 0;
                ack.reason      = 0;
 
-               ackinfo.rxMTU   = htonl(5692);
-//             ackinfo.rxMTU   = htonl(call->conn->trans->peer->maxdata);
-               ackinfo.maxMTU  = htonl(call->conn->trans->peer->maxdata);
-               ackinfo.rwind   = htonl(32);
-               ackinfo.jumbo_max = htonl(4);
-
                spin_lock_bh(&call->lock);
                ack.reason = call->ackr_reason;
                ack.serial = call->ackr_serial;
@@ -1116,6 +1162,15 @@ send_ACK_with_skew:
        ack.maxSkew = htons(atomic_read(&call->conn->hi_serial) -
                            ntohl(ack.serial));
 send_ACK:
+       mtu = call->conn->trans->peer->if_mtu;
+       mtu -= call->conn->trans->peer->hdrsize;
+       ackinfo.maxMTU  = htonl(mtu);
+       ackinfo.rwind   = htonl(32);
+
+       /* permit the peer to send us jumbo packets if it wants to */
+       ackinfo.rxMTU   = htonl(5692);
+       ackinfo.jumbo_max = htonl(4);
+
        hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
        _proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
               ntohl(hdr.serial),
@@ -1166,7 +1221,7 @@ send_message_2:
                _debug("sendmsg failed: %d", ret);
                read_lock_bh(&call->state_lock);
                if (call->state < RXRPC_CALL_DEAD)
-                       schedule_work(&call->processor);
+                       rxrpc_queue_call(call);
                read_unlock_bh(&call->state_lock);
                goto error;
        }
@@ -1210,7 +1265,7 @@ maybe_reschedule:
        if (call->events || !skb_queue_empty(&call->rx_queue)) {
                read_lock_bh(&call->state_lock);
                if (call->state < RXRPC_CALL_DEAD)
-                       schedule_work(&call->processor);
+                       rxrpc_queue_call(call);
                read_unlock_bh(&call->state_lock);
        }
 
@@ -1224,7 +1279,7 @@ maybe_reschedule:
                read_lock_bh(&call->state_lock);
                if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
                    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
-                       schedule_work(&call->processor);
+                       rxrpc_queue_call(call);
                read_unlock_bh(&call->state_lock);
        }
 
@@ -1238,7 +1293,7 @@ error:
         * work pending bit and the work item being processed again */
        if (call->events && !work_pending(&call->processor)) {
                _debug("jumpstart %x", ntohl(call->conn->cid));
-               schedule_work(&call->processor);
+               rxrpc_queue_call(call);
        }
 
        _leave("");