]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/rxrpc/ar-local.c
Merge tag 'cpumask-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-jammy-kernel.git] / net / rxrpc / ar-local.c
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("");
+}