RxRPC: Handle VERSION Rx protocol packets
authorDavid Howells <dhowells@redhat.com>
Wed, 1 Apr 2015 15:31:26 +0000 (16:31 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 1 Apr 2015 15:31:26 +0000 (16:31 +0100)
Handle VERSION Rx protocol packets.  We should respond to a VERSION packet
with a string indicating the Rx version.  This is a maximum of 64 characters
and is padded out to 65 chars with NUL bytes.

Note that other AFS clients use the version request as a NAT keepalive so we
need to handle it rather than returning an abort.

The standard formulation seems to be:

<project> <version> built <yyyy>-<mm>-<dd>

for example:

" OpenAFS 1.6.2 built  2013-05-07 "

(note the three extra spaces) as obtained with:

rxdebug grand.mit.edu -version

from the openafs package.

Signed-off-by: David Howells <dhowells@redhat.com>
include/rxrpc/packet.h
net/rxrpc/ar-input.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-local.c

index f2902ef7ab75cdf2f81880b95db6fea4486bd461..4dce116bfd80c81ab09aec171817e082723ad74e 100644 (file)
@@ -47,7 +47,8 @@ struct rxrpc_header {
 #define RXRPC_PACKET_TYPE_CHALLENGE    6       /* connection security challenge (SRVR->CLNT) */
 #define RXRPC_PACKET_TYPE_RESPONSE     7       /* connection secutity response (CLNT->SRVR) */
 #define RXRPC_PACKET_TYPE_DEBUG                8       /* debug info request */
-#define RXRPC_N_PACKET_TYPES           9       /* number of packet types (incl type 0) */
+#define RXRPC_PACKET_TYPE_VERSION      13      /* version string request */
+#define RXRPC_N_PACKET_TYPES           14      /* number of packet types (incl type 0) */
 
        uint8_t         flags;          /* packet flags */
 #define RXRPC_CLIENT_INITIATED 0x01            /* signifies a packet generated by a client */
index 481f89f93789a147fd5979e894e62145f4d9d767..4505a691d88c283bbbd8038c2dd088825015bd32 100644 (file)
@@ -28,7 +28,7 @@
 const char *rxrpc_pkts[] = {
        "?00",
        "DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG",
-       "?09", "?10", "?11", "?12", "?13", "?14", "?15"
+       "?09", "?10", "?11", "?12", "VERSION", "?14", "?15"
 };
 
 /*
@@ -593,6 +593,20 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
        rxrpc_queue_conn(conn);
 }
 
+/*
+ * post endpoint-level events to the local endpoint
+ * - this includes debug and version messages
+ */
+static void rxrpc_post_packet_to_local(struct rxrpc_local *local,
+                                      struct sk_buff *skb)
+{
+       _enter("%p,%p", local, skb);
+
+       atomic_inc(&local->usage);
+       skb_queue_tail(&local->event_queue, skb);
+       rxrpc_queue_work(&local->event_processor);
+}
+
 static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local,
                                               struct sk_buff *skb,
                                               struct rxrpc_skb_priv *sp)
@@ -699,6 +713,11 @@ void rxrpc_data_ready(struct sock *sk)
                goto bad_message;
        }
 
+       if (sp->hdr.type == RXRPC_PACKET_TYPE_VERSION) {
+               rxrpc_post_packet_to_local(local, skb);
+               goto out;
+       }
+       
        if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
            (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))
                goto bad_message;
@@ -731,6 +750,8 @@ void rxrpc_data_ready(struct sock *sk)
                else
                        goto cant_route_call;
        }
+
+out:
        rxrpc_put_local(local);
        return;
 
