1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7
8#include <assert.h>
9#include <camkes/io.h>
10#include "client.h"
11
12
13seL4_CPtr echo_control_notification();
14
15virtqueue_driver_t tx_virtqueue;
16virtqueue_driver_t rx_virtqueue;
17
18
19static void handle_picoserver_notification(UNUSED seL4_Word badge, UNUSED void *cookie)
20{
21    picoserver_event_t server_event = echo_control_event_poll();
22    int socket = 0;
23    uint16_t events = 0;
24    while (server_event.num_events_left > 0 || server_event.events) {
25        socket = server_event.socket_fd;
26        events = server_event.events;
27        if (socket == utiliz_socket || socket == peer_socket) {
28            handle_tcp_utiliz_notification(events, socket);
29            server_event = echo_control_event_poll();
30        } else if (socket == socket_in || socket == tcp_echo_client) {
31            handle_tcp_echo_notification(events, socket);
32            server_event = echo_control_event_poll();
33
34        } else {
35            ZF_LOGE("Got event for socket: %d but no registered handler", socket);
36        }
37
38        server_event = echo_control_event_poll();
39    }
40}
41
42static tx_msg_t *get_msg_from_queue(virtqueue_driver_t *queue)
43{
44    virtqueue_ring_object_t handle;
45    uint32_t len;
46    if (virtqueue_get_used_buf(queue, &handle, &len) == 0) {
47        return NULL;
48    }
49
50    vq_flags_t flag;
51    void *buf;
52    int more = virtqueue_gather_used(queue, &handle, &buf, &len, &flag);
53    if (more == 0) {
54        ZF_LOGF("Failed to dequeue message from the queue");
55    }
56    return DECODE_DMA_ADDRESS(buf);
57
58}
59
60
61
62static void async_event(UNUSED seL4_Word badge, void *cookie)
63{
64    while (true) {
65
66        tx_msg_t *msg = get_msg_from_queue(&tx_virtqueue);
67        if (!msg) {
68            break;
69        }
70        if ((uintptr_t)msg->client_cookie == UDP_SOCKETS_ASYNC_ID) {
71            udp_socket_handle_async_sent(msg);
72
73        } else if ((uintptr_t)msg->client_cookie == TCP_SOCKETS_ASYNC_ID) {
74            tcp_socket_handle_async_sent(msg);
75        } else {
76            ZF_LOGE("Message sent but bad socket: %d", msg->socket_fd);
77        }
78    }
79    while (true) {
80
81        tx_msg_t *msg = get_msg_from_queue(&rx_virtqueue);
82        if (!msg) {
83            break;
84        }
85        if ((uintptr_t)msg->client_cookie == UDP_SOCKETS_ASYNC_ID) {
86            udp_socket_handle_async_received(msg);
87        } else if ((uintptr_t)msg->client_cookie == TCP_SOCKETS_ASYNC_ID) {
88            tcp_socket_handle_async_received(msg);
89        } else {
90            ZF_LOGE("Message received but bad socket: %d", msg->socket_fd);
91        }
92    }
93
94    tx_virtqueue.notify();
95}
96
97
98int setup_echo_server(ps_io_ops_t *io_ops)
99{
100    seL4_Word tx_badge;
101    seL4_Word rx_badge;
102    /* Initialise read virtqueue */
103    int error = camkes_virtqueue_driver_init_with_recv(&tx_virtqueue, camkes_virtqueue_get_id_from_name("echo_tx"),
104                                                       NULL, &tx_badge);
105    if (error) {
106        ZF_LOGE("Unable to initialise TX virtqueue");
107    }
108
109    /* Initialise write virtqueue */
110    error = camkes_virtqueue_driver_init_with_recv(&rx_virtqueue, camkes_virtqueue_get_id_from_name("echo_rx"),
111                                                   NULL, &rx_badge);
112    if (error) {
113        ZF_LOGE("Unable to initialise RX virtqueue");
114    }
115
116    /* Now poll for events and handle them */
117    single_threaded_component_register_handler(tx_badge, "async_notification", async_event, NULL);
118    single_threaded_component_register_handler(echo_control_notification_badge(), "sync_notification",
119                                               handle_picoserver_notification, NULL);
120    tx_virtqueue.notify();
121    return 0;
122}
123
124CAMKES_POST_INIT_MODULE_DEFINE(setup_echo, setup_echo_server);
125