160f3e654SNathan Skrzypczak/*
260f3e654SNathan Skrzypczak * Copyright (c) 2019 Cisco and/or its affiliates.
360f3e654SNathan Skrzypczak * Licensed under the Apache License, Version 2.0 (the "License");
460f3e654SNathan Skrzypczak * you may not use this file except in compliance with the License.
560f3e654SNathan Skrzypczak * You may obtain a copy of the License at:
660f3e654SNathan Skrzypczak *
760f3e654SNathan Skrzypczak *     http://www.apache.org/licenses/LICENSE-2.0
860f3e654SNathan Skrzypczak *
960f3e654SNathan Skrzypczak * Unless required by applicable law or agreed to in writing, software
1060f3e654SNathan Skrzypczak * distributed under the License is distributed on an "AS IS" BASIS,
1160f3e654SNathan Skrzypczak * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1260f3e654SNathan Skrzypczak * See the License for the specific language governing permissions and
1360f3e654SNathan Skrzypczak * limitations under the License.
1460f3e654SNathan Skrzypczak */
1560f3e654SNathan Skrzypczak
1660f3e654SNathan Skrzypczak#include <sys/socket.h>
1760f3e654SNathan Skrzypczak
1860f3e654SNathan Skrzypczak#include <vnet/session/application.h>
1960f3e654SNathan Skrzypczak#include <vnet/session/transport.h>
2060f3e654SNathan Skrzypczak#include <vnet/session/session.h>
2160f3e654SNathan Skrzypczak#include <vlib/unix/plugin.h>
2260f3e654SNathan Skrzypczak#include <vpp/app/version.h>
2360f3e654SNathan Skrzypczak
2460f3e654SNathan Skrzypczak#include <vppinfra/lock.h>
2560f3e654SNathan Skrzypczak
2660f3e654SNathan Skrzypczak#include <quic/quic.h>
271c2af068SAloys Augustin#include <quic/certs.h>
281c2af068SAloys Augustin#include <quic/error.h>
2960f3e654SNathan Skrzypczak
30ecb9d18cSMathiasRaoul#include <quicly/constants.h>
31ba123e15SAloys Augustin#include <quicly/defaults.h>
3292de6b65SMathiasRaoul#include <picotls.h>
3392de6b65SMathiasRaoul
3492de6b65SMathiasRaoul#include <quic/quic_crypto.h>
3592de6b65SMathiasRaoul
3692de6b65SMathiasRaoulextern quicly_crypto_engine_t quic_crypto_engine;
3760f3e654SNathan Skrzypczak
38ff1f6faaSMathiasRaoulstatic char *quic_error_strings[] = {
39ff1f6faaSMathiasRaoul#define quic_error(n,s) s,
4065f6cfcdSNathan Skrzypczak#include <quic/quic_error.def>
41ff1f6faaSMathiasRaoul#undef quic_error
42ff1f6faaSMathiasRaoul};
439082b43dSMathias Raoul
4492de6b65SMathiasRaoul#define DEFAULT_MAX_PACKETS_PER_KEY 16777216
4592de6b65SMathiasRaoul
4692de6b65SMathiasRaoulquic_main_t quic_main;
4760f3e654SNathan Skrzypczakstatic void quic_update_timer (quic_ctx_t * ctx);
48d9577b4aSNathan Skrzypczakstatic void quic_check_quic_session_connected (quic_ctx_t * ctx);
49d9577b4aSNathan Skrzypczakstatic int quic_reset_connection (u64 udp_session_handle,
50d9577b4aSNathan Skrzypczak				  quic_rx_packet_ctx_t * pctx);
51d9577b4aSNathan Skrzypczakstatic void quic_proto_on_close (u32 ctx_index, u32 thread_index);
52d9577b4aSNathan Skrzypczak
53c298f376SNathan Skrzypczakstatic quicly_stream_open_t on_stream_open;
54c298f376SNathan Skrzypczakstatic quicly_closed_by_peer_t on_closed_by_peer;
55c298f376SNathan Skrzypczakstatic quicly_now_t quicly_vpp_now_cb;
56c298f376SNathan Skrzypczak
57d1b9e706SNathan Skrzypczak/* Crypto contexts */
58d1b9e706SNathan Skrzypczak
59d1b9e706SNathan Skrzypczakstatic inline void
60d1b9e706SNathan Skrzypczakquic_crypto_context_make_key_from_ctx (clib_bihash_kv_24_8_t * kv,
61d1b9e706SNathan Skrzypczak				       quic_ctx_t * ctx)
62d1b9e706SNathan Skrzypczak{
63d1b9e706SNathan Skrzypczak  application_t *app = application_get (ctx->parent_app_id);
64d1b9e706SNathan Skrzypczak  kv->key[0] = ((u64) ctx->ckpair_index) << 32 | (u64) ctx->crypto_engine;
65d1b9e706SNathan Skrzypczak  kv->key[1] = app->sm_properties.rx_fifo_size - 1;
66d1b9e706SNathan Skrzypczak  kv->key[2] = app->sm_properties.tx_fifo_size - 1;
67d1b9e706SNathan Skrzypczak}
68d1b9e706SNathan Skrzypczak
69d1b9e706SNathan Skrzypczakstatic inline void
70d1b9e706SNathan Skrzypczakquic_crypto_context_make_key_from_crctx (clib_bihash_kv_24_8_t * kv,
71d1b9e706SNathan Skrzypczak					 crypto_context_t * crctx)
72d1b9e706SNathan Skrzypczak{
73d1b9e706SNathan Skrzypczak  quic_crypto_context_data_t *data =
74d1b9e706SNathan Skrzypczak    (quic_crypto_context_data_t *) crctx->data;
75d1b9e706SNathan Skrzypczak  kv->key[0] = ((u64) crctx->ckpair_index) << 32 | (u64) crctx->crypto_engine;
76d1b9e706SNathan Skrzypczak  kv->key[1] = data->quicly_ctx.transport_params.max_stream_data.bidi_local;
77d1b9e706SNathan Skrzypczak  kv->key[2] = data->quicly_ctx.transport_params.max_stream_data.bidi_remote;
78d1b9e706SNathan Skrzypczak}
79d1b9e706SNathan Skrzypczak
80d1b9e706SNathan Skrzypczakstatic void
81d1b9e706SNathan Skrzypczakquic_crypto_context_free_if_needed (crypto_context_t * crctx, u8 thread_index)
82d1b9e706SNathan Skrzypczak{
83d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
84d1b9e706SNathan Skrzypczak  clib_bihash_kv_24_8_t kv;
85d1b9e706SNathan Skrzypczak  if (crctx->n_subscribers)
86d1b9e706SNathan Skrzypczak    return;
87d1b9e706SNathan Skrzypczak  quic_crypto_context_make_key_from_crctx (&kv, crctx);
88d1b9e706SNathan Skrzypczak  clib_bihash_add_del_24_8 (&qm->wrk_ctx[thread_index].crypto_context_hash,
89d1b9e706SNathan Skrzypczak			    &kv, 0 /* is_add */ );
90d1b9e706SNathan Skrzypczak  clib_mem_free (crctx->data);
91d1b9e706SNathan Skrzypczak  pool_put (qm->wrk_ctx[thread_index].crypto_ctx_pool, crctx);
92d1b9e706SNathan Skrzypczak}
93d1b9e706SNathan Skrzypczak
9492de6b65SMathiasRaoulstatic quicly_datagram_t *
9592de6b65SMathiasRaoulquic_alloc_packet (quicly_packet_allocator_t * self, size_t payloadsize)
9692de6b65SMathiasRaoul{
9792de6b65SMathiasRaoul  quicly_datagram_t *packet;
9892de6b65SMathiasRaoul  if ((packet =
9992de6b65SMathiasRaoul       clib_mem_alloc (sizeof (*packet) + payloadsize +
10092de6b65SMathiasRaoul		       sizeof (quic_encrypt_cb_ctx))) == NULL)
10192de6b65SMathiasRaoul    return NULL;
10292de6b65SMathiasRaoul  packet->data.base =
10392de6b65SMathiasRaoul    (uint8_t *) packet + sizeof (*packet) + sizeof (quic_encrypt_cb_ctx);
10492de6b65SMathiasRaoul  quic_encrypt_cb_ctx *encrypt_cb_ctx =
10592de6b65SMathiasRaoul    (quic_encrypt_cb_ctx *) ((uint8_t *) packet + sizeof (*packet));
10692de6b65SMathiasRaoul
10792de6b65SMathiasRaoul  clib_memset (encrypt_cb_ctx, 0, sizeof (*encrypt_cb_ctx));
10892de6b65SMathiasRaoul  return packet;
10992de6b65SMathiasRaoul}
11092de6b65SMathiasRaoul
11192de6b65SMathiasRaoulstatic void
11292de6b65SMathiasRaoulquic_free_packet (quicly_packet_allocator_t * self,
11392de6b65SMathiasRaoul		  quicly_datagram_t * packet)
11492de6b65SMathiasRaoul{
11592de6b65SMathiasRaoul  clib_mem_free (packet);
11692de6b65SMathiasRaoul}
11792de6b65SMathiasRaoul
11892de6b65SMathiasRaoulquicly_packet_allocator_t quic_packet_allocator =
11992de6b65SMathiasRaoul  { quic_alloc_packet, quic_free_packet };
12092de6b65SMathiasRaoul
121c298f376SNathan Skrzypczakstatic int
122d1b9e706SNathan Skrzypczakquic_app_cert_key_pair_delete_callback (app_cert_key_pair_t * ckpair)
123c298f376SNathan Skrzypczak{
124c298f376SNathan Skrzypczak  quic_main_t *qm = &quic_main;
125d1b9e706SNathan Skrzypczak  crypto_context_t *crctx;
126d1b9e706SNathan Skrzypczak  clib_bihash_kv_24_8_t kv;
127d1b9e706SNathan Skrzypczak  vlib_thread_main_t *vtm = vlib_get_thread_main ();
128d1b9e706SNathan Skrzypczak  int num_threads = 1 /* main thread */  + vtm->n_threads;
129d1b9e706SNathan Skrzypczak  int i;
130c298f376SNathan Skrzypczak
131d1b9e706SNathan Skrzypczak  for (i = 0; i < num_threads; i++)
132c298f376SNathan Skrzypczak    {
133d1b9e706SNathan Skrzypczak      /* *INDENT-OFF* */
134d1b9e706SNathan Skrzypczak      pool_foreach (crctx, qm->wrk_ctx[i].crypto_ctx_pool, ({
135d1b9e706SNathan Skrzypczak	if (crctx->ckpair_index == ckpair->cert_key_index)
136d1b9e706SNathan Skrzypczak	  {
137d1b9e706SNathan Skrzypczak	    quic_crypto_context_make_key_from_crctx (&kv, crctx);
138d1b9e706SNathan Skrzypczak	    clib_bihash_add_del_24_8 (&qm->wrk_ctx[i].crypto_context_hash, &kv, 0 /* is_add */ );
139d1b9e706SNathan Skrzypczak	  }
140d1b9e706SNathan Skrzypczak      }));
141d1b9e706SNathan Skrzypczak      /* *INDENT-ON* */
142c298f376SNathan Skrzypczak    }
143d1b9e706SNathan Skrzypczak  return 0;
144d1b9e706SNathan Skrzypczak}
145d1b9e706SNathan Skrzypczak
146d1b9e706SNathan Skrzypczakstatic crypto_context_t *
147d1b9e706SNathan Skrzypczakquic_crypto_context_alloc (u8 thread_index)
148d1b9e706SNathan Skrzypczak{
149d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
150d1b9e706SNathan Skrzypczak  crypto_context_t *crctx;
151d1b9e706SNathan Skrzypczak  u32 idx;
152d1b9e706SNathan Skrzypczak
153d1b9e706SNathan Skrzypczak  pool_get (qm->wrk_ctx[thread_index].crypto_ctx_pool, crctx);
154d1b9e706SNathan Skrzypczak  clib_memset (crctx, 0, sizeof (*crctx));
155d1b9e706SNathan Skrzypczak  idx = (crctx - qm->wrk_ctx[thread_index].crypto_ctx_pool);
156d1b9e706SNathan Skrzypczak  crctx->ctx_index = ((u32) thread_index) << 24 | idx;
157d1b9e706SNathan Skrzypczak
158d1b9e706SNathan Skrzypczak  return crctx;
159d1b9e706SNathan Skrzypczak}
160d1b9e706SNathan Skrzypczak
161d1b9e706SNathan Skrzypczakstatic crypto_context_t *
162d1b9e706SNathan Skrzypczakquic_crypto_context_get (u32 cr_index, u32 thread_index)
163d1b9e706SNathan Skrzypczak{
164d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
165d1b9e706SNathan Skrzypczak  ASSERT (cr_index >> 24 == thread_index);
166d1b9e706SNathan Skrzypczak  return pool_elt_at_index (qm->wrk_ctx[thread_index].crypto_ctx_pool,
167d1b9e706SNathan Skrzypczak			    cr_index & 0x00ffffff);
168d1b9e706SNathan Skrzypczak}
169d1b9e706SNathan Skrzypczak
170d1b9e706SNathan Skrzypczakstatic clib_error_t *
171d1b9e706SNathan Skrzypczakquic_list_crypto_context_command_fn (vlib_main_t * vm,
172d1b9e706SNathan Skrzypczak				     unformat_input_t * input,
173d1b9e706SNathan Skrzypczak				     vlib_cli_command_t * cmd)
174d1b9e706SNathan Skrzypczak{
175d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
176d1b9e706SNathan Skrzypczak  crypto_context_t *crctx;
177d1b9e706SNathan Skrzypczak  vlib_thread_main_t *vtm = vlib_get_thread_main ();
178d1b9e706SNathan Skrzypczak  int i, num_threads = 1 /* main thread */  + vtm->n_threads;
179d1b9e706SNathan Skrzypczak  for (i = 0; i < num_threads; i++)
180c298f376SNathan Skrzypczak    {
181d1b9e706SNathan Skrzypczak      /* *INDENT-OFF* */
182d1b9e706SNathan Skrzypczak      pool_foreach (crctx, qm->wrk_ctx[i].crypto_ctx_pool, ({
183d1b9e706SNathan Skrzypczak	vlib_cli_output (vm, "[%d][Q]%U", i, format_crypto_context, crctx);
184d1b9e706SNathan Skrzypczak      }));
185d1b9e706SNathan Skrzypczak      /* *INDENT-ON* */
186c298f376SNathan Skrzypczak    }
187d1b9e706SNathan Skrzypczak  return 0;
188d1b9e706SNathan Skrzypczak}
189d1b9e706SNathan Skrzypczak
19092de6b65SMathiasRaoulstatic clib_error_t *
19192de6b65SMathiasRaoulquic_set_max_packets_per_key_fn (vlib_main_t * vm,
19292de6b65SMathiasRaoul				 unformat_input_t * input,
19392de6b65SMathiasRaoul				 vlib_cli_command_t * cmd)
19492de6b65SMathiasRaoul{
19592de6b65SMathiasRaoul  quic_main_t *qm = &quic_main;
19692de6b65SMathiasRaoul  unformat_input_t _line_input, *line_input = &_line_input;
19792de6b65SMathiasRaoul  u64 tmp;
19892de6b65SMathiasRaoul
19992de6b65SMathiasRaoul  if (!unformat_user (input, unformat_line_input, line_input))
20092de6b65SMathiasRaoul    return 0;
20192de6b65SMathiasRaoul
20292de6b65SMathiasRaoul  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
20392de6b65SMathiasRaoul    {
20492de6b65SMathiasRaoul      if (unformat (line_input, "%U", unformat_memory_size, &tmp))
20592de6b65SMathiasRaoul	{
20692de6b65SMathiasRaoul	  qm->max_packets_per_key = tmp;
20792de6b65SMathiasRaoul	}
20892de6b65SMathiasRaoul      else
20992de6b65SMathiasRaoul	return clib_error_return (0, "unknown input '%U'",
21092de6b65SMathiasRaoul				  format_unformat_error, line_input);
21192de6b65SMathiasRaoul    }
21292de6b65SMathiasRaoul
21392de6b65SMathiasRaoul  return 0;
21492de6b65SMathiasRaoul}
21592de6b65SMathiasRaoul
216d1b9e706SNathan Skrzypczakstatic void
217d1b9e706SNathan Skrzypczakquic_release_crypto_context (u32 crypto_context_index, u8 thread_index)
218d1b9e706SNathan Skrzypczak{
219d1b9e706SNathan Skrzypczak  crypto_context_t *crctx;
220d1b9e706SNathan Skrzypczak  crctx = quic_crypto_context_get (crypto_context_index, thread_index);
221d1b9e706SNathan Skrzypczak  crctx->n_subscribers--;
222d1b9e706SNathan Skrzypczak  quic_crypto_context_free_if_needed (crctx, thread_index);
223d1b9e706SNathan Skrzypczak}
224d1b9e706SNathan Skrzypczak
225d1b9e706SNathan Skrzypczakstatic int
226d1b9e706SNathan Skrzypczakquic_init_crypto_context (crypto_context_t * crctx, quic_ctx_t * ctx)
227d1b9e706SNathan Skrzypczak{
228d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
229d1b9e706SNathan Skrzypczak  quicly_context_t *quicly_ctx;
230d1b9e706SNathan Skrzypczak  ptls_iovec_t key_vec;
231d1b9e706SNathan Skrzypczak  app_cert_key_pair_t *ckpair;
232d1b9e706SNathan Skrzypczak  application_t *app;
233d1b9e706SNathan Skrzypczak  quic_crypto_context_data_t *data;
234d1b9e706SNathan Skrzypczak  ptls_context_t *ptls_ctx;
235d1b9e706SNathan Skrzypczak
236d1b9e706SNathan Skrzypczak  QUIC_DBG (2, "Init quic crctx %d thread %d", crctx->ctx_index,
237d1b9e706SNathan Skrzypczak	    ctx->c_thread_index);
238d1b9e706SNathan Skrzypczak
239d1b9e706SNathan Skrzypczak  data = clib_mem_alloc (sizeof (*data));
240d1b9e706SNathan Skrzypczak  /* picotls depends on data being zeroed */
241d1b9e706SNathan Skrzypczak  clib_memset (data, 0, sizeof (*data));
242d1b9e706SNathan Skrzypczak  crctx->data = (void *) data;
243d1b9e706SNathan Skrzypczak  quicly_ctx = &data->quicly_ctx;
244d1b9e706SNathan Skrzypczak  ptls_ctx = &data->ptls_ctx;
245c298f376SNathan Skrzypczak
246c298f376SNathan Skrzypczak  ptls_ctx->random_bytes = ptls_openssl_random_bytes;
247c298f376SNathan Skrzypczak  ptls_ctx->get_time = &ptls_get_time;
248c298f376SNathan Skrzypczak  ptls_ctx->key_exchanges = ptls_openssl_key_exchanges;
249d1b9e706SNathan Skrzypczak  ptls_ctx->cipher_suites = qm->quic_ciphers[ctx->crypto_engine];
250c298f376SNathan Skrzypczak  ptls_ctx->certificates.list = NULL;
251c298f376SNathan Skrzypczak  ptls_ctx->certificates.count = 0;
252c298f376SNathan Skrzypczak  ptls_ctx->esni = NULL;
253c298f376SNathan Skrzypczak  ptls_ctx->on_client_hello = NULL;
254c298f376SNathan Skrzypczak  ptls_ctx->emit_certificate = NULL;
255c298f376SNathan Skrzypczak  ptls_ctx->sign_certificate = NULL;
256c298f376SNathan Skrzypczak  ptls_ctx->verify_certificate = NULL;
257c298f376SNathan Skrzypczak  ptls_ctx->ticket_lifetime = 86400;
258c298f376SNathan Skrzypczak  ptls_ctx->max_early_data_size = 8192;
259c298f376SNathan Skrzypczak  ptls_ctx->hkdf_label_prefix__obsolete = NULL;
260c298f376SNathan Skrzypczak  ptls_ctx->require_dhe_on_psk = 1;
261c298f376SNathan Skrzypczak  ptls_ctx->encrypt_ticket = &qm->session_cache.super;
262c298f376SNathan Skrzypczak  clib_memcpy (quicly_ctx, &quicly_spec_context, sizeof (quicly_context_t));
263c298f376SNathan Skrzypczak
264c298f376SNathan Skrzypczak  quicly_ctx->max_packet_size = QUIC_MAX_PACKET_SIZE;
26592de6b65SMathiasRaoul  quicly_ctx->max_packets_per_key = qm->max_packets_per_key;
266c298f376SNathan Skrzypczak  quicly_ctx->tls = ptls_ctx;
267c298f376SNathan Skrzypczak  quicly_ctx->stream_open = &on_stream_open;
268c298f376SNathan Skrzypczak  quicly_ctx->closed_by_peer = &on_closed_by_peer;
269c298f376SNathan Skrzypczak  quicly_ctx->now = &quicly_vpp_now_cb;
270c298f376SNathan Skrzypczak  quicly_amend_ptls_context (quicly_ctx->tls);
271c298f376SNathan Skrzypczak
27292de6b65SMathiasRaoul  quicly_ctx->packet_allocator = &quic_packet_allocator;
27392de6b65SMathiasRaoul  quicly_ctx->crypto_engine = &quic_crypto_engine;
274c298f376SNathan Skrzypczak  quicly_ctx->transport_params.max_data = QUIC_INT_MAX;
275c298f376SNathan Skrzypczak  quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60;
276c298f376SNathan Skrzypczak  quicly_ctx->transport_params.max_streams_bidi = (uint64_t) 1 << 60;
27762b1cea6SMathiasRaoul  quicly_ctx->transport_params.max_idle_timeout = qm->connection_timeout;
278c298f376SNathan Skrzypczak
279d1b9e706SNathan Skrzypczak  app = application_get (ctx->parent_app_id);
280d1b9e706SNathan Skrzypczak  quicly_ctx->transport_params.max_stream_data.bidi_local =
281d1b9e706SNathan Skrzypczak    app->sm_properties.rx_fifo_size - 1;
282d1b9e706SNathan Skrzypczak  quicly_ctx->transport_params.max_stream_data.bidi_remote =
283d1b9e706SNathan Skrzypczak    app->sm_properties.tx_fifo_size - 1;
284c298f376SNathan Skrzypczak  quicly_ctx->transport_params.max_stream_data.uni = QUIC_INT_MAX;
285c298f376SNathan Skrzypczak
286d1b9e706SNathan Skrzypczak  if (!app->quic_iv_set)
287d1b9e706SNathan Skrzypczak    {
288d1b9e706SNathan Skrzypczak      ptls_openssl_random_bytes (app->quic_iv, QUIC_IV_LEN - 1);
289d1b9e706SNathan Skrzypczak      app->quic_iv[QUIC_IV_LEN - 1] = 0;
290d1b9e706SNathan Skrzypczak      app->quic_iv_set = 1;
291d1b9e706SNathan Skrzypczak    }
292d1b9e706SNathan Skrzypczak
293d1b9e706SNathan Skrzypczak  clib_memcpy (data->cid_key, app->quic_iv, QUIC_IV_LEN);
294d1b9e706SNathan Skrzypczak  key_vec = ptls_iovec_init (data->cid_key, QUIC_IV_LEN);
295c298f376SNathan Skrzypczak  quicly_ctx->cid_encryptor =
296c298f376SNathan Skrzypczak    quicly_new_default_cid_encryptor (&ptls_openssl_bfecb,
297c298f376SNathan Skrzypczak				      &ptls_openssl_aes128ecb,
298c298f376SNathan Skrzypczak				      &ptls_openssl_sha256, key_vec);
299c298f376SNathan Skrzypczak
300d1b9e706SNathan Skrzypczak  ckpair = app_cert_key_pair_get_if_valid (crctx->ckpair_index);
301c298f376SNathan Skrzypczak  if (!ckpair || !ckpair->key || !ckpair->cert)
302c298f376SNathan Skrzypczak    {
303d1b9e706SNathan Skrzypczak      QUIC_DBG (1, "Wrong ckpair id %d\n", crctx->ckpair_index);
304d1b9e706SNathan Skrzypczak      return -1;
305c298f376SNathan Skrzypczak    }
306c298f376SNathan Skrzypczak  if (load_bio_private_key (quicly_ctx->tls, (char *) ckpair->key))
307c298f376SNathan Skrzypczak    {
308c298f376SNathan Skrzypczak      QUIC_DBG (1, "failed to read private key from app configuration\n");
309d1b9e706SNathan Skrzypczak      return -1;
310c298f376SNathan Skrzypczak    }
311c298f376SNathan Skrzypczak  if (load_bio_certificate_chain (quicly_ctx->tls, (char *) ckpair->cert))
312c298f376SNathan Skrzypczak    {
313c298f376SNathan Skrzypczak      QUIC_DBG (1, "failed to load certificate\n");
314d1b9e706SNathan Skrzypczak      return -1;
315c298f376SNathan Skrzypczak    }
316c298f376SNathan Skrzypczak  return 0;
317c298f376SNathan Skrzypczak
318d1b9e706SNathan Skrzypczak}
319d1b9e706SNathan Skrzypczak
320d1b9e706SNathan Skrzypczakstatic int
321d1b9e706SNathan Skrzypczakquic_acquire_crypto_context (quic_ctx_t * ctx)
322d1b9e706SNathan Skrzypczak{
323d1b9e706SNathan Skrzypczak  quic_main_t *qm = &quic_main;
324d1b9e706SNathan Skrzypczak  crypto_context_t *crctx;
325d1b9e706SNathan Skrzypczak  clib_bihash_kv_24_8_t kv;
326d1b9e706SNathan Skrzypczak
327d1b9e706SNathan Skrzypczak  if (ctx->crypto_engine == CRYPTO_ENGINE_NONE)
328d1b9e706SNathan Skrzypczak    {
329d1b9e706SNathan Skrzypczak      QUIC_DBG (2, "No crypto engine specified, using %d",
330d1b9e706SNathan Skrzypczak		qm->default_crypto_engine);
331d1b9e706SNathan Skrzypczak      ctx->crypto_engine = qm->default_crypto_engine;
332d1b9e706SNathan Skrzypczak    }
333d1b9e706SNathan Skrzypczak  if (!clib_bitmap_get (qm->available_crypto_engines, ctx->crypto_engine))
334d1b9e706SNathan Skrzypczak    {
335d1b9e706SNathan Skrzypczak      QUIC_DBG (1, "Quic does not support crypto engine %d",
336d1b9e706SNathan Skrzypczak		ctx->crypto_engine);
337d1b9e706SNathan Skrzypczak      return VNET_API_ERROR_MISSING_CERT_KEY;
338d1b9e706SNathan Skrzypczak    }
339d1b9e706SNathan Skrzypczak
340d1b9e706SNathan Skrzypczak  /* Check for exisiting crypto ctx */
341d1b9e706SNathan Skrzypczak  quic_crypto_context_make_key_from_ctx (&kv, ctx);
342d1b9e706SNathan Skrzypczak  if (clib_bihash_search_24_8
343d1b9e706SNathan Skrzypczak      (&qm->wrk_ctx[ctx->c_thread_index].crypto_context_hash, &kv, &kv) == 0)
344d1b9e706SNathan Skrzypczak    {
345d1b9e706SNathan Skrzypczak      crctx = quic_crypto_context_get (kv.value, ctx->c_thread_index);
346d1b9e706SNathan Skrzypczak      QUIC_DBG (2, "Found exisiting crypto context %d", kv.value);
347d1b9e706SNathan Skrzypczak      ctx->crypto_context_index = kv.value;
348d1b9e706SNathan Skrzypczak      crctx->n_subscribers++;
349d1b9e706SNathan Skrzypczak      return 0;
350d1b9e706SNathan Skrzypczak    }
351d1b9e706SNathan Skrzypczak
352d1b9e706SNathan Skrzypczak  crctx = quic_crypto_context_alloc (ctx->c_thread_index);
353d1b9e706SNathan Skrzypczak  ctx->crypto_context_index = crctx->ctx_index;
354d1b9e706SNathan Skrzypczak  kv.value = crctx->ctx_index;
355d1b9e706SNathan Skrzypczak  crctx->crypto_engine = ctx->crypto_engine;
356d1b9e706SNathan Skrzypczak  crctx->ckpair_index = ctx->ckpair_index;
357d1b9e706SNathan Skrzypczak  if (quic_init_crypto_context (crctx, ctx))
358d1b9e706SNathan Skrzypczak    goto error;
359d1b9e706SNathan Skrzypczak  if (vnet_app_add_cert_key_interest (ctx->ckpair_index, qm->app_index))
360d1b9e706SNathan Skrzypczak    goto error;
361d1b9e706SNathan Skrzypczak  crctx->n_subscribers++;
362d1b9e706SNathan Skrzypczak  clib_bihash_add_del_24_8 (&qm->
363d1b9e706SNathan Skrzypczak			    wrk_ctx[ctx->c_thread_index].crypto_context_hash,
364d1b9e706SNathan Skrzypczak			    &kv, 1 /* is_add */ );
365d1b9e706SNathan Skrzypczak  return 0;
366d1b9e706SNathan Skrzypczak
367c298f376SNathan Skrzypczakerror:
368d1b9e706SNathan Skrzypczak  quic_crypto_context_free_if_needed (crctx, ctx->c_thread_index);
369c298f376SNathan Skrzypczak  return VNET_API_ERROR_MISSING_CERT_KEY;
370c298f376SNathan Skrzypczak}
371c298f376SNathan Skrzypczak
3721dc90824SNathan Skrzypczak/*  Helper functions */
3733a34b1d9SNathan Skrzypczak
37439d04099SAloys Augustinstatic u32
375ba123e15SAloys Augustinquic_ctx_alloc (u32 thread_index)
37660f3e654SNathan Skrzypczak{
37760f3e654SNathan Skrzypczak  quic_main_t *qm = &quic_main;
37860f3e654SNathan Skrzypczak  quic_ctx_t *ctx;
37960f3e654SNathan Skrzypczak
38060f3e654SNathan Skrzypczak  pool_get (qm->ctx_pool[thread_index], ctx);
38160f3e654SNathan Skrzypczak
3821dc90824SNathan Skrzypczak  clib_memset (ctx, 0, sizeof (quic_ctx_t));
38360f3e654SNathan Skrzypczak  ctx->c_thread_index = thread_index;
3847f39e91fSNathan Skrzypczak  ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
38546eb1950SNathan Skrzypczak  QUIC_DBG (3, "Allocated quic_ctx %u on thread %u",
386ba123e15SAloys Augustin	    ctx - qm->ctx_pool[thread_index], thread_index);
38760f3e654SNathan Skrzypczak  return ctx - qm->ctx_pool[thread_index];
38860f3e654SNathan Skrzypczak}
38960f3e654SNathan Skrzypczak
39060f3e654SNathan Skrzypczakstatic void
39160f3e654SNathan Skrzypczakquic_ctx_free (quic_ctx_t * ctx)
39260f3e654SNathan Skrzypczak{
393caa7acf5SNathan Skrzypczak  QUIC_DBG (2, "Free ctx %u %x", ctx->c_thread_index, ctx->c_c_index);
39460f3e654SNathan Skrzypczak  u32 thread_index = ctx->c_thread_index;
395c9cb8f6dSNathan Skrzypczak  QUIC_ASSERT (ctx->timer_handle == QUIC_TIMER_HANDLE_INVALID);
39660f3e654SNathan Skrzypczak  if (CLIB_DEBUG)
3971dc90824SNathan Skrzypczak    clib_memset (ctx, 0xfb, sizeof (*ctx));
39860f3e654SNathan Skrzypczak  pool_put (quic_main.ctx_pool[thread_index], ctx);
39960f3e654SNathan Skrzypczak}
40060f3e654SNathan Skrzypczak
40160f3e654SNathan Skrzypczakstatic quic_ctx_t *
402ba123e15SAloys Augustinquic_ctx_get (u32 ctx_index, u32 thread_index)
40360f3e654SNathan Skrzypczak{
404ba123e15SAloys Augustin  return pool_elt_at_index (quic_main.ctx_pool[thread_index], ctx_index);
40560f3e654SNathan Skrzypczak}
40660f3e654SNathan Skrzypczak
407ace51525SNathan Skrzypczakstatic quic_ctx_t *
408ace51525SNathan Skrzypczakquic_ctx_get_if_valid (u32 ctx_index, u32 thread_index)
409ace51525SNathan Skrzypczak{
410ace51525SNathan Skrzypczak  if (pool_is_free_index (quic_main.ctx_pool[thread_index], ctx_index))
411ace51525SNathan Skrzypczak    return 0;
412ace51525SNathan Skrzypczak  return pool_elt_at_index (quic_main.ctx_pool[thread_index], ctx_index);
413ace51525SNathan Skrzypczak}
414ace51525SNathan Skrzypczak
41592de6b65SMathiasRaoulquic_ctx_t *
416ba123e15SAloys Augustinquic_get_conn_ctx (quicly_conn_t * conn)
41760f3e654SNathan Skrzypczak{
418ba123e15SAloys Augustin  u64 conn_data;
419ba123e15SAloys Augustin  conn_data = (u64) * quicly_get_data (conn);
420ba123e15SAloys Augustin  return quic_ctx_get (conn_data & UINT32_MAX, conn_data >> 32);
421ba123e15SAloys Augustin}
422ba123e15SAloys Augustin
423ba123e15SAloys Augustinstatic void
424ba123e15SAloys Augustinquic_store_conn_ctx (quicly_conn_t * conn, quic_ctx_t * ctx)
425ba123e15SAloys Augustin{
426ba123e15SAloys Augustin  *quicly_get_data (conn) =
427ba123e15SAloys Augustin    (void *) (((u64) ctx->c_thread_index) << 32 | (u64) ctx->c_c_index);
42860f3e654SNathan Skrzypczak}
42960f3e654SNathan Skrzypczak
430e92090b4SNathan Skrzypczakstatic inline int
431e92090b4SNathan Skrzypczakquic_ctx_is_stream (quic_ctx_t * ctx)
432e92090b4SNathan Skrzypczak{
433e92090b4SNathan Skrzypczak  return (ctx->flags & QUIC_F_IS_STREAM);
434e92090b4SNathan Skrzypczak}
435e92090b4SNathan Skrzypczak
436e92090b4SNathan Skrzypczakstatic inline int
437e92090b4SNathan Skrzypczakquic_ctx_is_listener (quic_ctx_t * ctx)
438e92090b4SNathan Skrzypczak{
439e92090b4SNathan Skrzypczak  return (ctx->flags & QUIC_F_IS_LISTENER);
440e92090b4SNathan Skrzypczak}
441e92090b4SNathan Skrzypczak
442deaf97f4SNathan Skrzypczakstatic inline int
443deaf97f4SNathan Skrzypczakquic_ctx_is_conn (quic_ctx_t * ctx)
444deaf97f4SNathan Skrzypczak{
445deaf97f4SNathan Skrzypczak  return !(quic_ctx_is_listener (ctx) || quic_ctx_is_stream (ctx));
446deaf97f4SNathan Skrzypczak}
447deaf97f4SNathan Skrzypczak
44892e13146SAloys Augustinstatic inline session_t *
44992e13146SAloys Augustinget_stream_session_and_ctx_from_stream (quicly_stream_t * stream,
45092e13146SAloys Augustin					quic_ctx_t ** ctx)
451e92090b4SNathan Skrzypczak{
452e92090b4SNathan Skrzypczak  quic_stream_data_t *stream_data;
453e92090b4SNathan Skrzypczak
454e92090b4SNathan Skrzypczak  stream_data = (quic_stream_data_t *) stream->data;
45592e13146SAloys Augustin  *ctx = quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
45692e13146SAloys Augustin  return session_get ((*ctx)->c_s_index, stream_data->thread_index);
457e92090b4SNathan Skrzypczak}
458e92090b4SNathan Skrzypczak
459e92090b4SNathan Skrzypczakstatic inline void
460e92090b4SNathan Skrzypczakquic_make_connection_key (clib_bihash_kv_16_8_t * kv,
461e92090b4SNathan Skrzypczak			  const quicly_cid_plaintext_t * id)
462e92090b4SNathan Skrzypczak{
463e92090b4SNathan Skrzypczak  kv->key[0] = ((u64) id->master_id) << 32 | (u64) id->thread_id;
464e92090b4SNathan Skrzypczak  kv->key[1] = id->node_id;
465e92090b4SNathan Skrzypczak}
466e92090b4SNathan Skrzypczak
467e92090b4SNathan Skrzypczakstatic int
468e92090b4SNathan Skrzypczakquic_sendable_packet_count (session_t * udp_session)
469e92090b4SNathan Skrzypczak{
470e92090b4SNathan Skrzypczak  u32 max_enqueue;
471e92090b4SNathan Skrzypczak  u32 packet_size = QUIC_MAX_PACKET_SIZE + SESSION_CONN_HDR_LEN;
472e92090b4SNathan Skrzypczak  max_enqueue = svm_fifo_max_enqueue (udp_session->tx_fifo);
473e92090b4SNathan Skrzypczak  return clib_min (max_enqueue / packet_size, QUIC_SEND_PACKET_VEC_SIZE);
474e92090b4SNathan Skrzypczak}
475e92090b4SNathan Skrzypczak
476797848d4SNathan Skrzypczakstatic quicly_context_t *
477797848d4SNathan Skrzypczakquic_get_quicly_ctx_from_ctx (quic_ctx_t * ctx)
478797848d4SNathan Skrzypczak{
479d1b9e706SNathan Skrzypczak  crypto_context_t *crctx =
480d1b9e706SNathan Skrzypczak    quic_crypto_context_get (ctx->crypto_context_index, ctx->c_thread_index);
481d1b9e706SNathan Skrzypczak  quic_crypto_context_data_t *data =
482d1b9e706SNathan Skrzypczak    (quic_crypto_context_data_t *) crctx->data;
483d1b9e706SNathan Skrzypczak  return &data->quicly_ctx;
484797848d4SNathan Skrzypczak}
485797848d4SNathan Skrzypczak
486797848d4SNathan Skrzypczakstatic quicly_context_t *
487243e1933SAloys Augustinquic_get_quicly_ctx_from_udp (u64 udp_session_handle)
488797848d4SNathan Skrzypczak{
489caa7acf5SNathan Skrzypczak  session_t *udp_session = session_get_from_handle (udp_session_handle);
490caa7acf5SNathan Skrzypczak  quic_ctx_t *ctx =
491caa7acf5SNathan Skrzypczak    quic_ctx_get (udp_session->opaque, udp_session->thread_index);
492d1b9e706SNathan Skrzypczak  return quic_get_quicly_ctx_from_ctx (ctx);
493797848d4SNathan Skrzypczak}
494e92090b4SNathan Skrzypczak
4951dc90824SNathan Skrzypczakstatic inline void
4961dc90824SNathan Skrzypczakquic_set_udp_tx_evt (session_t * udp_session)
4971dc90824SNathan Skrzypczak{
4981dc90824SNathan Skrzypczak  int rv = 0;
4991dc90824SNathan Skrzypczak  if (svm_fifo_set_event (udp_session->tx_fifo))
5001dc90824SNathan Skrzypczak    rv = session_send_io_evt_to_thread (udp_session->tx_fifo,
5011dc90824SNathan Skrzypczak					SESSION_IO_EVT_TX);
5021dc90824SNathan Skrzypczak  if (PREDICT_FALSE (rv))
5031dc90824SNathan Skrzypczak    clib_warning ("Event enqueue errored %d", rv);
5041dc90824SNathan Skrzypczak}
5051dc90824SNathan Skrzypczak
5067f39e91fSNathan Skrzypczakstatic inline void
5077f39e91fSNathan Skrzypczakquic_stop_ctx_timer (quic_ctx_t * ctx)
5087f39e91fSNathan Skrzypczak{
5097f39e91fSNathan Skrzypczak  tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
5107f39e91fSNathan Skrzypczak  if (ctx->timer_handle == QUIC_TIMER_HANDLE_INVALID)
5117f39e91fSNathan Skrzypczak    return;
5127f39e91fSNathan Skrzypczak  tw = &quic_main.wrk_ctx[ctx->c_thread_index].timer_wheel;
5137f39e91fSNathan Skrzypczak  tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
5147f39e91fSNathan Skrzypczak  ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
5157f39e91fSNathan Skrzypczak  QUIC_DBG (4, "Stopping timer for ctx %u", ctx->c_c_index);
5167f39e91fSNathan Skrzypczak}
5177f39e91fSNathan Skrzypczak
5181dc90824SNathan Skrzypczak/* QUIC protocol actions */
5191dc90824SNathan Skrzypczak
520e92090b4SNathan Skrzypczakstatic void
521e92090b4SNathan Skrzypczakquic_ack_rx_data (session_t * stream_session)
522e92090b4SNathan Skrzypczak{
523e92090b4SNathan Skrzypczak  u32 max_deq;
524e92090b4SNathan Skrzypczak  quic_ctx_t *sctx;
525e92090b4SNathan Skrzypczak  svm_fifo_t *f;
526e92090b4SNathan Skrzypczak  quicly_stream_t *stream;
527e92090b4SNathan Skrzypczak  quic_stream_data_t *stream_data;
528e92090b4SNathan Skrzypczak
5291dc90824SNathan Skrzypczak  sctx = quic_ctx_get (stream_session->connection_index,
5301dc90824SNathan Skrzypczak		       stream_session->thread_index);
531c9cb8f6dSNathan Skrzypczak  QUIC_ASSERT (quic_ctx_is_stream (sctx));
5321c2af068SAloys Augustin  stream = sctx->stream;
533e92090b4SNathan Skrzypczak  stream_data = (quic_stream_data_t *) stream->data;
534e92090b4SNathan Skrzypczak
535e92090b4SNathan Skrzypczak  f = stream_session->rx_fifo;
536e92090b4SNathan Skrzypczak  max_deq = svm_fifo_max_dequeue (f);
537e92090b4SNathan Skrzypczak
538c9cb8f6dSNathan Skrzypczak  QUIC_ASSERT (stream_data->app_rx_data_len >= max_deq);
539e92090b4SNathan Skrzypczak  quicly_stream_sync_recvbuf (stream, stream_data->app_rx_data_len - max_deq);
540e92090b4SNathan Skrzypczak  QUIC_DBG (3, "Acking %u bytes", stream_data->app_rx_data_len - max_deq);
541e92090b4SNathan Skrzypczak  stream_data->app_rx_data_len = max_deq;
542e92090b4SNathan Skrzypczak}
543e92090b4SNathan Skrzypczak
54460f3e654SNathan Skrzypczakstatic void
54560f3e654SNathan Skrzypczakquic_disconnect_transport (quic_ctx_t * ctx)
54660f3e654SNathan Skrzypczak{
547e92090b4SNathan Skrzypczak  QUIC_DBG (2, "Disconnecting transport 0x%lx", ctx->udp_session_handle);
54860f3e654SNathan Skrzypczak  vnet_disconnect_args_t a = {
549e92090b4SNathan Skrzypczak    .handle = ctx->udp_session_handle,
55060f3e654SNathan Skrzypczak    .app_index = quic_main.app_index,
55160f3e654SNathan Skrzypczak  };
55260f3e654SNathan Skrzypczak
55360f3e654SNathan Skrzypczak  if (vnet_disconnect_session (&a))
554e92090b4SNathan Skrzypczak    clib_warning ("UDP session 0x%lx disconnect errored",
555e92090b4SNathan Skrzypczak		  ctx->udp_session_handle);
556e92090b4SNathan Skrzypczak}
557e92090b4SNathan Skrzypczak
558e92090b4SNathan Skrzypczakstatic void
559b725ebb3SAloys Augustinquic_connection_delete (quic_ctx_t * ctx)
560e92090b4SNathan Skrzypczak{
561e92090b4SNathan Skrzypczak  clib_bihash_kv_16_8_t kv;
562e92090b4SNathan Skrzypczak  quicly_conn_t *conn;
563e92090b4SNathan Skrzypczak
564b725ebb3SAloys Augustin  QUIC_DBG (2, "Deleting connection %u", ctx->c_c_index);
565b725ebb3SAloys Augustin
566c9cb8f6dSNathan Skrzypczak  QUIC_ASSERT (!quic_ctx_is_stream (ctx));
5677f39e91fSNathan Skrzypczak  quic_stop_ctx_timer (ctx);
568e92090b4SNathan Skrzypczak
569e92090b4SNathan Skrzypczak  /*  Delete the connection from the connection map */
5701c2af068SAloys Augustin  conn = ctx->conn;
571deaf97f4SNathan Skrzypczak  ctx->conn = NULL;
572e92090b4SNathan Skrzypczak  quic_make_connection_key (&kv, quicly_get_master_id (conn));
573b725ebb3SAloys Augustin  QUIC_DBG (2, "Deleting conn with id %lu %lu from map", kv.key[0],
574b725ebb3SAloys Augustin	    kv.key[1]);
575e92090b4SNathan Skrzypczak  clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ );
576e92090b4SNathan Skrzypczak
577e92090b4SNathan Skrzypczak  quic_disconnect_transport (ctx);
578b725ebb3SAloys Augustin
5791c2af068SAloys Augustin  if (ctx->conn)
5801c2af068SAloys Augustin    quicly_free (ctx->conn);
581b725ebb3SAloys Augustin  session_transport_delete_notify (&ctx->connection);
58260f3e654SNathan Skrzypczak}
58360f3e654SNathan Skrzypczak
584ff1f6faaSMathiasRaoulvoid
585ff1f6faaSMathiasRaoulquic_increment_counter (u8 evt, u8 val)
586ff1f6faaSMathiasRaoul{
587ff1f6faaSMathiasRaoul  vlib_main_t *vm = vlib_get_main ();
588ff1f6faaSMathiasRaoul  vlib_node_increment_counter (vm, quic_input_node.index, evt, val);
589ff1f6faaSMathiasRaoul}
590ff1f6faaSMathiasRaoul
591b725ebb3SAloys Augustin/**
592b725ebb3SAloys Augustin * Called when quicly return an error
593b725ebb3SAloys Augustin * This function interacts tightly with quic_proto_on_close
594b725ebb3SAloys Augustin */
595b725ebb3SAloys Augustinstatic void
596b725ebb3SAloys Augustinquic_connection_closed (quic_ctx_t * ctx)
597b725ebb3SAloys Augustin{
598b725ebb3SAloys Augustin  QUIC_DBG (2, "QUIC connection %u/%u closed", ctx->c_thread_index,
599b725ebb3SAloys Augustin	    ctx->c_c_index);
600b725ebb3SAloys Augustin
601b725ebb3SAloys Augustin  /* TODO if connection is not established, just delete the session? */
602b725ebb3SAloys Augustin  /* Actually should send connect or accept error */
603b725ebb3SAloys Augustin
6041c2af068SAloys Augustin  switch (ctx->conn_state)
605b725ebb3SAloys Augustin    {
606b725ebb3SAloys Augustin    case QUIC_CONN_STATE_READY:
607b725ebb3SAloys Augustin      /* Error on an opened connection (timeout...)
608b725ebb3SAloys Augustin         This puts the session in closing state, we should receive a notification
609b725ebb3SAloys Augustin         when the app has closed its session */
610b725ebb3SAloys Augustin      session_transport_reset_notify (&ctx->connection);
611b725ebb3SAloys Augustin      /* This ensures we delete the connection when the app confirms the close */
6121c2af068SAloys Augustin      ctx->conn_state = QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED;
613b725ebb3SAloys Augustin      break;
614b725ebb3SAloys Augustin    case QUIC_CONN_STATE_PASSIVE_CLOSING:
6151c2af068SAloys Augustin      ctx->conn_state = QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED;
616b725ebb3SAloys Augustin      /* quic_proto_on_close will eventually be called when the app confirms the close
617b725ebb3SAloys Augustin         , we delete the connection at that point */
618b725ebb3SAloys Augustin      break;
619b725ebb3SAloys Augustin    case QUIC_CONN_STATE_PASSIVE_CLOSING_APP_CLOSED:
620b725ebb3SAloys Augustin      /* App already confirmed close, we can delete the connection */
621b725ebb3SAloys Augustin      quic_connection_delete (ctx);
622b725ebb3SAloys Augustin      break;
623d9577b4aSNathan Skrzypczak    case QUIC_CONN_STATE_OPENED:
624d9577b4aSNathan Skrzypczak    case QUIC_CONN_STATE_HANDSHAKE:
625b725ebb3SAloys Augustin    case QUIC_CONN_STATE_ACTIVE_CLOSING:
626b725ebb3SAloys Augustin      quic_connection_delete (ctx);
627b725ebb3SAloys Augustin      break;
628b725ebb3SAloys Augustin    default:
629caa7acf5SNathan Skrzypczak      QUIC_DBG (0, "BUG %d", ctx->conn_state);
630b725ebb3SAloys Augustin      break;
631b725ebb3SAloys Augustin    }
632b725ebb3SAloys Augustin}
633b725ebb3SAloys Augustin
63460f3e654SNathan Skrzypczakstatic int
63539d04099SAloys Augustinquic_send_datagram (session_t * udp_session, quicly_datagram_t * packet)
63660f3e654SNathan Skrzypczak{
63760f3e654SNathan Skrzypczak  u32 max_enqueue;
63860f3e654SNathan Skrzypczak  session_dgram_hdr_t hdr;
6393a34b1d9SNathan Skrzypczak  u32 len, ret;
64060f3e654SNathan Skrzypczak  svm_fifo_t *f;
64160f3e654SNathan Skrzypczak  transport_connection_t *tc;
64260f3e654SNathan Skrzypczak
64360f3e654SNathan Skrzypczak  len = packet->data.len;
64439d04099SAloys Augustin  f = udp_session->tx_fifo;
64539d04099SAloys Augustin  tc = session_get_transport (udp_session);
64660f3e654SNathan Skrzypczak  max_enqueue = svm_fifo_max_enqueue (f);
647e82a7adeSNathan Skrzypczak  if (max_enqueue < SESSION_CONN_HDR_LEN + len)
6483a34b1d9SNathan Skrzypczak    {
6490b6c9c48SNathan Skrzypczak      QUIC_ERR ("Too much data to send, max_enqueue %u, len %u",
650e82a7adeSNathan Skrzypczak		max_enqueue, len + SESSION_CONN_HDR_LEN);
651cefb5ad3SNathan Skrzypczak      return QUIC_ERROR_FULL_FIFO;
6523a34b1d9SNathan Skrzypczak    }
65360f3e654SNathan Skrzypczak
6543a34b1d9SNathan Skrzypczak  /*  Build packet header for fifo */
65560f3e654SNathan Skrzypczak  hdr.data_length = len;
65660f3e654SNathan Skrzypczak  hdr.data_offset = 0;
65760f3e654SNathan Skrzypczak  hdr.is_ip4 = tc->is_ip4;
65860f3e654SNathan Skrzypczak  clib_memcpy (&hdr.lcl_ip, &tc->lcl_ip, sizeof (ip46_address_t));
65960f3e654SNathan Skrzypczak  hdr.lcl_port = tc->lcl_port;
66060f3e654SNathan Skrzypczak
6613a34b1d9SNathan Skrzypczak  /*  Read dest address from quicly-provided sockaddr */
66260f3e654SNathan Skrzypczak  if (hdr.is_ip4)
66360f3e654SNathan Skrzypczak    {
664c9cb8f6dSNathan Skrzypczak      QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET);
66572c159e6SMathiasRaoul      struct sockaddr_in *sa4 = (struct sockaddr_in *) &packet->dest.sa;
666