lsquic_mini_conn_ietf.c revision 0adf085a
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_mini_conn_ietf.c -- Mini connection used by the IETF QUIC
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <stddef.h>
10#include <stdint.h>
11#include <string.h>
12#include <sys/queue.h>
13#include <stdlib.h>
14
15#include "lsquic.h"
16#include "lsquic_int_types.h"
17#include "lsquic_sizes.h"
18#include "lsquic_hash.h"
19#include "lsquic_conn.h"
20#include "lsquic_mm.h"
21#include "lsquic_malo.h"
22#include "lsquic_engine_public.h"
23#include "lsquic_packet_common.h"
24#include "lsquic_packet_in.h"
25#include "lsquic_packet_out.h"
26#include "lsquic_parse.h"
27#include "lsquic_rtt.h"
28#include "lsquic_util.h"
29#include "lsquic_enc_sess.h"
30#include "lsquic_mini_conn_ietf.h"
31#include "lsquic_ev_log.h"
32#include "lsquic_trans_params.h"
33#include "lsquic_ietf.h"
34#include "lsquic_packet_ietf.h"
35#include "lsquic_attq.h"
36#include "lsquic_alarmset.h"
37
38#define LSQUIC_LOGGER_MODULE LSQLM_MINI_CONN
39#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(&conn->imc_conn)
40#include "lsquic_logger.h"
41
42#define MIN(a, b) ((a) < (b) ? (a) : (b))
43#define MAX(a, b) ((a) > (b) ? (a) : (b))
44
45static const struct conn_iface mini_conn_ietf_iface;
46
47static unsigned highest_bit_set (unsigned long long);
48
49
50static const enum header_type el2hety[] =
51{
52    [ENC_LEV_INIT]  = HETY_HANDSHAKE,
53    [ENC_LEV_CLEAR] = HETY_INITIAL,
54    [ENC_LEV_FORW]  = HETY_NOT_SET,
55    [ENC_LEV_EARLY] = 0,    /* Invalid */
56};
57
58
59static void
60imico_destroy_packet (struct ietf_mini_conn *conn,
61                                        struct lsquic_packet_out *packet_out)
62{
63    lsquic_packet_out_destroy(packet_out, conn->imc_enpub,
64                                                conn->imc_path.np_peer_ctx);
65}
66
67
68int
69lsquic_mini_conn_ietf_ecn_ok (const struct ietf_mini_conn *conn)
70{
71    packno_set_t acked;
72
73    /* First flight has only Initial and Handshake packets */
74    acked = conn->imc_acked_packnos[PNS_INIT]
75          | conn->imc_acked_packnos[PNS_HSK]
76          ;
77    return 0 != (conn->imc_ecn_packnos & acked);
78}
79
80
81#define imico_ecn_ok lsquic_mini_conn_ietf_ecn_ok
82
83
84static enum ecn
85imico_get_ecn (struct ietf_mini_conn *conn)
86{
87    if (!conn->imc_enpub->enp_settings.es_ecn)
88        return ECN_NOT_ECT;
89    else if (!conn->imc_sent_packnos /* We set ECT0 in first flight */
90                                                    || imico_ecn_ok(conn))
91        return ECN_ECT0;
92    else
93        return ECN_NOT_ECT;
94}
95
96
97static struct lsquic_packet_out *
98imico_get_packet_out (struct ietf_mini_conn *conn,
99                                    enum header_type header_type, size_t need)
100{
101    struct lsquic_packet_out *packet_out;
102    enum ecn ecn;
103
104    if (need)
105        TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
106            if (!(packet_out->po_flags & PO_SENT)
107                    && packet_out->po_header_type == header_type
108                    && lsquic_packet_out_avail(packet_out) >= need)
109                return packet_out;
110
111    if (conn->imc_next_packno >= MAX_PACKETS)
112    {
113        LSQ_DEBUG("ran out of outgoing packet numbers, won't allocate packet");
114        return NULL;
115    }
116
117    packet_out = lsquic_packet_out_new(&conn->imc_enpub->enp_mm, NULL, 1,
118            &conn->imc_conn, IQUIC_PACKNO_LEN_1, NULL, NULL, &conn->imc_path);
119    if (!packet_out)
120    {
121        LSQ_WARN("could not allocate packet: %s", strerror(errno));
122        return NULL;
123    }
124
125    packet_out->po_header_type = header_type;
126    packet_out->po_packno = conn->imc_next_packno++;
127    packet_out->po_flags |= PO_MINI;
128    lsquic_packet_out_set_pns(packet_out, lsquic_hety2pns[header_type]);
129    ecn = imico_get_ecn(conn);
130    packet_out->po_lflags |= ecn << POECN_SHIFT;
131    TAILQ_INSERT_TAIL(&conn->imc_packets_out, packet_out, po_next);
132    packet_out->po_loss_chain = packet_out;
133    return packet_out;
134}
135
136
137static struct ietf_mini_conn *
138cryst_get_conn (const struct mini_crypto_stream *cryst)
139{
140    return (void *)
141        ((unsigned char *) (cryst - cryst->mcs_enc_level)
142                        - offsetof(struct ietf_mini_conn, imc_streams));
143}
144
145
146struct msg_ctx
147{
148    const unsigned char       *buf;
149    const unsigned char *const end;
150};
151
152
153static size_t
154read_from_msg_ctx (void *ctx, void *buf, size_t len)
155{
156    struct msg_ctx *msg_ctx = ctx;
157    if (len > (uintptr_t) (msg_ctx->end - msg_ctx->buf))
158        len = msg_ctx->end - msg_ctx->buf;
159    memcpy(buf, msg_ctx->buf, len);
160    msg_ctx->buf += len;
161    return len;
162}
163
164
165static ssize_t
166imico_stream_write (void *stream, const void *bufp, size_t bufsz)
167{
168    struct mini_crypto_stream *const cryst = stream;
169    struct ietf_mini_conn *const conn = cryst_get_conn(cryst);
170    struct lsquic_conn *const lconn = &conn->imc_conn;
171    const struct parse_funcs *const pf = lconn->cn_pf;
172    struct msg_ctx msg_ctx = { bufp, (unsigned char *) bufp + bufsz, };
173    struct lsquic_packet_out *packet_out;
174    size_t header_sz, need;
175    const unsigned char *p;
176    int len;
177
178    if (PNS_INIT == lsquic_enclev2pns[ cryst->mcs_enc_level ]
179                                        && (conn->imc_flags & IMC_IGNORE_INIT))
180    {
181        LSQ_WARN("trying to write at the ignored Initial level");
182        return bufsz;
183    }
184
185    while (msg_ctx.buf < msg_ctx.end)
186    {
187        header_sz = lconn->cn_pf->pf_calc_crypto_frame_header_sz(
188                                                        cryst->mcs_write_off);
189        need = header_sz + 1;
190        packet_out = imico_get_packet_out(conn,
191                                        el2hety[ cryst->mcs_enc_level ], need);
192        if (!packet_out)
193            return -1;
194
195        p = msg_ctx.buf;
196        len = pf->pf_gen_crypto_frame(packet_out->po_data + packet_out->po_data_sz,
197                    lsquic_packet_out_avail(packet_out), cryst->mcs_write_off,
198                    msg_ctx.end - msg_ctx.buf, read_from_msg_ctx, &msg_ctx);
199        if (len < 0)
200            return len;
201        EV_LOG_GENERATED_CRYPTO_FRAME(LSQUIC_LOG_CONN_ID, pf,
202                                packet_out->po_data + packet_out->po_data_sz, len);
203        packet_out->po_data_sz += len;
204        packet_out->po_frame_types |= 1 << QUIC_FRAME_CRYPTO;
205        packet_out->po_flags |= PO_HELLO;
206        cryst->mcs_write_off += msg_ctx.buf - p;
207    }
208
209    assert(msg_ctx.buf == msg_ctx.end);
210    return bufsz;
211}
212
213
214static int
215imico_stream_flush (void *stream)
216{
217    return 0;
218}
219
220
221static ssize_t
222imico_stream_readf (void *stream,
223        size_t (*readf)(void *, const unsigned char *, size_t, int), void *ctx)
224{
225    struct mini_crypto_stream *const cryst = stream;
226    struct ietf_mini_conn *const conn = cryst_get_conn(cryst);
227    struct stream_frame *frame = conn->imc_last_in.frame;
228    size_t nread;
229
230    if (cryst->mcs_enc_level == conn->imc_last_in.enc_level
231            && frame && cryst->mcs_read_off == DF_ROFF(frame))
232    {
233        nread = readf(ctx, frame->data_frame.df_data
234            + frame->data_frame.df_read_off, DF_SIZE(frame)
235            - frame->data_frame.df_read_off, DF_FIN(frame));
236        cryst->mcs_read_off += nread;
237        frame->data_frame.df_read_off += nread;
238        LSQ_DEBUG("read %zu bytes at offset %"PRIu64" on enc level %u", nread,
239            DF_ROFF(frame), cryst->mcs_enc_level);
240        return nread;
241    }
242    else
243    {
244        errno = EWOULDBLOCK;
245        return -1;
246    }
247}
248
249
250static int
251imico_stream_wantX (struct mini_crypto_stream *cryst, int bit, int is_want)
252{
253    int old;
254
255    old = (cryst->mcs_flags & (1 << bit)) > 0;
256    cryst->mcs_flags &= ~(1 << bit);
257    cryst->mcs_flags |= !!is_want << bit;
258    return old;
259}
260
261
262static int
263imico_stream_wantwrite (void *stream, int is_want)
264{
265    return imico_stream_wantX(stream, MCSBIT_WANTWRITE, is_want);
266}
267
268
269static int
270imico_stream_wantread (void *stream, int is_want)
271{
272    return imico_stream_wantX(stream, MCSBIT_WANTREAD, is_want);
273}
274
275
276static enum enc_level
277imico_stream_enc_level (void *stream)
278{
279    struct mini_crypto_stream *const cryst = stream;
280    return cryst->mcs_enc_level;
281}
282
283
284static const struct crypto_stream_if crypto_stream_if =
285{
286    .csi_write      = imico_stream_write,
287    .csi_flush      = imico_stream_flush,
288    .csi_readf      = imico_stream_readf,
289    .csi_wantwrite  = imico_stream_wantwrite,
290    .csi_wantread   = imico_stream_wantread,
291    .csi_enc_level  = imico_stream_enc_level,
292};
293
294
295static int
296is_first_packet_ok (const struct lsquic_packet_in *packet_in)
297{
298    /* TODO: Move decryption of the first packet into this function? */
299    return 1;   /* TODO */
300}
301
302
303struct lsquic_conn *
304lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
305               const struct lsquic_packet_in *packet_in,
306           enum lsquic_version version, int is_ipv4, const lsquic_cid_t *odcid)
307{
308    struct ietf_mini_conn *conn;
309    enc_session_t *enc_sess;
310    enum enc_level i;
311    const struct enc_session_funcs_iquic *esfi;
312
313    if (!is_first_packet_ok(packet_in))
314        return NULL;
315
316    conn = lsquic_malo_get(enpub->enp_mm.malo.mini_conn_ietf);
317    if (!conn)
318    {
319        LSQ_LOG1(LSQ_LOG_WARN, "cannot allocate mini connection: %s",
320                                                            strerror(errno));
321        return NULL;
322    }
323    memset(conn, 0, sizeof(*conn));
324    conn->imc_conn.cn_if = &mini_conn_ietf_iface;
325    conn->imc_conn.cn_cces = conn->imc_cces;
326    conn->imc_conn.cn_n_cces = sizeof(conn->imc_cces)
327                                                / sizeof(conn->imc_cces[0]);
328    conn->imc_cces[0].cce_cid = packet_in->pi_dcid;
329    conn->imc_cces[0].cce_flags = CCE_USED;
330    conn->imc_conn.cn_cces_mask = 1;
331    lsquic_scid_from_packet_in(packet_in, &conn->imc_path.np_dcid);
332    LSQ_DEBUGC("recv SCID from client %"CID_FMT, CID_BITS(&conn->imc_cces[0].cce_cid));
333    LSQ_DEBUGC("recv DCID from client %"CID_FMT, CID_BITS(&conn->imc_path.np_dcid));
334
335    /* Generate new SCID. Since is not the original SCID, it is given
336     * a sequence number (0) and therefore can be retired by the client.
337     */
338    lsquic_generate_cid(&conn->imc_conn.cn_cces[1].cce_cid,
339                                        enpub->enp_settings.es_scid_len);
340    LSQ_DEBUGC("generated SCID %"CID_FMT" at index %u, switching to it",
341                CID_BITS(&conn->imc_conn.cn_cces[1].cce_cid), 1);
342    conn->imc_conn.cn_cces[1].cce_flags = CCE_SEQNO | CCE_USED;
343    conn->imc_conn.cn_cces_mask |= 1u << 1;
344    conn->imc_conn.cn_cur_cce_idx = 1;
345
346    conn->imc_conn.cn_flags = LSCONN_MINI|LSCONN_IETF|LSCONN_SERVER;
347
348    for (i = 0; i < N_ENC_LEVS; ++i)
349    {
350        conn->imc_streams[i].mcs_enc_level = i;
351        conn->imc_stream_ps[i] = &conn->imc_streams[i];
352    }
353
354    esfi = select_esf_iquic_by_ver(version);
355    enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
356                &packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
357                odcid);
358    if (!enc_sess)
359    {
360        lsquic_malo_put(conn);
361        return NULL;
362    }
363
364    conn->imc_enpub = enpub;
365    conn->imc_created = packet_in->pi_received;
366    conn->imc_path.np_pack_size = is_ipv4 ? IQUIC_MAX_IPv4_PACKET_SZ
367                                                    : IQUIC_MAX_IPv6_PACKET_SZ;
368#ifndef NDEBUG
369    if (getenv("LSQUIC_CN_PACK_SIZE"))
370        conn->imc_path.np_pack_size = atoi(getenv("LSQUIC_CN_PACK_SIZE"));
371#endif
372    conn->imc_conn.cn_version = version;
373    conn->imc_conn.cn_pf = select_pf_by_ver(version);
374    conn->imc_conn.cn_esf.i = esfi;
375    conn->imc_conn.cn_enc_session = enc_sess;
376    conn->imc_conn.cn_esf_c = select_esf_common_by_ver(version);
377    TAILQ_INIT(&conn->imc_packets_out);
378    TAILQ_INIT(&conn->imc_app_packets);
379
380    LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
381                                                conn, conn->imc_path.np_pack_size);
382    return &conn->imc_conn;
383}
384
385
386static void
387ietf_mini_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
388{
389    assert(0);
390}
391
392
393static void
394ietf_mini_conn_ci_destroy (struct lsquic_conn *lconn)
395{
396    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
397    struct lsquic_packet_out *packet_out;
398    struct lsquic_packet_in *packet_in;
399
400    while ((packet_out = TAILQ_FIRST(&conn->imc_packets_out)))
401    {
402        TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
403        imico_destroy_packet(conn, packet_out);
404    }
405    while ((packet_in = TAILQ_FIRST(&conn->imc_app_packets)))
406    {
407        TAILQ_REMOVE(&conn->imc_app_packets, packet_in, pi_next);
408        lsquic_packet_in_put(&conn->imc_enpub->enp_mm, packet_in);
409    }
410    if (lconn->cn_enc_session)
411        lconn->cn_esf.i->esfi_destroy(lconn->cn_enc_session);
412    LSQ_DEBUG("ietf_mini_conn_ci_destroyed");
413    lsquic_malo_put(conn);
414}
415
416
417static struct lsquic_engine *
418ietf_mini_conn_ci_get_engine (struct lsquic_conn *lconn)
419{
420    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
421    return conn->imc_enpub->enp_engine;
422}
423
424
425static void
426ietf_mini_conn_ci_hsk_done (struct lsquic_conn *lconn,
427                                                enum lsquic_hsk_status status)
428{
429    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
430
431    switch (status)
432    {
433    case LSQ_HSK_OK:
434    case LSQ_HSK_0RTT_OK:
435        conn->imc_flags |= IMC_HSK_OK;
436        conn->imc_conn.cn_flags |= LSCONN_HANDSHAKE_DONE;
437        LSQ_DEBUG("handshake OK");
438        break;
439    default:
440        assert(0);
441        /* fall-through */
442    case LSQ_HSK_FAIL:
443        conn->imc_flags |= IMC_HSK_FAILED|IMC_ERROR;
444        LSQ_INFO("handshake failed");
445        break;
446    }
447}
448
449
450static void
451ietf_mini_conn_ci_tls_alert (struct lsquic_conn *lconn, uint8_t alert)
452{
453    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
454    LSQ_DEBUG("got TLS alert %"PRIu8, alert);
455    conn->imc_flags |= IMC_ERROR|IMC_TLS_ALERT;
456    conn->imc_tls_alert = alert;
457}
458
459
460static int
461ietf_mini_conn_ci_is_tickable (struct lsquic_conn *lconn)
462{
463    /* A mini connection is never tickable:  Either there are incoming
464     * packets, in which case, the connection is going to be ticked, or
465     * there is an alarm pending, in which case it will be handled via
466     * the attq.
467     */
468    return 0;
469}
470
471
472static int
473imico_can_send (const struct ietf_mini_conn *conn, size_t size)
474{
475    return (conn->imc_flags & IMC_ADDR_VALIDATED)
476        || conn->imc_bytes_in * 3 >= conn->imc_bytes_out + size
477        ;
478}
479
480
481static struct lsquic_packet_out *
482ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
483{
484    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
485    struct lsquic_packet_out *packet_out;
486    size_t packet_size;
487
488    TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
489    {
490        if (packet_out->po_flags & PO_SENT)
491            continue;
492        packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
493        if (size == 0 || packet_size + size <= conn->imc_path.np_pack_size)
494        {
495            if (!imico_can_send(conn, packet_size + IQUIC_TAG_LEN))
496            {
497                LSQ_DEBUG("cannot send packet %"PRIu64" of size %zu: client "
498                    "address has not been validated", packet_out->po_packno,
499                    packet_size + IQUIC_TAG_LEN);
500                return NULL;
501            }
502            packet_out->po_flags |= PO_SENT;
503            conn->imc_bytes_out += packet_size + IQUIC_TAG_LEN;
504            if (size == 0)
505                LSQ_DEBUG("packet_to_send: %"PRIu64, packet_out->po_packno);
506            else
507                LSQ_DEBUG("packet_to_send: %"PRIu64" (coalesced)",
508                                                    packet_out->po_packno);
509            return packet_out;
510        }
511        else
512            return NULL;
513    }
514
515    return NULL;
516}
517
518
519static int
520imico_calc_retx_timeout (const struct ietf_mini_conn *conn)
521{
522    lsquic_time_t to;
523    to = lsquic_rtt_stats_get_srtt(&conn->imc_rtt_stats);
524    if (to)
525    {
526        to += to / 2;
527        if (to < 10000)
528            to = 10000;
529    }
530    else
531        to = 300000;
532    return to << conn->imc_hsk_count;
533}
534
535
536static lsquic_time_t
537ietf_mini_conn_ci_next_tick_time (struct lsquic_conn *lconn, unsigned *why)
538{
539    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
540    const struct lsquic_packet_out *packet_out;
541    lsquic_time_t exp_time, retx_time;
542
543    exp_time = conn->imc_created +
544                        conn->imc_enpub->enp_settings.es_handshake_to;
545
546    TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
547        if (packet_out->po_flags & PO_SENT)
548        {
549            retx_time = packet_out->po_sent + imico_calc_retx_timeout(conn);
550            if (retx_time < exp_time)
551            {
552                *why = N_AEWS + AL_RETX_HSK;
553                return retx_time;
554            }
555            else
556            {
557                *why = AEW_MINI_EXPIRE;
558                return exp_time;
559            }
560        }
561
562    *why = AEW_MINI_EXPIRE;
563    return exp_time;
564}
565
566
567#define IMICO_PROC_FRAME_ARGS                                           \
568    struct ietf_mini_conn *conn, struct lsquic_packet_in *packet_in,    \
569    const unsigned char *p, size_t len
570
571
572static void
573imico_dispatch_stream_events (struct ietf_mini_conn *conn)
574{
575    enum enc_level i;
576
577    for (i = 0; i < N_ENC_LEVS; ++i)
578        if ((conn->imc_streams[i].mcs_flags & (MCS_CREATED|MCS_WANTREAD))
579                                                == (MCS_CREATED|MCS_WANTREAD))
580        {
581            LSQ_DEBUG("dispatch read events on level #%u", i);
582            lsquic_mini_cry_sm_if.on_read((void *) &conn->imc_streams[i],
583                                            conn->imc_conn.cn_enc_session);
584        }
585
586    for (i = 0; i < N_ENC_LEVS; ++i)
587        if ((conn->imc_streams[i].mcs_flags & (MCS_CREATED|MCS_WANTWRITE))
588                                                == (MCS_CREATED|MCS_WANTWRITE))
589        {
590            LSQ_DEBUG("dispatch write events on level #%u", i);
591            lsquic_mini_cry_sm_if.on_write((void *) &conn->imc_streams[i],
592                                            conn->imc_conn.cn_enc_session);
593        }
594}
595
596
597static unsigned
598imico_process_stream_frame (IMICO_PROC_FRAME_ARGS)
599{
600    LSQ_WARN("%s: TODO", __func__);
601    return 0;
602}
603
604
605static unsigned
606imico_process_crypto_frame (IMICO_PROC_FRAME_ARGS)
607{
608    int parsed_len;
609    enum enc_level enc_level, i;
610    struct stream_frame stream_frame;
611    const struct transport_params *params;
612
613    parsed_len = conn->imc_conn.cn_pf->pf_parse_crypto_frame(p, len,
614                                                                &stream_frame);
615    if (parsed_len < 0)
616        return 0;
617
618    enc_level = lsquic_packet_in_enc_level(packet_in);
619    EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame, enc_level);
620
621    if (!(conn->imc_streams[enc_level].mcs_flags & MCS_CREATED)
622            || conn->imc_streams[enc_level].mcs_read_off <
623                    stream_frame.data_frame.df_offset
624                                + stream_frame.data_frame.df_size)
625        LSQ_DEBUG("Got CRYPTO frame for enc level #%u", enc_level);
626    else
627    {
628        LSQ_DEBUG("Got duplicate CRYPTO frame for enc level #%u -- ignore",
629                                                                    enc_level);
630        return parsed_len;
631    }
632
633    if (!(conn->imc_flags & IMC_ENC_SESS_INITED))
634    {
635        if (0 != conn->imc_conn.cn_esf.i->esfi_init_server(
636                                            conn->imc_conn.cn_enc_session))
637            return -1;
638        conn->imc_flags |= IMC_ENC_SESS_INITED;
639    }
640
641    if (!(conn->imc_streams[enc_level].mcs_flags & MCS_CREATED))
642    {
643        LSQ_DEBUG("creating stream on level #%u", enc_level);
644        conn->imc_streams[enc_level].mcs_flags |= MCS_CREATED;
645        lsquic_mini_cry_sm_if.on_new_stream(conn->imc_conn.cn_enc_session,
646                                    (void *) &conn->imc_streams[enc_level]);
647    }
648
649    /* Assume that receiving a CRYPTO frame at a higher level means that we
650     * no longer want to read from a lower level.
651     */
652    for (i = 0; i < enc_level; ++i)
653        conn->imc_streams[i].mcs_flags &= ~MCS_WANTREAD;
654
655    conn->imc_last_in.frame = &stream_frame;
656    conn->imc_last_in.enc_level = enc_level;
657    imico_dispatch_stream_events(conn);
658    conn->imc_last_in.frame = NULL;
659
660
661    if (enc_level == ENC_LEV_CLEAR && stream_frame.data_frame.df_offset == 0
662        /* Assume that we have ClientHello at offset zero and that it has
663         * transport parameters.
664         */
665        && (conn->imc_flags & (IMC_ENC_SESS_INITED|IMC_HAVE_TP))
666                                                    == IMC_ENC_SESS_INITED)
667    {
668        params = conn->imc_conn.cn_esf.i->esfi_get_peer_transport_params(
669                                                conn->imc_conn.cn_enc_session);
670        if (params)
671        {
672            conn->imc_flags |= IMC_HAVE_TP;
673            conn->imc_ack_exp = params->tp_ack_delay_exponent;
674        }
675        else
676        {
677            conn->imc_flags |= IMC_BAD_TRANS_PARAMS;
678            return 0;
679        }
680    }
681
682    return parsed_len;
683}
684
685
686static ptrdiff_t
687imico_count_zero_bytes (const unsigned char *p, size_t len)
688{
689    const unsigned char *const end = p + len;
690    while (p < end && 0 == *p)
691        ++p;
692    return len - (end - p);
693}
694
695
696static unsigned
697imico_process_padding_frame (IMICO_PROC_FRAME_ARGS)
698{
699    len = (size_t) imico_count_zero_bytes(p, len);
700    EV_LOG_PADDING_FRAME_IN(LSQUIC_LOG_CONN_ID, len);
701    return len;
702}
703
704
705static void
706imico_take_rtt_sample (struct ietf_mini_conn *conn,
707                            const struct lsquic_packet_out *packet_out,
708                            lsquic_time_t now, lsquic_time_t lack_delta)
709{
710    assert(packet_out->po_sent);
711    lsquic_time_t measured_rtt = now - packet_out->po_sent;
712    if (lack_delta < measured_rtt)
713    {
714        lsquic_rtt_stats_update(&conn->imc_rtt_stats, measured_rtt, lack_delta);
715        LSQ_DEBUG("srtt: %"PRIu64" usec, var: %"PRIu64,
716                        lsquic_rtt_stats_get_srtt(&conn->imc_rtt_stats),
717                        lsquic_rtt_stats_get_rttvar(&conn->imc_rtt_stats));
718    }
719}
720
721
722static unsigned
723imico_process_ack_frame (IMICO_PROC_FRAME_ARGS)
724{
725    int parsed_len;
726    unsigned n;
727    lsquic_packet_out_t *packet_out, *next;
728    struct ack_info *acki;
729    lsquic_packno_t packno;
730    lsquic_time_t warn_time;
731    packno_set_t acked;
732    enum packnum_space pns;
733    uint8_t ack_exp;
734
735    if (conn->imc_flags & IMC_HAVE_TP)
736        ack_exp = conn->imc_ack_exp;
737    else
738        ack_exp = TP_DEF_ACK_DELAY_EXP; /* Odd: no transport params yet? */
739    acki = conn->imc_enpub->enp_mm.acki;
740    parsed_len = conn->imc_conn.cn_pf->pf_parse_ack_frame(p, len, acki,
741                                                                    ack_exp);
742    if (parsed_len < 0)
743        return 0;
744
745    pns = lsquic_hety2pns[ packet_in->pi_header_type ];
746    acked = 0;
747
748    for (n = 0; n < acki->n_ranges; ++n)
749    {
750        if (acki->ranges[n].high <= MAX_PACKETS)
751        {
752            acked |= (1ULL << acki->ranges[n].high)
753                                        | ((1ULL << acki->ranges[n].high) - 1);
754            acked &= ~((1ULL << acki->ranges[n].low) - 1);
755        }
756        else
757        {
758            packno = acki->ranges[n].high;
759            goto err_never_sent;
760        }
761    }
762    if (acked & ~conn->imc_sent_packnos)
763    {
764        packno = highest_bit_set(acked & ~conn->imc_sent_packnos);
765        goto err_never_sent;
766    }
767
768    EV_LOG_ACK_FRAME_IN(LSQUIC_LOG_CONN_ID, acki);
769    for (packet_out = TAILQ_FIRST(&conn->imc_packets_out); packet_out;
770                                                            packet_out = next)
771    {
772        next = TAILQ_NEXT(packet_out, po_next);
773        if ((1ULL << packet_out->po_packno) & acked)
774        {
775            assert(lsquic_packet_out_pns(packet_out) == pns);
776            LSQ_DEBUG("Got ACK for packet %"PRIu64, packet_out->po_packno);
777            if (packet_out->po_packno == largest_acked(acki))
778                imico_take_rtt_sample(conn, packet_out,
779                                    packet_in->pi_received, acki->lack_delta);
780            TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
781            imico_destroy_packet(conn, packet_out);
782        }
783    }
784
785    if (conn->imc_sent_packnos & ~conn->imc_acked_packnos[pns] & acked)
786    {
787        LSQ_DEBUG("Newly acked packets, reset handshake count");
788        conn->imc_hsk_count = 0;
789    }
790
791    conn->imc_acked_packnos[pns] |= acked;
792
793    return parsed_len;
794
795  err_never_sent:
796    warn_time = lsquic_time_now();
797    if (0 == conn->imc_enpub->enp_last_warning[WT_ACKPARSE_MINI]
798        || conn->imc_enpub->enp_last_warning[WT_ACKPARSE_MINI]
799                + WARNING_INTERVAL < warn_time)
800    {
801        conn->imc_enpub->enp_last_warning[WT_ACKPARSE_MINI] = warn_time;
802        LSQ_WARN("packet %"PRIu64" (pns: %u) was never sent", packno, pns);
803    }
804    else
805        LSQ_DEBUG("packet %"PRIu64" (pns: %u) was never sent", packno, pns);
806    return 0;
807}
808
809
810static unsigned
811imico_process_ping_frame (IMICO_PROC_FRAME_ARGS)
812{
813    LSQ_DEBUG("got a PING frame, do nothing");
814    return 1;
815}
816
817
818static unsigned
819imico_process_connection_close_frame (IMICO_PROC_FRAME_ARGS)
820{
821    struct lsquic_packet_out *packet_out;
822    uint64_t error_code;
823    uint16_t reason_len;
824    uint8_t reason_off;
825    int parsed_len, app_error;
826
827    while ((packet_out = TAILQ_FIRST(&conn->imc_packets_out)))
828    {
829        TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
830        imico_destroy_packet(conn, packet_out);
831    }
832    conn->imc_flags |= IMC_CLOSE_RECVD;
833    parsed_len = conn->imc_conn.cn_pf->pf_parse_connect_close_frame(p, len,
834                            &app_error, &error_code, &reason_len, &reason_off);
835    if (parsed_len < 0)
836        return 0;
837    EV_LOG_CONNECTION_CLOSE_FRAME_IN(LSQUIC_LOG_CONN_ID, error_code,
838                            (int) reason_len, (const char *) p + reason_off);
839    LSQ_INFO("Received CONNECTION_CLOSE frame (%s-level code: %"PRIu64"; "
840            "reason: %.*s)", app_error ? "application" : "transport",
841                error_code, (int) reason_len, (const char *) p + reason_off);
842    return 0;   /* This shuts down the connection */
843}
844
845
846static unsigned
847imico_process_invalid_frame (IMICO_PROC_FRAME_ARGS)
848{
849    LSQ_DEBUG("invalid frame %u (%s)", p[0],
850        frame_type_2_str[ conn->imc_conn.cn_pf->pf_parse_frame_type(p[0]) ]);
851    return 0;
852}
853
854
855static unsigned (*const imico_process_frames[N_QUIC_FRAMES])
856                                                (IMICO_PROC_FRAME_ARGS) =
857{
858    [QUIC_FRAME_PADDING]            =  imico_process_padding_frame,
859    [QUIC_FRAME_STREAM]             =  imico_process_stream_frame,
860    [QUIC_FRAME_CRYPTO]             =  imico_process_crypto_frame,
861    [QUIC_FRAME_ACK]                =  imico_process_ack_frame,
862    [QUIC_FRAME_PING]               =  imico_process_ping_frame,
863    [QUIC_FRAME_CONNECTION_CLOSE]   =  imico_process_connection_close_frame,
864    /* XXX: Some of them are invalid, while others are unexpected.  We treat
865     * them the same: handshake cannot proceed.
866     */
867    [QUIC_FRAME_RST_STREAM]         =  imico_process_invalid_frame,
868    [QUIC_FRAME_MAX_DATA]           =  imico_process_invalid_frame,
869    [QUIC_FRAME_MAX_STREAM_DATA]    =  imico_process_invalid_frame,
870    [QUIC_FRAME_MAX_STREAMS]        =  imico_process_invalid_frame,
871    [QUIC_FRAME_BLOCKED]            =  imico_process_invalid_frame,
872    [QUIC_FRAME_STREAM_BLOCKED]     =  imico_process_invalid_frame,
873    [QUIC_FRAME_STREAMS_BLOCKED]    =  imico_process_invalid_frame,
874    [QUIC_FRAME_NEW_CONNECTION_ID]  =  imico_process_invalid_frame,
875    [QUIC_FRAME_STOP_SENDING]       =  imico_process_invalid_frame,
876    [QUIC_FRAME_PATH_CHALLENGE]     =  imico_process_invalid_frame,
877    [QUIC_FRAME_PATH_RESPONSE]      =  imico_process_invalid_frame,
878};
879
880
881static unsigned
882imico_process_packet_frame (struct ietf_mini_conn *conn,
883        struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
884{
885    enum enc_level enc_level = lsquic_packet_in_enc_level(packet_in);
886    enum quic_frame_type type = conn->imc_conn.cn_pf->pf_parse_frame_type(p[0]);
887    if (lsquic_legal_frames_by_level[enc_level] & (1 << type))
888    {
889        packet_in->pi_frame_types |= 1 << type;
890        return imico_process_frames[type](conn, packet_in, p, len);
891    }
892    else
893    {
894        LSQ_DEBUG("invalid frame %u at encryption level %s", type,
895                                                lsquic_enclev2str[enc_level]);
896        return 0;
897    }
898}
899
900
901static int
902imico_parse_regular_packet (struct ietf_mini_conn *conn,
903                                        struct lsquic_packet_in *packet_in)
904{
905    const unsigned char *p, *pend;
906    unsigned len;
907
908    p = packet_in->pi_data + packet_in->pi_header_sz;
909    pend = packet_in->pi_data + packet_in->pi_data_sz;
910
911    while (p < pend)
912    {
913        len = imico_process_packet_frame(conn, packet_in, p, pend - p);
914        if (len > 0)
915            p += len;
916        else
917            return -1;
918    }
919
920    return 0;
921}
922
923
924static unsigned
925highest_bit_set (unsigned long long sz)
926{
927#if __GNUC__
928    unsigned clz = __builtin_clzll(sz);
929    return 63 - clz;
930#else
931    unsigned long y;
932    unsigned n;
933    n = 64;
934    y = sz >> 32;     if (y) { n -= 32; sz = y; }
935    y = sz >> 16;     if (y) { n -= 16; sz = y; }
936    y = sz >>  8;     if (y) { n -=  8; sz = y; }
937    y = sz >>  4;     if (y) { n -=  4; sz = y; }
938    y = sz >>  2;     if (y) { n -=  2; sz = y; }
939    y = sz >>  1;     if (y) return 63 - n + 2;
940    return 63 - n + sz;
941#endif
942}
943
944
945static void
946ignore_init (struct ietf_mini_conn *conn)
947{
948    struct lsquic_packet_out *packet_out, *next;
949    unsigned count;
950
951    conn->imc_flags |= IMC_IGNORE_INIT;
952    conn->imc_flags &= ~(IMC_QUEUED_ACK_INIT << PNS_INIT);
953
954    count = 0;
955    for (packet_out = TAILQ_FIRST(&conn->imc_packets_out); packet_out;
956                                                            packet_out = next)
957    {
958        next = TAILQ_NEXT(packet_out, po_next);
959        if (PNS_INIT == lsquic_packet_out_pns(packet_out))
960        {
961            TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
962            imico_destroy_packet(conn, packet_out);
963            ++count;
964        }
965    }
966
967    LSQ_DEBUG("henceforth, no Initial packets shall be sent or received; "
968        "destroyed %u packet%.*s", count, count != 1, "s");
969}
970
971
972/* Only a single packet is supported */
973static void
974ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
975                        struct lsquic_packet_in *packet_in)
976{
977    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
978    enum dec_packin dec_packin;
979    enum packnum_space pns;
980
981    if (conn->imc_flags & IMC_ERROR)
982    {
983        LSQ_DEBUG("ignore incoming packet: connection is in error state");
984        return;
985    }
986
987    pns = lsquic_hety2pns[ packet_in->pi_header_type ];
988    if (pns == PNS_INIT && (conn->imc_flags & IMC_IGNORE_INIT))
989    {
990        LSQ_DEBUG("ignore init packet");    /* Don't bother decrypting */
991        return;
992    }
993
994    dec_packin = lconn->cn_esf_c->esf_decrypt_packet(lconn->cn_enc_session,
995                                        conn->imc_enpub, lconn, packet_in);
996    if (dec_packin != DECPI_OK)
997    {
998        /* TODO: handle reordering perhaps? */
999        LSQ_DEBUG("could not decrypt packet");
1000        return;
1001    }
1002
1003    EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
1004    conn->imc_bytes_in += packet_in->pi_data_sz + IQUIC_TAG_LEN;
1005
1006    if (pns == PNS_APP)
1007    {
1008        lsquic_packet_in_upref(packet_in);
1009        TAILQ_INSERT_TAIL(&conn->imc_app_packets, packet_in, pi_next);
1010        LSQ_DEBUG("delay processing of packet %"PRIu64" in pns %u",
1011            packet_in->pi_packno, pns);
1012        return;
1013    }
1014    else if (pns == PNS_HSK)
1015        conn->imc_flags |= IMC_ADDR_VALIDATED;
1016
1017    if (((conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3) < pns)
1018    {
1019        conn->imc_flags &= ~(3 << IMCBIT_PNS_BIT_SHIFT);
1020        conn->imc_flags |= pns << IMCBIT_PNS_BIT_SHIFT;
1021    }
1022
1023    if (pns == PNS_HSK && !(conn->imc_flags & IMC_IGNORE_INIT))
1024        ignore_init(conn);
1025
1026    if (conn->imc_recvd_packnos[pns] & (1ULL << packet_in->pi_packno))
1027    {
1028        LSQ_DEBUG("duplicate packet %"PRIu64, packet_in->pi_packno);
1029        return;
1030    }
1031
1032    /* Update receive history before processing the packet: if there is an
1033     * error, the connection is terminated and recording this packet number
1034     * is helpful when it is printed along with other diagnostics in dtor.
1035     */
1036    if (0 == conn->imc_recvd_packnos[pns] ||
1037            packet_in->pi_packno > highest_bit_set(conn->imc_recvd_packnos[pns]))
1038        conn->imc_largest_recvd[pns] = packet_in->pi_received;
1039    conn->imc_recvd_packnos[pns] |= 1ULL << packet_in->pi_packno;
1040
1041    if (0 != imico_parse_regular_packet(conn, packet_in))
1042    {
1043        LSQ_DEBUG("connection is now in error state");
1044        conn->imc_flags |= IMC_ERROR;
1045        return;
1046    }
1047
1048    conn->imc_flags |= IMC_QUEUED_ACK_INIT << pns;
1049    ++conn->imc_ecn_counts_in[pns][ lsquic_packet_in_ecn(packet_in) ];
1050    conn->imc_incoming_ecn <<= 1;
1051    conn->imc_incoming_ecn |= lsquic_packet_in_ecn(packet_in) != ECN_NOT_ECT;
1052}
1053
1054
1055static void
1056ietf_mini_conn_ci_packet_sent (struct lsquic_conn *lconn,
1057                              struct lsquic_packet_out *packet_out)
1058{
1059    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1060    conn->imc_sent_packnos |= 1ULL << packet_out->po_packno;
1061    conn->imc_ecn_packnos |= !!lsquic_packet_out_ecn(packet_out)
1062                                                    << packet_out->po_packno;
1063#if 0
1064    if (packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
1065    {
1066        assert(mc->mc_flags & MC_UNSENT_ACK);
1067        mc->mc_flags &= ~MC_UNSENT_ACK;
1068    }
1069#endif
1070    ++conn->imc_ecn_counts_out[ lsquic_packet_out_pns(packet_out) ]
1071                              [ lsquic_packet_out_ecn(packet_out) ];
1072    if (packet_out->po_header_type == HETY_HANDSHAKE)
1073        conn->imc_flags |= IMC_HSK_PACKET_SENT;
1074    LSQ_DEBUG("%s: packet %"PRIu64" sent", __func__, packet_out->po_packno);
1075}
1076
1077
1078static void
1079ietf_mini_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
1080                              struct lsquic_packet_out *packet_out)
1081{
1082    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1083    size_t packet_size;
1084
1085    packet_out->po_flags &= ~PO_SENT;
1086    packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
1087    conn->imc_bytes_out -= packet_size + IQUIC_TAG_LEN;
1088    LSQ_DEBUG("%s: packet %"PRIu64" not sent", __func__, packet_out->po_packno);
1089}
1090
1091
1092static void
1093imico_return_enc_data (struct ietf_mini_conn *conn,
1094                                        struct lsquic_packet_out *packet_out)
1095{
1096    conn->imc_enpub->enp_pmi->pmi_return(conn->imc_enpub->enp_pmi_ctx,
1097        conn->imc_path.np_peer_ctx, packet_out->po_enc_data,
1098        lsquic_packet_out_ipv6(packet_out));
1099    packet_out->po_flags &= ~PO_ENCRYPTED;
1100    packet_out->po_enc_data = NULL;
1101}
1102
1103
1104static int
1105imico_repackage_packet (struct ietf_mini_conn *conn,
1106                                        struct lsquic_packet_out *packet_out)
1107{
1108    const lsquic_packno_t oldno = packet_out->po_packno;
1109    const lsquic_packno_t packno = conn->imc_next_packno++;
1110    if (packno > MAX_PACKETS)
1111        return -1;
1112
1113    LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
1114                                                        oldno, packno);
1115    EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
1116        "resending as packet %"PRIu64, oldno, packno);
1117    packet_out->po_packno = packno;
1118    packet_out->po_flags &= ~PO_SENT;
1119    lsquic_packet_out_set_ecn(packet_out, imico_get_ecn(conn));
1120    if (packet_out->po_flags & PO_ENCRYPTED)
1121        imico_return_enc_data(conn, packet_out);
1122    TAILQ_INSERT_TAIL(&conn->imc_packets_out, packet_out, po_next);
1123    return 0;
1124}
1125
1126
1127static int
1128imico_handle_losses_and_have_unsent (struct ietf_mini_conn *conn,
1129                                                            lsquic_time_t now)
1130{
1131    TAILQ_HEAD(, lsquic_packet_out) lost_packets =
1132                                    TAILQ_HEAD_INITIALIZER(lost_packets);
1133    lsquic_packet_out_t *packet_out, *next;
1134    lsquic_time_t retx_to = 0;
1135    unsigned n_to_send = 0;
1136
1137    for (packet_out = TAILQ_FIRST(&conn->imc_packets_out); packet_out;
1138                                                        packet_out = next)
1139    {
1140        next = TAILQ_NEXT(packet_out, po_next);
1141        if (packet_out->po_flags & PO_SENT)
1142        {
1143            if (0 == retx_to)
1144                retx_to = imico_calc_retx_timeout(conn);
1145            if (packet_out->po_sent + retx_to < now)
1146            {
1147                LSQ_DEBUG("packet %"PRIu64" has been lost (rto: %"PRIu64")",
1148                                                packet_out->po_packno, retx_to);
1149                TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
1150                TAILQ_INSERT_TAIL(&lost_packets, packet_out, po_next);
1151            }
1152        }
1153        else
1154            ++n_to_send;
1155    }
1156
1157    conn->imc_hsk_count += !TAILQ_EMPTY(&lost_packets);
1158
1159    while ((packet_out = TAILQ_FIRST(&lost_packets)))
1160    {
1161        TAILQ_REMOVE(&lost_packets, packet_out, po_next);
1162        if ((packet_out->po_frame_types & IQUIC_FRAME_RETX_MASK)
1163                            && 0 == imico_repackage_packet(conn, packet_out))
1164            ++n_to_send;
1165        else
1166            imico_destroy_packet(conn, packet_out);
1167    }
1168
1169    return n_to_send > 0;
1170}
1171
1172
1173static int
1174imico_have_packets_to_send (struct ietf_mini_conn *conn, lsquic_time_t now)
1175{
1176    return imico_handle_losses_and_have_unsent(conn, now);
1177}
1178
1179
1180struct ietf_mini_rechist
1181{
1182    const struct ietf_mini_conn *conn;
1183    packno_set_t                 cur_set;
1184    struct lsquic_packno_range   range;   /* We return a pointer to this */
1185    int                          cur_idx;
1186    enum packnum_space           pns;
1187};
1188
1189
1190static void
1191imico_rechist_init (struct ietf_mini_rechist *rechist,
1192                    const struct ietf_mini_conn *conn, enum packnum_space pns)
1193{
1194    rechist->conn    = conn;
1195    rechist->pns     = pns;
1196    rechist->cur_set = 0;
1197    rechist->cur_idx = 0;
1198}
1199
1200
1201static lsquic_time_t
1202imico_rechist_largest_recv (void *rechist_ctx)
1203{
1204    struct ietf_mini_rechist *rechist = rechist_ctx;
1205    return rechist->conn->imc_largest_recvd[ rechist->pns ];
1206}
1207
1208
1209static const struct lsquic_packno_range *
1210imico_rechist_next (void *rechist_ctx)
1211{
1212    struct ietf_mini_rechist *rechist = rechist_ctx;
1213    const struct ietf_mini_conn *conn = rechist->conn;
1214    packno_set_t packnos;
1215    int i;
1216
1217    packnos = rechist->cur_set;
1218    if (0 == packnos)
1219        return NULL;
1220
1221    /* There may be a faster way to do this, but for now, we just want
1222     * correctness.
1223     */
1224    for (i = rechist->cur_idx; i >= 0; --i)
1225        if (packnos & (1ULL << i))
1226        {
1227            rechist->range.low  = i;
1228            rechist->range.high = i;
1229            break;
1230        }
1231    assert(i >= 0); /* We must have hit at least one bit */
1232    --i;
1233    for ( ; i >= 0 && (packnos & (1ULL << i)); --i)
1234        rechist->range.low = i;
1235    if (i >= 0)
1236    {
1237        rechist->cur_set = packnos & ((1ULL << i) - 1);
1238        rechist->cur_idx = i;
1239    }
1240    else
1241        rechist->cur_set = 0;
1242    LSQ_DEBUG("%s: return [%"PRIu64", %"PRIu64"]", __func__,
1243                                rechist->range.low, rechist->range.high);
1244    return &rechist->range;
1245}
1246
1247
1248static const struct lsquic_packno_range *
1249imico_rechist_first (void *rechist_ctx)
1250{
1251    struct ietf_mini_rechist *rechist = rechist_ctx;
1252    rechist->cur_set = rechist->conn->imc_recvd_packnos[ rechist->pns ];
1253    rechist->cur_idx = highest_bit_set(rechist->cur_set);
1254    return imico_rechist_next(rechist_ctx);
1255}
1256
1257
1258static const enum header_type pns2hety[] =
1259{
1260    [PNS_INIT]  = HETY_INITIAL,
1261    [PNS_HSK]   = HETY_HANDSHAKE,
1262    [PNS_APP]   = HETY_NOT_SET,
1263};
1264
1265
1266static int
1267imico_generate_ack (struct ietf_mini_conn *conn, enum packnum_space pns,
1268                                                            lsquic_time_t now)
1269{
1270    struct lsquic_packet_out *packet_out;
1271    enum header_type header_type;
1272    struct ietf_mini_rechist rechist;
1273    int not_used_has_missing, len;
1274    uint64_t ecn_counts_buf[4];
1275    const uint64_t *ecn_counts;
1276
1277    header_type = pns2hety[pns];
1278
1279    if (conn->imc_incoming_ecn)
1280    {
1281        ecn_counts_buf[0]   = conn->imc_ecn_counts_in[pns][0];
1282        ecn_counts_buf[1]   = conn->imc_ecn_counts_in[pns][1];
1283        ecn_counts_buf[2]   = conn->imc_ecn_counts_in[pns][2];
1284        ecn_counts_buf[3]   = conn->imc_ecn_counts_in[pns][3];
1285        ecn_counts = ecn_counts_buf;
1286    }
1287    else
1288        ecn_counts = NULL;
1289
1290    packet_out = imico_get_packet_out(conn, header_type, 0);
1291    if (!packet_out)
1292        return -1;
1293
1294    /* Generate ACK frame */
1295    imico_rechist_init(&rechist, conn, pns);
1296    len = conn->imc_conn.cn_pf->pf_gen_ack_frame(
1297                packet_out->po_data + packet_out->po_data_sz,
1298                lsquic_packet_out_avail(packet_out), imico_rechist_first,
1299                imico_rechist_next, imico_rechist_largest_recv, &rechist,
1300                now, &not_used_has_missing, &packet_out->po_ack2ed, ecn_counts);
1301    if (len < 0)
1302    {
1303        LSQ_WARN("could not generate ACK frame");
1304        return -1;
1305    }
1306    EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, conn->imc_conn.cn_pf,
1307                        packet_out->po_data + packet_out->po_data_sz, len);
1308    packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
1309    packet_out->po_data_sz += len;
1310    packet_out->po_regen_sz += len;
1311    conn->imc_flags &= ~(IMC_QUEUED_ACK_INIT << pns);
1312    LSQ_DEBUG("wrote ACK frame of size %d", len);
1313    return 0;
1314}
1315
1316
1317static int
1318imico_generate_acks (struct ietf_mini_conn *conn, lsquic_time_t now)
1319{
1320    enum packnum_space pns;
1321
1322    for (pns = PNS_INIT; pns < N_PNS; ++pns)
1323        if (conn->imc_flags & (IMC_QUEUED_ACK_INIT << pns)
1324                && !(pns == PNS_INIT && (conn->imc_flags & IMC_IGNORE_INIT)))
1325            if (0 != imico_generate_ack(conn, pns, now))
1326                return -1;
1327
1328    return 0;
1329}
1330
1331
1332static void
1333imico_generate_conn_close (struct ietf_mini_conn *conn)
1334{
1335    struct lsquic_packet_out *packet_out;
1336    enum header_type header_type;
1337    enum packnum_space pns, pns_max;
1338    unsigned error_code;
1339    const char *reason;
1340    size_t need;
1341    int sz, rlen, is_app;
1342    char reason_buf[0x20];
1343
1344    if (conn->imc_flags & IMC_ABORT_ERROR)
1345    {
1346        is_app = !!(conn->imc_flags & IMC_ABORT_ISAPP);
1347        error_code = conn->imc_error_code;
1348        reason = NULL;
1349        rlen = 0;
1350    }
1351    else if (conn->imc_flags & IMC_TLS_ALERT)
1352    {
1353        is_app = 0;
1354        error_code = 0x100 + conn->imc_tls_alert;
1355        if (ALERT_NO_APPLICATION_PROTOCOL == conn->imc_tls_alert)
1356            reason = "no suitable application protocol";
1357        else
1358        {
1359            snprintf(reason_buf, sizeof(reason_buf), "TLS alert %"PRIu8,
1360                                                        conn->imc_tls_alert);
1361            reason = reason_buf;
1362        }
1363        rlen = strlen(reason);
1364    }
1365    else if (conn->imc_flags & IMC_BAD_TRANS_PARAMS)
1366    {
1367        is_app = 0;
1368        error_code = TEC_NO_ERROR;
1369        reason = "bad transport parameters";
1370        rlen = 24;
1371    }
1372    else if (conn->imc_flags & IMC_HSK_FAILED)
1373    {
1374        is_app = 0;
1375        error_code = TEC_NO_ERROR;
1376        reason = "handshake failed";
1377        rlen = 16;
1378    }
1379    else
1380    {
1381        is_app = 0;
1382        error_code = TEC_INTERNAL_ERROR;
1383        reason = NULL;
1384        rlen = 0;
1385    }
1386
1387
1388/* [draft-ietf-quic-transport-23] Section 12.2:
1389 *
1390 " A client will always know whether the server has Handshake keys (see
1391 " Section 17.2.2.1), but it is possible that a server does not know
1392 " whether the client has Handshake keys.  Under these circumstances, a
1393 " server SHOULD send a CONNECTION_CLOSE frame in both Handshake and
1394 " Initial packets to ensure that at least one of them is processable by
1395 " the client.
1396 */
1397
1398    pns = (conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3;
1399    switch ((!!(conn->imc_flags & IMC_HSK_PACKET_SENT) << 1)
1400                | (pns == PNS_HSK) /* Handshake packet received */)
1401    {
1402    case (0 << 1) | 0:
1403        pns = PNS_INIT;
1404        pns_max = PNS_INIT;
1405        break;
1406    case (1 << 1) | 0:
1407        pns = PNS_INIT;
1408        pns_max = PNS_HSK;
1409        break;
1410    default:
1411        pns = PNS_HSK;
1412        pns_max = PNS_HSK;
1413        break;
1414    }
1415
1416    LSQ_DEBUG("will generate %u CONNECTION_CLOSE frame%.*s",
1417        pns_max - pns + 1, pns_max > pns, "s");
1418    do
1419    {
1420        header_type = pns2hety[pns];
1421        need = 30;  /* Guess */ /* TODO: calculate, don't guess */
1422        packet_out = imico_get_packet_out(conn, header_type, need);
1423        if (!packet_out)
1424            return;
1425        sz = conn->imc_conn.cn_pf->pf_gen_connect_close_frame(
1426                 packet_out->po_data + packet_out->po_data_sz,
1427                 lsquic_packet_out_avail(packet_out), is_app, error_code, reason,
1428                 rlen);
1429        if (sz >= 0)
1430        {
1431            packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
1432            packet_out->po_data_sz += sz;
1433            LSQ_DEBUG("generated CONNECTION_CLOSE frame");
1434        }
1435        else
1436            LSQ_WARN("could not generate CONNECTION_CLOSE frame");
1437        ++pns;
1438    }
1439    while (pns <= pns_max);
1440}
1441
1442
1443static enum tick_st
1444ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
1445{
1446    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1447    enum tick_st tick;
1448
1449    if (conn->imc_created + conn->imc_enpub->enp_settings.es_handshake_to < now)
1450    {
1451        LSQ_DEBUG("connection expired: closing");
1452        return TICK_CLOSE;
1453    }
1454
1455    if (conn->imc_flags &
1456            (IMC_QUEUED_ACK_INIT|IMC_QUEUED_ACK_HSK|IMC_QUEUED_ACK_APP))
1457    {
1458        if (0 != imico_generate_acks(conn, now))
1459        {
1460            conn->imc_flags |= IMC_ERROR;
1461            return TICK_CLOSE;
1462        }
1463    }
1464
1465
1466    tick = 0;
1467
1468    if (conn->imc_flags & IMC_ERROR)
1469    {
1470        if (!(conn->imc_flags & IMC_CLOSE_RECVD))
1471            imico_generate_conn_close(conn);
1472        tick |= TICK_CLOSE;
1473    }
1474    else if (conn->imc_flags & IMC_HSK_OK)
1475        tick |= TICK_PROMOTE;
1476
1477    if (imico_have_packets_to_send(conn, now))
1478        tick |= TICK_SEND;
1479    else
1480        tick |= TICK_QUIET;
1481
1482    LSQ_DEBUG("Return TICK %d", tick);
1483    return tick;
1484}
1485
1486
1487static void
1488ietf_mini_conn_ci_internal_error (struct lsquic_conn *lconn,
1489                                                    const char *format, ...)
1490{
1491    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1492    LSQ_INFO("internal error reported");
1493    conn->imc_flags |= IMC_ERROR;
1494}
1495
1496
1497static void
1498ietf_mini_conn_ci_abort_error (struct lsquic_conn *lconn, int is_app,
1499                                unsigned error_code, const char *fmt, ...)
1500{
1501    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1502    va_list ap;
1503    const char *err_str, *percent;
1504    char err_buf[0x100];
1505
1506    percent = strchr(fmt, '%');
1507    if (percent)
1508    {
1509        va_start(ap, fmt);
1510        vsnprintf(err_buf, sizeof(err_buf), fmt, ap);
1511        va_end(ap);
1512        err_str = err_buf;
1513    }
1514    else
1515        err_str = fmt;
1516    LSQ_INFO("abort error: is_app: %d; error code: %u; error str: %s",
1517        is_app, error_code, err_str);
1518    conn->imc_flags |= IMC_ERROR|IMC_ABORT_ERROR;
1519    if (is_app)
1520        conn->imc_flags |= IMC_ABORT_ISAPP;
1521    conn->imc_error_code = error_code;
1522}
1523
1524
1525static struct network_path *
1526ietf_mini_conn_ci_get_path (struct lsquic_conn *lconn,
1527                                                    const struct sockaddr *sa)
1528{
1529    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1530
1531    return &conn->imc_path;
1532}
1533
1534
1535static const lsquic_cid_t *
1536ietf_mini_conn_ci_get_log_cid (const struct lsquic_conn *lconn)
1537{
1538    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1539
1540    if (conn->imc_path.np_dcid.len)
1541        return &conn->imc_path.np_dcid;
1542    else
1543        return CN_SCID(lconn);
1544}
1545
1546
1547static unsigned char
1548ietf_mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
1549            const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
1550{
1551    struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
1552    struct lsquic_packet_out *packet_out;
1553    size_t len;
1554
1555    if (NP_IS_IPv6(&conn->imc_path) != (AF_INET6 == peer_sa->sa_family))
1556        TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
1557            if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED)
1558                imico_return_enc_data(conn, packet_out);
1559
1560    len = local_sa->sa_family == AF_INET ? sizeof(struct sockaddr_in)
1561                                                : sizeof(struct sockaddr_in6);
1562
1563    memcpy(conn->imc_path.np_peer_addr, peer_sa, len);
1564    memcpy(conn->imc_path.np_local_addr, local_sa, len);
1565    conn->imc_path.np_peer_ctx = peer_ctx;
1566    return 0;
1567}
1568
1569
1570static const struct conn_iface mini_conn_ietf_iface = {
1571    .ci_abort_error          =  ietf_mini_conn_ci_abort_error,
1572    .ci_client_call_on_new   =  ietf_mini_conn_ci_client_call_on_new,
1573    .ci_destroy              =  ietf_mini_conn_ci_destroy,
1574    .ci_get_engine           =  ietf_mini_conn_ci_get_engine,
1575    .ci_get_log_cid          =  ietf_mini_conn_ci_get_log_cid,
1576    .ci_get_path             =  ietf_mini_conn_ci_get_path,
1577    .ci_hsk_done             =  ietf_mini_conn_ci_hsk_done,
1578    .ci_internal_error       =  ietf_mini_conn_ci_internal_error,
1579    .ci_is_tickable          =  ietf_mini_conn_ci_is_tickable,
1580    .ci_next_packet_to_send  =  ietf_mini_conn_ci_next_packet_to_send,
1581    .ci_next_tick_time       =  ietf_mini_conn_ci_next_tick_time,
1582    .ci_packet_in            =  ietf_mini_conn_ci_packet_in,
1583    .ci_packet_not_sent      =  ietf_mini_conn_ci_packet_not_sent,
1584    .ci_packet_sent          =  ietf_mini_conn_ci_packet_sent,
1585    .ci_record_addrs         =  ietf_mini_conn_ci_record_addrs,
1586    .ci_tick                 =  ietf_mini_conn_ci_tick,
1587    .ci_tls_alert            =  ietf_mini_conn_ci_tls_alert,
1588};
1589