index ba9fd36d3f156452c470a93a0b04e428672daa35..9a4f7a26adc6d98aa0c78f71fddfcfa7c6197afe 100644 (file)
@@ -152,11 +152,13 @@ struct rxrpc_local {
        struct work_struct      destroyer;      /* endpoint destroyer */
        struct work_struct      acceptor;       /* incoming call processor */
        struct work_struct      rejecter;       /* packet reject writer */
+       struct work_struct      event_processor; /* endpoint event processor */
        struct list_head        services;       /* services listening on this endpoint */
        struct list_head        link;           /* link in endpoint list */
        struct rw_semaphore     defrag_sem;     /* control re-enablement of IP DF bit */
        struct sk_buff_head     accept_queue;   /* incoming calls awaiting acceptance */
        struct sk_buff_head     reject_queue;   /* packets awaiting rejection */
+       struct sk_buff_head     event_queue;    /* endpoint event packets awaiting processing */
        spinlock_t              lock;           /* access lock */
        rwlock_t                services_lock;  /* lock for services list */
        atomic_t                usage;
index 87f7135d238b498f9208543cf4608c1cb78a59d3..ca904ed5400a11bd08e47fea56d0caeb30f0a442 100644 (file)
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
+#include <generated/utsrelease.h>
 #include "ar-internal.h"
 
+static const char rxrpc_version_string[65] = "linux-" UTS_RELEASE " AF_RXRPC";
+
 static LIST_HEAD(rxrpc_locals);
 DEFINE_RWLOCK(rxrpc_local_lock);
 static DECLARE_RWSEM(rxrpc_local_sem);
 static DECLARE_WAIT_QUEUE_HEAD(rxrpc_local_wq);
 
 static void rxrpc_destroy_local(struct work_struct *work);
+static void rxrpc_process_local_events(struct work_struct *work);
 
 /*
  * allocate a new local
@@ -37,11 +43,13 @@ struct rxrpc_local *rxrpc_alloc_local(struct sockaddr_rxrpc *srx)
                INIT_WORK(&local->destroyer, &rxrpc_destroy_local);
                INIT_WORK(&local->acceptor, &rxrpc_accept_incoming_calls);
                INIT_WORK(&local->rejecter, &rxrpc_reject_packets);
+               INIT_WORK(&local->event_processor, &rxrpc_process_local_events);
                INIT_LIST_HEAD(&local->services);
                INIT_LIST_HEAD(&local->link);
                init_rwsem(&local->defrag_sem);
                skb_queue_head_init(&local->accept_queue);
                skb_queue_head_init(&local->reject_queue);
+               skb_queue_head_init(&local->event_queue);
                spin_lock_init(&local->lock);
                rwlock_init(&local->services_lock);
                atomic_set(&local->usage, 1);
@@ -264,10 +272,12 @@ static void rxrpc_destroy_local(struct work_struct *work)
        ASSERT(list_empty(&local->services));
        ASSERT(!work_pending(&local->acceptor));
        ASSERT(!work_pending(&local->rejecter));
+       ASSERT(!work_pending(&local->event_processor));
 
        /* finish cleaning up the local descriptor */
        rxrpc_purge_queue(&local->accept_queue);
        rxrpc_purge_queue(&local->reject_queue);
+       rxrpc_purge_queue(&local->event_queue);
        kernel_sock_shutdown(local->socket, SHUT_RDWR);
        sock_release(local->socket);
 
@@ -308,3 +318,91 @@ void __exit rxrpc_destroy_all_locals(void)
 
        _leave("");
 }
+
+/*
+ * Reply to a version request
+ */
+static void rxrpc_send_version_request(struct rxrpc_local *local,
+                                      struct rxrpc_header *hdr,
+                                      struct sk_buff *skb)
+{
+       struct sockaddr_in sin;
+       struct msghdr msg;
+       struct kvec iov[2];
+       size_t len;
+       int ret;
+
+       _enter("");
+
+       sin.sin_family = AF_INET;
+       sin.sin_port = udp_hdr(skb)->source;
+       sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
+
+       msg.msg_name    = &sin;
+       msg.msg_namelen = sizeof(sin);
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_flags   = 0;
+
+       hdr->seq        = 0;
+       hdr->serial     = 0;
+       hdr->type       = RXRPC_PACKET_TYPE_VERSION;
+       hdr->flags      = RXRPC_LAST_PACKET | (~hdr->flags & RXRPC_CLIENT_INITIATED);
+       hdr->userStatus = 0;
+       hdr->_rsvd      = 0;
+
+       iov[0].iov_base = hdr;
+       iov[0].iov_len  = sizeof(*hdr);
+       iov[1].iov_base = (char *)rxrpc_version_string;
+       iov[1].iov_len  = sizeof(rxrpc_version_string);
+
+       len = iov[0].iov_len + iov[1].iov_len;
+
+       _proto("Tx VERSION (reply)");
+
+       ret = kernel_sendmsg(local->socket, &msg, iov, 2, len);
+       if (ret < 0)
+               _debug("sendmsg failed: %d", ret);
+
+       _leave("");
+}
+
+/*
+ * Process event packets targetted at a local endpoint.
+ */
+static void rxrpc_process_local_events(struct work_struct *work)
+{
+       struct rxrpc_local *local = container_of(work, struct rxrpc_local, event_processor);
+       struct sk_buff *skb;
+       char v;
+
+       _enter("");
+
+       atomic_inc(&local->usage);
+       
+       while ((skb = skb_dequeue(&local->event_queue))) {
+               struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+               kdebug("{%d},{%u}", local->debug_id, sp->hdr.type);
+
+               switch (sp->hdr.type) {
+               case RXRPC_PACKET_TYPE_VERSION:
+                       if (skb_copy_bits(skb, 0, &v, 1) < 0)
+                               return;
+                       _proto("Rx VERSION { %02x }", v);
+                       if (v == 0)
+                               rxrpc_send_version_request(local, &sp->hdr, skb);
+                       break;
+
+               default:
+                       /* Just ignore anything we don't understand */
+                       break;
+               }
+
+               rxrpc_put_local(local);
+               rxrpc_free_skb(skb);
+       }
+
+       rxrpc_put_local(local);
+       _leave("");
+}