tls: fix handling of client and server init errors
[vpp.git] / src / vnet / tls / tls.c
1 /*
2  * Copyright (c) 2018-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/session/application_interface.h>
17 #include <vppinfra/lock.h>
18 #include <vnet/tls/tls.h>
19
20 static tls_main_t tls_main;
21 static tls_engine_vft_t *tls_vfts;
22
23 #define TLS_INVALID_HANDLE      ~0
24 #define TLS_IDX_MASK            0x00FFFFFF
25 #define TLS_ENGINE_TYPE_SHIFT   28
26
27 void tls_disconnect (u32 ctx_handle, u32 thread_index);
28
29 void
30 tls_disconnect_transport (tls_ctx_t * ctx)
31 {
32   vnet_disconnect_args_t a = {
33     .handle = ctx->tls_session_handle,
34     .app_index = tls_main.app_index,
35   };
36
37   if (vnet_disconnect_session (&a))
38     clib_warning ("disconnect returned");
39 }
40
41 crypto_engine_type_t
42 tls_get_available_engine (void)
43 {
44   int i;
45   for (i = 0; i < vec_len (tls_vfts); i++)
46     {
47       if (tls_vfts[i].ctx_alloc)
48         return i;
49     }
50   return CRYPTO_ENGINE_NONE;
51 }
52
53 int
54 tls_add_vpp_q_rx_evt (session_t * s)
55 {
56   if (svm_fifo_set_event (s->rx_fifo))
57     session_send_io_evt_to_thread (s->rx_fifo, SESSION_IO_EVT_RX);
58   return 0;
59 }
60
61 int
62 tls_add_vpp_q_builtin_rx_evt (session_t * s)
63 {
64   session_enqueue_notify (s);
65   return 0;
66 }
67
68 int
69 tls_add_vpp_q_tx_evt (session_t * s)
70 {
71   if (svm_fifo_set_event (s->tx_fifo))
72     session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX);
73   return 0;
74 }
75
76 static inline int
77 tls_add_app_q_evt (app_worker_t *app_wrk, session_t *app_session)
78 {
79   app_worker_add_event (app_wrk, app_session, SESSION_IO_EVT_RX);
80   return 0;
81 }
82
83 u32
84 tls_listener_ctx_alloc (void)
85 {
86   tls_main_t *tm = &tls_main;
87   tls_ctx_t *ctx;
88
89   pool_get (tm->listener_ctx_pool, ctx);
90   clib_memset (ctx, 0, sizeof (*ctx));
91   return ctx - tm->listener_ctx_pool;
92 }
93
94 void
95 tls_listener_ctx_free (tls_ctx_t * ctx)
96 {
97   if (CLIB_DEBUG)
98     memset (ctx, 0xfb, sizeof (*ctx));
99   pool_put (tls_main.listener_ctx_pool, ctx);
100 }
101
102 tls_ctx_t *
103 tls_listener_ctx_get (u32 ctx_index)
104 {
105   return pool_elt_at_index (tls_main.listener_ctx_pool, ctx_index);
106 }
107
108 u32
109 tls_listener_ctx_index (tls_ctx_t * ctx)
110 {
111   return (ctx - tls_main.listener_ctx_pool);
112 }
113
114 u32
115 tls_ctx_half_open_alloc (void)
116 {
117   tls_main_t *tm = &tls_main;
118   tls_ctx_t *ctx;
119
120   pool_get_aligned_safe (tm->half_open_ctx_pool, ctx, CLIB_CACHE_LINE_BYTES);
121
122   clib_memset (ctx, 0, sizeof (*ctx));
123   ctx->c_c_index = ctx - tm->half_open_ctx_pool;
124   ctx->c_thread_index = transport_cl_thread ();
125
126   return ctx->c_c_index;
127 }
128
129 void
130 tls_ctx_half_open_free (u32 ho_index)
131 {
132   pool_put_index (tls_main.half_open_ctx_pool, ho_index);
133 }
134
135 tls_ctx_t *
136 tls_ctx_half_open_get (u32 ctx_index)
137 {
138   tls_main_t *tm = &tls_main;
139   return pool_elt_at_index (tm->half_open_ctx_pool, ctx_index);
140 }
141
142 void
143 tls_notify_app_enqueue (tls_ctx_t * ctx, session_t * app_session)
144 {
145   app_worker_t *app_wrk;
146   app_wrk = app_worker_get_if_valid (app_session->app_wrk_index);
147   if (PREDICT_TRUE (app_wrk != 0))
148     tls_add_app_q_evt (app_wrk, app_session);
149 }
150
151 int
152 tls_notify_app_accept (tls_ctx_t * ctx)
153 {
154   session_t *app_listener, *app_session;
155   app_worker_t *app_wrk;
156   tls_ctx_t *lctx;
157   int rv;
158
159   lctx = tls_listener_ctx_get (ctx->listener_ctx_index);
160   app_listener = listen_session_get_from_handle (lctx->app_session_handle);
161
162   app_session = session_get (ctx->c_s_index, ctx->c_thread_index);
163   app_session->app_wrk_index = ctx->parent_app_wrk_index;
164   app_session->connection_index = ctx->tls_ctx_handle;
165   app_session->session_type = app_listener->session_type;
166   app_session->listener_handle = listen_session_get_handle (app_listener);
167   app_session->session_state = SESSION_STATE_ACCEPTING;
168
169   if ((rv = app_worker_init_accepted (app_session)))
170     {
171       TLS_DBG (1, "failed to allocate fifos");
172       session_free (app_session);
173       return rv;
174     }
175   ctx->app_session_handle = session_handle (app_session);
176   ctx->parent_app_wrk_index = app_session->app_wrk_index;
177   app_wrk = app_worker_get (app_session->app_wrk_index);
178   return app_worker_accept_notify (app_wrk, app_session);
179 }
180
181 int
182 tls_notify_app_connected (tls_ctx_t * ctx, session_error_t err)
183 {
184   u32 parent_app_api_ctx;
185   session_t *app_session;
186   app_worker_t *app_wrk;
187
188   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_index);
189   if (!app_wrk)
190     {
191       if (ctx->tls_type == TRANSPORT_PROTO_TLS)
192         session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
193       ctx->no_app_session = 1;
194       return -1;
195     }
196
197   if (err)
198     {
199       /* Free app session pre-allocated when transport was established */
200       if (ctx->tls_type == TRANSPORT_PROTO_TLS)
201         session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
202       ctx->no_app_session = 1;
203       goto send_reply;
204     }
205
206   /* For DTLS the app session is not preallocated because the underlying udp
207    * session might migrate to a different worker during the handshake */
208   if (ctx->tls_type == TRANSPORT_PROTO_DTLS)
209     {
210       session_type_t st;
211       /* Cleanup half-open session as we don't get notification from udp */
212       session_half_open_delete_notify (&ctx->connection);
213       app_session = session_alloc (ctx->c_thread_index);
214       app_session->session_state = SESSION_STATE_CREATED;
215       ctx->c_s_index = app_session->session_index;
216       st =
217         session_type_from_proto_and_ip (TRANSPORT_PROTO_DTLS, ctx->tcp_is_ip4);
218       app_session->session_type = st;
219       app_session->connection_index = ctx->tls_ctx_handle;
220     }
221   else
222     {
223       app_session = session_get (ctx->c_s_index, ctx->c_thread_index);
224     }
225
226   app_session->app_wrk_index = ctx->parent_app_wrk_index;
227   app_session->opaque = ctx->parent_app_api_context;
228
229   if ((err = app_worker_init_connected (app_wrk, app_session)))
230     {
231       app_worker_connect_notify (app_wrk, 0, err, ctx->parent_app_api_context);
232       ctx->no_app_session = 1;
233       session_free (app_session);
234       return -1;
235     }
236
237   app_session->session_state = SESSION_STATE_READY;
238   parent_app_api_ctx = ctx->parent_app_api_context;
239   ctx->app_session_handle = session_handle (app_session);
240
241   if (app_worker_connect_notify (app_wrk, app_session, SESSION_E_NONE,
242                                  parent_app_api_ctx))
243     {
244       TLS_DBG (1, "failed to notify app");
245       session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
246       ctx->no_app_session = 1;
247       return -1;
248     }
249
250   return 0;
251
252 send_reply:
253   return app_worker_connect_notify (app_wrk, 0, err,
254                                     ctx->parent_app_api_context);
255 }
256
257 static inline void
258 tls_ctx_parse_handle (u32 ctx_handle, u32 * ctx_index, u32 * engine_type)
259 {
260   *ctx_index = ctx_handle & TLS_IDX_MASK;
261   *engine_type = ctx_handle >> TLS_ENGINE_TYPE_SHIFT;
262 }
263
264 static inline crypto_engine_type_t
265 tls_get_engine_type (crypto_engine_type_t requested,
266                      crypto_engine_type_t preferred)
267 {
268   if (requested != CRYPTO_ENGINE_NONE)
269     {
270       if (tls_vfts[requested].ctx_alloc)
271         return requested;
272       return CRYPTO_ENGINE_NONE;
273     }
274   if (!tls_vfts[preferred].ctx_alloc)
275     return tls_get_available_engine ();
276   return preferred;
277 }
278
279 static inline u32
280 tls_ctx_alloc (crypto_engine_type_t engine_type)
281 {
282   u32 ctx_index;
283   ctx_index = tls_vfts[engine_type].ctx_alloc ();
284   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
285 }
286
287 static inline u32
288 tls_ctx_alloc_w_thread (crypto_engine_type_t engine_type, u32 thread_index)
289 {
290   u32 ctx_index;
291   ctx_index = tls_vfts[engine_type].ctx_alloc_w_thread (thread_index);
292   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
293 }
294
295 static inline u32
296 tls_ctx_attach (crypto_engine_type_t engine_type, u32 thread_index, void *ctx)
297 {
298   u32 ctx_index;
299   ctx_index = tls_vfts[engine_type].ctx_attach (thread_index, ctx);
300   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
301 }
302
303 static inline void *
304 tls_ctx_detach (tls_ctx_t *ctx)
305 {
306   return tls_vfts[ctx->tls_ctx_engine].ctx_detach (ctx);
307 }
308
309 static inline tls_ctx_t *
310 tls_ctx_get (u32 ctx_handle)
311 {
312   u32 ctx_index, engine_type;
313   tls_ctx_parse_handle (ctx_handle, &ctx_index, &engine_type);
314   return tls_vfts[engine_type].ctx_get (ctx_index);
315 }
316
317 static inline tls_ctx_t *
318 tls_ctx_get_w_thread (u32 ctx_handle, u8 thread_index)
319 {
320   u32 ctx_index, engine_type;
321   tls_ctx_parse_handle (ctx_handle, &ctx_index, &engine_type);
322   return tls_vfts[engine_type].ctx_get_w_thread (ctx_index, thread_index);
323 }
324
325 static inline int
326 tls_ctx_init_server (tls_ctx_t * ctx)
327 {
328   return tls_vfts[ctx->tls_ctx_engine].ctx_init_server (ctx);
329 }
330
331 static inline int
332 tls_ctx_init_client (tls_ctx_t * ctx)
333 {
334   return tls_vfts[ctx->tls_ctx_engine].ctx_init_client (ctx);
335 }
336
337 static inline int
338 tls_ctx_write (tls_ctx_t * ctx, session_t * app_session,
339                transport_send_params_t * sp)
340 {
341   u32 n_wrote;
342
343   sp->max_burst_size = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS;
344   n_wrote = tls_vfts[ctx->tls_ctx_engine].ctx_write (ctx, app_session, sp);
345   sp->bytes_dequeued = n_wrote;
346   return n_wrote > 0 ? clib_max (n_wrote / TRANSPORT_PACER_MIN_MSS, 1) : 0;
347 }
348
349 static inline int
350 tls_ctx_read (tls_ctx_t * ctx, session_t * tls_session)
351 {
352   return tls_vfts[ctx->tls_ctx_engine].ctx_read (ctx, tls_session);
353 }
354
355 static inline int
356 tls_ctx_transport_close (tls_ctx_t * ctx)
357 {
358   return tls_vfts[ctx->tls_ctx_engine].ctx_transport_close (ctx);
359 }
360
361 static inline int
362 tls_ctx_app_close (tls_ctx_t * ctx)
363 {
364   return tls_vfts[ctx->tls_ctx_engine].ctx_app_close (ctx);
365 }
366
367 void
368 tls_ctx_free (tls_ctx_t * ctx)
369 {
370   tls_vfts[ctx->tls_ctx_engine].ctx_free (ctx);
371 }
372
373 u8
374 tls_ctx_handshake_is_over (tls_ctx_t * ctx)
375 {
376   return tls_vfts[ctx->tls_ctx_engine].ctx_handshake_is_over (ctx);
377 }
378
379 int
380 tls_reinit_ca_chain (crypto_engine_type_t tls_engine_id)
381 {
382   return tls_vfts[tls_engine_id].ctx_reinit_cachain ();
383 }
384
385 void
386 tls_notify_app_io_error (tls_ctx_t *ctx)
387 {
388   ASSERT (tls_ctx_handshake_is_over (ctx));
389
390   session_transport_reset_notify (&ctx->connection);
391   session_transport_closed_notify (&ctx->connection);
392   tls_disconnect_transport (ctx);
393 }
394
395 void
396 tls_session_reset_callback (session_t * s)
397 {
398   tls_ctx_t *ctx;
399   transport_connection_t *tc;
400   session_t *app_session;
401
402   ctx = tls_ctx_get (s->opaque);
403   ctx->is_passive_close = 1;
404   tc = &ctx->connection;
405   if (tls_ctx_handshake_is_over (ctx))
406     {
407       session_transport_reset_notify (tc);
408       session_transport_closed_notify (tc);
409       tls_disconnect_transport (ctx);
410     }
411   else
412     if ((app_session =
413          session_get_if_valid (ctx->c_s_index, ctx->c_thread_index)))
414     {
415       session_free (app_session);
416       ctx->c_s_index = SESSION_INVALID_INDEX;
417       tls_disconnect_transport (ctx);
418     }
419 }
420
421 static void
422 tls_session_cleanup_ho (session_t *s)
423 {
424   tls_ctx_t *ctx;
425   u32 ho_index;
426
427   /* session opaque stores the opaque passed on connect */
428   ho_index = s->opaque;
429   ctx = tls_ctx_half_open_get (ho_index);
430   session_half_open_delete_notify (&ctx->connection);
431   tls_ctx_half_open_free (ho_index);
432 }
433
434 int
435 tls_add_segment_callback (u32 client_index, u64 segment_handle)
436 {
437   /* No-op for builtin */
438   return 0;
439 }
440
441 int
442 tls_del_segment_callback (u32 client_index, u64 segment_handle)
443 {
444   return 0;
445 }
446
447 void
448 tls_session_disconnect_callback (session_t * tls_session)
449 {
450   tls_ctx_t *ctx;
451
452   TLS_DBG (1, "TCP disconnecting handle %x session %u", tls_session->opaque,
453            tls_session->session_index);
454
455   ASSERT (tls_session->thread_index == vlib_get_thread_index ()
456           || vlib_thread_is_main_w_barrier ());
457
458   ctx = tls_ctx_get_w_thread (tls_session->opaque, tls_session->thread_index);
459   ctx->is_passive_close = 1;
460   tls_ctx_transport_close (ctx);
461 }
462
463 int
464 tls_session_accept_callback (session_t * tls_session)
465 {
466   session_t *tls_listener, *app_session;
467   tls_ctx_t *lctx, *ctx;
468   u32 ctx_handle;
469
470   tls_listener =
471     listen_session_get_from_handle (tls_session->listener_handle);
472   lctx = tls_listener_ctx_get (tls_listener->opaque);
473
474   ctx_handle = tls_ctx_alloc (lctx->tls_ctx_engine);
475   ctx = tls_ctx_get (ctx_handle);
476   memcpy (ctx, lctx, sizeof (*lctx));
477   ctx->c_thread_index = vlib_get_thread_index ();
478   ctx->tls_ctx_handle = ctx_handle;
479   tls_session->session_state = SESSION_STATE_READY;
480   tls_session->opaque = ctx_handle;
481   ctx->tls_session_handle = session_handle (tls_session);
482   ctx->listener_ctx_index = tls_listener->opaque;
483   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
484   ctx->ckpair_index = lctx->ckpair_index;
485
486   /* Preallocate app session. Avoids allocating a session post handshake
487    * on tls_session rx and potentially invalidating the session pool */
488   app_session = session_alloc (ctx->c_thread_index);
489   app_session->session_state = SESSION_STATE_CREATED;
490   app_session->session_type =
491     session_type_from_proto_and_ip (TRANSPORT_PROTO_TLS, ctx->tcp_is_ip4);
492   app_session->connection_index = ctx->tls_ctx_handle;
493   ctx->c_s_index = app_session->session_index;
494
495   TLS_DBG (1, "Accept on listener %u new connection [%u]%x",
496            tls_listener->opaque, vlib_get_thread_index (), ctx_handle);
497
498   if (tls_ctx_init_server (ctx))
499     {
500       /* Do not free ctx yet, in case we have pending rx events */
501       session_free (app_session);
502       ctx->no_app_session = 1;
503       tls_disconnect_transport (ctx);
504     }
505
506   return 0;
507 }
508
509 int
510 tls_app_rx_callback (session_t *ts)
511 {
512   tls_ctx_t *ctx;
513
514   /* DTLS session migrating, wait for next notification */
515   if (PREDICT_FALSE (ts->flags & SESSION_F_IS_MIGRATING))
516     return 0;
517
518   /* Read rescheduled but underlying transport deleted now */
519   if (PREDICT_FALSE ((ts->session_state == SESSION_STATE_TRANSPORT_DELETED)))
520     return 0;
521
522   ctx = tls_ctx_get (ts->opaque);
523   if (PREDICT_FALSE (ctx->no_app_session || ctx->app_closed))
524     {
525       TLS_DBG (1, "Local App closed");
526       return 0;
527     }
528   tls_ctx_read (ctx, ts);
529   return 0;
530 }
531
532 int
533 tls_app_tx_callback (session_t * tls_session)
534 {
535   tls_ctx_t *ctx;
536
537   ctx = tls_ctx_get (tls_session->opaque);
538   transport_connection_reschedule (&ctx->connection);
539
540   return 0;
541 }
542
543 int
544 tls_session_connected_cb (u32 tls_app_index, u32 ho_ctx_index,
545                           session_t *tls_session, session_error_t err)
546 {
547   session_t *app_session;
548   tls_ctx_t *ho_ctx, *ctx;
549   session_type_t st;
550   u32 ctx_handle;
551
552   ho_ctx = tls_ctx_half_open_get (ho_ctx_index);
553
554   ctx_handle = tls_ctx_alloc (ho_ctx->tls_ctx_engine);
555   ctx = tls_ctx_get (ctx_handle);
556   clib_memcpy_fast (ctx, ho_ctx, sizeof (*ctx));
557   /* Half-open freed on tcp half-open cleanup notification */
558
559   ctx->c_thread_index = vlib_get_thread_index ();
560   ctx->tls_ctx_handle = ctx_handle;
561   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
562
563   TLS_DBG (1, "TCP connect for %u returned %u. New connection [%u]%x",
564            ho_ctx_index, err, vlib_get_thread_index (),
565            (ctx) ? ctx_handle : ~0);
566
567   ctx->tls_session_handle = session_handle (tls_session);
568   tls_session->opaque = ctx_handle;
569   tls_session->session_state = SESSION_STATE_READY;
570
571   /* Preallocate app session. Avoids allocating a session post handshake
572    * on tls_session rx and potentially invalidating the session pool */
573   app_session = session_alloc (ctx->c_thread_index);
574   app_session->session_state = SESSION_STATE_CREATED;
575   ctx->c_s_index = app_session->session_index;
576   st = session_type_from_proto_and_ip (TRANSPORT_PROTO_TLS, ctx->tcp_is_ip4);
577   app_session->session_type = st;
578   app_session->connection_index = ctx->tls_ctx_handle;
579
580   if (tls_ctx_init_client (ctx))
581     {
582       tls_notify_app_connected (ctx, SESSION_E_TLS_HANDSHAKE);
583       tls_disconnect_transport (ctx);
584     }
585
586   return 0;
587 }
588
589 int
590 dtls_session_connected_cb (u32 app_wrk_index, u32 ctx_handle, session_t *us,
591                            session_error_t err)
592 {
593   tls_ctx_t *ctx;
594
595   ctx = tls_ctx_get_w_thread (ctx_handle, transport_cl_thread ());
596
597   ctx->tls_session_handle = session_handle (us);
598   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
599   us->opaque = ctx_handle;
600
601   /* We don't preallocate the app session because the udp session might
602    * actually migrate to a different worker at the end of the handshake */
603
604   return tls_ctx_init_client (ctx);
605 }
606
607 int
608 tls_session_connected_callback (u32 tls_app_index, u32 ho_ctx_index,
609                                 session_t *tls_session, session_error_t err)
610 {
611   if (err)
612     {
613       app_worker_t *app_wrk;
614       tls_ctx_t *ho_ctx;
615       u32 api_context;
616
617       ho_ctx = tls_ctx_half_open_get (ho_ctx_index);
618       app_wrk = app_worker_get_if_valid (ho_ctx->parent_app_wrk_index);
619       if (app_wrk)
620         {
621           api_context = ho_ctx->parent_app_api_context;
622           app_worker_connect_notify (app_wrk, 0, err, api_context);
623         }
624
625       return 0;
626     }
627
628   if (session_get_transport_proto (tls_session) == TRANSPORT_PROTO_TCP)
629     return tls_session_connected_cb (tls_app_index, ho_ctx_index, tls_session,
630                                      err);
631   else
632     return dtls_session_connected_cb (tls_app_index, ho_ctx_index, tls_session,
633                                       err);
634 }
635
636 static void
637 tls_app_session_cleanup (session_t * s, session_cleanup_ntf_t ntf)
638 {
639   tls_ctx_t *ctx;
640
641   if (ntf == SESSION_CLEANUP_TRANSPORT)
642     {
643       /* Allow cleanup of tcp session */
644       if (s->session_state == SESSION_STATE_TRANSPORT_DELETED)
645         session_close (s);
646       return;
647     }
648
649   ctx = tls_ctx_get (s->opaque);
650   if (!ctx->no_app_session)
651     session_transport_delete_notify (&ctx->connection);
652   tls_ctx_free (ctx);
653 }
654
655 static void
656 dtls_migrate_ctx (void *arg)
657 {
658   tls_ctx_t *ctx = (tls_ctx_t *) arg;
659   u32 ctx_handle, thread_index;
660   session_t *us;
661
662   thread_index = session_thread_from_handle (ctx->tls_session_handle);
663   ASSERT (thread_index == vlib_get_thread_index ());
664
665   ctx_handle = tls_ctx_attach (ctx->tls_ctx_engine, thread_index, ctx);
666   ctx = tls_ctx_get_w_thread (ctx_handle, thread_index);
667   ctx->tls_ctx_handle = ctx_handle;
668
669   us = session_get_from_handle (ctx->tls_session_handle);
670   us->opaque = ctx_handle;
671   us->flags &= ~SESSION_F_IS_MIGRATING;
672
673   /* Probably the app detached while the session was migrating. Cleanup */
674   if (session_half_open_migrated_notify (&ctx->connection))
675     {
676       ctx->no_app_session = 1;
677       tls_disconnect (ctx->tls_ctx_handle, vlib_get_thread_index ());
678       return;
679     }
680
681   if (svm_fifo_max_dequeue (us->tx_fifo))
682     session_send_io_evt_to_thread (us->tx_fifo, SESSION_IO_EVT_TX);
683 }
684
685 static void
686 dtls_session_migrate_callback (session_t *us, session_handle_t new_sh)
687 {
688   u32 new_thread = session_thread_from_handle (new_sh);
689   tls_ctx_t *ctx, *cloned_ctx;
690
691   /* Migrate dtls context to new thread */
692   ctx = tls_ctx_get_w_thread (us->opaque, us->thread_index);
693   ctx->tls_session_handle = new_sh;
694   cloned_ctx = tls_ctx_detach (ctx);
695   ctx->is_migrated = 1;
696   session_half_open_migrate_notify (&ctx->connection);
697
698   session_send_rpc_evt_to_thread (new_thread, dtls_migrate_ctx,
699                                   (void *) cloned_ctx);
700
701   tls_ctx_free (ctx);
702 }
703
704 static void
705 tls_session_transport_closed_callback (session_t *ts)
706 {
707   tls_ctx_t *ctx;
708
709   ctx = tls_ctx_get_w_thread (ts->opaque, ts->thread_index);
710   session_transport_closed_notify (&ctx->connection);
711 }
712
713 static session_cb_vft_t tls_app_cb_vft = {
714   .session_accept_callback = tls_session_accept_callback,
715   .session_disconnect_callback = tls_session_disconnect_callback,
716   .session_connected_callback = tls_session_connected_callback,
717   .session_reset_callback = tls_session_reset_callback,
718   .session_transport_closed_callback = tls_session_transport_closed_callback,
719   .half_open_cleanup_callback = tls_session_cleanup_ho,
720   .add_segment_callback = tls_add_segment_callback,
721   .del_segment_callback = tls_del_segment_callback,
722   .builtin_app_rx_callback = tls_app_rx_callback,
723   .builtin_app_tx_callback = tls_app_tx_callback,
724   .session_migrate_callback = dtls_session_migrate_callback,
725   .session_cleanup_callback = tls_app_session_cleanup,
726 };
727
728 int
729 tls_connect (transport_endpoint_cfg_t * tep)
730 {
731   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
732   transport_endpt_crypto_cfg_t *ccfg;
733   crypto_engine_type_t engine_type;
734   session_endpoint_cfg_t *sep;
735   tls_main_t *tm = &tls_main;
736   app_worker_t *app_wrk;
737   application_t *app;
738   tls_ctx_t *ctx;
739   u32 ctx_index;
740   int rv;
741
742   sep = (session_endpoint_cfg_t *) tep;
743   if (!sep->ext_cfg)
744     return SESSION_E_NOEXTCFG;
745
746   app_wrk = app_worker_get (sep->app_wrk_index);
747   app = application_get (app_wrk->app_index);
748
749   ccfg = &sep->ext_cfg->crypto;
750   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
751   if (engine_type == CRYPTO_ENGINE_NONE)
752     {
753       clib_warning ("No tls engine_type available");
754       return SESSION_E_NOCRYPTOENG;
755     }
756
757   ctx_index = tls_ctx_half_open_alloc ();
758   ctx = tls_ctx_half_open_get (ctx_index);
759   ctx->parent_app_wrk_index = sep->app_wrk_index;
760   ctx->parent_app_api_context = sep->opaque;
761   ctx->tcp_is_ip4 = sep->is_ip4;
762   ctx->tls_type = sep->transport_proto;
763   ctx->ckpair_index = ccfg->ckpair_index;
764   ctx->c_proto = TRANSPORT_PROTO_TLS;
765   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
766   if (ccfg->hostname[0])
767     {
768       ctx->srv_hostname = format (0, "%s", ccfg->hostname);
769       vec_terminate_c_string (ctx->srv_hostname);
770     }
771
772   ctx->tls_ctx_engine = engine_type;
773
774   clib_memcpy_fast (&cargs->sep, sep, sizeof (session_endpoint_t));
775   cargs->sep.transport_proto = TRANSPORT_PROTO_TCP;
776   cargs->app_index = tm->app_index;
777   cargs->api_context = ctx_index;
778   cargs->sep_ext.ns_index = app->ns_index;
779   if ((rv = vnet_connect (cargs)))
780     return rv;
781
782   /* Track half-open tcp session in case we need to clean it up */
783   ctx->tls_session_handle = cargs->sh;
784
785   TLS_DBG (1, "New connect request %u engine %d", ctx_index, engine_type);
786   return ctx_index;
787 }
788
789 void
790 tls_disconnect (u32 ctx_handle, u32 thread_index)
791 {
792   tls_ctx_t *ctx;
793
794   TLS_DBG (1, "Disconnecting %x", ctx_handle);
795
796   ctx = tls_ctx_get (ctx_handle);
797   tls_ctx_app_close (ctx);
798 }
799
800 u32
801 tls_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep)
802 {
803   vnet_listen_args_t _bargs, *args = &_bargs;
804   transport_endpt_crypto_cfg_t *ccfg;
805   app_worker_t *app_wrk;
806   tls_main_t *tm = &tls_main;
807   session_handle_t tls_al_handle;
808   session_endpoint_cfg_t *sep;
809   session_t *tls_listener;
810   session_t *app_listener;
811   crypto_engine_type_t engine_type;
812   application_t *app;
813   app_listener_t *al;
814   tls_ctx_t *lctx;
815   u32 lctx_index;
816   int rv;
817
818   sep = (session_endpoint_cfg_t *) tep;
819   if (!sep->ext_cfg)
820     return SESSION_E_NOEXTCFG;
821
822   app_wrk = app_worker_get (sep->app_wrk_index);
823   app = application_get (app_wrk->app_index);
824
825   ccfg = &sep->ext_cfg->crypto;
826   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
827   if (engine_type == CRYPTO_ENGINE_NONE)
828     {
829       clib_warning ("No tls engine_type available");
830       return SESSION_E_NOCRYPTOENG;
831     }
832
833   clib_memset (args, 0, sizeof (*args));
834   args->app_index = tm->app_index;
835   args->sep_ext = *sep;
836   args->sep_ext.ns_index = app->ns_index;
837   args->sep_ext.transport_proto = TRANSPORT_PROTO_TCP;
838   if (sep->transport_proto == TRANSPORT_PROTO_DTLS)
839     {
840       args->sep_ext.transport_proto = TRANSPORT_PROTO_UDP;
841       args->sep_ext.transport_flags = TRANSPORT_CFG_F_CONNECTED;
842     }
843   if ((rv = vnet_listen (args)))
844     return rv;
845
846   lctx_index = tls_listener_ctx_alloc ();
847   tls_al_handle = args->handle;
848   al = app_listener_get_w_handle (tls_al_handle);
849   tls_listener = app_listener_get_session (al);
850   tls_listener->opaque = lctx_index;
851
852   app_listener = listen_session_get (app_listener_index);
853
854   lctx = tls_listener_ctx_get (lctx_index);
855   lctx->parent_app_wrk_index = sep->app_wrk_index;
856   lctx->tls_session_handle = tls_al_handle;
857   lctx->app_session_handle = listen_session_get_handle (app_listener);
858   lctx->tcp_is_ip4 = sep->is_ip4;
859   lctx->tls_ctx_engine = engine_type;
860   lctx->tls_type = sep->transport_proto;
861   lctx->ckpair_index = ccfg->ckpair_index;
862   lctx->c_s_index = app_listener_index;
863   lctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
864
865   if (tls_vfts[engine_type].ctx_start_listen (lctx))
866     {
867       vnet_unlisten_args_t a = {
868         .handle = lctx->tls_session_handle,
869         .app_index = tls_main.app_index,
870         .wrk_map_index = 0
871       };
872       if ((vnet_unlisten (&a)))
873         clib_warning ("unlisten returned");
874       tls_listener_ctx_free (lctx);
875       lctx_index = SESSION_INVALID_INDEX;
876     }
877
878   TLS_DBG (1, "Started listening %d, engine type %d", lctx_index,
879            engine_type);
880   return lctx_index;
881 }
882
883 u32
884 tls_stop_listen (u32 lctx_index)
885 {
886   session_endpoint_t sep = SESSION_ENDPOINT_NULL;
887   crypto_engine_type_t engine_type;
888   transport_connection_t *lc;
889   tls_ctx_t *lctx;
890   session_t *ls;
891   int rv;
892
893   lctx = tls_listener_ctx_get (lctx_index);
894
895   /* Cleanup listener from session lookup table */
896   ls = session_get_from_handle (lctx->tls_session_handle);
897   lc = session_get_transport (ls);
898
899   sep.fib_index = lc->fib_index;
900   sep.port = lc->lcl_port;
901   sep.is_ip4 = lc->is_ip4;
902   sep.transport_proto = lctx->tls_type;
903   clib_memcpy (&sep.ip, &lc->lcl_ip, sizeof (lc->lcl_ip));
904   session_lookup_del_session_endpoint2 (&sep);
905
906   vnet_unlisten_args_t a = {
907     .handle = lctx->tls_session_handle,
908     .app_index = tls_main.app_index,
909     .wrk_map_index = 0          /* default wrk */
910   };
911   if ((rv = vnet_unlisten (&a)))
912     clib_warning ("unlisten returned %d", rv);
913
914   engine_type = lctx->tls_ctx_engine;
915   tls_vfts[engine_type].ctx_stop_listen (lctx);
916
917   tls_listener_ctx_free (lctx);
918   return 0;
919 }
920
921 transport_connection_t *
922 tls_connection_get (u32 ctx_index, u32 thread_index)
923 {
924   tls_ctx_t *ctx;
925   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
926   return &ctx->connection;
927 }
928
929 transport_connection_t *
930 tls_listener_get (u32 listener_index)
931 {
932   tls_ctx_t *ctx;
933   ctx = tls_listener_ctx_get (listener_index);
934   return &ctx->connection;
935 }
936
937 static transport_connection_t *
938 tls_half_open_get (u32 ho_index)
939 {
940   tls_ctx_t *ctx;
941   ctx = tls_ctx_half_open_get (ho_index);
942   return &ctx->connection;
943 }
944
945 static void
946 tls_cleanup_ho (u32 ho_index)
947 {
948   tls_ctx_t *ctx;
949
950   ctx = tls_ctx_half_open_get (ho_index);
951   session_cleanup_half_open (ctx->tls_session_handle);
952   tls_ctx_half_open_free (ho_index);
953 }
954
955 int
956 tls_custom_tx_callback (void *session, transport_send_params_t * sp)
957 {
958   session_t *as = (session_t *) session;
959   tls_ctx_t *ctx;
960
961   if (PREDICT_FALSE (as->session_state >= SESSION_STATE_TRANSPORT_CLOSED ||
962                      as->session_state <= SESSION_STATE_ACCEPTING))
963     {
964       sp->flags |= TRANSPORT_SND_F_DESCHED;
965       return 0;
966     }
967
968   ctx = tls_ctx_get (as->connection_index);
969   return tls_ctx_write (ctx, as, sp);
970 }
971
972 u8 *
973 format_tls_ctx (u8 * s, va_list * args)
974 {
975   u32 tcp_si, tcp_ti, ctx_index, ctx_engine;
976   tls_ctx_t *ctx = va_arg (*args, tls_ctx_t *);
977   char *proto;
978
979   proto = ctx->tls_type == TRANSPORT_PROTO_TLS ? "TLS" : "DTLS";
980   session_parse_handle (ctx->tls_session_handle, &tcp_si, &tcp_ti);
981   tls_ctx_parse_handle (ctx->tls_ctx_handle, &ctx_index, &ctx_engine);
982   s =
983     format (s, "[%d:%d][%s] app_wrk %u index %u engine %u ts %d:%d",
984             ctx->c_thread_index, ctx->c_s_index, proto,
985             ctx->parent_app_wrk_index, ctx_index, ctx_engine, tcp_ti, tcp_si);
986
987   return s;
988 }
989
990 static u8 *
991 format_tls_listener_ctx (u8 * s, va_list * args)
992 {
993   session_t *tls_listener;
994   app_listener_t *al;
995   tls_ctx_t *ctx;
996   char *proto;
997
998   ctx = va_arg (*args, tls_ctx_t *);
999
1000   proto = ctx->tls_type == TRANSPORT_PROTO_TLS ? "TLS" : "DTLS";
1001   al = app_listener_get_w_handle (ctx->tls_session_handle);
1002   tls_listener = app_listener_get_session (al);
1003   s = format (s, "[%d:%d][%s] app_wrk %u engine %u ts %d:%d",
1004               ctx->c_thread_index, ctx->c_s_index, proto,
1005               ctx->parent_app_wrk_index, ctx->tls_ctx_engine,
1006               tls_listener->thread_index, tls_listener->session_index);
1007
1008   return s;
1009 }
1010
1011 static u8 *
1012 format_tls_ctx_state (u8 * s, va_list * args)
1013 {
1014   tls_ctx_t *ctx;
1015   session_t *ts;
1016
1017   ctx = va_arg (*args, tls_ctx_t *);
1018   ts = session_get (ctx->c_s_index, ctx->c_thread_index);
1019   if (ts->session_state == SESSION_STATE_LISTENING)
1020     s = format (s, "%s", "LISTEN");
1021   else
1022     {
1023       if (ts->session_state >= SESSION_STATE_TRANSPORT_CLOSED)
1024         s = format (s, "%s", "CLOSED");
1025       else if (ts->session_state == SESSION_STATE_APP_CLOSED)
1026         s = format (s, "%s", "APP-CLOSED");
1027       else if (ts->session_state >= SESSION_STATE_TRANSPORT_CLOSING)
1028         s = format (s, "%s", "CLOSING");
1029       else if (tls_ctx_handshake_is_over (ctx))
1030         s = format (s, "%s", "ESTABLISHED");
1031       else
1032         s = format (s, "%s", "HANDSHAKE");
1033     }
1034
1035   return s;
1036 }
1037
1038 u8 *
1039 format_tls_connection (u8 * s, va_list * args)
1040 {
1041   u32 ctx_index = va_arg (*args, u32);
1042   u32 thread_index = va_arg (*args, u32);
1043   u32 verbose = va_arg (*args, u32);
1044   tls_ctx_t *ctx;
1045
1046   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
1047   if (!ctx)
1048     return s;
1049
1050   s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_tls_ctx, ctx);
1051   if (verbose)
1052     {
1053       s = format (s, "%-" SESSION_CLI_STATE_LEN "U", format_tls_ctx_state,
1054                   ctx);
1055       if (verbose > 1)
1056         s = format (s, "\n");
1057     }
1058   return s;
1059 }
1060
1061 u8 *
1062 format_tls_listener (u8 * s, va_list * args)
1063 {
1064   u32 tc_index = va_arg (*args, u32);
1065   u32 __clib_unused thread_index = va_arg (*args, u32);
1066   u32 verbose = va_arg (*args, u32);
1067   tls_ctx_t *ctx = tls_listener_ctx_get (tc_index);
1068
1069   s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_tls_listener_ctx, ctx);
1070   if (verbose)
1071     s = format (s, "%-" SESSION_CLI_STATE_LEN "U", format_tls_ctx_state, ctx);
1072   return s;
1073 }
1074
1075 u8 *
1076 format_tls_half_open (u8 * s, va_list * args)
1077 {
1078   u32 ho_index = va_arg (*args, u32);
1079   u32 __clib_unused thread_index = va_arg (*args, u32);
1080   u32 __clib_unused verbose = va_arg (*args, u32);
1081   session_t *tcp_ho;
1082   tls_ctx_t *ho_ctx;
1083
1084   ho_ctx = tls_ctx_half_open_get (ho_index);
1085
1086   tcp_ho = session_get_from_handle (ho_ctx->tls_session_handle);
1087   s = format (s, "[%d:%d][%s] half-open app_wrk %u engine %u ts %d:%d",
1088               ho_ctx->c_thread_index, ho_ctx->c_s_index, "TLS",
1089               ho_ctx->parent_app_wrk_index, ho_ctx->tls_ctx_engine,
1090               tcp_ho->thread_index, tcp_ho->session_index);
1091
1092   return s;
1093 }
1094
1095 static void
1096 tls_transport_endpoint_get (u32 ctx_handle, u32 thread_index,
1097                             transport_endpoint_t * tep, u8 is_lcl)
1098 {
1099   tls_ctx_t *ctx = tls_ctx_get_w_thread (ctx_handle, thread_index);
1100   session_t *tcp_session;
1101
1102   tcp_session = session_get_from_handle (ctx->tls_session_handle);
1103   session_get_endpoint (tcp_session, tep, is_lcl);
1104 }
1105
1106 static void
1107 tls_transport_listener_endpoint_get (u32 ctx_handle,
1108                                      transport_endpoint_t * tep, u8 is_lcl)
1109 {
1110   session_t *tls_listener;
1111   app_listener_t *al;
1112   tls_ctx_t *ctx = tls_listener_ctx_get (ctx_handle);
1113
1114   al = app_listener_get_w_handle (ctx->tls_session_handle);
1115   tls_listener = app_listener_get_session (al);
1116   session_get_endpoint (tls_listener, tep, is_lcl);
1117 }
1118
1119 static clib_error_t *
1120 tls_enable (vlib_main_t * vm, u8 is_en)
1121 {
1122   vnet_app_detach_args_t _da, *da = &_da;
1123   vnet_app_attach_args_t _a, *a = &_a;
1124   u64 options[APP_OPTIONS_N_OPTIONS];
1125   tls_main_t *tm = &tls_main;
1126   u32 fifo_size = 512 << 10;
1127
1128   if (!is_en)
1129     {
1130       da->app_index = tm->app_index;
1131       da->api_client_index = APP_INVALID_INDEX;
1132       vnet_application_detach (da);
1133       return 0;
1134     }
1135
1136   fifo_size = tm->fifo_size ? tm->fifo_size : fifo_size;
1137
1138   clib_memset (a, 0, sizeof (*a));
1139   clib_memset (options, 0, sizeof (options));
1140
1141   a->session_cb_vft = &tls_app_cb_vft;
1142   a->api_client_index = APP_INVALID_INDEX;
1143   a->options = options;
1144   a->name = format (0, "tls");
1145   a->options[APP_OPTIONS_SEGMENT_SIZE] = tm->first_seg_size;
1146   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = tm->add_seg_size;
1147   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
1148   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
1149   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1150   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1151   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
1152
1153   if (vnet_application_attach (a))
1154     {
1155       clib_warning ("failed to attach tls app");
1156       return clib_error_return (0, "failed to attach tls app");
1157     }
1158
1159   tm->app_index = a->app_index;
1160   vec_free (a->name);
1161
1162   return 0;
1163 }
1164
1165 static const transport_proto_vft_t tls_proto = {
1166   .enable = tls_enable,
1167   .connect = tls_connect,
1168   .close = tls_disconnect,
1169   .start_listen = tls_start_listen,
1170   .stop_listen = tls_stop_listen,
1171   .get_connection = tls_connection_get,
1172   .get_listener = tls_listener_get,
1173   .get_half_open = tls_half_open_get,
1174   .cleanup_ho = tls_cleanup_ho,
1175   .custom_tx = tls_custom_tx_callback,
1176   .format_connection = format_tls_connection,
1177   .format_half_open = format_tls_half_open,
1178   .format_listener = format_tls_listener,
1179   .get_transport_endpoint = tls_transport_endpoint_get,
1180   .get_transport_listener_endpoint = tls_transport_listener_endpoint_get,
1181   .transport_options = {
1182     .name = "tls",
1183     .short_name = "J",
1184     .tx_type = TRANSPORT_TX_INTERNAL,
1185     .service_type = TRANSPORT_SERVICE_VC,
1186   },
1187 };
1188
1189 int
1190 dtls_connect (transport_endpoint_cfg_t *tep)
1191 {
1192   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
1193   transport_endpt_crypto_cfg_t *ccfg;
1194   crypto_engine_type_t engine_type;
1195   session_endpoint_cfg_t *sep;
1196   tls_main_t *tm = &tls_main;
1197   app_worker_t *app_wrk;
1198   application_t *app;
1199   tls_ctx_t *ctx;
1200   u32 ctx_handle;
1201   int rv;
1202
1203   sep = (session_endpoint_cfg_t *) tep;
1204   if (!sep->ext_cfg)
1205     return -1;
1206
1207   app_wrk = app_worker_get (sep->app_wrk_index);
1208   app = application_get (app_wrk->app_index);
1209
1210   ccfg = &sep->ext_cfg->crypto;
1211   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
1212   if (engine_type == CRYPTO_ENGINE_NONE)
1213     {
1214       clib_warning ("No tls engine_type available");
1215       return -1;
1216     }
1217
1218   ctx_handle = tls_ctx_alloc_w_thread (engine_type, transport_cl_thread ());
1219   ctx = tls_ctx_get_w_thread (ctx_handle, transport_cl_thread ());
1220   ctx->parent_app_wrk_index = sep->app_wrk_index;
1221   ctx->parent_app_api_context = sep->opaque;
1222   ctx->tcp_is_ip4 = sep->is_ip4;
1223   ctx->ckpair_index = ccfg->ckpair_index;
1224   ctx->tls_type = sep->transport_proto;
1225   ctx->tls_ctx_handle = ctx_handle;
1226   ctx->c_proto = TRANSPORT_PROTO_DTLS;
1227   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1228   if (ccfg->hostname[0])
1229     {
1230       ctx->srv_hostname = format (0, "%s", ccfg->hostname);
1231       vec_terminate_c_string (ctx->srv_hostname);
1232     }
1233
1234   ctx->tls_ctx_engine = engine_type;
1235
1236   clib_memcpy_fast (&cargs->sep, sep, sizeof (session_endpoint_t));
1237   cargs->sep.transport_proto = TRANSPORT_PROTO_UDP;
1238   cargs->app_index = tm->app_index;
1239   cargs->api_context = ctx_handle;
1240   cargs->sep_ext.ns_index = app->ns_index;
1241   cargs->sep_ext.transport_flags = TRANSPORT_CFG_F_CONNECTED;
1242   if ((rv = vnet_connect (cargs)))
1243     return rv;
1244
1245   TLS_DBG (1, "New DTLS connect request %x engine %d", ctx_handle,
1246            engine_type);
1247   return ctx_handle;
1248 }
1249
1250 static transport_connection_t *
1251 dtls_half_open_get (u32 ho_index)
1252 {
1253   tls_ctx_t *ho_ctx;
1254   ho_ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1255   return &ho_ctx->connection;
1256 }
1257
1258 static void
1259 dtls_cleanup_callback (u32 ctx_index, u32 thread_index)
1260 {
1261   /* No op */
1262 }
1263
1264 static void
1265 dtls_cleanup_ho (u32 ho_index)
1266 {
1267   tls_ctx_t *ctx;
1268   ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1269   tls_ctx_free (ctx);
1270 }
1271
1272 u8 *
1273 format_dtls_half_open (u8 *s, va_list *args)
1274 {
1275   u32 ho_index = va_arg (*args, u32);
1276   u32 __clib_unused thread_index = va_arg (*args, u32);
1277   tls_ctx_t *ho_ctx;
1278   session_t *us;
1279
1280   ho_ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1281
1282   us = session_get_from_handle (ho_ctx->tls_session_handle);
1283   s = format (s, "[%d:%d][%s] half-open app_wrk %u engine %u us %d:%d",
1284               ho_ctx->c_thread_index, ho_ctx->c_s_index, "DTLS",
1285               ho_ctx->parent_app_wrk_index, ho_ctx->tls_ctx_engine,
1286               us->thread_index, us->session_index);
1287
1288   return s;
1289 }
1290
1291 static const transport_proto_vft_t dtls_proto = {
1292   .enable = 0,
1293   .connect = dtls_connect,
1294   .close = tls_disconnect,
1295   .start_listen = tls_start_listen,
1296   .stop_listen = tls_stop_listen,
1297   .get_connection = tls_connection_get,
1298   .get_listener = tls_listener_get,
1299   .get_half_open = dtls_half_open_get,
1300   .custom_tx = tls_custom_tx_callback,
1301   .cleanup = dtls_cleanup_callback,
1302   .cleanup_ho = dtls_cleanup_ho,
1303   .format_connection = format_tls_connection,
1304   .format_half_open = format_dtls_half_open,
1305   .format_listener = format_tls_listener,
1306   .get_transport_endpoint = tls_transport_endpoint_get,
1307   .get_transport_listener_endpoint = tls_transport_listener_endpoint_get,
1308   .transport_options = {
1309     .name = "dtls",
1310     .short_name = "D",
1311     .tx_type = TRANSPORT_TX_INTERNAL,
1312     .service_type = TRANSPORT_SERVICE_VC,
1313   },
1314 };
1315
1316 void
1317 tls_register_engine (const tls_engine_vft_t * vft, crypto_engine_type_t type)
1318 {
1319   vec_validate (tls_vfts, type);
1320   tls_vfts[type] = *vft;
1321 }
1322
1323 static clib_error_t *
1324 tls_init (vlib_main_t * vm)
1325 {
1326   vlib_thread_main_t *vtm = vlib_get_thread_main ();
1327   tls_main_t *tm = &tls_main;
1328   u32 num_threads;
1329
1330   num_threads = 1 /* main thread */  + vtm->n_threads;
1331
1332   if (!tm->ca_cert_path)
1333     tm->ca_cert_path = TLS_CA_CERT_PATH;
1334
1335   vec_validate (tm->rx_bufs, num_threads - 1);
1336   vec_validate (tm->tx_bufs, num_threads - 1);
1337
1338   tm->first_seg_size = 32 << 20;
1339   tm->add_seg_size = 256 << 20;
1340
1341   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
1342                                FIB_PROTOCOL_IP4, ~0);
1343   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
1344                                FIB_PROTOCOL_IP6, ~0);
1345
1346   transport_register_protocol (TRANSPORT_PROTO_DTLS, &dtls_proto,
1347                                FIB_PROTOCOL_IP4, ~0);
1348   transport_register_protocol (TRANSPORT_PROTO_DTLS, &dtls_proto,
1349                                FIB_PROTOCOL_IP6, ~0);
1350   return 0;
1351 }
1352
1353 VLIB_INIT_FUNCTION (tls_init);
1354
1355 static clib_error_t *
1356 tls_config_fn (vlib_main_t * vm, unformat_input_t * input)
1357 {
1358   tls_main_t *tm = &tls_main;
1359   uword tmp;
1360   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1361     {
1362       if (unformat (input, "use-test-cert-in-ca"))
1363         tm->use_test_cert_in_ca = 1;
1364       else if (unformat (input, "ca-cert-path %s", &tm->ca_cert_path))
1365         ;
1366       else if (unformat (input, "first-segment-size %U", unformat_memory_size,
1367                          &tm->first_seg_size))
1368         ;
1369       else if (unformat (input, "add-segment-size %U", unformat_memory_size,
1370                          &tm->add_seg_size))
1371         ;
1372       else if (unformat (input, "fifo-size %U", unformat_memory_size, &tmp))
1373         {
1374           if (tmp >= 0x100000000ULL)
1375             {
1376               return clib_error_return
1377                 (0, "fifo-size %llu (0x%llx) too large", tmp, tmp);
1378             }
1379           tm->fifo_size = tmp;
1380         }
1381       else
1382         return clib_error_return (0, "unknown input `%U'",
1383                                   format_unformat_error, input);
1384     }
1385   return 0;
1386 }
1387
1388 VLIB_CONFIG_FUNCTION (tls_config_fn, "tls");
1389
1390 tls_main_t *
1391 vnet_tls_get_main (void)
1392 {
1393   return &tls_main;
1394 }
1395
1396 /*
1397  * fd.io coding-style-patch-verification: ON
1398  *
1399  * Local Variables:
1400  * eval: (c-set-style "gnu")
1401  * End:
1402  */