rxrpc: Fix generation of serial numbers to skip zero
authorDavid Howells <dhowells@redhat.com>
Fri, 2 Feb 2024 15:19:13 +0000 (15:19 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 5 Feb 2024 12:34:06 +0000 (12:34 +0000)
In the Rx protocol, every packet generated is marked with a per-connection
monotonically increasing serial number.  This number can be referenced in
an ACK packet generated in response to an incoming packet - thereby
allowing the sender to use this for RTT determination, amongst other
things.

However, if the reference field in the ACK is zero, it doesn't refer to any
incoming packet (it could be a ping to find out if a packet got lost, for
example) - so we shouldn't generate zero serial numbers.

Fix the generation of serial numbers to retry if it comes up with a zero.

Furthermore, since the serial numbers are only ever allocated within the
I/O thread this connection is bound to, there's no need for atomics so
remove that too.

Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
net/rxrpc/ar-internal.h
net/rxrpc/conn_event.c
net/rxrpc/output.c
net/rxrpc/proc.c
net/rxrpc/rxkad.c

index dbeb75c298573adc580568744d6781a5c6193b0d..31b0dd8c9b2d746d5b14ac2451e3e264a13977a1 100644 (file)
@@ -510,7 +510,7 @@ struct rxrpc_connection {
        enum rxrpc_call_completion completion;  /* Completion condition */
        s32                     abort_code;     /* Abort code of connection abort */
        int                     debug_id;       /* debug ID for printks */
-       atomic_t                serial;         /* packet serial number counter */
+       rxrpc_serial_t          tx_serial;      /* Outgoing packet serial number counter */
        unsigned int            hi_serial;      /* highest serial number received */
        u32                     service_id;     /* Service ID, possibly upgraded */
        u32                     security_level; /* Security level selected */
@@ -822,6 +822,20 @@ static inline bool rxrpc_sending_to_client(const struct rxrpc_txbuf *txb)
 
 #include <trace/events/rxrpc.h>
 
+/*
+ * Allocate the next serial number on a connection.  0 must be skipped.
+ */
+static inline rxrpc_serial_t rxrpc_get_next_serial(struct rxrpc_connection *conn)
+{
+       rxrpc_serial_t serial;
+
+       serial = conn->tx_serial;
+       if (serial == 0)
+               serial = 1;
+       conn->tx_serial = serial + 1;
+       return serial;
+}
+
 /*
  * af_rxrpc.c
  */
index 95f4bc206b3dc9a571abe6fb63cc6fe05575e9c9..ec5eae60ab0c4b943991695967373a5054ce87ba 100644 (file)
@@ -117,7 +117,7 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
        iov[2].iov_base = &ack_info;
        iov[2].iov_len  = sizeof(ack_info);
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
 
        pkt.whdr.epoch          = htonl(conn->proto.epoch);
        pkt.whdr.cid            = htonl(conn->proto.cid | channel);
index a0906145e8293ca457fd0b1493ba3892f5f0729a..4a292f860ae37a41bddcd99f7e3bdc6a2c092d29 100644 (file)
@@ -216,7 +216,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
        iov[0].iov_len  = sizeof(txb->wire) + sizeof(txb->ack) + n;
        len = iov[0].iov_len;
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        txb->wire.serial = htonl(serial);
        trace_rxrpc_tx_ack(call->debug_id, serial,
                           ntohl(txb->ack.firstPacket),
@@ -302,7 +302,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
        iov[0].iov_base = &pkt;
        iov[0].iov_len  = sizeof(pkt);
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        pkt.whdr.serial = htonl(serial);
 
        iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, sizeof(pkt));
@@ -334,7 +334,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
        _enter("%x,{%d}", txb->seq, txb->len);
 
        /* Each transmission of a Tx packet needs a new serial number */
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        txb->wire.serial = htonl(serial);
 
        if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) &&
@@ -558,7 +558,7 @@ void rxrpc_send_conn_abort(struct rxrpc_connection *conn)
 
        len = iov[0].iov_len + iov[1].iov_len;
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        whdr.serial = htonl(serial);
 
        iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len);
index 6c86cbb98d1d601edc9dad728c72f887067a376e..26dc2f26d92d8d67f82229675254d7217c2184e0 100644 (file)
@@ -181,7 +181,7 @@ print:
                   atomic_read(&conn->active),
                   state,
                   key_serial(conn->key),
-                  atomic_read(&conn->serial),
+                  conn->tx_serial,
                   conn->hi_serial,
                   conn->channels[0].call_id,
                   conn->channels[1].call_id,
index b52dedcebce0a7aafe0888f97e79bb81435749f2..6b32d61d4cdc46719d4a011987f6ea112ae59fc1 100644 (file)
@@ -664,7 +664,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
 
        len = iov[0].iov_len + iov[1].iov_len;
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        whdr.serial = htonl(serial);
 
        ret = kernel_sendmsg(conn->local->socket, &msg, iov, 2, len);
@@ -721,7 +721,7 @@ static int rxkad_send_response(struct rxrpc_connection *conn,
 
        len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
 
-       serial = atomic_inc_return(&conn->serial);
+       serial = rxrpc_get_next_serial(conn);
        whdr.serial = htonl(serial);
 
        rxrpc_local_dont_fragment(conn->local, false);