blob: 669c6cf73c763fd1532ec51b51767cbafcea93c1 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file openssl/tls_udp.c DTLS backend using OpenSSL
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7#include <sys/time.h>
8#include <openssl/ssl.h>
9#include <openssl/err.h>
10#include <re_types.h>
11#include <re_fmt.h>
12#include <re_mem.h>
13#include <re_mbuf.h>
14#include <re_list.h>
15#include <re_hash.h>
16#include <re_sa.h>
17#include <re_srtp.h>
18#include <re_udp.h>
19#include <re_tmr.h>
20#include <re_tls.h>
21#include "tls.h"
22
23
24#define DEBUG_MODULE "dtls"
25#define DEBUG_LEVEL 5
26#include <re_dbg.h>
27
28
29enum {
Austin Schuh35a2f492021-04-07 21:41:56 -070030 MTU_DEFAULT = 1400,
31 MTU_FALLBACK = 548,
32 HEADROOM_DEFAULT = 4,
James Kuszmaul82f6c042021-01-17 11:30:16 -080033};
34
35
36struct dtls_sock {
37 struct sa peer;
38 struct udp_helper *uh;
39 struct udp_sock *us;
40 struct hash *ht;
41 struct mbuf *mb;
42 dtls_conn_h *connh;
Austin Schuh35a2f492021-04-07 21:41:56 -070043 dtls_send_h *sendh;
44 dtls_mtu_h *mtuh;
James Kuszmaul82f6c042021-01-17 11:30:16 -080045 void *arg;
46 size_t mtu;
Austin Schuh35a2f492021-04-07 21:41:56 -070047 size_t headroom;
James Kuszmaul82f6c042021-01-17 11:30:16 -080048};
49
50
51/* NOTE: shadow struct defined in tls_*.c */
52struct tls_conn {
53 SSL *ssl; /* inheritance */
54#ifdef TLS_BIO_OPAQUE
55 BIO_METHOD *biomet;
56#endif
57 BIO *sbio_out;
58 BIO *sbio_in;
59 struct tmr tmr;
60 struct sa peer;
61 struct le he;
62 struct dtls_sock *sock;
63 dtls_estab_h *estabh;
64 dtls_recv_h *recvh;
65 dtls_close_h *closeh;
66 void *arg;
67 bool active;
68 bool up;
69};
70
71
72static int bio_create(BIO *b)
73{
74#ifdef TLS_BIO_OPAQUE
75 BIO_set_init(b, 1);
76 BIO_set_data(b, NULL);
77 BIO_set_flags(b, 0);
78#else
79 b->init = 1;
80 b->num = 0;
81 b->ptr = NULL;
82 b->flags = 0;
83#endif
84
85 return 1;
86}
87
88
89static int bio_destroy(BIO *b)
90{
91 if (!b)
92 return 0;
93
94#ifdef TLS_BIO_OPAQUE
95 BIO_set_init(b, 0);
96 BIO_set_data(b, NULL);
97 BIO_set_flags(b, 0);
98#else
99 b->ptr = NULL;
100 b->init = 0;
101 b->flags = 0;
102#endif
103
104 return 1;
105}
106
107
108static int bio_write(BIO *b, const char *buf, int len)
109{
110#ifdef TLS_BIO_OPAQUE
111 struct tls_conn *tc = BIO_get_data(b);
112#else
113 struct tls_conn *tc = b->ptr;
114#endif
115 struct mbuf *mb;
James Kuszmaul82f6c042021-01-17 11:30:16 -0800116 int err;
117
Austin Schuh35a2f492021-04-07 21:41:56 -0700118 mb = mbuf_alloc(tc->sock->headroom + len);
James Kuszmaul82f6c042021-01-17 11:30:16 -0800119 if (!mb)
120 return -1;
121
Austin Schuh35a2f492021-04-07 21:41:56 -0700122 mb->pos = tc->sock->headroom;
James Kuszmaul82f6c042021-01-17 11:30:16 -0800123 (void)mbuf_write_mem(mb, (void *)buf, len);
Austin Schuh35a2f492021-04-07 21:41:56 -0700124 mb->pos = tc->sock->headroom;
James Kuszmaul82f6c042021-01-17 11:30:16 -0800125
Austin Schuh35a2f492021-04-07 21:41:56 -0700126 err = tc->sock->sendh(tc, &tc->peer, mb, tc->arg);
James Kuszmaul82f6c042021-01-17 11:30:16 -0800127
128 mem_deref(mb);
129
130 return err ? -1 : len;
131}
132
133
134static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
135{
136#ifdef TLS_BIO_OPAQUE
137 struct tls_conn *tc = BIO_get_data(b);
138#else
139 struct tls_conn *tc = b->ptr;
140#endif
141 (void)num;
142 (void)ptr;
143
144 switch (cmd) {
145
146 case BIO_CTRL_FLUSH:
147 /* The OpenSSL library needs this */
148 return 1;
149
150#if defined (BIO_CTRL_DGRAM_QUERY_MTU)
151 case BIO_CTRL_DGRAM_QUERY_MTU:
Austin Schuh35a2f492021-04-07 21:41:56 -0700152 if (tc) {
153 if (tc->sock->mtuh) {
154 return tc->sock->mtuh(tc, tc->arg);
155 }
156 else {
157 return tc->sock->mtu;
158 }
159 }
160 else {
161 return MTU_DEFAULT;
162 }
James Kuszmaul82f6c042021-01-17 11:30:16 -0800163#endif
164
165#if defined (BIO_CTRL_DGRAM_GET_FALLBACK_MTU)
166 case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
167 return MTU_FALLBACK;
168#endif
169 }
170
171 return 0;
172}
173
174
175#ifdef TLS_BIO_OPAQUE
176
177static BIO_METHOD *bio_method_udp(void)
178{
179 BIO_METHOD *method;
180
181 method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "udp_send");
182 if (!method) {
183 DEBUG_WARNING("alloc: BIO_meth_new() failed\n");
184 ERR_clear_error();
185 return NULL;
186 }
187
188 BIO_meth_set_write(method, bio_write);
189 BIO_meth_set_ctrl(method, bio_ctrl);
190 BIO_meth_set_create(method, bio_create);
191 BIO_meth_set_destroy(method, bio_destroy);
192
193 return method;
194}
195
196#else
197
198static struct bio_method_st bio_udp_send = {
199 BIO_TYPE_SOURCE_SINK,
200 "udp_send",
201 bio_write,
202 0,
203 0,
204 0,
205 bio_ctrl,
206 bio_create,
207 bio_destroy,
208 0
209};
210
211#endif
212
213
214static void tls_close(struct tls_conn *tc)
215{
216 int r;
217
218 if (!tc->ssl)
219 return;
220
221 r = SSL_shutdown(tc->ssl);
222 if (r <= 0)
223 ERR_clear_error();
224
225 SSL_free(tc->ssl);
226 tc->ssl = NULL;
227}
228
229
230static void conn_destructor(void *arg)
231{
232 struct tls_conn *tc = arg;
233
234 hash_unlink(&tc->he);
235 tmr_cancel(&tc->tmr);
236 tls_close(tc);
237
238#ifdef TLS_BIO_OPAQUE
239 if (tc->biomet)
240 BIO_meth_free(tc->biomet);
241#endif
242
243 mem_deref(tc->sock);
244}
245
246
247static void conn_close(struct tls_conn *tc, int err)
248{
249 tmr_cancel(&tc->tmr);
250 tls_close(tc);
251 tc->up = false;
252
253 if (tc->closeh)
254 tc->closeh(err, tc->arg);
255}
256
257
258#if defined (DTLS_CTRL_HANDLE_TIMEOUT) && defined(DTLS_CTRL_GET_TIMEOUT)
259
260static void check_timer(struct tls_conn *tc);
261
262
263static void timeout(void *arg)
264{
265 struct tls_conn *tc = arg;
266
267 DEBUG_INFO("timeout\n");
268
269 if (0 <= DTLSv1_handle_timeout(tc->ssl)) {
270
271 check_timer(tc);
272 }
273 else {
274 ERR_clear_error();
275 conn_close(tc, ETIMEDOUT);
276 }
277}
278
279
280static void check_timer(struct tls_conn *tc)
281{
282 struct timeval tv = {0, 0};
283
284 if (1 == DTLSv1_get_timeout(tc->ssl, &tv)) {
285
286 tmr_start(&tc->tmr, tv.tv_sec * 1000 + tv.tv_usec / 1000,
287 timeout, tc);
288 }
289 else {
290 tmr_cancel(&tc->tmr);
291 }
292}
293
294#else
295
296static void check_timer(struct tls_conn *tc)
297{
298 (void)tc;
299}
300
301#endif
302
303
304static int tls_connect(struct tls_conn *tc)
305{
306 int r;
307
308 ERR_clear_error();
309
310 r = SSL_connect(tc->ssl);
311 if (r <= 0) {
312 const int ssl_err = SSL_get_error(tc->ssl, r);
313
314 tls_flush_error();
315
316 switch (ssl_err) {
317
318 case SSL_ERROR_WANT_READ:
319 break;
320
321 default:
322 DEBUG_WARNING("connect error: %i\n", ssl_err);
323 return EPROTO;
324 }
325 }
326
327 check_timer(tc);
328
329 return 0;
330}
331
332
333static int tls_accept(struct tls_conn *tc)
334{
335 int r;
336
337 ERR_clear_error();
338
339 r = SSL_accept(tc->ssl);
340 if (r <= 0) {
341 const int ssl_err = SSL_get_error(tc->ssl, r);
342
343 tls_flush_error();
344
345 switch (ssl_err) {
346
347 case SSL_ERROR_WANT_READ:
348 break;
349
350 default:
351 DEBUG_WARNING("accept error: %i\n", ssl_err);
352 return EPROTO;
353 }
354 }
355
356 check_timer(tc);
357
358 return 0;
359}
360
361
362static void conn_recv(struct tls_conn *tc, struct mbuf *mb)
363{
364 int err, r;
365
366 if (!tc->ssl)
367 return;
368
369 /* feed SSL data to the BIO */
370 r = BIO_write(tc->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb));
371 if (r <= 0) {
372 DEBUG_WARNING("receive bio write error: %i\n", r);
373 ERR_clear_error();
374 conn_close(tc, ENOMEM);
375 return;
376 }
377
378 if (SSL_state(tc->ssl) != SSL_ST_OK) {
379
380 if (tc->up) {
381 conn_close(tc, EPROTO);
382 return;
383 }
384
385 if (tc->active) {
386 err = tls_connect(tc);
387 }
388 else {
389 err = tls_accept(tc);
390 }
391
392 if (err) {
393 conn_close(tc, err);
394 return;
395 }
396
397 DEBUG_INFO("%s: state=0x%04x\n",
398 tc->active ? "client" : "server",
399 SSL_state(tc->ssl));
400
401 /* TLS connection is established */
402 if (SSL_state(tc->ssl) != SSL_ST_OK)
403 return;
404
405 tc->up = true;
406
407 if (tc->estabh) {
408 uint32_t nrefs;
409
410 mem_ref(tc);
411
412 tc->estabh(tc->arg);
413
414 nrefs = mem_nrefs(tc);
415 mem_deref(tc);
416
417 /* check if connection was deref'd from handler */
418 if (nrefs == 1)
419 return;
420 }
421 }
422
423 mbuf_set_pos(mb, 0);
424
425 for (;;) {
426 int n;
427
428 if (mbuf_get_space(mb) < 4096) {
429 err = mbuf_resize(mb, mb->size + 8192);
430 if (err) {
431 conn_close(tc, err);
432 return;
433 }
434 }
435
436 ERR_clear_error();
437
438 n = SSL_read(tc->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb));
439 if (n <= 0) {
440 const int ssl_err = SSL_get_error(tc->ssl, n);
441
442 ERR_clear_error();
443
444 switch (ssl_err) {
445
446 case SSL_ERROR_WANT_READ:
447 break;
448
449 case SSL_ERROR_ZERO_RETURN:
450 conn_close(tc, ECONNRESET);
451 return;
452
453 default:
454 DEBUG_WARNING("read error: %i\n", ssl_err);
455 conn_close(tc, EPROTO);
456 return;
457 }
458
459 break;
460 }
461
462 mb->pos += n;
463 }
464
465 mbuf_set_end(mb, mb->pos);
466 mbuf_set_pos(mb, 0);
467
468 if (tc->recvh && mbuf_get_left(mb) > 0)
469 tc->recvh(mb, tc->arg);
470
471 return;
472}
473
474
475static int conn_alloc(struct tls_conn **ptc, struct tls *tls,
476 struct dtls_sock *sock, const struct sa *peer,
477 dtls_estab_h *estabh, dtls_recv_h *recvh,
478 dtls_close_h *closeh, void *arg)
479{
480 struct tls_conn *tc;
481 int err = 0;
482
483 tc = mem_zalloc(sizeof(*tc), conn_destructor);
484 if (!tc)
485 return ENOMEM;
486
487 hash_append(sock->ht, sa_hash(peer, SA_ALL), &tc->he, tc);
488
489 tc->sock = mem_ref(sock);
490 tc->peer = *peer;
491 tc->estabh = estabh;
492 tc->recvh = recvh;
493 tc->closeh = closeh;
494 tc->arg = arg;
495
496#ifdef TLS_BIO_OPAQUE
497 tc->biomet = bio_method_udp();
498 if (!tc->biomet) {
499 err = ENOMEM;
500 goto out;
501 }
502#endif
503
504 /* Connect the SSL socket */
505 tc->ssl = SSL_new(tls->ctx);
506 if (!tc->ssl) {
507 DEBUG_WARNING("ssl new failed: %i\n",
508 ERR_GET_REASON(ERR_get_error()));
509 ERR_clear_error();
510 err = ENOMEM;
511 goto out;
512 }
513
514 tc->sbio_in = BIO_new(BIO_s_mem());
515 if (!tc->sbio_in) {
516 ERR_clear_error();
517 err = ENOMEM;
518 goto out;
519 }
520
521#ifdef TLS_BIO_OPAQUE
522 tc->sbio_out = BIO_new(tc->biomet);
523#else
524 tc->sbio_out = BIO_new(&bio_udp_send);
525#endif
526 if (!tc->sbio_out) {
527 ERR_clear_error();
528 BIO_free(tc->sbio_in);
529 err = ENOMEM;
530 goto out;
531 }
532
533#ifdef TLS_BIO_OPAQUE
534 BIO_set_data(tc->sbio_out, tc);
535#else
536 tc->sbio_out->ptr = tc;
537#endif
538
539 SSL_set_bio(tc->ssl, tc->sbio_in, tc->sbio_out);
540
541 SSL_set_read_ahead(tc->ssl, 1);
542
543 out:
544 if (err)
545 mem_deref(tc);
546 else
547 *ptc = tc;
548
549 return err;
550}
551
552
553/**
554 * DTLS Connect
555 *
556 * @param ptc Pointer to allocated DTLS connection
557 * @param tls TLS Context
558 * @param sock DTLS Socket
559 * @param peer Peer address
560 * @param estabh Establish handler
561 * @param recvh Receive handler
562 * @param closeh Close handler
563 * @param arg Handler argument
564 *
565 * @return 0 if success, otherwise errorcode
566 */
567int dtls_connect(struct tls_conn **ptc, struct tls *tls,
568 struct dtls_sock *sock, const struct sa *peer,
569 dtls_estab_h *estabh, dtls_recv_h *recvh,
570 dtls_close_h *closeh, void *arg)
571{
572 struct tls_conn *tc;
573 int err;
574
575 if (!ptc || !tls || !sock || !peer)
576 return EINVAL;
577
578 err = conn_alloc(&tc, tls, sock, peer, estabh, recvh, closeh, arg);
579 if (err)
580 return err;
581
582 tc->active = true;
583
584 err = tls_connect(tc);
585 if (err)
586 goto out;
587
588 out:
589 if (err)
590 mem_deref(tc);
591 else
592 *ptc = tc;
593
594 return err;
595}
596
597
598/**
599 * DTLS Accept
600 *
601 * @param ptc Pointer to allocated DTLS connection
602 * @param tls TLS Context
603 * @param sock DTLS Socket
604 * @param estabh Establish handler
605 * @param recvh Receive handler
606 * @param closeh Close handler
607 * @param arg Handler argument
608 *
609 * @return 0 if success, otherwise errorcode
610 */
611int dtls_accept(struct tls_conn **ptc, struct tls *tls,
612 struct dtls_sock *sock,
613 dtls_estab_h *estabh, dtls_recv_h *recvh,
614 dtls_close_h *closeh, void *arg)
615{
616 struct tls_conn *tc;
617 int err, r;
618
619 if (!ptc || !tls || !sock || !sock->mb)
620 return EINVAL;
621
622 err = conn_alloc(&tc, tls, sock, &sock->peer, estabh, recvh, closeh,
623 arg);
624 if (err)
625 return err;
626
627 tc->active = false;
628
629 r = BIO_write(tc->sbio_in, mbuf_buf(sock->mb),
630 (int)mbuf_get_left(sock->mb));
631 if (r <= 0) {
632 DEBUG_WARNING("accept bio write error: %i\n", r);
633 ERR_clear_error();
634 err = ENOMEM;
635 goto out;
636 }
637
638 err = tls_accept(tc);
639 if (err)
640 goto out;
641
642 sock->mb = mem_deref(sock->mb);
643
644 out:
645 if (err)
646 mem_deref(tc);
647 else
648 *ptc = tc;
649
650 return err;
651}
652
653
654/**
655 * Send data on a DTLS connection
656 *
657 * @param tc DTLS connection
658 * @param mb Buffer to send
659 *
660 * @return 0 if success, otherwise errorcode
661 */
662int dtls_send(struct tls_conn *tc, struct mbuf *mb)
663{
664 int r;
665
666 if (!tc || !mb)
667 return EINVAL;
668
669 if (!tc->up || !tc->ssl)
670 return ENOTCONN;
671
672 ERR_clear_error();
673
674 r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb));
675 if (r <= 0) {
676 DEBUG_WARNING("write error: %i\n", SSL_get_error(tc->ssl, r));
677 ERR_clear_error();
678 return EPROTO;
679 }
680
681 return 0;
682}
683
684
685/**
686 * Set handlers on a DTLS Connection
687 *
688 * @param tc DTLS Connection
689 * @param estabh DTLS Connection Established handler
690 * @param recvh DTLS Connection Receive data handler
691 * @param closeh DTLS Connection Close handler
692 * @param arg Handler argument
693 */
694void dtls_set_handlers(struct tls_conn *tc, dtls_estab_h *estabh,
695 dtls_recv_h *recvh, dtls_close_h *closeh, void *arg)
696{
697 if (!tc)
698 return;
699
700 tc->estabh = estabh;
701 tc->recvh = recvh;
702 tc->closeh = closeh;
703 tc->arg = arg;
704}
705
706
707/**
708 * Get the remote peer of a DTLS Connection
709 *
710 * @param tc DTLS Connection
711 *
712 * @return Remote peer
713 */
714const struct sa *dtls_peer(const struct tls_conn *tc)
715{
716 return tc ? &tc->peer : NULL;
717}
718
719
720/**
721 * Set the remote peer of a DTLS Connection
722 *
723 * @param tc DTLS Connection
724 * @param peer Peer address
725 */
726void dtls_set_peer(struct tls_conn *tc, const struct sa *peer)
727{
728 if (!tc || !peer)
729 return;
730
731 hash_unlink(&tc->he);
732 hash_append(tc->sock->ht, sa_hash(peer, SA_ALL), &tc->he, tc);
733
734 tc->peer = *peer;
735}
736
737
738static void sock_destructor(void *arg)
739{
740 struct dtls_sock *sock = arg;
741
742 hash_clear(sock->ht);
743 mem_deref(sock->uh);
744 mem_deref(sock->us);
745 mem_deref(sock->ht);
746 mem_deref(sock->mb);
747}
748
749
750static bool cmp_handler(struct le *le, void *arg)
751{
752 struct tls_conn *tc = le->data;
753
754 return sa_cmp(&tc->peer, arg, SA_ALL);
755}
756
757
758static struct tls_conn *conn_lookup(struct dtls_sock *sock,
759 const struct sa *peer)
760{
761 return list_ledata(hash_lookup(sock->ht, sa_hash(peer, SA_ALL),
762 cmp_handler, (void *)peer));
763}
764
765
Austin Schuh35a2f492021-04-07 21:41:56 -0700766static int send_handler(struct tls_conn *tc, const struct sa *dst,
767 struct mbuf *mb, void *arg) {
768 (void)arg;
769 return udp_send_helper(tc->sock->us, dst, mb, tc->sock->uh);
770}
771
772
James Kuszmaul82f6c042021-01-17 11:30:16 -0800773static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
774{
775 struct dtls_sock *sock = arg;
776 struct tls_conn *tc;
777 uint8_t b;
778
779 if (mbuf_get_left(mb) < 1)
780 return false;
781
782 b = mb->buf[mb->pos];
783 if (b < 20 || b > 63)
784 return false;
785
786 tc = conn_lookup(sock, src);
787 if (tc) {
788 conn_recv(tc, mb);
789 return true;
790 }
791
792 if (sock->connh) {
793
794 mem_deref(sock->mb);
795 sock->mb = mem_ref(mb);
796 sock->peer = *src;
797
798 sock->connh(src, sock->arg);
799 }
800
801 return true;
802}
803
804
805/**
Austin Schuh35a2f492021-04-07 21:41:56 -0700806 * Feed data to a DTLS socket
807 *
808 * @param sock DTLS socket
809 * @param src Source address
810 * @param mb Buffer to receive
811 *
812 * @return whether the packet has been handled.
813 */
814bool dtls_receive(struct dtls_sock *sock, struct sa *src, struct mbuf *mb) {
815 return recv_handler(src, mb, sock);
816}
817
818
819/**
James Kuszmaul82f6c042021-01-17 11:30:16 -0800820 * Create DTLS Socket
821 *
822 * @param sockp Pointer to returned DTLS Socket
823 * @param laddr Local listen address (optional)
824 * @param us External UDP socket (optional)
825 * @param htsize Connection hash table size
826 * @param layer UDP protocol layer
827 * @param connh Connect handler
828 * @param arg Handler argument
829 *
830 * @return 0 if success, otherwise errorcode
831 */
832int dtls_listen(struct dtls_sock **sockp, const struct sa *laddr,
833 struct udp_sock *us, uint32_t htsize, int layer,
834 dtls_conn_h *connh, void *arg)
835{
836 struct dtls_sock *sock;
837 int err;
838
839 if (!sockp)
840 return EINVAL;
841
842 sock = mem_zalloc(sizeof(*sock), sock_destructor);
843 if (!sock)
844 return ENOMEM;
845
846 if (us) {
847 sock->us = mem_ref(us);
848 }
849 else {
850 err = udp_listen(&sock->us, laddr, NULL, NULL);
851 if (err)
852 goto out;
853 }
854
855 err = udp_register_helper(&sock->uh, sock->us, layer,
856 NULL, recv_handler, sock);
857 if (err)
858 goto out;
859
860 err = hash_alloc(&sock->ht, hash_valid_size(htsize));
861 if (err)
862 goto out;
863
Austin Schuh35a2f492021-04-07 21:41:56 -0700864 sock->mtu = MTU_DEFAULT;
865 sock->headroom = HEADROOM_DEFAULT;
866 sock->connh = connh;
867 sock->sendh = send_handler;
868 sock->arg = arg;
869
870 out:
871 if (err)
872 mem_deref(sock);
873 else
874 *sockp = sock;
875
876 return err;
877}
878
879
880/**
881 * Create a DTLS Socket without using an UDP socket underneath
882 *
883 * @param sockp Pointer to returned DTLS Socket
884 * @param htsize Connection hash table size. Set to 0 if one DTLS session shall
885 * be used for all peers.
886 * @param connh Connect handler
887 * @param sendh Send handler
888 * @param mtuh MTU handler
889 * @param arg Handler argument
890 *
891 * @return 0 if success, otherwise errorcode
892 */
893int dtls_socketless(struct dtls_sock **sockp, uint32_t htsize,
894 dtls_conn_h *connh, dtls_send_h *sendh, dtls_mtu_h *mtuh,
895 void *arg)
896{
897 struct dtls_sock *sock;
898 int err;
899
900 if (!sockp || !sendh)
901 return EINVAL;
902
903 sock = mem_zalloc(sizeof(*sock), sock_destructor);
904 if (!sock)
905 return ENOMEM;
906
907 err = hash_alloc(&sock->ht, hash_valid_size(htsize));
908 if (err)
909 goto out;
910
James Kuszmaul82f6c042021-01-17 11:30:16 -0800911 sock->mtu = MTU_DEFAULT;
912 sock->connh = connh;
Austin Schuh35a2f492021-04-07 21:41:56 -0700913 sock->sendh = sendh;
914 sock->mtuh = mtuh;
James Kuszmaul82f6c042021-01-17 11:30:16 -0800915 sock->arg = arg;
916
917 out:
918 if (err)
919 mem_deref(sock);
920 else
921 *sockp = sock;
922
923 return err;
924}
925
926
927/**
928 * Get the underlying UDP socket of a DTLS Socket
929 *
930 * @param sock DTLS Socket
931 *
932 * @return UDP Socket
933 */
934struct udp_sock *dtls_udp_sock(struct dtls_sock *sock)
935{
936 return sock ? sock->us : NULL;
937}
938
939
940/**
941 * Set MTU on a DTLS Socket
942 *
943 * @param sock DTLS Socket
944 * @param mtu MTU value
945 */
946void dtls_set_mtu(struct dtls_sock *sock, size_t mtu)
947{
948 if (!sock)
949 return;
950
951 sock->mtu = mtu;
952}
953
954
Austin Schuh35a2f492021-04-07 21:41:56 -0700955/*
956 * Get headroom of a DTLS Socket
957 *
958 * @param sock DTLS Socket
959 *
960 * @return Headroom value.
961 */
962size_t dtls_headroom(struct dtls_sock *sock)
963{
964 return sock ? sock->headroom : 0;
965}
966
967
968/**
969 * Set headroom on a DTLS Socket
970 *
971 * @param sock DTLS Socket
972 * @param headroom Headroom value
973 */
974void dtls_set_headroom(struct dtls_sock *sock, size_t headroom)
975{
976 if (!sock)
977 return;
978
979 sock->headroom = headroom;
980}
981
982
James Kuszmaul82f6c042021-01-17 11:30:16 -0800983void dtls_recv_packet(struct dtls_sock *sock, const struct sa *src,
984 struct mbuf *mb)
985{
986 struct sa addr;
987
988 if (!sock || !src || !mb)
989 return;
990
991 addr = *src;
992
993 recv_handler(&addr, mb, sock);
994}