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