LCOV - code coverage report
Current view: top level - home/net-next/net/quic - sample_test.c (source / functions) Hit Total Coverage
Test: quic.info Lines: 327 395 82.8 %
Date: 2025-07-04 13:24:45 Functions: 11 11 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* QUIC kernel implementation
       3             :  * (C) Copyright Red Hat Corp. 2023
       4             :  *
       5             :  * This file is kernel test of the QUIC kernel implementation
       6             :  *
       7             :  * Initialization/cleanup for QUIC protocol support.
       8             :  *
       9             :  * Written or modified by:
      10             :  *    Xin Long <lucien.xin@gmail.com>
      11             :  */
      12             : 
      13             : #include <linux/completion.h>
      14             : #include <linux/module.h>
      15             : #include <linux/socket.h>
      16             : #include <linux/kernel.h>
      17             : #include <linux/delay.h>
      18             : #include <linux/quic.h>
      19             : #include <linux/inet.h>
      20             : #include <linux/net.h>
      21             : #include <linux/key.h>
      22             : 
      23             : #include <net/handshake.h>
      24             : #include <net/sock.h>
      25             : 
      26             : #define ROLE_LEN        10
      27             : #define IP_LEN          20
      28             : #define ALPN_LEN        20
      29             : 
      30             : static char role[ROLE_LEN] = "client";
      31             : static char alpn[ALPN_LEN] = "sample";
      32             : static char ip[IP_LEN] = "127.0.0.1";
      33             : static int port = 1234;
      34             : static int psk;
      35             : 
      36             : static u8 session_data[4096];
      37             : 
      38             : /* Receive a message and extract QUIC stream metadata from control message. */
      39          22 : static int quic_test_recvmsg(struct socket *sock, void *msg, int len, s64 *sid, u32 *flags)
      40             : {
      41          22 :         char incmsg[CMSG_SPACE(sizeof(struct quic_stream_info))];
      42          22 :         struct quic_stream_info *rinfo;
      43          22 :         struct cmsghdr *cmsg;
      44          22 :         struct msghdr inmsg;
      45          22 :         struct kvec iov;
      46          22 :         int err;
      47             : 
      48          22 :         iov.iov_base = msg;
      49          22 :         iov.iov_len = len;
      50             : 
      51          22 :         memset(&inmsg, 0, sizeof(inmsg));
      52          22 :         inmsg.msg_control = incmsg;
      53          22 :         inmsg.msg_controllen = sizeof(incmsg);
      54             : 
      55          22 :         err = kernel_recvmsg(sock, &inmsg, &iov, 1, len, (int)(*flags));
      56          22 :         if (err < 0)
      57             :                 return err;
      58             : 
      59          16 :         *flags = inmsg.msg_flags;
      60             : 
      61          16 :         cmsg = (struct cmsghdr *)incmsg;
      62          16 :         if (SOL_QUIC == cmsg->cmsg_level &&  QUIC_STREAM_INFO == cmsg->cmsg_type) {
      63          16 :                 rinfo = CMSG_DATA(cmsg);
      64          16 :                 *sid = rinfo->stream_id;
      65          16 :                 *flags |= rinfo->stream_flags;
      66             :         }
      67             :         return err;
      68             : }
      69             : 
      70             : /* Send a message with QUIC stream metadata via control message. */
      71          16 : static int quic_test_sendmsg(struct socket *sock, const void *msg, int len, s64 sid, u32 flags)
      72             : {
      73          16 :         char outcmsg[CMSG_SPACE(sizeof(struct quic_stream_info))];
      74          16 :         struct quic_stream_info *sinfo;
      75          16 :         struct msghdr outmsg;
      76          16 :         struct cmsghdr *cmsg;
      77          16 :         struct kvec iov;
      78             : 
      79          16 :         iov.iov_base = (void *)msg;
      80          16 :         iov.iov_len = len;
      81             : 
      82          16 :         memset(&outmsg, 0, sizeof(outmsg));
      83          16 :         outmsg.msg_control = outcmsg;
      84          16 :         outmsg.msg_controllen = sizeof(outcmsg);
      85          16 :         outmsg.msg_flags = flags;
      86             : 
      87          16 :         cmsg = (struct cmsghdr *)outcmsg;
      88          16 :         cmsg->cmsg_level = SOL_QUIC;
      89          16 :         cmsg->cmsg_type = QUIC_STREAM_INFO;
      90          16 :         cmsg->cmsg_len = CMSG_LEN(sizeof(*sinfo));
      91             : 
      92          16 :         outmsg.msg_controllen = cmsg->cmsg_len;
      93          16 :         sinfo = CMSG_DATA(cmsg);
      94          16 :         sinfo->stream_id = sid;
      95          16 :         sinfo->stream_flags = flags;
      96             : 
      97          16 :         return kernel_sendmsg(sock, &outmsg, &iov, 1, len);
      98             : }
      99             : 
     100             : struct quic_test_priv {
     101             :         struct completion sk_handshake_done;
     102             :         struct file *filp;
     103             :         int status;
     104             : };
     105             : 
     106             : /* Callback for handshake completion: stores status and wakes waiting context. */
     107          16 : static void quic_test_handshake_done(void *data, int status, key_serial_t peerid)
     108             : {
     109          16 :         struct quic_test_priv *priv = data;
     110             : 
     111          16 :         priv->status = status;
     112          16 :         complete_all(&priv->sk_handshake_done);
     113          16 : }
     114             : 
     115             : /* Client handshake logic using the kernel TLS handshake API. */
     116           8 : static int quic_test_client_handshake(struct socket *sock, struct quic_test_priv *priv)
     117             : {
     118           8 :         struct tls_handshake_args args = {};
     119           8 :         int err;
     120             : 
     121           8 :         init_completion(&priv->sk_handshake_done);
     122             : 
     123           8 :         args.ta_sock = sock;
     124           8 :         args.ta_done = quic_test_handshake_done;
     125           8 :         args.ta_data = priv;
     126           8 :         args.ta_timeout_ms = 3000;
     127             : 
     128           8 :         if (psk) { /* Use PSK if key_serial_t is configured, otherwise X.509-based handshake. */
     129           2 :                 args.ta_my_peerids[0] = psk;
     130           2 :                 args.ta_num_peerids = 1;
     131           2 :                 err = tls_client_hello_psk(&args, GFP_KERNEL);
     132           2 :                 if (err)
     133             :                         return err;
     134           2 :                 goto wait;
     135             :         }
     136             : 
     137           6 :         args.ta_peername = "server.test";
     138           6 :         err = tls_client_hello_x509(&args, GFP_KERNEL);
     139           6 :         if (err)
     140             :                 return err;
     141           6 : wait:
     142             :         /* Wait for handshake completion or timeout. */
     143           8 :         err = wait_for_completion_interruptible_timeout(&priv->sk_handshake_done, HZ * 5UL);
     144           8 :         if (err <= 0) {
     145           0 :                 tls_handshake_cancel(sock->sk);
     146           0 :                 return -EINVAL;
     147             :         }
     148           8 :         return priv->status;
     149             : }
     150             : 
     151             : /* Server handshake logic using kernel TLS API. Similar to quic_test_client_handshake().*/
     152           8 : static int quic_test_server_handshake(struct socket *sock, struct quic_test_priv *priv)
     153             : {
     154           8 :         struct tls_handshake_args args = {};
     155           8 :         int err;
     156             : 
     157           8 :         init_completion(&priv->sk_handshake_done);
     158             : 
     159           8 :         args.ta_sock = sock;
     160           8 :         args.ta_done = quic_test_handshake_done;
     161           8 :         args.ta_data = priv;
     162           8 :         args.ta_timeout_ms = 3000;
     163             : 
     164           8 :         if (psk) {
     165           2 :                 err = tls_server_hello_psk(&args, GFP_KERNEL);
     166           2 :                 if (err)
     167             :                         return err;
     168           2 :                 goto wait;
     169             :         }
     170             : 
     171           6 :         err = tls_server_hello_x509(&args, GFP_KERNEL);
     172           6 :         if (err)
     173             :                 return err;
     174           6 : wait:
     175           8 :         err = wait_for_completion_interruptible_timeout(&priv->sk_handshake_done, HZ * 5UL);
     176           8 :         if (err <= 0) {
     177           0 :                 tls_handshake_cancel(sock->sk);
     178           0 :                 return -EINVAL;
     179             :         }
     180           8 :         return priv->status;
     181             : }
     182             : 
     183           4 : static int quic_test_do_sample_client(void)
     184             : {
     185           4 :         struct quic_test_priv priv = {};
     186           4 :         struct sockaddr_in ra = {};
     187           4 :         struct socket *sock;
     188           4 :         u32 flags = 0;
     189           4 :         char msg[64];
     190           4 :         int err;
     191           4 :         s64 sid;
     192             : 
     193           4 :         err = __sock_create(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_QUIC, &sock, 1);
     194           4 :         if (err < 0)
     195             :                 return err;
     196             :         /* Allocate a file descriptor for the new socket to expose it to userspace. */
     197           4 :         priv.filp = sock_alloc_file(sock, 0, NULL);
     198           4 :         if (IS_ERR(priv.filp))
     199           0 :                 return PTR_ERR(priv.filp);
     200             :         /* Set ALPN (Application-Layer Protocol Negotiation) on the socket.
     201             :          *
     202             :          * This value will be exposed to userspace via getsockopt(QUIC_SOCKOPT_ALPN)
     203             :          * and used during the TLS handshake (e.g., to select HTTP/3 or custom protocol).
     204             :          *
     205             :          * Setting this here allows the userspace handshake implementation to retrieve
     206             :          * and embed the ALPN value in the ClientHello sent to the server.
     207             :          */
     208           8 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_ALPN, alpn, strlen(alpn));
     209           4 :         if (err)
     210           0 :                 goto free;
     211           4 :         ra.sin_family = AF_INET;
     212           4 :         ra.sin_port = htons((u16)port);
     213           8 :         if (!in4_pton(ip, strlen(ip), (u8 *)&ra.sin_addr.s_addr, -1, NULL))
     214           0 :                 goto free;
     215           4 :         err = kernel_connect(sock, (struct sockaddr *)&ra, sizeof(ra), 0);
     216           4 :         if (err < 0)
     217           0 :                 goto free;
     218             : 
     219           4 :         err = quic_test_client_handshake(sock, &priv);
     220           4 :         if (err < 0)
     221           0 :                 goto free;
     222             : 
     223           4 :         pr_info("quic_test: handshake completed\n");
     224             : 
     225             :         /* Send a message on a new unidirectional stream and then receive a response.
     226             :          *
     227             :          * - MSG_STREAM_NEW tells the stack to open a new stream with the given stream ID (sid).
     228             :          *   Alternatively, a stream can be opened via getsockopt(QUIC_SOCKOPT_STREAM_OPEN).
     229             :          *
     230             :          * - MSG_STREAM_FIN marks the end of the stream, signaling no more data will follow.
     231             :          *
     232             :          * We send "hello quic server!" on a unidirectional stream (QUIC_STREAM_TYPE_UNI_MASK),
     233             :          * and expect a response on a peer-initiated stream, which we receive with recvmsg().
     234             :          */
     235           4 :         strscpy(msg, "hello quic server!", sizeof(msg));
     236           4 :         sid = QUIC_STREAM_TYPE_UNI_MASK;
     237           4 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     238           8 :         err = quic_test_sendmsg(sock, msg, strlen(msg), sid, flags);
     239           4 :         if (err < 0) {
     240           0 :                 pr_info("quic_test: send err: %d\n", err);
     241           0 :                 goto free;
     242             :         }
     243           4 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     244             : 
     245           4 :         memset(msg, 0, sizeof(msg));
     246           4 :         flags = 0;
     247           4 :         err = quic_test_recvmsg(sock, msg, sizeof(msg) - 1, &sid, &flags);
     248           4 :         if (err < 0) {
     249           0 :                 pr_info("quic_test: recv err: %d\n", err);
     250           0 :                 goto free;
     251             :         }
     252           4 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     253             : 
     254           4 :         err = 0;
     255           4 : free:
     256           4 :         fput(priv.filp);
     257           4 :         return err;
     258             : }
     259             : 
     260           2 : static int quic_test_do_ticket_client(void)
     261             : {
     262           2 :         struct quic_transport_param param = {};
     263           2 :         unsigned int param_len, ticket_len;
     264           2 :         struct quic_test_priv priv = {};
     265           2 :         struct quic_config config = {};
     266           2 :         struct sockaddr_in ra = {};
     267           2 :         struct socket *sock;
     268           2 :         u32 flags = 0;
     269           2 :         char msg[64];
     270           2 :         int err;
     271           2 :         s64 sid;
     272             : 
     273           2 :         err = __sock_create(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_QUIC, &sock, 1);
     274           2 :         if (err < 0)
     275             :                 return err;
     276           2 :         priv.filp = sock_alloc_file(sock, 0, NULL);
     277           2 :         if (IS_ERR(priv.filp))
     278           0 :                 return PTR_ERR(priv.filp);
     279           4 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_ALPN, alpn, strlen(alpn));
     280           2 :         if (err)
     281           0 :                 goto free;
     282             : 
     283             :         /* Instruct the userspace handshake to capture and provide the session ticket
     284             :          * during the handshake process via QUIC_SOCKOPT_SESSION_TICKET socket option.
     285             :          */
     286           2 :         config.receive_session_ticket = 1;
     287           2 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_CONFIG, &config, sizeof(config));
     288           2 :         if (err)
     289           0 :                 goto free;
     290             : 
     291           2 :         ra.sin_family = AF_INET;
     292           2 :         ra.sin_port = htons((u16)port);
     293           4 :         if (!in4_pton(ip, strlen(ip), (u8 *)&ra.sin_addr.s_addr, -1, NULL))
     294           0 :                 goto free;
     295           2 :         err = kernel_connect(sock, (struct sockaddr *)&ra, sizeof(ra), 0);
     296           2 :         if (err < 0)
     297           0 :                 goto free;
     298             : 
     299           2 :         err = quic_test_client_handshake(sock, &priv);
     300           2 :         if (err < 0)
     301           0 :                 goto free;
     302             : 
     303           2 :         pr_info("quic_test: handshake completed\n");
     304             : 
     305             :         /* Retrieve the session ticket from userspace (set via
     306             :          * setsockopt(QUIC_SOCKOPT_SESSION_TICKET) during the handshake) and store it in
     307             :          * 'session_data' for later session resumption.
     308             :          */
     309           2 :         ticket_len = sizeof(session_data);
     310           2 :         err = quic_kernel_getsockopt(sock->sk, QUIC_SOCKOPT_SESSION_TICKET, session_data,
     311             :                                      &ticket_len);
     312           2 :         if (err < 0)
     313           0 :                 goto free;
     314             : 
     315             :         /* Retrieve and store the server's transport parameters into 'param'.  These are
     316             :          * needed later to enable early data transmission during session resumption.
     317             :          */
     318           2 :         param_len = sizeof(param);
     319           2 :         param.remote = 1;
     320           2 :         err = quic_kernel_getsockopt(sock->sk, QUIC_SOCKOPT_TRANSPORT_PARAM, &param, &param_len);
     321           2 :         if (err < 0)
     322           0 :                 goto free;
     323             : 
     324           2 :         pr_info("quic_test: save session ticket: %d, transport param %d for session resumption\n",
     325             :                 ticket_len, param_len);
     326             : 
     327           2 :         strscpy(msg, "hello quic server!", sizeof(msg));
     328           2 :         sid = QUIC_STREAM_TYPE_UNI_MASK;
     329           2 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     330           4 :         err = quic_test_sendmsg(sock, msg, strlen(msg), sid, flags);
     331           2 :         if (err < 0) {
     332           0 :                 pr_info("quic_test: send err: %d\n", err);
     333           0 :                 goto free;
     334             :         }
     335           2 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     336             : 
     337           2 :         memset(msg, 0, sizeof(msg));
     338           2 :         flags = 0;
     339           2 :         err = quic_test_recvmsg(sock, msg, sizeof(msg) - 1, &sid, &flags);
     340           2 :         if (err < 0) {
     341           0 :                 pr_info("quic_test: recv err: %d\n", err);
     342           0 :                 goto free;
     343             :         }
     344           2 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     345             : 
     346           2 :         __fput_sync(priv.filp);
     347           2 :         msleep(100);
     348             : 
     349           2 :         err = __sock_create(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_QUIC, &sock, 1);
     350           2 :         if (err < 0)
     351             :                 return err;
     352           2 :         priv.filp = sock_alloc_file(sock, 0, NULL);
     353           2 :         if (IS_ERR(priv.filp))
     354           0 :                 return PTR_ERR(priv.filp);
     355           4 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_ALPN, alpn, strlen(alpn));
     356           2 :         if (err)
     357           0 :                 goto free;
     358             : 
     359           2 :         ra.sin_family = AF_INET;
     360           2 :         ra.sin_port = htons((u16)port);
     361           4 :         if (!in4_pton(ip, strlen(ip), (u8 *)&ra.sin_addr.s_addr, -1, NULL))
     362           0 :                 goto free;
     363           2 :         err = kernel_connect(sock, (struct sockaddr *)&ra, sizeof(ra), 0);
     364           2 :         if (err < 0)
     365           0 :                 goto free;
     366             : 
     367             :         /* Provide the session ticket for resumption. It will be retrieved by userspace via
     368             :          * getsockopt(QUIC_SOCKOPT_SESSION_TICKET) and used during the handshake.
     369             :          */
     370           2 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_SESSION_TICKET, session_data,
     371             :                                      ticket_len);
     372           2 :         if (err)
     373           0 :                 goto free;
     374             : 
     375             :         /* Provide the server's transport parameters for early data transmission. */
     376           2 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_TRANSPORT_PARAM, &param, param_len);
     377           2 :         if (err)
     378           0 :                 goto free;
     379             : 
     380             :         /* Queue early application data to be sent before the handshake begins. */
     381           2 :         strscpy(msg, "hello quic server! I'm back!", sizeof(msg));
     382           2 :         sid = QUIC_STREAM_TYPE_UNI_MASK;
     383           2 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     384           4 :         err = quic_test_sendmsg(sock, msg, strlen(msg), sid, flags);
     385           2 :         if (err < 0) {
     386           0 :                 pr_info("quic_test: send err: %d\n", err);
     387           0 :                 goto free;
     388             :         }
     389           2 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     390             : 
     391           2 :         err = quic_test_client_handshake(sock, &priv);
     392           2 :         if (err < 0)
     393           0 :                 goto free;
     394             : 
     395           2 :         pr_info("quic_test: handshake completed\n");
     396             : 
     397           2 :         memset(msg, 0, sizeof(msg));
     398           2 :         flags = 0;
     399           2 :         err = quic_test_recvmsg(sock, msg, sizeof(msg) - 1, &sid, &flags);
     400           2 :         if (err < 0) {
     401           0 :                 pr_info("quic_test: recv err: %d\n", err);
     402           0 :                 goto free;
     403             :         }
     404           2 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     405             : 
     406           2 :         err = 0;
     407           2 : free:
     408           2 :         __fput_sync(priv.filp);
     409           2 :         return err;
     410             : }
     411             : 
     412           4 : static int quic_test_do_sample_server(void)
     413             : {
     414           4 :         struct quic_test_priv priv = {};
     415           4 :         struct socket *sock, *newsock;
     416           4 :         struct sockaddr_in la = {};
     417           4 :         u32 flags = 0;
     418           4 :         char msg[64];
     419           4 :         int err;
     420           4 :         s64 sid;
     421             : 
     422           4 :         err = __sock_create(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_QUIC, &sock, 1);
     423           4 :         if (err < 0)
     424             :                 return err;
     425             : 
     426           4 :         la.sin_family = AF_INET;
     427           4 :         la.sin_port = htons((u16)port);
     428           8 :         if (!in4_pton(ip, strlen(ip), (u8 *)&la.sin_addr.s_addr, -1, NULL))
     429           0 :                 goto free;
     430           4 :         err = kernel_bind(sock, (struct sockaddr *)&la, sizeof(la));
     431           4 :         if (err < 0)
     432           0 :                 goto free;
     433           8 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_ALPN, alpn, strlen(alpn));
     434           4 :         if (err)
     435           0 :                 goto free;
     436           4 :         err = kernel_listen(sock, 1);
     437           4 :         if (err < 0)
     438           0 :                 goto free;
     439           4 :         err = kernel_accept(sock, &newsock, 0);
     440           4 :         if (err < 0)
     441           0 :                 goto free;
     442             : 
     443           4 :         priv.filp = sock_alloc_file(newsock, 0, NULL);
     444           4 :         if (IS_ERR(priv.filp)) {
     445           0 :                 err = PTR_ERR(priv.filp);
     446           0 :                 goto free;
     447             :         }
     448             : 
     449           4 :         err = quic_test_server_handshake(newsock, &priv);
     450           4 :         if (err < 0)
     451           0 :                 goto free_flip;
     452             : 
     453           4 :         pr_info("quic_test: handshake completed\n");
     454             : 
     455           4 :         memset(msg, 0, sizeof(msg));
     456           4 :         flags = 0;
     457           4 :         err = quic_test_recvmsg(newsock, msg, sizeof(msg) - 1, &sid, &flags);
     458           4 :         if (err < 0) {
     459           0 :                 pr_info("quic_test: recv err %d\n", err);
     460           0 :                 goto free_flip;
     461             :         }
     462           4 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     463             : 
     464           4 :         strscpy(msg, "hello quic client!", sizeof(msg));
     465           4 :         sid = QUIC_STREAM_TYPE_SERVER_MASK;
     466           4 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     467           8 :         err = quic_test_sendmsg(newsock, msg, strlen(msg), sid, flags);
     468           4 :         if (err < 0) {
     469           0 :                 pr_info("quic_test: send err: %d\n", err);
     470           0 :                 goto free_flip;
     471             :         }
     472           4 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     473             : 
     474           4 :         flags = 0;
     475           4 :         quic_test_recvmsg(newsock, msg, sizeof(msg) - 1, &sid, &flags);
     476           4 :         err = 0;
     477           4 : free_flip:
     478           4 :         fput(priv.filp);
     479           4 : free:
     480           4 :         sock_release(sock);
     481           4 :         return err;
     482             : }
     483             : 
     484           2 : static int quic_test_do_ticket_server(void)
     485             : {
     486           2 :         struct quic_test_priv priv = {};
     487           2 :         struct socket *sock, *newsock;
     488           2 :         struct sockaddr_in la = {};
     489           2 :         u32 flags = 0;
     490           2 :         char msg[64];
     491           2 :         int err;
     492           2 :         s64 sid;
     493             : 
     494           2 :         err = __sock_create(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_QUIC, &sock, 1);
     495           2 :         if (err < 0)
     496             :                 return err;
     497             : 
     498           2 :         la.sin_family = AF_INET;
     499           2 :         la.sin_port = htons((u16)port);
     500           4 :         if (!in4_pton(ip, strlen(ip), (u8 *)&la.sin_addr.s_addr, -1, NULL))
     501           0 :                 goto free;
     502           2 :         err = kernel_bind(sock, (struct sockaddr *)&la, sizeof(la));
     503           2 :         if (err < 0)
     504           0 :                 goto free;
     505           4 :         err = quic_kernel_setsockopt(sock->sk, QUIC_SOCKOPT_ALPN, alpn, strlen(alpn));
     506           2 :         if (err)
     507           0 :                 goto free;
     508           2 :         err = kernel_listen(sock, 1);
     509           2 :         if (err < 0)
     510           0 :                 goto free;
     511             : 
     512           2 :         err = kernel_accept(sock, &newsock, 0);
     513           2 :         if (err < 0)
     514           0 :                 goto free;
     515             : 
     516           2 :         priv.filp = sock_alloc_file(newsock, 0, NULL);
     517           2 :         if (IS_ERR(priv.filp)) {
     518           0 :                 err = PTR_ERR(priv.filp);
     519           0 :                 goto free;
     520             :         }
     521             : 
     522           2 :         err = quic_test_server_handshake(newsock, &priv);
     523           2 :         if (err < 0)
     524           0 :                 goto free_flip;
     525             : 
     526           2 :         pr_info("quic_test: handshake completed\n");
     527             : 
     528           2 :         memset(msg, 0, sizeof(msg));
     529           2 :         flags = 0;
     530           2 :         err = quic_test_recvmsg(newsock, msg, sizeof(msg) - 1, &sid, &flags);
     531           2 :         if (err < 0) {
     532           0 :                 pr_info("quic_test: recv err: %d\n", err);
     533           0 :                 goto free_flip;
     534             :         }
     535           2 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     536             : 
     537           2 :         strscpy(msg, "hello quic client!", sizeof(msg));
     538           2 :         sid = QUIC_STREAM_TYPE_SERVER_MASK;
     539           2 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     540           4 :         err = quic_test_sendmsg(newsock, msg, strlen(msg), sid, flags);
     541           2 :         if (err < 0) {
     542           0 :                 pr_info("quic_test: send err: %d\n", err);
     543           0 :                 goto free_flip;
     544             :         }
     545           2 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     546             : 
     547           2 :         __fput_sync(priv.filp);
     548             : 
     549           2 :         pr_info("quic_test: wait for next connection from client...\n");
     550             : 
     551           2 :         err = kernel_accept(sock, &newsock, 0);
     552           2 :         if (err < 0)
     553           0 :                 goto free;
     554             : 
     555           2 :         priv.filp = sock_alloc_file(newsock, 0, NULL);
     556           2 :         if (IS_ERR(priv.filp)) {
     557           0 :                 err = PTR_ERR(priv.filp);
     558           0 :                 goto free;
     559             :         }
     560             : 
     561           2 :         err = quic_test_server_handshake(newsock, &priv);
     562           2 :         if (err < 0)
     563           0 :                 goto free_flip;
     564             : 
     565           2 :         pr_info("quic_test: handshake completed\n");
     566             : 
     567           2 :         memset(msg, 0, sizeof(msg));
     568           2 :         flags = 0;
     569           2 :         err = quic_test_recvmsg(newsock, msg, sizeof(msg) - 1, &sid, &flags);
     570           2 :         if (err < 0) {
     571           0 :                 pr_info("quic_test: recv err: %d\n", err);
     572           0 :                 goto free_flip;
     573             :         }
     574           2 :         pr_info("quic_test: recv '%s' on stream %lld\n", msg, sid);
     575             : 
     576           2 :         strscpy(msg, "hello quic client! welcome back!", sizeof(msg));
     577           2 :         sid = QUIC_STREAM_TYPE_SERVER_MASK;
     578           2 :         flags = MSG_STREAM_NEW | MSG_STREAM_FIN;
     579           4 :         err = quic_test_sendmsg(newsock, msg, strlen(msg), sid, flags);
     580           2 :         if (err < 0) {
     581           0 :                 pr_info("quic_test: send err: %d\n", err);
     582           0 :                 goto free_flip;
     583             :         }
     584           2 :         pr_info("quic_test: send '%s' on stream %lld\n", msg, sid);
     585             : 
     586           2 :         flags = 0;
     587           2 :         quic_test_recvmsg(newsock, msg, sizeof(msg) - 1, &sid, &flags);
     588           2 :         err = 0;
     589           2 : free_flip:
     590           2 :         __fput_sync(priv.filp);
     591           2 : free:
     592           2 :         sock_release(sock);
     593           2 :         return err;
     594             : }
     595             : 
     596          12 : static int quic_test_init(void)
     597             : {
     598          12 :         pr_info("quic_test: init\n");
     599          12 :         if (!strcmp(role, "client")) { /* Run client-side tests. */
     600             :                 /* Reuse 'alpn' as test selector: "ticket" triggers the ticket test. */
     601           6 :                 if (!strcmp(alpn, "ticket"))
     602           2 :                         return quic_test_do_ticket_client();
     603             :                 /* Otherwise, run sample test. */
     604           4 :                 return quic_test_do_sample_client();
     605             :         }
     606           6 :         if (!strcmp(role, "server")) { /* Run server-side tests. */
     607           6 :                 if (!strcmp(alpn, "ticket"))
     608           2 :                         return quic_test_do_ticket_server();
     609           4 :                 return quic_test_do_sample_server();
     610             :         }
     611             :         return -EINVAL;
     612             : }
     613             : 
     614          12 : static void quic_test_exit(void)
     615             : {
     616          12 :         pr_info("quic_test: exit\n");
     617          12 : }
     618             : 
     619             : module_init(quic_test_init);
     620             : module_exit(quic_test_exit);
     621             : 
     622             : module_param_string(role, role, ROLE_LEN, 0644);
     623             : module_param_string(alpn, alpn, ALPN_LEN, 0644);
     624             : module_param_string(ip, ip, IP_LEN, 0644);
     625             : module_param_named(port, port, int, 0644);
     626             : module_param_named(psk, psk, int, 0644);
     627             : 
     628             : MODULE_PARM_DESC(role, "Client or server");
     629             : MODULE_PARM_DESC(ip, "Server Address");
     630             : MODULE_PARM_DESC(port, "Server Port");
     631             : MODULE_PARM_DESC(alpn, "ALPN name");
     632             : MODULE_PARM_DESC(psk, "key_serial_t for psk");
     633             : 
     634             : MODULE_AUTHOR("Xin Long <lucien.xin@gmail.com>");
     635             : MODULE_DESCRIPTION("Test For Support for the QUIC protocol (RFC9000)");
     636             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14