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, ¶m, ¶m_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, ¶m, 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");
|