xref: /freebsd/crypto/openssl/test/helpers/pktsplitbio.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery #include <openssl/bio.h>
11*e7be843bSPierre Pronchery #include "quictestlib.h"
12*e7be843bSPierre Pronchery #include "../testutil.h"
13*e7be843bSPierre Pronchery 
pkt_split_dgram_ctrl(BIO * bio,int cmd,long num,void * ptr)14*e7be843bSPierre Pronchery static long pkt_split_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
15*e7be843bSPierre Pronchery {
16*e7be843bSPierre Pronchery     long ret;
17*e7be843bSPierre Pronchery     BIO *next = BIO_next(bio);
18*e7be843bSPierre Pronchery 
19*e7be843bSPierre Pronchery     if (next == NULL)
20*e7be843bSPierre Pronchery         return 0;
21*e7be843bSPierre Pronchery 
22*e7be843bSPierre Pronchery     switch (cmd) {
23*e7be843bSPierre Pronchery     case BIO_CTRL_DUP:
24*e7be843bSPierre Pronchery         ret = 0L;
25*e7be843bSPierre Pronchery         break;
26*e7be843bSPierre Pronchery     default:
27*e7be843bSPierre Pronchery         ret = BIO_ctrl(next, cmd, num, ptr);
28*e7be843bSPierre Pronchery         break;
29*e7be843bSPierre Pronchery     }
30*e7be843bSPierre Pronchery     return ret;
31*e7be843bSPierre Pronchery }
32*e7be843bSPierre Pronchery 
pkt_split_dgram_sendmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * msgs_processed)33*e7be843bSPierre Pronchery static int pkt_split_dgram_sendmmsg(BIO *bio, BIO_MSG *msg, size_t stride,
34*e7be843bSPierre Pronchery                                     size_t num_msg, uint64_t flags,
35*e7be843bSPierre Pronchery                                     size_t *msgs_processed)
36*e7be843bSPierre Pronchery {
37*e7be843bSPierre Pronchery     BIO *next = BIO_next(bio);
38*e7be843bSPierre Pronchery 
39*e7be843bSPierre Pronchery     if (next == NULL)
40*e7be843bSPierre Pronchery         return 0;
41*e7be843bSPierre Pronchery 
42*e7be843bSPierre Pronchery     /*
43*e7be843bSPierre Pronchery      * We only introduce noise when receiving messages. We just pass this on
44*e7be843bSPierre Pronchery      * to the underlying BIO.
45*e7be843bSPierre Pronchery      */
46*e7be843bSPierre Pronchery     return BIO_sendmmsg(next, msg, stride, num_msg, flags, msgs_processed);
47*e7be843bSPierre Pronchery }
48*e7be843bSPierre Pronchery 
pkt_split_dgram_recvmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * msgs_processed)49*e7be843bSPierre Pronchery static int pkt_split_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride,
50*e7be843bSPierre Pronchery                                     size_t num_msg, uint64_t flags,
51*e7be843bSPierre Pronchery                                     size_t *msgs_processed)
52*e7be843bSPierre Pronchery {
53*e7be843bSPierre Pronchery     BIO *next = BIO_next(bio);
54*e7be843bSPierre Pronchery     size_t i, j, data_len = 0, msg_cnt = 0;
55*e7be843bSPierre Pronchery     BIO_MSG *thismsg;
56*e7be843bSPierre Pronchery     QTEST_DATA *bdata = BIO_get_data(bio);
57*e7be843bSPierre Pronchery 
58*e7be843bSPierre Pronchery     if (!TEST_ptr(next) || !TEST_ptr(bdata))
59*e7be843bSPierre Pronchery         return 0;
60*e7be843bSPierre Pronchery 
61*e7be843bSPierre Pronchery     /*
62*e7be843bSPierre Pronchery      * For simplicity we assume that all elements in the msg array have the
63*e7be843bSPierre Pronchery      * same data_len. They are not required to by the API, but it would be quite
64*e7be843bSPierre Pronchery      * strange for that not to be the case - and our code that calls
65*e7be843bSPierre Pronchery      * BIO_recvmmsg does do this (which is all that is important for this test
66*e7be843bSPierre Pronchery      * code). We test the invariant here.
67*e7be843bSPierre Pronchery      */
68*e7be843bSPierre Pronchery     for (i = 0; i < num_msg; i++) {
69*e7be843bSPierre Pronchery         if (i == 0)
70*e7be843bSPierre Pronchery             data_len = msg[i].data_len;
71*e7be843bSPierre Pronchery         else if (!TEST_size_t_eq(msg[i].data_len, data_len))
72*e7be843bSPierre Pronchery             return 0;
73*e7be843bSPierre Pronchery     }
74*e7be843bSPierre Pronchery 
75*e7be843bSPierre Pronchery     if (!BIO_recvmmsg(next, msg, stride, num_msg, flags, msgs_processed))
76*e7be843bSPierre Pronchery         return 0;
77*e7be843bSPierre Pronchery 
78*e7be843bSPierre Pronchery     msg_cnt = *msgs_processed;
79*e7be843bSPierre Pronchery     if (msg_cnt == num_msg)
80*e7be843bSPierre Pronchery         return 1; /* We've used all our slots and can't split any more */
81*e7be843bSPierre Pronchery     assert(msg_cnt < num_msg);
82*e7be843bSPierre Pronchery 
83*e7be843bSPierre Pronchery     for (i = 0, thismsg = msg; i < msg_cnt; i++, thismsg++) {
84*e7be843bSPierre Pronchery         QUIC_PKT_HDR hdr;
85*e7be843bSPierre Pronchery         PACKET pkt;
86*e7be843bSPierre Pronchery         size_t remain;
87*e7be843bSPierre Pronchery 
88*e7be843bSPierre Pronchery         if (!PACKET_buf_init(&pkt, thismsg->data, thismsg->data_len))
89*e7be843bSPierre Pronchery             return 0;
90*e7be843bSPierre Pronchery 
91*e7be843bSPierre Pronchery         /* Decode the packet header */
92*e7be843bSPierre Pronchery         if (ossl_quic_wire_decode_pkt_hdr(&pkt, bdata->short_conn_id_len,
93*e7be843bSPierre Pronchery                                           0, 0, &hdr, NULL, NULL) != 1)
94*e7be843bSPierre Pronchery             return 0;
95*e7be843bSPierre Pronchery         remain = PACKET_remaining(&pkt);
96*e7be843bSPierre Pronchery         if (remain > 0) {
97*e7be843bSPierre Pronchery             for (j = msg_cnt; j > i; j--) {
98*e7be843bSPierre Pronchery                 if (!bio_msg_copy(&msg[j], &msg[j - 1]))
99*e7be843bSPierre Pronchery                     return 0;
100*e7be843bSPierre Pronchery             }
101*e7be843bSPierre Pronchery             thismsg->data_len -= remain;
102*e7be843bSPierre Pronchery             msg[i + 1].data_len = remain;
103*e7be843bSPierre Pronchery             memmove(msg[i + 1].data,
104*e7be843bSPierre Pronchery                     (unsigned char *)msg[i + 1].data + thismsg->data_len,
105*e7be843bSPierre Pronchery                     remain);
106*e7be843bSPierre Pronchery             msg_cnt++;
107*e7be843bSPierre Pronchery         }
108*e7be843bSPierre Pronchery     }
109*e7be843bSPierre Pronchery 
110*e7be843bSPierre Pronchery     *msgs_processed = msg_cnt;
111*e7be843bSPierre Pronchery     return 1;
112*e7be843bSPierre Pronchery }
113*e7be843bSPierre Pronchery 
114*e7be843bSPierre Pronchery /* Choose a sufficiently large type likely to be unused for this custom BIO */
115*e7be843bSPierre Pronchery #define BIO_TYPE_PKT_SPLIT_DGRAM_FILTER  (0x81 | BIO_TYPE_FILTER)
116*e7be843bSPierre Pronchery 
117*e7be843bSPierre Pronchery static BIO_METHOD *method_pkt_split_dgram = NULL;
118*e7be843bSPierre Pronchery 
119*e7be843bSPierre Pronchery /* Note: Not thread safe! */
bio_f_pkt_split_dgram_filter(void)120*e7be843bSPierre Pronchery const BIO_METHOD *bio_f_pkt_split_dgram_filter(void)
121*e7be843bSPierre Pronchery {
122*e7be843bSPierre Pronchery     if (method_pkt_split_dgram == NULL) {
123*e7be843bSPierre Pronchery         method_pkt_split_dgram = BIO_meth_new(BIO_TYPE_PKT_SPLIT_DGRAM_FILTER,
124*e7be843bSPierre Pronchery                                               "Packet splitting datagram filter");
125*e7be843bSPierre Pronchery         if (method_pkt_split_dgram == NULL
126*e7be843bSPierre Pronchery             || !BIO_meth_set_ctrl(method_pkt_split_dgram, pkt_split_dgram_ctrl)
127*e7be843bSPierre Pronchery             || !BIO_meth_set_sendmmsg(method_pkt_split_dgram,
128*e7be843bSPierre Pronchery                                       pkt_split_dgram_sendmmsg)
129*e7be843bSPierre Pronchery             || !BIO_meth_set_recvmmsg(method_pkt_split_dgram,
130*e7be843bSPierre Pronchery                                       pkt_split_dgram_recvmmsg))
131*e7be843bSPierre Pronchery             return NULL;
132*e7be843bSPierre Pronchery     }
133*e7be843bSPierre Pronchery     return method_pkt_split_dgram;
134*e7be843bSPierre Pronchery }
135*e7be843bSPierre Pronchery 
bio_f_pkt_split_dgram_filter_free(void)136*e7be843bSPierre Pronchery void bio_f_pkt_split_dgram_filter_free(void)
137*e7be843bSPierre Pronchery {
138*e7be843bSPierre Pronchery     BIO_meth_free(method_pkt_split_dgram);
139*e7be843bSPierre Pronchery }
140