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 part 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/quic.h>
14 :
15 : #include "common.h"
16 : #include "stream.h"
17 :
18 : /* Check if a stream ID is valid for sending. */
19 2252848 : static bool quic_stream_id_send(s64 stream_id, bool is_serv)
20 : {
21 2252848 : u8 type = (stream_id & QUIC_STREAM_TYPE_MASK);
22 :
23 2252848 : if (is_serv) {
24 26267 : if (type == QUIC_STREAM_TYPE_CLIENT_UNI)
25 : return false;
26 2226581 : } else if (type == QUIC_STREAM_TYPE_SERVER_UNI) {
27 : return false;
28 : }
29 : return true;
30 : }
31 :
32 : /* Check if a stream ID is valid for receiving. */
33 6372034 : static bool quic_stream_id_recv(s64 stream_id, bool is_serv)
34 : {
35 6372034 : u8 type = (stream_id & QUIC_STREAM_TYPE_MASK);
36 :
37 6372034 : if (is_serv) {
38 6189927 : if (type == QUIC_STREAM_TYPE_SERVER_UNI)
39 : return false;
40 182107 : } else if (type == QUIC_STREAM_TYPE_CLIENT_UNI) {
41 : return false;
42 : }
43 : return true;
44 : }
45 :
46 : /* Check if a stream ID was initiated locally. */
47 34990 : static bool quic_stream_id_local(s64 stream_id, u8 is_serv)
48 : {
49 34990 : return is_serv ^ !(stream_id & QUIC_STREAM_TYPE_SERVER_MASK);
50 : }
51 :
52 : /* Check if a stream ID represents a unidirectional stream. */
53 123566 : static bool quic_stream_id_uni(s64 stream_id)
54 : {
55 123566 : return stream_id & QUIC_STREAM_TYPE_UNI_MASK;
56 : }
57 :
58 8610192 : struct quic_stream *quic_stream_find(struct quic_stream_table *streams, s64 stream_id)
59 : {
60 8610192 : struct quic_hash_head *head = quic_stream_head(&streams->ht, stream_id);
61 8609649 : struct quic_stream *stream;
62 :
63 18500328 : hlist_for_each_entry(stream, &head->head, node) {
64 9239829 : if (stream->id == stream_id)
65 : break;
66 : }
67 8609649 : return stream;
68 : }
69 :
70 20274 : static void quic_stream_add(struct quic_stream_table *streams, struct quic_stream *stream)
71 : {
72 20274 : struct quic_hash_head *head;
73 :
74 20274 : head = quic_stream_head(&streams->ht, stream->id);
75 20274 : hlist_add_head(&stream->node, &head->head);
76 20274 : }
77 :
78 17753 : static void quic_stream_delete(struct quic_stream *stream)
79 : {
80 17753 : hlist_del_init(&stream->node);
81 17753 : kfree(stream);
82 17755 : }
83 :
84 : /* Create and register new streams for sending. */
85 9006 : static struct quic_stream *quic_stream_send_create(struct quic_stream_table *streams,
86 : s64 max_stream_id, u8 is_serv)
87 : {
88 9006 : struct quic_stream *stream;
89 9006 : s64 stream_id;
90 :
91 9006 : stream_id = streams->send.next_bidi_stream_id;
92 9006 : if (quic_stream_id_uni(max_stream_id))
93 202 : stream_id = streams->send.next_uni_stream_id;
94 :
95 : /* rfc9000#section-2.1: A stream ID that is used out of order results in all streams
96 : * of that type with lower-numbered stream IDs also being opened.
97 : */
98 19224 : while (stream_id <= max_stream_id) {
99 10218 : stream = kzalloc(sizeof(*stream), GFP_KERNEL);
100 10218 : if (!stream)
101 : return NULL;
102 :
103 10218 : stream->id = stream_id;
104 10218 : if (quic_stream_id_uni(stream_id)) {
105 1010 : stream->send.max_bytes = streams->send.max_stream_data_uni;
106 :
107 1010 : if (streams->send.next_uni_stream_id < stream_id + QUIC_STREAM_ID_STEP)
108 1010 : streams->send.next_uni_stream_id = stream_id + QUIC_STREAM_ID_STEP;
109 1010 : streams->send.streams_uni++;
110 :
111 1010 : quic_stream_add(streams, stream);
112 1010 : stream_id += QUIC_STREAM_ID_STEP;
113 1010 : continue;
114 : }
115 :
116 9208 : if (streams->send.next_bidi_stream_id < stream_id + QUIC_STREAM_ID_STEP)
117 9208 : streams->send.next_bidi_stream_id = stream_id + QUIC_STREAM_ID_STEP;
118 9208 : streams->send.streams_bidi++;
119 :
120 9208 : if (quic_stream_id_local(stream_id, is_serv)) {
121 9208 : stream->send.max_bytes = streams->send.max_stream_data_bidi_remote;
122 9208 : stream->recv.max_bytes = streams->recv.max_stream_data_bidi_local;
123 : } else {
124 0 : stream->send.max_bytes = streams->send.max_stream_data_bidi_local;
125 0 : stream->recv.max_bytes = streams->recv.max_stream_data_bidi_remote;
126 : }
127 9208 : stream->recv.window = stream->recv.max_bytes;
128 :
129 9208 : quic_stream_add(streams, stream);
130 9208 : stream_id += QUIC_STREAM_ID_STEP;
131 : }
132 : return stream;
133 : }
134 :
135 : /* Create and register new streams for receiving. */
136 8827 : static struct quic_stream *quic_stream_recv_create(struct quic_stream_table *streams,
137 : s64 max_stream_id, u8 is_serv)
138 : {
139 8827 : struct quic_stream *stream;
140 8827 : s64 stream_id;
141 :
142 8827 : stream_id = streams->recv.next_bidi_stream_id;
143 8827 : if (quic_stream_id_uni(max_stream_id))
144 179 : stream_id = streams->recv.next_uni_stream_id;
145 :
146 : /* rfc9000#section-2.1: A stream ID that is used out of order results in all streams
147 : * of that type with lower-numbered stream IDs also being opened.
148 : */
149 18883 : while (stream_id <= max_stream_id) {
150 10056 : stream = kzalloc(sizeof(*stream), GFP_ATOMIC);
151 10056 : if (!stream)
152 : return NULL;
153 :
154 10056 : stream->id = stream_id;
155 10056 : if (quic_stream_id_uni(stream_id)) {
156 1004 : stream->recv.window = streams->recv.max_stream_data_uni;
157 1004 : stream->recv.max_bytes = stream->recv.window;
158 :
159 1004 : if (streams->recv.next_uni_stream_id < stream_id + QUIC_STREAM_ID_STEP)
160 1004 : streams->recv.next_uni_stream_id = stream_id + QUIC_STREAM_ID_STEP;
161 1004 : streams->recv.streams_uni++;
162 :
163 1004 : quic_stream_add(streams, stream);
164 1004 : stream_id += QUIC_STREAM_ID_STEP;
165 1004 : continue;
166 : }
167 :
168 9052 : if (streams->recv.next_bidi_stream_id < stream_id + QUIC_STREAM_ID_STEP)
169 9052 : streams->recv.next_bidi_stream_id = stream_id + QUIC_STREAM_ID_STEP;
170 9052 : streams->recv.streams_bidi++;
171 :
172 9052 : if (quic_stream_id_local(stream_id, is_serv)) {
173 0 : stream->send.max_bytes = streams->send.max_stream_data_bidi_remote;
174 0 : stream->recv.max_bytes = streams->recv.max_stream_data_bidi_local;
175 : } else {
176 9052 : stream->send.max_bytes = streams->send.max_stream_data_bidi_local;
177 9052 : stream->recv.max_bytes = streams->recv.max_stream_data_bidi_remote;
178 : }
179 9052 : stream->recv.window = stream->recv.max_bytes;
180 :
181 9052 : quic_stream_add(streams, stream);
182 9052 : stream_id += QUIC_STREAM_ID_STEP;
183 : }
184 : return stream;
185 : }
186 :
187 : /* Check if a send stream ID is already closed. */
188 9962 : static bool quic_stream_id_send_closed(struct quic_stream_table *streams, s64 stream_id)
189 : {
190 9962 : if (quic_stream_id_uni(stream_id)) {
191 222 : if (stream_id < streams->send.next_uni_stream_id)
192 : return true;
193 : } else {
194 9740 : if (stream_id < streams->send.next_bidi_stream_id)
195 : return true;
196 : }
197 : return false;
198 : }
199 :
200 : /* Check if a receive stream ID is already closed. */
201 8836 : static bool quic_stream_id_recv_closed(struct quic_stream_table *streams, s64 stream_id)
202 : {
203 8836 : if (quic_stream_id_uni(stream_id)) {
204 179 : if (stream_id < streams->recv.next_uni_stream_id)
205 : return true;
206 : } else {
207 8657 : if (stream_id < streams->recv.next_bidi_stream_id)
208 : return true;
209 : }
210 : return false;
211 : }
212 :
213 : /* Check if a receive stream ID exceeds would exceed local's limits. */
214 8827 : static bool quic_stream_id_recv_exceeds(struct quic_stream_table *streams, s64 stream_id)
215 : {
216 8827 : if (quic_stream_id_uni(stream_id)) {
217 179 : if (stream_id > streams->recv.max_uni_stream_id)
218 : return true;
219 : } else {
220 8648 : if (stream_id > streams->recv.max_bidi_stream_id)
221 : return true;
222 : }
223 : return false;
224 : }
225 :
226 : /* Check if a send stream ID would exceed peer's limits. */
227 13709 : bool quic_stream_id_send_exceeds(struct quic_stream_table *streams, s64 stream_id)
228 : {
229 13709 : u64 nstreams;
230 :
231 13709 : if (quic_stream_id_uni(stream_id)) {
232 218 : if (stream_id > streams->send.max_uni_stream_id)
233 : return true;
234 : } else {
235 13491 : if (stream_id > streams->send.max_bidi_stream_id)
236 : return true;
237 : }
238 :
239 9887 : if (quic_stream_id_uni(stream_id)) {
240 202 : stream_id -= streams->send.next_uni_stream_id;
241 202 : nstreams = quic_stream_id_to_streams(stream_id);
242 202 : if (nstreams + streams->send.streams_uni > streams->send.max_streams_uni)
243 0 : return true;
244 : } else {
245 9685 : stream_id -= streams->send.next_bidi_stream_id;
246 9685 : nstreams = quic_stream_id_to_streams(stream_id);
247 9685 : if (nstreams + streams->send.streams_bidi > streams->send.max_streams_bidi)
248 0 : return true;
249 : }
250 : return false;
251 : }
252 :
253 : /* Get or create a send stream by ID. */
254 2244021 : struct quic_stream *quic_stream_send_get(struct quic_stream_table *streams, s64 stream_id,
255 : u32 flags, bool is_serv)
256 : {
257 2244021 : struct quic_stream *stream;
258 :
259 2244021 : if (!quic_stream_id_send(stream_id, is_serv))
260 : return ERR_PTR(-EINVAL);
261 :
262 2244021 : stream = quic_stream_find(streams, stream_id);
263 2244021 : if (stream) {
264 2234090 : if ((flags & MSG_STREAM_NEW) &&
265 112 : stream->send.state != QUIC_STREAM_SEND_STATE_READY)
266 : return ERR_PTR(-EINVAL);
267 2234078 : return stream;
268 : }
269 :
270 9931 : if (quic_stream_id_send_closed(streams, stream_id))
271 : return ERR_PTR(-ENOSTR);
272 :
273 9907 : if (!(flags & MSG_STREAM_NEW))
274 : return ERR_PTR(-EINVAL);
275 :
276 9903 : if (quic_stream_id_send_exceeds(streams, stream_id))
277 : return ERR_PTR(-EAGAIN);
278 :
279 9006 : stream = quic_stream_send_create(streams, stream_id, is_serv);
280 9006 : if (!stream)
281 : return ERR_PTR(-ENOSTR);
282 9006 : streams->send.active_stream_id = stream_id;
283 9006 : return stream;
284 : }
285 :
286 : /* Get or create a receive stream by ID. */
287 6372034 : struct quic_stream *quic_stream_recv_get(struct quic_stream_table *streams, s64 stream_id,
288 : bool is_serv)
289 : {
290 6372034 : struct quic_stream *stream;
291 :
292 6372034 : if (!quic_stream_id_recv(stream_id, is_serv))
293 : return ERR_PTR(-EINVAL);
294 :
295 6372034 : stream = quic_stream_find(streams, stream_id);
296 6372034 : if (stream)
297 : return stream;
298 :
299 8867 : if (quic_stream_id_local(stream_id, is_serv)) {
300 31 : if (quic_stream_id_send_closed(streams, stream_id))
301 : return ERR_PTR(-ENOSTR);
302 0 : return ERR_PTR(-EINVAL);
303 : }
304 :
305 8836 : if (quic_stream_id_recv_closed(streams, stream_id))
306 : return ERR_PTR(-ENOSTR);
307 :
308 8827 : if (quic_stream_id_recv_exceeds(streams, stream_id))
309 : return ERR_PTR(-EAGAIN);
310 :
311 8827 : stream = quic_stream_recv_create(streams, stream_id, is_serv);
312 8827 : if (!stream)
313 : return ERR_PTR(-ENOSTR);
314 8827 : if (quic_stream_id_send(stream_id, is_serv))
315 8648 : streams->send.active_stream_id = stream_id;
316 : return stream;
317 : }
318 :
319 : /* Release or clean up a send stream. This function updates stream counters and state when
320 : * a send stream has either successfully sent all data or has been reset.
321 : */
322 17656 : void quic_stream_send_put(struct quic_stream_table *streams, struct quic_stream *stream,
323 : bool is_serv)
324 : {
325 17656 : if (quic_stream_id_uni(stream->id)) {
326 : /* For unidirectional streams, decrement uni count and delete immediately. */
327 138 : streams->send.streams_uni--;
328 138 : quic_stream_delete(stream);
329 138 : return;
330 : }
331 :
332 : /* For bidi streams, only proceed if receive side is in a final state. */
333 17518 : if (stream->recv.state != QUIC_STREAM_RECV_STATE_RECVD &&
334 17518 : stream->recv.state != QUIC_STREAM_RECV_STATE_READ &&
335 : stream->recv.state != QUIC_STREAM_RECV_STATE_RESET_RECVD)
336 : return;
337 :
338 11907 : if (quic_stream_id_local(stream->id, is_serv)) {
339 : /* Local-initiated stream: mark send done and decrement send.bidi count. */
340 3241 : if (!stream->send.done) {
341 3241 : stream->send.done = 1;
342 3241 : streams->send.streams_bidi--;
343 : }
344 3241 : goto out;
345 : }
346 : /* Remote-initiated stream: mark recv done and decrement recv bidi count. */
347 8666 : if (!stream->recv.done) {
348 8666 : stream->recv.done = 1;
349 8666 : streams->recv.streams_bidi--;
350 8666 : streams->recv.bidi_pending = 1;
351 : }
352 0 : out:
353 : /* Delete stream if fully read or no data received. */
354 11907 : if (stream->recv.state == QUIC_STREAM_RECV_STATE_READ || !stream->recv.offset)
355 8853 : quic_stream_delete(stream);
356 : }
357 :
358 : /* Release or clean up a receive stream. This function updates stream counters and state when
359 : * the receive side has either consumed all data or has been reset.
360 : */
361 35296 : void quic_stream_recv_put(struct quic_stream_table *streams, struct quic_stream *stream,
362 : bool is_serv)
363 : {
364 35296 : if (quic_stream_id_uni(stream->id)) {
365 : /* For uni streams, decrement uni count and mark done. */
366 268 : if (!stream->recv.done) {
367 142 : stream->recv.done = 1;
368 142 : streams->recv.streams_uni--;
369 142 : streams->recv.uni_pending = 1;
370 : }
371 268 : goto out;
372 : }
373 :
374 : /* For bidi streams, only proceed if send side is in a final state. */
375 35028 : if (stream->send.state != QUIC_STREAM_SEND_STATE_RECVD &&
376 : stream->send.state != QUIC_STREAM_SEND_STATE_RESET_RECVD)
377 : return;
378 :
379 14216 : if (quic_stream_id_local(stream->id, is_serv)) {
380 : /* Local-initiated stream: mark send done and decrement send.bidi count. */
381 14216 : if (!stream->send.done) {
382 5581 : stream->send.done = 1;
383 5581 : streams->send.streams_bidi--;
384 : }
385 14216 : goto out;
386 : }
387 : /* Remote-initiated stream: mark recv done and decrement recv bidi count. */
388 0 : if (!stream->recv.done) {
389 0 : stream->recv.done = 1;
390 0 : streams->recv.streams_bidi--;
391 0 : streams->recv.bidi_pending = 1;
392 : }
393 0 : out:
394 : /* Delete stream if fully read or no data received. */
395 14484 : if (stream->recv.state == QUIC_STREAM_RECV_STATE_READ || !stream->recv.offset)
396 8765 : quic_stream_delete(stream);
397 : }
398 :
399 : /* Updates the maximum allowed incoming stream IDs if any streams were recently closed.
400 : * Recalculates the max_uni and max_bidi stream ID limits based on the number of open
401 : * streams and whether any were marked for deletion.
402 : *
403 : * Returns true if either max_uni or max_bidi was updated, indicating that a
404 : * MAX_STREAMS_UNI or MAX_STREAMS_BIDI frame should be sent to the peer.
405 : */
406 6570917 : bool quic_stream_max_streams_update(struct quic_stream_table *streams, s64 *max_uni, s64 *max_bidi)
407 : {
408 6570917 : if (streams->recv.uni_pending) {
409 142 : streams->recv.max_uni_stream_id =
410 142 : streams->recv.next_uni_stream_id - QUIC_STREAM_ID_STEP +
411 142 : ((streams->recv.max_streams_uni - streams->recv.streams_uni) <<
412 : QUIC_STREAM_TYPE_BITS);
413 142 : *max_uni = quic_stream_id_to_streams(streams->recv.max_uni_stream_id);
414 142 : streams->recv.uni_pending = 0;
415 : }
416 6570917 : if (streams->recv.bidi_pending) {
417 689 : streams->recv.max_bidi_stream_id =
418 689 : streams->recv.next_bidi_stream_id - QUIC_STREAM_ID_STEP +
419 689 : ((streams->recv.max_streams_bidi - streams->recv.streams_bidi) <<
420 : QUIC_STREAM_TYPE_BITS);
421 689 : *max_bidi = quic_stream_id_to_streams(streams->recv.max_bidi_stream_id);
422 689 : streams->recv.bidi_pending = 0;
423 : }
424 :
425 6570917 : return *max_uni || *max_bidi;
426 : }
427 :
428 1119 : int quic_stream_init(struct quic_stream_table *streams)
429 : {
430 1119 : struct quic_hash_table *ht = &streams->ht;
431 1119 : struct quic_hash_head *head;
432 1119 : int i, size = QUIC_HT_SIZE;
433 :
434 1119 : head = kmalloc_array(size, sizeof(*head), GFP_KERNEL);
435 1119 : if (!head)
436 : return -ENOMEM;
437 72735 : for (i = 0; i < size; i++)
438 71616 : INIT_HLIST_HEAD(&head[i].head);
439 1119 : ht->size = size;
440 1119 : ht->hash = head;
441 1119 : return 0;
442 : }
443 :
444 1118 : void quic_stream_free(struct quic_stream_table *streams)
445 : {
446 1118 : struct quic_hash_table *ht = &streams->ht;
447 1118 : struct quic_hash_head *head;
448 1118 : struct quic_stream *stream;
449 1118 : struct hlist_node *tmp;
450 1118 : int i;
451 :
452 72653 : for (i = 0; i < ht->size; i++) {
453 71535 : head = &ht->hash[i];
454 146733 : hlist_for_each_entry_safe(stream, tmp, &head->head, node) {
455 2146 : hlist_del_init(&stream->node);
456 2146 : kfree(stream);
457 : }
458 : }
459 1118 : kfree(ht->hash);
460 1118 : }
461 :
462 : /* Populate transport parameters from stream hash table. */
463 2079 : void quic_stream_get_param(struct quic_stream_table *streams, struct quic_transport_param *p,
464 : bool is_serv)
465 : {
466 2079 : if (p->remote) {
467 24 : p->max_stream_data_bidi_remote = streams->send.max_stream_data_bidi_remote;
468 24 : p->max_stream_data_bidi_local = streams->send.max_stream_data_bidi_local;
469 24 : p->max_stream_data_uni = streams->send.max_stream_data_uni;
470 24 : p->max_streams_bidi = streams->send.max_streams_bidi;
471 24 : p->max_streams_uni = streams->send.max_streams_uni;
472 24 : return;
473 : }
474 :
475 2055 : p->max_stream_data_bidi_remote = streams->recv.max_stream_data_bidi_remote;
476 2055 : p->max_stream_data_bidi_local = streams->recv.max_stream_data_bidi_local;
477 2055 : p->max_stream_data_uni = streams->recv.max_stream_data_uni;
478 2055 : p->max_streams_bidi = streams->recv.max_streams_bidi;
479 2055 : p->max_streams_uni = streams->recv.max_streams_uni;
480 : }
481 :
482 : /* Configure stream hashtable from transport parameters. */
483 3172 : void quic_stream_set_param(struct quic_stream_table *streams, struct quic_transport_param *p,
484 : bool is_serv)
485 : {
486 3172 : u8 type;
487 :
488 3172 : if (p->remote) {
489 1004 : streams->send.max_stream_data_bidi_local = p->max_stream_data_bidi_local;
490 1004 : streams->send.max_stream_data_bidi_remote = p->max_stream_data_bidi_remote;
491 1004 : streams->send.max_stream_data_uni = p->max_stream_data_uni;
492 1004 : streams->send.max_streams_bidi = p->max_streams_bidi;
493 1004 : streams->send.max_streams_uni = p->max_streams_uni;
494 1004 : streams->send.active_stream_id = -1;
495 :
496 1004 : if (is_serv) {
497 420 : type = QUIC_STREAM_TYPE_SERVER_BIDI;
498 420 : streams->send.max_bidi_stream_id =
499 420 : quic_stream_streams_to_id(p->max_streams_bidi, type);
500 420 : streams->send.next_bidi_stream_id = type;
501 :
502 420 : type = QUIC_STREAM_TYPE_SERVER_UNI;
503 420 : streams->send.max_uni_stream_id =
504 420 : quic_stream_streams_to_id(p->max_streams_uni, type);
505 420 : streams->send.next_uni_stream_id = type;
506 420 : return;
507 : }
508 :
509 584 : type = QUIC_STREAM_TYPE_CLIENT_BIDI;
510 584 : streams->send.max_bidi_stream_id =
511 584 : quic_stream_streams_to_id(p->max_streams_bidi, type);
512 584 : streams->send.next_bidi_stream_id = type;
513 :
514 584 : type = QUIC_STREAM_TYPE_CLIENT_UNI;
515 584 : streams->send.max_uni_stream_id =
516 584 : quic_stream_streams_to_id(p->max_streams_uni, type);
517 584 : streams->send.next_uni_stream_id = type;
518 584 : return;
519 : }
520 :
521 2168 : streams->recv.max_stream_data_bidi_local = p->max_stream_data_bidi_local;
522 2168 : streams->recv.max_stream_data_bidi_remote = p->max_stream_data_bidi_remote;
523 2168 : streams->recv.max_stream_data_uni = p->max_stream_data_uni;
524 2168 : streams->recv.max_streams_bidi = p->max_streams_bidi;
525 2168 : streams->recv.max_streams_uni = p->max_streams_uni;
526 :
527 2168 : if (is_serv) {
528 424 : type = QUIC_STREAM_TYPE_CLIENT_BIDI;
529 424 : streams->recv.max_bidi_stream_id =
530 424 : quic_stream_streams_to_id(p->max_streams_bidi, type);
531 424 : streams->recv.next_bidi_stream_id = type;
532 :
533 424 : type = QUIC_STREAM_TYPE_CLIENT_UNI;
534 424 : streams->recv.max_uni_stream_id =
535 424 : quic_stream_streams_to_id(p->max_streams_uni, type);
536 424 : streams->recv.next_uni_stream_id = type;
537 424 : return;
538 : }
539 :
540 1744 : type = QUIC_STREAM_TYPE_SERVER_BIDI;
541 1744 : streams->recv.max_bidi_stream_id =
542 1744 : quic_stream_streams_to_id(p->max_streams_bidi, type);
543 1744 : streams->recv.next_bidi_stream_id = type;
544 :
545 1744 : type = QUIC_STREAM_TYPE_SERVER_UNI;
546 1744 : streams->recv.max_uni_stream_id =
547 1744 : quic_stream_streams_to_id(p->max_streams_uni, type);
548 1744 : streams->recv.next_uni_stream_id = type;
549 : }
|