lsquic_parse_Q046.c revision c7d81ce1
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_parse_Q046.c -- Parsing functions specific to GQUIC Q046
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <string.h>
10#include <sys/queue.h>
11#ifndef WIN32
12#include <sys/types.h>
13#else
14#include <vc_compat.h>
15#endif
16
17#include "lsquic_types.h"
18#include "lsquic_packet_common.h"
19#include "lsquic_packet_in.h"
20#include "lsquic_packet_out.h"
21#include "lsquic_parse.h"
22#include "lsquic_parse_common.h"
23#include "lsquic_version.h"
24#include "lsquic.h"
25#include "lsquic_parse_gquic_be.h"
26#include "lsquic_byteswap.h"
27#include "lsquic_conn.h"
28
29#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
30#include "lsquic_logger.h"
31
32
33
34
35static unsigned
36gquic_Q046_packno_bits2len (enum packno_bits bits)
37{
38    return bits + 1;
39}
40
41
42#define iquic_packno_bits2len gquic_Q046_packno_bits2len
43
44
45static enum packno_bits
46gquic_Q046_calc_packno_bits (lsquic_packno_t packno,
47                    lsquic_packno_t least_unacked, uint64_t n_in_flight)
48{
49    uint64_t delta;
50    unsigned bits;
51
52    delta = packno - least_unacked;
53    if (n_in_flight > delta)
54        delta = n_in_flight;
55
56    delta *= 4;
57    bits = (delta >= (1ULL <<  8))
58         + (delta >= (1ULL << 16))
59         + (delta >= (1ULL << 24))
60         ;
61
62    return bits;
63}
64
65
66static unsigned
67write_packno (unsigned char *p, lsquic_packno_t packno, enum packno_bits bits)
68{
69    unsigned char *const begin = p;
70
71    switch (bits)
72    {
73    case IQUIC_PACKNO_LEN_4:
74        *p++ = packno >> 24;
75    case IQUIC_PACKNO_LEN_3:
76        *p++ = packno >> 16;
77    case IQUIC_PACKNO_LEN_2:
78        *p++ = packno >> 8;
79    default:
80        *p++ = packno;
81    }
82
83    return p - begin;
84}
85
86
87static int
88gen_short_pkt_header (const struct lsquic_conn *lconn,
89            const struct lsquic_packet_out *packet_out, unsigned char *buf,
90                                                                size_t bufsz)
91{
92    unsigned packno_len, need;
93    enum packno_bits bits;
94
95    bits = lsquic_packet_out_packno_bits(packet_out);
96    packno_len = iquic_packno_bits2len(bits);
97
98    need = 1 + 8 /* CID */ + packno_len;
99
100    if (need > bufsz)
101        return -1;
102
103    *buf++ = 0x40 | bits;
104
105    memcpy(buf, &lconn->cn_cid, 8);
106    buf += 8;
107
108    (void) write_packno(buf, packet_out->po_packno, bits);
109
110    return need;
111}
112
113
114static size_t
115gquic_Q046_packout_header_size_long (const struct lsquic_conn *lconn,
116                                                enum packet_out_flags flags)
117{
118    return GQUIC_IETF_LONG_HEADER_SIZE;
119}
120
121
122/* [draft-ietf-quic-transport-17] Section-17.2 */
123static const unsigned char header_type_to_bin[] = {
124    [HETY_INITIAL]      = 0x0,
125    [HETY_0RTT]         = 0x1,
126    [HETY_HANDSHAKE]    = 0x2,
127    [HETY_RETRY]        = 0x3,
128};
129
130
131static int
132gen_long_pkt_header (const struct lsquic_conn *lconn,
133            const struct lsquic_packet_out *packet_out, unsigned char *buf,
134                                                                size_t bufsz)
135{
136    enum packno_bits packno_bits;
137    lsquic_ver_tag_t ver_tag;
138    unsigned char *p;
139    size_t need;
140
141    need = gquic_Q046_packout_header_size_long(lconn, packet_out->po_flags);
142    if (need > bufsz)
143    {
144        errno = EINVAL;
145        return -1;
146    }
147
148    p = buf;
149    packno_bits = IQUIC_PACKNO_LEN_4;
150    *p++ = 0x80 | 0x40
151         | (header_type_to_bin[ packet_out->po_header_type ] << 4)
152         | packno_bits;
153    ver_tag = lsquic_ver2tag(lconn->cn_version);
154    memcpy(p, &ver_tag, sizeof(ver_tag));
155    p += sizeof(ver_tag);
156
157    *p++ = 0x50;
158
159    memcpy(p, &lconn->cn_cid, 8);
160    p += 8;
161
162    p += write_packno(p, packet_out->po_packno, packno_bits);
163
164
165    assert(need == (unsigned int)(p - buf));
166    return p - buf;
167}
168
169
170static int
171gquic_Q046_gen_reg_pkt_header (const struct lsquic_conn *lconn,
172            const struct lsquic_packet_out *packet_out, unsigned char *buf,
173                                                                size_t bufsz)
174{
175    if (0 == (packet_out->po_flags & PO_LONGHEAD))
176        return gen_short_pkt_header(lconn, packet_out, buf, bufsz);
177    else
178        return gen_long_pkt_header(lconn, packet_out, buf, bufsz);
179}
180
181
182static size_t
183gquic_Q046_packout_header_size_short (const struct lsquic_conn *lconn,
184                                            enum packet_out_flags flags)
185{
186    enum packno_bits bits;
187    size_t sz;
188
189    bits = (flags >> POBIT_SHIFT) & 0x3;
190    sz = 1; /* Type */
191    sz += 8; /* CID */
192    sz += iquic_packno_bits2len(bits);
193
194    return sz;
195}
196
197
198static size_t
199gquic_Q046_packout_header_size (const struct lsquic_conn *lconn,
200                                enum packet_out_flags flags)
201{
202    if (0 == (flags & PO_LONGHEAD))
203        return gquic_Q046_packout_header_size_short(lconn, flags);
204    else
205        return gquic_Q046_packout_header_size_long(lconn, flags);
206}
207
208
209static size_t
210gquic_Q046_packout_size (const struct lsquic_conn *lconn,
211                                const struct lsquic_packet_out *packet_out)
212{
213    size_t sz;
214
215    if (0 == (packet_out->po_flags & PO_LONGHEAD))
216        sz = gquic_Q046_packout_header_size_short(lconn, packet_out->po_flags);
217    else
218        sz = gquic_Q046_packout_header_size_long(lconn, packet_out->po_flags);
219
220    sz += packet_out->po_data_sz;
221    sz += QUIC_PACKET_HASH_SZ;
222
223    return sz;
224}
225
226
227const struct parse_funcs lsquic_parse_funcs_gquic_Q046 =
228{
229    .pf_gen_reg_pkt_header            =  gquic_Q046_gen_reg_pkt_header,
230    .pf_parse_packet_in_finish        =  gquic_be_parse_packet_in_finish,
231    .pf_gen_stream_frame              =  gquic_be_gen_stream_frame,
232    .pf_calc_stream_frame_header_sz   =  calc_stream_frame_header_sz_gquic,
233    .pf_parse_stream_frame            =  gquic_be_parse_stream_frame,
234    .pf_parse_ack_frame               =  gquic_be_parse_ack_frame,
235    .pf_gen_ack_frame                 =  gquic_be_gen_ack_frame,
236    .pf_gen_stop_waiting_frame        =  gquic_be_gen_stop_waiting_frame,
237    .pf_parse_stop_waiting_frame      =  gquic_be_parse_stop_waiting_frame,
238    .pf_skip_stop_waiting_frame       =  gquic_be_skip_stop_waiting_frame,
239    .pf_gen_window_update_frame       =  gquic_be_gen_window_update_frame,
240    .pf_parse_window_update_frame     =  gquic_be_parse_window_update_frame,
241    .pf_gen_blocked_frame             =  gquic_be_gen_blocked_frame,
242    .pf_parse_blocked_frame           =  gquic_be_parse_blocked_frame,
243    .pf_gen_rst_frame                 =  gquic_be_gen_rst_frame,
244    .pf_parse_rst_frame               =  gquic_be_parse_rst_frame,
245    .pf_gen_connect_close_frame       =  gquic_be_gen_connect_close_frame,
246    .pf_parse_connect_close_frame     =  gquic_be_parse_connect_close_frame,
247    .pf_gen_goaway_frame              =  gquic_be_gen_goaway_frame,
248    .pf_parse_goaway_frame            =  gquic_be_parse_goaway_frame,
249    .pf_gen_ping_frame                =  gquic_be_gen_ping_frame,
250#ifndef NDEBUG
251    .pf_write_float_time16            =  gquic_be_write_float_time16,
252    .pf_read_float_time16             =  gquic_be_read_float_time16,
253#endif
254    .pf_parse_frame_type              =  parse_frame_type_gquic_Q035_thru_Q039,
255    .pf_turn_on_fin                   =  lsquic_turn_on_fin_Q035_thru_Q039,
256    .pf_packout_size                  =  gquic_Q046_packout_size,
257    .pf_packout_header_size           =  gquic_Q046_packout_header_size,
258    .pf_calc_packno_bits              =  gquic_Q046_calc_packno_bits,
259    .pf_packno_bits2len               =  gquic_Q046_packno_bits2len,
260};
261