1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2005-2022 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#ifndef _GNU_SOURCE
11e1051a39Sopenharmony_ci# define _GNU_SOURCE
12e1051a39Sopenharmony_ci#endif
13e1051a39Sopenharmony_ci
14e1051a39Sopenharmony_ci#include <stdio.h>
15e1051a39Sopenharmony_ci#include <errno.h>
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ci#include "bio_local.h"
18e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DGRAM
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_SCTP
21e1051a39Sopenharmony_ci#  include <netinet/sctp.h>
22e1051a39Sopenharmony_ci#  include <fcntl.h>
23e1051a39Sopenharmony_ci#  define OPENSSL_SCTP_DATA_CHUNK_TYPE            0x00
24e1051a39Sopenharmony_ci#  define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0
25e1051a39Sopenharmony_ci# endif
26e1051a39Sopenharmony_ci
27e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU)
28e1051a39Sopenharmony_ci#  define IP_MTU      14        /* linux is lame */
29e1051a39Sopenharmony_ci# endif
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci# if OPENSSL_USE_IPV6 && !defined(IPPROTO_IPV6)
32e1051a39Sopenharmony_ci#  define IPPROTO_IPV6 41       /* windows is lame */
33e1051a39Sopenharmony_ci# endif
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_ci# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED)
36e1051a39Sopenharmony_ci/* Standard definition causes type-punning problems. */
37e1051a39Sopenharmony_ci#  undef IN6_IS_ADDR_V4MAPPED
38e1051a39Sopenharmony_ci#  define s6_addr32 __u6_addr.__u6_addr32
39e1051a39Sopenharmony_ci#  define IN6_IS_ADDR_V4MAPPED(a)               \
40e1051a39Sopenharmony_ci        (((a)->s6_addr32[0] == 0) &&          \
41e1051a39Sopenharmony_ci         ((a)->s6_addr32[1] == 0) &&          \
42e1051a39Sopenharmony_ci         ((a)->s6_addr32[2] == htonl(0x0000ffff)))
43e1051a39Sopenharmony_ci# endif
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_cistatic int dgram_write(BIO *h, const char *buf, int num);
46e1051a39Sopenharmony_cistatic int dgram_read(BIO *h, char *buf, int size);
47e1051a39Sopenharmony_cistatic int dgram_puts(BIO *h, const char *str);
48e1051a39Sopenharmony_cistatic long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
49e1051a39Sopenharmony_cistatic int dgram_new(BIO *h);
50e1051a39Sopenharmony_cistatic int dgram_free(BIO *data);
51e1051a39Sopenharmony_cistatic int dgram_clear(BIO *bio);
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_SCTP
54e1051a39Sopenharmony_cistatic int dgram_sctp_write(BIO *h, const char *buf, int num);
55e1051a39Sopenharmony_cistatic int dgram_sctp_read(BIO *h, char *buf, int size);
56e1051a39Sopenharmony_cistatic int dgram_sctp_puts(BIO *h, const char *str);
57e1051a39Sopenharmony_cistatic long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
58e1051a39Sopenharmony_cistatic int dgram_sctp_new(BIO *h);
59e1051a39Sopenharmony_cistatic int dgram_sctp_free(BIO *data);
60e1051a39Sopenharmony_cistatic int dgram_sctp_wait_for_dry(BIO *b);
61e1051a39Sopenharmony_cistatic int dgram_sctp_msg_waiting(BIO *b);
62e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
63e1051a39Sopenharmony_cistatic void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification
64e1051a39Sopenharmony_ci                                                  *snp);
65e1051a39Sopenharmony_ci#  endif
66e1051a39Sopenharmony_ci# endif
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_cistatic int BIO_dgram_should_retry(int s);
69e1051a39Sopenharmony_ci
70e1051a39Sopenharmony_cistatic void get_current_time(struct timeval *t);
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_cistatic const BIO_METHOD methods_dgramp = {
73e1051a39Sopenharmony_ci    BIO_TYPE_DGRAM,
74e1051a39Sopenharmony_ci    "datagram socket",
75e1051a39Sopenharmony_ci    bwrite_conv,
76e1051a39Sopenharmony_ci    dgram_write,
77e1051a39Sopenharmony_ci    bread_conv,
78e1051a39Sopenharmony_ci    dgram_read,
79e1051a39Sopenharmony_ci    dgram_puts,
80e1051a39Sopenharmony_ci    NULL,                       /* dgram_gets,         */
81e1051a39Sopenharmony_ci    dgram_ctrl,
82e1051a39Sopenharmony_ci    dgram_new,
83e1051a39Sopenharmony_ci    dgram_free,
84e1051a39Sopenharmony_ci    NULL,                       /* dgram_callback_ctrl */
85e1051a39Sopenharmony_ci};
86e1051a39Sopenharmony_ci
87e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_SCTP
88e1051a39Sopenharmony_cistatic const BIO_METHOD methods_dgramp_sctp = {
89e1051a39Sopenharmony_ci    BIO_TYPE_DGRAM_SCTP,
90e1051a39Sopenharmony_ci    "datagram sctp socket",
91e1051a39Sopenharmony_ci    bwrite_conv,
92e1051a39Sopenharmony_ci    dgram_sctp_write,
93e1051a39Sopenharmony_ci    bread_conv,
94e1051a39Sopenharmony_ci    dgram_sctp_read,
95e1051a39Sopenharmony_ci    dgram_sctp_puts,
96e1051a39Sopenharmony_ci    NULL,                       /* dgram_gets,         */
97e1051a39Sopenharmony_ci    dgram_sctp_ctrl,
98e1051a39Sopenharmony_ci    dgram_sctp_new,
99e1051a39Sopenharmony_ci    dgram_sctp_free,
100e1051a39Sopenharmony_ci    NULL,                       /* dgram_callback_ctrl */
101e1051a39Sopenharmony_ci};
102e1051a39Sopenharmony_ci# endif
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_citypedef struct bio_dgram_data_st {
105e1051a39Sopenharmony_ci    BIO_ADDR peer;
106e1051a39Sopenharmony_ci    unsigned int connected;
107e1051a39Sopenharmony_ci    unsigned int _errno;
108e1051a39Sopenharmony_ci    unsigned int mtu;
109e1051a39Sopenharmony_ci    struct timeval next_timeout;
110e1051a39Sopenharmony_ci    struct timeval socket_timeout;
111e1051a39Sopenharmony_ci    unsigned int peekmode;
112e1051a39Sopenharmony_ci} bio_dgram_data;
113e1051a39Sopenharmony_ci
114e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_SCTP
115e1051a39Sopenharmony_citypedef struct bio_dgram_sctp_save_message_st {
116e1051a39Sopenharmony_ci    BIO *bio;
117e1051a39Sopenharmony_ci    char *data;
118e1051a39Sopenharmony_ci    int length;
119e1051a39Sopenharmony_ci} bio_dgram_sctp_save_message;
120e1051a39Sopenharmony_ci
121e1051a39Sopenharmony_citypedef struct bio_dgram_sctp_data_st {
122e1051a39Sopenharmony_ci    BIO_ADDR peer;
123e1051a39Sopenharmony_ci    unsigned int connected;
124e1051a39Sopenharmony_ci    unsigned int _errno;
125e1051a39Sopenharmony_ci    unsigned int mtu;
126e1051a39Sopenharmony_ci    struct bio_dgram_sctp_sndinfo sndinfo;
127e1051a39Sopenharmony_ci    struct bio_dgram_sctp_rcvinfo rcvinfo;
128e1051a39Sopenharmony_ci    struct bio_dgram_sctp_prinfo prinfo;
129e1051a39Sopenharmony_ci    BIO_dgram_sctp_notification_handler_fn handle_notifications;
130e1051a39Sopenharmony_ci    void *notification_context;
131e1051a39Sopenharmony_ci    int in_handshake;
132e1051a39Sopenharmony_ci    int ccs_rcvd;
133e1051a39Sopenharmony_ci    int ccs_sent;
134e1051a39Sopenharmony_ci    int save_shutdown;
135e1051a39Sopenharmony_ci    int peer_auth_tested;
136e1051a39Sopenharmony_ci} bio_dgram_sctp_data;
137e1051a39Sopenharmony_ci# endif
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_datagram(void)
140e1051a39Sopenharmony_ci{
141e1051a39Sopenharmony_ci    return &methods_dgramp;
142e1051a39Sopenharmony_ci}
143e1051a39Sopenharmony_ci
144e1051a39Sopenharmony_ciBIO *BIO_new_dgram(int fd, int close_flag)
145e1051a39Sopenharmony_ci{
146e1051a39Sopenharmony_ci    BIO *ret;
147e1051a39Sopenharmony_ci
148e1051a39Sopenharmony_ci    ret = BIO_new(BIO_s_datagram());
149e1051a39Sopenharmony_ci    if (ret == NULL)
150e1051a39Sopenharmony_ci        return NULL;
151e1051a39Sopenharmony_ci    BIO_set_fd(ret, fd, close_flag);
152e1051a39Sopenharmony_ci    return ret;
153e1051a39Sopenharmony_ci}
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_cistatic int dgram_new(BIO *bi)
156e1051a39Sopenharmony_ci{
157e1051a39Sopenharmony_ci    bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data));
158e1051a39Sopenharmony_ci
159e1051a39Sopenharmony_ci    if (data == NULL)
160e1051a39Sopenharmony_ci        return 0;
161e1051a39Sopenharmony_ci    bi->ptr = data;
162e1051a39Sopenharmony_ci    return 1;
163e1051a39Sopenharmony_ci}
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_cistatic int dgram_free(BIO *a)
166e1051a39Sopenharmony_ci{
167e1051a39Sopenharmony_ci    bio_dgram_data *data;
168e1051a39Sopenharmony_ci
169e1051a39Sopenharmony_ci    if (a == NULL)
170e1051a39Sopenharmony_ci        return 0;
171e1051a39Sopenharmony_ci    if (!dgram_clear(a))
172e1051a39Sopenharmony_ci        return 0;
173e1051a39Sopenharmony_ci
174e1051a39Sopenharmony_ci    data = (bio_dgram_data *)a->ptr;
175e1051a39Sopenharmony_ci    OPENSSL_free(data);
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    return 1;
178e1051a39Sopenharmony_ci}
179e1051a39Sopenharmony_ci
180e1051a39Sopenharmony_cistatic int dgram_clear(BIO *a)
181e1051a39Sopenharmony_ci{
182e1051a39Sopenharmony_ci    if (a == NULL)
183e1051a39Sopenharmony_ci        return 0;
184e1051a39Sopenharmony_ci    if (a->shutdown) {
185e1051a39Sopenharmony_ci        if (a->init) {
186e1051a39Sopenharmony_ci            BIO_closesocket(a->num);
187e1051a39Sopenharmony_ci        }
188e1051a39Sopenharmony_ci        a->init = 0;
189e1051a39Sopenharmony_ci        a->flags = 0;
190e1051a39Sopenharmony_ci    }
191e1051a39Sopenharmony_ci    return 1;
192e1051a39Sopenharmony_ci}
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_cistatic void dgram_adjust_rcv_timeout(BIO *b)
195e1051a39Sopenharmony_ci{
196e1051a39Sopenharmony_ci# if defined(SO_RCVTIMEO)
197e1051a39Sopenharmony_ci    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
198e1051a39Sopenharmony_ci
199e1051a39Sopenharmony_ci    /* Is a timer active? */
200e1051a39Sopenharmony_ci    if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
201e1051a39Sopenharmony_ci        struct timeval timenow, timeleft;
202e1051a39Sopenharmony_ci
203e1051a39Sopenharmony_ci        /* Read current socket timeout */
204e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
205e1051a39Sopenharmony_ci        int timeout;
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci        int sz = sizeof(timeout);
208e1051a39Sopenharmony_ci        if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
209e1051a39Sopenharmony_ci                       (void *)&timeout, &sz) < 0) {
210e1051a39Sopenharmony_ci            perror("getsockopt");
211e1051a39Sopenharmony_ci        } else {
212e1051a39Sopenharmony_ci            data->socket_timeout.tv_sec = timeout / 1000;
213e1051a39Sopenharmony_ci            data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
214e1051a39Sopenharmony_ci        }
215e1051a39Sopenharmony_ci#  else
216e1051a39Sopenharmony_ci        socklen_t sz = sizeof(data->socket_timeout);
217e1051a39Sopenharmony_ci        if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
218e1051a39Sopenharmony_ci                       &(data->socket_timeout), &sz) < 0) {
219e1051a39Sopenharmony_ci            perror("getsockopt");
220e1051a39Sopenharmony_ci        } else
221e1051a39Sopenharmony_ci            OPENSSL_assert(sz <= sizeof(data->socket_timeout));
222e1051a39Sopenharmony_ci#  endif
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci        /* Get current time */
225e1051a39Sopenharmony_ci        get_current_time(&timenow);
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci        /* Calculate time left until timer expires */
228e1051a39Sopenharmony_ci        memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
229e1051a39Sopenharmony_ci        if (timeleft.tv_usec < timenow.tv_usec) {
230e1051a39Sopenharmony_ci            timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec;
231e1051a39Sopenharmony_ci            timeleft.tv_sec--;
232e1051a39Sopenharmony_ci        } else {
233e1051a39Sopenharmony_ci            timeleft.tv_usec -= timenow.tv_usec;
234e1051a39Sopenharmony_ci        }
235e1051a39Sopenharmony_ci        if (timeleft.tv_sec < timenow.tv_sec) {
236e1051a39Sopenharmony_ci            timeleft.tv_sec = 0;
237e1051a39Sopenharmony_ci            timeleft.tv_usec = 1;
238e1051a39Sopenharmony_ci        } else {
239e1051a39Sopenharmony_ci            timeleft.tv_sec -= timenow.tv_sec;
240e1051a39Sopenharmony_ci        }
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci        /*
243e1051a39Sopenharmony_ci         * Adjust socket timeout if next handshake message timer will expire
244e1051a39Sopenharmony_ci         * earlier.
245e1051a39Sopenharmony_ci         */
246e1051a39Sopenharmony_ci        if ((data->socket_timeout.tv_sec == 0
247e1051a39Sopenharmony_ci             && data->socket_timeout.tv_usec == 0)
248e1051a39Sopenharmony_ci            || (data->socket_timeout.tv_sec > timeleft.tv_sec)
249e1051a39Sopenharmony_ci            || (data->socket_timeout.tv_sec == timeleft.tv_sec
250e1051a39Sopenharmony_ci                && data->socket_timeout.tv_usec >= timeleft.tv_usec)) {
251e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
252e1051a39Sopenharmony_ci            timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
253e1051a39Sopenharmony_ci            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
254e1051a39Sopenharmony_ci                           (void *)&timeout, sizeof(timeout)) < 0) {
255e1051a39Sopenharmony_ci                perror("setsockopt");
256e1051a39Sopenharmony_ci            }
257e1051a39Sopenharmony_ci#  else
258e1051a39Sopenharmony_ci            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
259e1051a39Sopenharmony_ci                           sizeof(struct timeval)) < 0) {
260e1051a39Sopenharmony_ci                perror("setsockopt");
261e1051a39Sopenharmony_ci            }
262e1051a39Sopenharmony_ci#  endif
263e1051a39Sopenharmony_ci        }
264e1051a39Sopenharmony_ci    }
265e1051a39Sopenharmony_ci# endif
266e1051a39Sopenharmony_ci}
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_cistatic void dgram_reset_rcv_timeout(BIO *b)
269e1051a39Sopenharmony_ci{
270e1051a39Sopenharmony_ci# if defined(SO_RCVTIMEO)
271e1051a39Sopenharmony_ci    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
272e1051a39Sopenharmony_ci
273e1051a39Sopenharmony_ci    /* Is a timer active? */
274e1051a39Sopenharmony_ci    if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
275e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
276e1051a39Sopenharmony_ci        int timeout = data->socket_timeout.tv_sec * 1000 +
277e1051a39Sopenharmony_ci            data->socket_timeout.tv_usec / 1000;
278e1051a39Sopenharmony_ci        if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
279e1051a39Sopenharmony_ci                       (void *)&timeout, sizeof(timeout)) < 0) {
280e1051a39Sopenharmony_ci            perror("setsockopt");
281e1051a39Sopenharmony_ci        }
282e1051a39Sopenharmony_ci#  else
283e1051a39Sopenharmony_ci        if (setsockopt
284e1051a39Sopenharmony_ci            (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
285e1051a39Sopenharmony_ci             sizeof(struct timeval)) < 0) {
286e1051a39Sopenharmony_ci            perror("setsockopt");
287e1051a39Sopenharmony_ci        }
288e1051a39Sopenharmony_ci#  endif
289e1051a39Sopenharmony_ci    }
290e1051a39Sopenharmony_ci# endif
291e1051a39Sopenharmony_ci}
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_cistatic int dgram_read(BIO *b, char *out, int outl)
294e1051a39Sopenharmony_ci{
295e1051a39Sopenharmony_ci    int ret = 0;
296e1051a39Sopenharmony_ci    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
297e1051a39Sopenharmony_ci    int flags = 0;
298e1051a39Sopenharmony_ci
299e1051a39Sopenharmony_ci    BIO_ADDR peer;
300e1051a39Sopenharmony_ci    socklen_t len = sizeof(peer);
301e1051a39Sopenharmony_ci
302e1051a39Sopenharmony_ci    if (out != NULL) {
303e1051a39Sopenharmony_ci        clear_socket_error();
304e1051a39Sopenharmony_ci        memset(&peer, 0, sizeof(peer));
305e1051a39Sopenharmony_ci        dgram_adjust_rcv_timeout(b);
306e1051a39Sopenharmony_ci        if (data->peekmode)
307e1051a39Sopenharmony_ci            flags = MSG_PEEK;
308e1051a39Sopenharmony_ci        ret = recvfrom(b->num, out, outl, flags,
309e1051a39Sopenharmony_ci                       BIO_ADDR_sockaddr_noconst(&peer), &len);
310e1051a39Sopenharmony_ci
311e1051a39Sopenharmony_ci        if (!data->connected && ret >= 0)
312e1051a39Sopenharmony_ci            BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
313e1051a39Sopenharmony_ci
314e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
315e1051a39Sopenharmony_ci        if (ret < 0) {
316e1051a39Sopenharmony_ci            if (BIO_dgram_should_retry(ret)) {
317e1051a39Sopenharmony_ci                BIO_set_retry_read(b);
318e1051a39Sopenharmony_ci                data->_errno = get_last_socket_error();
319e1051a39Sopenharmony_ci            }
320e1051a39Sopenharmony_ci        }
321e1051a39Sopenharmony_ci
322e1051a39Sopenharmony_ci        dgram_reset_rcv_timeout(b);
323e1051a39Sopenharmony_ci    }
324e1051a39Sopenharmony_ci    return ret;
325e1051a39Sopenharmony_ci}
326e1051a39Sopenharmony_ci
327e1051a39Sopenharmony_cistatic int dgram_write(BIO *b, const char *in, int inl)
328e1051a39Sopenharmony_ci{
329e1051a39Sopenharmony_ci    int ret;
330e1051a39Sopenharmony_ci    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
331e1051a39Sopenharmony_ci    clear_socket_error();
332e1051a39Sopenharmony_ci
333e1051a39Sopenharmony_ci    if (data->connected)
334e1051a39Sopenharmony_ci        ret = writesocket(b->num, in, inl);
335e1051a39Sopenharmony_ci    else {
336e1051a39Sopenharmony_ci        int peerlen = BIO_ADDR_sockaddr_size(&data->peer);
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci        ret = sendto(b->num, in, inl, 0,
339e1051a39Sopenharmony_ci                     BIO_ADDR_sockaddr(&data->peer), peerlen);
340e1051a39Sopenharmony_ci    }
341e1051a39Sopenharmony_ci
342e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
343e1051a39Sopenharmony_ci    if (ret <= 0) {
344e1051a39Sopenharmony_ci        if (BIO_dgram_should_retry(ret)) {
345e1051a39Sopenharmony_ci            BIO_set_retry_write(b);
346e1051a39Sopenharmony_ci            data->_errno = get_last_socket_error();
347e1051a39Sopenharmony_ci        }
348e1051a39Sopenharmony_ci    }
349e1051a39Sopenharmony_ci    return ret;
350e1051a39Sopenharmony_ci}
351e1051a39Sopenharmony_ci
352e1051a39Sopenharmony_cistatic long dgram_get_mtu_overhead(bio_dgram_data *data)
353e1051a39Sopenharmony_ci{
354e1051a39Sopenharmony_ci    long ret;
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci    switch (BIO_ADDR_family(&data->peer)) {
357e1051a39Sopenharmony_ci    case AF_INET:
358e1051a39Sopenharmony_ci        /*
359e1051a39Sopenharmony_ci         * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
360e1051a39Sopenharmony_ci         */
361e1051a39Sopenharmony_ci        ret = 28;
362e1051a39Sopenharmony_ci        break;
363e1051a39Sopenharmony_ci# if OPENSSL_USE_IPV6
364e1051a39Sopenharmony_ci    case AF_INET6:
365e1051a39Sopenharmony_ci        {
366e1051a39Sopenharmony_ci#  ifdef IN6_IS_ADDR_V4MAPPED
367e1051a39Sopenharmony_ci            struct in6_addr tmp_addr;
368e1051a39Sopenharmony_ci            if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
369e1051a39Sopenharmony_ci                && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
370e1051a39Sopenharmony_ci                /*
371e1051a39Sopenharmony_ci                 * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
372e1051a39Sopenharmony_ci                 */
373e1051a39Sopenharmony_ci                ret = 28;
374e1051a39Sopenharmony_ci            else
375e1051a39Sopenharmony_ci#  endif
376e1051a39Sopenharmony_ci            /*
377e1051a39Sopenharmony_ci             * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP
378e1051a39Sopenharmony_ci             */
379e1051a39Sopenharmony_ci            ret = 48;
380e1051a39Sopenharmony_ci        }
381e1051a39Sopenharmony_ci        break;
382e1051a39Sopenharmony_ci# endif
383e1051a39Sopenharmony_ci    default:
384e1051a39Sopenharmony_ci        /* We don't know. Go with the historical default */
385e1051a39Sopenharmony_ci        ret = 28;
386e1051a39Sopenharmony_ci        break;
387e1051a39Sopenharmony_ci    }
388e1051a39Sopenharmony_ci    return ret;
389e1051a39Sopenharmony_ci}
390e1051a39Sopenharmony_ci
391e1051a39Sopenharmony_cistatic long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
392e1051a39Sopenharmony_ci{
393e1051a39Sopenharmony_ci    long ret = 1;
394e1051a39Sopenharmony_ci    int *ip;
395e1051a39Sopenharmony_ci    bio_dgram_data *data = NULL;
396e1051a39Sopenharmony_ci    int sockopt_val = 0;
397e1051a39Sopenharmony_ci    int d_errno;
398e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
399e1051a39Sopenharmony_ci    socklen_t sockopt_len;      /* assume that system supporting IP_MTU is
400e1051a39Sopenharmony_ci                                 * modern enough to define socklen_t */
401e1051a39Sopenharmony_ci    socklen_t addr_len;
402e1051a39Sopenharmony_ci    BIO_ADDR addr;
403e1051a39Sopenharmony_ci# endif
404e1051a39Sopenharmony_ci
405e1051a39Sopenharmony_ci    data = (bio_dgram_data *)b->ptr;
406e1051a39Sopenharmony_ci
407e1051a39Sopenharmony_ci    switch (cmd) {
408e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
409e1051a39Sopenharmony_ci        num = 0;
410e1051a39Sopenharmony_ci        ret = 0;
411e1051a39Sopenharmony_ci        break;
412e1051a39Sopenharmony_ci    case BIO_CTRL_INFO:
413e1051a39Sopenharmony_ci        ret = 0;
414e1051a39Sopenharmony_ci        break;
415e1051a39Sopenharmony_ci    case BIO_C_SET_FD:
416e1051a39Sopenharmony_ci        dgram_clear(b);
417e1051a39Sopenharmony_ci        b->num = *((int *)ptr);
418e1051a39Sopenharmony_ci        b->shutdown = (int)num;
419e1051a39Sopenharmony_ci        b->init = 1;
420e1051a39Sopenharmony_ci        break;
421e1051a39Sopenharmony_ci    case BIO_C_GET_FD:
422e1051a39Sopenharmony_ci        if (b->init) {
423e1051a39Sopenharmony_ci            ip = (int *)ptr;
424e1051a39Sopenharmony_ci            if (ip != NULL)
425e1051a39Sopenharmony_ci                *ip = b->num;
426e1051a39Sopenharmony_ci            ret = b->num;
427e1051a39Sopenharmony_ci        } else
428e1051a39Sopenharmony_ci            ret = -1;
429e1051a39Sopenharmony_ci        break;
430e1051a39Sopenharmony_ci    case BIO_CTRL_GET_CLOSE:
431e1051a39Sopenharmony_ci        ret = b->shutdown;
432e1051a39Sopenharmony_ci        break;
433e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CLOSE:
434e1051a39Sopenharmony_ci        b->shutdown = (int)num;
435e1051a39Sopenharmony_ci        break;
436e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:
437e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:
438e1051a39Sopenharmony_ci        ret = 0;
439e1051a39Sopenharmony_ci        break;
440e1051a39Sopenharmony_ci    case BIO_CTRL_DUP:
441e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
442e1051a39Sopenharmony_ci        ret = 1;
443e1051a39Sopenharmony_ci        break;
444e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_CONNECT:
445e1051a39Sopenharmony_ci        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
446e1051a39Sopenharmony_ci        break;
447e1051a39Sopenharmony_ci        /* (Linux)kernel sets DF bit on outgoing IP packets */
448e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_MTU_DISCOVER:
449e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
450e1051a39Sopenharmony_ci        addr_len = (socklen_t) sizeof(addr);
451e1051a39Sopenharmony_ci        memset(&addr, 0, sizeof(addr));
452e1051a39Sopenharmony_ci        if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
453e1051a39Sopenharmony_ci            ret = 0;
454e1051a39Sopenharmony_ci            break;
455e1051a39Sopenharmony_ci        }
456e1051a39Sopenharmony_ci        switch (addr.sa.sa_family) {
457e1051a39Sopenharmony_ci        case AF_INET:
458e1051a39Sopenharmony_ci            sockopt_val = IP_PMTUDISC_DO;
459e1051a39Sopenharmony_ci            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
460e1051a39Sopenharmony_ci                                  &sockopt_val, sizeof(sockopt_val))) < 0)
461e1051a39Sopenharmony_ci                perror("setsockopt");
462e1051a39Sopenharmony_ci            break;
463e1051a39Sopenharmony_ci#  if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
464e1051a39Sopenharmony_ci        case AF_INET6:
465e1051a39Sopenharmony_ci            sockopt_val = IPV6_PMTUDISC_DO;
466e1051a39Sopenharmony_ci            if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
467e1051a39Sopenharmony_ci                                  &sockopt_val, sizeof(sockopt_val))) < 0)
468e1051a39Sopenharmony_ci                perror("setsockopt");
469e1051a39Sopenharmony_ci            break;
470e1051a39Sopenharmony_ci#  endif
471e1051a39Sopenharmony_ci        default:
472e1051a39Sopenharmony_ci            ret = -1;
473e1051a39Sopenharmony_ci            break;
474e1051a39Sopenharmony_ci        }
475e1051a39Sopenharmony_ci# else
476e1051a39Sopenharmony_ci        ret = -1;
477e1051a39Sopenharmony_ci# endif
478e1051a39Sopenharmony_ci        break;
479e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_QUERY_MTU:
480e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU)
481e1051a39Sopenharmony_ci        addr_len = (socklen_t) sizeof(addr);
482e1051a39Sopenharmony_ci        memset(&addr, 0, sizeof(addr));
483e1051a39Sopenharmony_ci        if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
484e1051a39Sopenharmony_ci            ret = 0;
485e1051a39Sopenharmony_ci            break;
486e1051a39Sopenharmony_ci        }
487e1051a39Sopenharmony_ci        sockopt_len = sizeof(sockopt_val);
488e1051a39Sopenharmony_ci        switch (addr.sa.sa_family) {
489e1051a39Sopenharmony_ci        case AF_INET:
490e1051a39Sopenharmony_ci            if ((ret =
491e1051a39Sopenharmony_ci                 getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
492e1051a39Sopenharmony_ci                            &sockopt_len)) < 0 || sockopt_val < 0) {
493e1051a39Sopenharmony_ci                ret = 0;
494e1051a39Sopenharmony_ci            } else {
495e1051a39Sopenharmony_ci                /*
496e1051a39Sopenharmony_ci                 * we assume that the transport protocol is UDP and no IP
497e1051a39Sopenharmony_ci                 * options are used.
498e1051a39Sopenharmony_ci                 */
499e1051a39Sopenharmony_ci                data->mtu = sockopt_val - 8 - 20;
500e1051a39Sopenharmony_ci                ret = data->mtu;
501e1051a39Sopenharmony_ci            }
502e1051a39Sopenharmony_ci            break;
503e1051a39Sopenharmony_ci#  if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
504e1051a39Sopenharmony_ci        case AF_INET6:
505e1051a39Sopenharmony_ci            if ((ret =
506e1051a39Sopenharmony_ci                 getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU,
507e1051a39Sopenharmony_ci                            (void *)&sockopt_val, &sockopt_len)) < 0
508e1051a39Sopenharmony_ci                || sockopt_val < 0) {
509e1051a39Sopenharmony_ci                ret = 0;
510e1051a39Sopenharmony_ci            } else {
511e1051a39Sopenharmony_ci                /*
512e1051a39Sopenharmony_ci                 * we assume that the transport protocol is UDP and no IPV6
513e1051a39Sopenharmony_ci                 * options are used.
514e1051a39Sopenharmony_ci                 */
515e1051a39Sopenharmony_ci                data->mtu = sockopt_val - 8 - 40;
516e1051a39Sopenharmony_ci                ret = data->mtu;
517e1051a39Sopenharmony_ci            }
518e1051a39Sopenharmony_ci            break;
519e1051a39Sopenharmony_ci#  endif
520e1051a39Sopenharmony_ci        default:
521e1051a39Sopenharmony_ci            ret = 0;
522e1051a39Sopenharmony_ci            break;
523e1051a39Sopenharmony_ci        }
524e1051a39Sopenharmony_ci# else
525e1051a39Sopenharmony_ci        ret = 0;
526e1051a39Sopenharmony_ci# endif
527e1051a39Sopenharmony_ci        break;
528e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
529e1051a39Sopenharmony_ci        ret = -dgram_get_mtu_overhead(data);
530e1051a39Sopenharmony_ci        switch (BIO_ADDR_family(&data->peer)) {
531e1051a39Sopenharmony_ci        case AF_INET:
532e1051a39Sopenharmony_ci            ret += 576;
533e1051a39Sopenharmony_ci            break;
534e1051a39Sopenharmony_ci# if OPENSSL_USE_IPV6
535e1051a39Sopenharmony_ci        case AF_INET6:
536e1051a39Sopenharmony_ci            {
537e1051a39Sopenharmony_ci#  ifdef IN6_IS_ADDR_V4MAPPED
538e1051a39Sopenharmony_ci                struct in6_addr tmp_addr;
539e1051a39Sopenharmony_ci                if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
540e1051a39Sopenharmony_ci                    && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
541e1051a39Sopenharmony_ci                    ret += 576;
542e1051a39Sopenharmony_ci                else
543e1051a39Sopenharmony_ci#  endif
544e1051a39Sopenharmony_ci                    ret += 1280;
545e1051a39Sopenharmony_ci            }
546e1051a39Sopenharmony_ci            break;
547e1051a39Sopenharmony_ci# endif
548e1051a39Sopenharmony_ci        default:
549e1051a39Sopenharmony_ci            ret += 576;
550e1051a39Sopenharmony_ci            break;
551e1051a39Sopenharmony_ci        }
552e1051a39Sopenharmony_ci        break;
553e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_MTU:
554e1051a39Sopenharmony_ci        return data->mtu;
555e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_MTU:
556e1051a39Sopenharmony_ci        data->mtu = num;
557e1051a39Sopenharmony_ci        ret = num;
558e1051a39Sopenharmony_ci        break;
559e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_CONNECTED:
560e1051a39Sopenharmony_ci        if (ptr != NULL) {
561e1051a39Sopenharmony_ci            data->connected = 1;
562e1051a39Sopenharmony_ci            BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
563e1051a39Sopenharmony_ci        } else {
564e1051a39Sopenharmony_ci            data->connected = 0;
565e1051a39Sopenharmony_ci            memset(&data->peer, 0, sizeof(data->peer));
566e1051a39Sopenharmony_ci        }
567e1051a39Sopenharmony_ci        break;
568e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_PEER:
569e1051a39Sopenharmony_ci        ret = BIO_ADDR_sockaddr_size(&data->peer);
570e1051a39Sopenharmony_ci        /* FIXME: if num < ret, we will only return part of an address.
571e1051a39Sopenharmony_ci           That should bee an error, no? */
572e1051a39Sopenharmony_ci        if (num == 0 || num > ret)
573e1051a39Sopenharmony_ci            num = ret;
574e1051a39Sopenharmony_ci        memcpy(ptr, &data->peer, (ret = num));
575e1051a39Sopenharmony_ci        break;
576e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_PEER:
577e1051a39Sopenharmony_ci        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
578e1051a39Sopenharmony_ci        break;
579e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
580e1051a39Sopenharmony_ci        memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
581e1051a39Sopenharmony_ci        break;
582e1051a39Sopenharmony_ci# if defined(SO_RCVTIMEO)
583e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
584e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
585e1051a39Sopenharmony_ci        {
586e1051a39Sopenharmony_ci            struct timeval *tv = (struct timeval *)ptr;
587e1051a39Sopenharmony_ci            int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
588e1051a39Sopenharmony_ci            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
589e1051a39Sopenharmony_ci                           (void *)&timeout, sizeof(timeout)) < 0) {
590e1051a39Sopenharmony_ci                perror("setsockopt");
591e1051a39Sopenharmony_ci                ret = -1;
592e1051a39Sopenharmony_ci            }
593e1051a39Sopenharmony_ci        }
594e1051a39Sopenharmony_ci#  else
595e1051a39Sopenharmony_ci        if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
596e1051a39Sopenharmony_ci                       sizeof(struct timeval)) < 0) {
597e1051a39Sopenharmony_ci            perror("setsockopt");
598e1051a39Sopenharmony_ci            ret = -1;
599e1051a39Sopenharmony_ci        }
600e1051a39Sopenharmony_ci#  endif
601e1051a39Sopenharmony_ci        break;
602e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
603e1051a39Sopenharmony_ci        {
604e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
605e1051a39Sopenharmony_ci            int sz = 0;
606e1051a39Sopenharmony_ci            int timeout;
607e1051a39Sopenharmony_ci            struct timeval *tv = (struct timeval *)ptr;
608e1051a39Sopenharmony_ci
609e1051a39Sopenharmony_ci            sz = sizeof(timeout);
610e1051a39Sopenharmony_ci            if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
611e1051a39Sopenharmony_ci                           (void *)&timeout, &sz) < 0) {
612e1051a39Sopenharmony_ci                perror("getsockopt");
613e1051a39Sopenharmony_ci                ret = -1;
614e1051a39Sopenharmony_ci            } else {
615e1051a39Sopenharmony_ci                tv->tv_sec = timeout / 1000;
616e1051a39Sopenharmony_ci                tv->tv_usec = (timeout % 1000) * 1000;
617e1051a39Sopenharmony_ci                ret = sizeof(*tv);
618e1051a39Sopenharmony_ci            }
619e1051a39Sopenharmony_ci#  else
620e1051a39Sopenharmony_ci            socklen_t sz = sizeof(struct timeval);
621e1051a39Sopenharmony_ci            if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
622e1051a39Sopenharmony_ci                           ptr, &sz) < 0) {
623e1051a39Sopenharmony_ci                perror("getsockopt");
624e1051a39Sopenharmony_ci                ret = -1;
625e1051a39Sopenharmony_ci            } else {
626e1051a39Sopenharmony_ci                OPENSSL_assert(sz <= sizeof(struct timeval));
627e1051a39Sopenharmony_ci                ret = (int)sz;
628e1051a39Sopenharmony_ci            }
629e1051a39Sopenharmony_ci#  endif
630e1051a39Sopenharmony_ci        }
631e1051a39Sopenharmony_ci        break;
632e1051a39Sopenharmony_ci# endif
633e1051a39Sopenharmony_ci# if defined(SO_SNDTIMEO)
634e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
635e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
636e1051a39Sopenharmony_ci        {
637e1051a39Sopenharmony_ci            struct timeval *tv = (struct timeval *)ptr;
638e1051a39Sopenharmony_ci            int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
639e1051a39Sopenharmony_ci            if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
640e1051a39Sopenharmony_ci                           (void *)&timeout, sizeof(timeout)) < 0) {
641e1051a39Sopenharmony_ci                perror("setsockopt");
642e1051a39Sopenharmony_ci                ret = -1;
643e1051a39Sopenharmony_ci            }
644e1051a39Sopenharmony_ci        }
645e1051a39Sopenharmony_ci#  else
646e1051a39Sopenharmony_ci        if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
647e1051a39Sopenharmony_ci                       sizeof(struct timeval)) < 0) {
648e1051a39Sopenharmony_ci            perror("setsockopt");
649e1051a39Sopenharmony_ci            ret = -1;
650e1051a39Sopenharmony_ci        }
651e1051a39Sopenharmony_ci#  endif
652e1051a39Sopenharmony_ci        break;
653e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
654e1051a39Sopenharmony_ci        {
655e1051a39Sopenharmony_ci#  ifdef OPENSSL_SYS_WINDOWS
656e1051a39Sopenharmony_ci            int sz = 0;
657e1051a39Sopenharmony_ci            int timeout;
658e1051a39Sopenharmony_ci            struct timeval *tv = (struct timeval *)ptr;
659e1051a39Sopenharmony_ci
660e1051a39Sopenharmony_ci            sz = sizeof(timeout);
661e1051a39Sopenharmony_ci            if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
662e1051a39Sopenharmony_ci                           (void *)&timeout, &sz) < 0) {
663e1051a39Sopenharmony_ci                perror("getsockopt");
664e1051a39Sopenharmony_ci                ret = -1;
665e1051a39Sopenharmony_ci            } else {
666e1051a39Sopenharmony_ci                tv->tv_sec = timeout / 1000;
667e1051a39Sopenharmony_ci                tv->tv_usec = (timeout % 1000) * 1000;
668e1051a39Sopenharmony_ci                ret = sizeof(*tv);
669e1051a39Sopenharmony_ci            }
670e1051a39Sopenharmony_ci#  else
671e1051a39Sopenharmony_ci            socklen_t sz = sizeof(struct timeval);
672e1051a39Sopenharmony_ci            if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
673e1051a39Sopenharmony_ci                           ptr, &sz) < 0) {
674e1051a39Sopenharmony_ci                perror("getsockopt");
675e1051a39Sopenharmony_ci                ret = -1;
676e1051a39Sopenharmony_ci            } else {
677e1051a39Sopenharmony_ci                OPENSSL_assert(sz <= sizeof(struct timeval));
678e1051a39Sopenharmony_ci                ret = (int)sz;
679e1051a39Sopenharmony_ci            }
680e1051a39Sopenharmony_ci#  endif
681e1051a39Sopenharmony_ci        }
682e1051a39Sopenharmony_ci        break;
683e1051a39Sopenharmony_ci# endif
684e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
685e1051a39Sopenharmony_ci        /* fall-through */
686e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
687e1051a39Sopenharmony_ci# ifdef OPENSSL_SYS_WINDOWS
688e1051a39Sopenharmony_ci        d_errno = (data->_errno == WSAETIMEDOUT);
689e1051a39Sopenharmony_ci# else
690e1051a39Sopenharmony_ci        d_errno = (data->_errno == EAGAIN);
691e1051a39Sopenharmony_ci# endif
692e1051a39Sopenharmony_ci        if (d_errno) {
693e1051a39Sopenharmony_ci            ret = 1;
694e1051a39Sopenharmony_ci            data->_errno = 0;
695e1051a39Sopenharmony_ci        } else
696e1051a39Sopenharmony_ci            ret = 0;
697e1051a39Sopenharmony_ci        break;
698e1051a39Sopenharmony_ci# ifdef EMSGSIZE
699e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_MTU_EXCEEDED:
700e1051a39Sopenharmony_ci        if (data->_errno == EMSGSIZE) {
701e1051a39Sopenharmony_ci            ret = 1;
702e1051a39Sopenharmony_ci            data->_errno = 0;
703e1051a39Sopenharmony_ci        } else
704e1051a39Sopenharmony_ci            ret = 0;
705e1051a39Sopenharmony_ci        break;
706e1051a39Sopenharmony_ci# endif
707e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_DONT_FRAG:
708e1051a39Sopenharmony_ci        sockopt_val = num ? 1 : 0;
709e1051a39Sopenharmony_ci
710e1051a39Sopenharmony_ci        switch (data->peer.sa.sa_family) {
711e1051a39Sopenharmony_ci        case AF_INET:
712e1051a39Sopenharmony_ci# if defined(IP_DONTFRAG)
713e1051a39Sopenharmony_ci            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAG,
714e1051a39Sopenharmony_ci                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
715e1051a39Sopenharmony_ci                perror("setsockopt");
716e1051a39Sopenharmony_ci                ret = -1;
717e1051a39Sopenharmony_ci            }
718e1051a39Sopenharmony_ci# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE)
719e1051a39Sopenharmony_ci            if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT),
720e1051a39Sopenharmony_ci                (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
721e1051a39Sopenharmony_ci                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
722e1051a39Sopenharmony_ci                perror("setsockopt");
723e1051a39Sopenharmony_ci                ret = -1;
724e1051a39Sopenharmony_ci            }
725e1051a39Sopenharmony_ci# elif defined(OPENSSL_SYS_WINDOWS) && defined(IP_DONTFRAGMENT)
726e1051a39Sopenharmony_ci            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAGMENT,
727e1051a39Sopenharmony_ci                                  (const char *)&sockopt_val,
728e1051a39Sopenharmony_ci                                  sizeof(sockopt_val))) < 0) {
729e1051a39Sopenharmony_ci                perror("setsockopt");
730e1051a39Sopenharmony_ci                ret = -1;
731e1051a39Sopenharmony_ci            }
732e1051a39Sopenharmony_ci# else
733e1051a39Sopenharmony_ci            ret = -1;
734e1051a39Sopenharmony_ci# endif
735e1051a39Sopenharmony_ci            break;
736e1051a39Sopenharmony_ci# if OPENSSL_USE_IPV6
737e1051a39Sopenharmony_ci        case AF_INET6:
738e1051a39Sopenharmony_ci#  if defined(IPV6_DONTFRAG)
739e1051a39Sopenharmony_ci            if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_DONTFRAG,
740e1051a39Sopenharmony_ci                                  (const void *)&sockopt_val,
741e1051a39Sopenharmony_ci                                  sizeof(sockopt_val))) < 0) {
742e1051a39Sopenharmony_ci                perror("setsockopt");
743e1051a39Sopenharmony_ci                ret = -1;
744e1051a39Sopenharmony_ci            }
745e1051a39Sopenharmony_ci#  elif defined(OPENSSL_SYS_LINUX) && defined(IPV6_MTUDISCOVER)
746e1051a39Sopenharmony_ci            if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT),
747e1051a39Sopenharmony_ci                (ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
748e1051a39Sopenharmony_ci                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
749e1051a39Sopenharmony_ci                perror("setsockopt");
750e1051a39Sopenharmony_ci                ret = -1;
751e1051a39Sopenharmony_ci            }
752e1051a39Sopenharmony_ci#  else
753e1051a39Sopenharmony_ci            ret = -1;
754e1051a39Sopenharmony_ci#  endif
755e1051a39Sopenharmony_ci            break;
756e1051a39Sopenharmony_ci# endif
757e1051a39Sopenharmony_ci        default:
758e1051a39Sopenharmony_ci            ret = -1;
759e1051a39Sopenharmony_ci            break;
760e1051a39Sopenharmony_ci        }
761e1051a39Sopenharmony_ci        break;
762e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
763e1051a39Sopenharmony_ci        ret = dgram_get_mtu_overhead(data);
764e1051a39Sopenharmony_ci        break;
765e1051a39Sopenharmony_ci
766e1051a39Sopenharmony_ci    /*
767e1051a39Sopenharmony_ci     * BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE is used here for compatibility
768e1051a39Sopenharmony_ci     * reasons. When BIO_CTRL_DGRAM_SET_PEEK_MODE was first defined its value
769e1051a39Sopenharmony_ci     * was incorrectly clashing with BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE. The
770e1051a39Sopenharmony_ci     * value has been updated to a non-clashing value. However to preserve
771e1051a39Sopenharmony_ci     * binary compatibility we now respond to both the old value and the new one
772e1051a39Sopenharmony_ci     */
773e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
774e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_PEEK_MODE:
775e1051a39Sopenharmony_ci        data->peekmode = (unsigned int)num;
776e1051a39Sopenharmony_ci        break;
777e1051a39Sopenharmony_ci    default:
778e1051a39Sopenharmony_ci        ret = 0;
779e1051a39Sopenharmony_ci        break;
780e1051a39Sopenharmony_ci    }
781e1051a39Sopenharmony_ci    return ret;
782e1051a39Sopenharmony_ci}
783e1051a39Sopenharmony_ci
784e1051a39Sopenharmony_cistatic int dgram_puts(BIO *bp, const char *str)
785e1051a39Sopenharmony_ci{
786e1051a39Sopenharmony_ci    int n, ret;
787e1051a39Sopenharmony_ci
788e1051a39Sopenharmony_ci    n = strlen(str);
789e1051a39Sopenharmony_ci    ret = dgram_write(bp, str, n);
790e1051a39Sopenharmony_ci    return ret;
791e1051a39Sopenharmony_ci}
792e1051a39Sopenharmony_ci
793e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_SCTP
794e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_datagram_sctp(void)
795e1051a39Sopenharmony_ci{
796e1051a39Sopenharmony_ci    return &methods_dgramp_sctp;
797e1051a39Sopenharmony_ci}
798e1051a39Sopenharmony_ci
799e1051a39Sopenharmony_ciBIO *BIO_new_dgram_sctp(int fd, int close_flag)
800e1051a39Sopenharmony_ci{
801e1051a39Sopenharmony_ci    BIO *bio;
802e1051a39Sopenharmony_ci    int ret, optval = 20000;
803e1051a39Sopenharmony_ci    int auth_data = 0, auth_forward = 0;
804e1051a39Sopenharmony_ci    unsigned char *p;
805e1051a39Sopenharmony_ci    struct sctp_authchunk auth;
806e1051a39Sopenharmony_ci    struct sctp_authchunks *authchunks;
807e1051a39Sopenharmony_ci    socklen_t sockopt_len;
808e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
809e1051a39Sopenharmony_ci#   ifdef SCTP_EVENT
810e1051a39Sopenharmony_ci    struct sctp_event event;
811e1051a39Sopenharmony_ci#   else
812e1051a39Sopenharmony_ci    struct sctp_event_subscribe event;
813e1051a39Sopenharmony_ci#   endif
814e1051a39Sopenharmony_ci#  endif
815e1051a39Sopenharmony_ci
816e1051a39Sopenharmony_ci    bio = BIO_new(BIO_s_datagram_sctp());
817e1051a39Sopenharmony_ci    if (bio == NULL)
818e1051a39Sopenharmony_ci        return NULL;
819e1051a39Sopenharmony_ci    BIO_set_fd(bio, fd, close_flag);
820e1051a39Sopenharmony_ci
821e1051a39Sopenharmony_ci    /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */
822e1051a39Sopenharmony_ci    auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE;
823e1051a39Sopenharmony_ci    ret =
824e1051a39Sopenharmony_ci        setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth,
825e1051a39Sopenharmony_ci                   sizeof(struct sctp_authchunk));
826e1051a39Sopenharmony_ci    if (ret < 0) {
827e1051a39Sopenharmony_ci        BIO_vfree(bio);
828e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_BIO, ERR_R_SYS_LIB,
829e1051a39Sopenharmony_ci                       "Ensure SCTP AUTH chunks are enabled in kernel");
830e1051a39Sopenharmony_ci        return NULL;
831e1051a39Sopenharmony_ci    }
832e1051a39Sopenharmony_ci    auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
833e1051a39Sopenharmony_ci    ret =
834e1051a39Sopenharmony_ci        setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth,
835e1051a39Sopenharmony_ci                   sizeof(struct sctp_authchunk));
836e1051a39Sopenharmony_ci    if (ret < 0) {
837e1051a39Sopenharmony_ci        BIO_vfree(bio);
838e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_BIO, ERR_R_SYS_LIB,
839e1051a39Sopenharmony_ci                       "Ensure SCTP AUTH chunks are enabled in kernel");
840e1051a39Sopenharmony_ci        return NULL;
841e1051a39Sopenharmony_ci    }
842e1051a39Sopenharmony_ci
843e1051a39Sopenharmony_ci    /*
844e1051a39Sopenharmony_ci     * Test if activation was successful. When using accept(), SCTP-AUTH has
845e1051a39Sopenharmony_ci     * to be activated for the listening socket already, otherwise the
846e1051a39Sopenharmony_ci     * connected socket won't use it. Similarly with connect(): the socket
847e1051a39Sopenharmony_ci     * prior to connection must be activated for SCTP-AUTH
848e1051a39Sopenharmony_ci     */
849e1051a39Sopenharmony_ci    sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
850e1051a39Sopenharmony_ci    authchunks = OPENSSL_zalloc(sockopt_len);
851e1051a39Sopenharmony_ci    if (authchunks == NULL) {
852e1051a39Sopenharmony_ci        BIO_vfree(bio);
853e1051a39Sopenharmony_ci        return NULL;
854e1051a39Sopenharmony_ci    }
855e1051a39Sopenharmony_ci    ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks,
856e1051a39Sopenharmony_ci                   &sockopt_len);
857e1051a39Sopenharmony_ci    if (ret < 0) {
858e1051a39Sopenharmony_ci        OPENSSL_free(authchunks);
859e1051a39Sopenharmony_ci        BIO_vfree(bio);
860e1051a39Sopenharmony_ci        return NULL;
861e1051a39Sopenharmony_ci    }
862e1051a39Sopenharmony_ci
863e1051a39Sopenharmony_ci    for (p = (unsigned char *)authchunks->gauth_chunks;
864e1051a39Sopenharmony_ci         p < (unsigned char *)authchunks + sockopt_len;
865e1051a39Sopenharmony_ci         p += sizeof(uint8_t)) {
866e1051a39Sopenharmony_ci        if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE)
867e1051a39Sopenharmony_ci            auth_data = 1;
868e1051a39Sopenharmony_ci        if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE)
869e1051a39Sopenharmony_ci            auth_forward = 1;
870e1051a39Sopenharmony_ci    }
871e1051a39Sopenharmony_ci
872e1051a39Sopenharmony_ci    OPENSSL_free(authchunks);
873e1051a39Sopenharmony_ci
874e1051a39Sopenharmony_ci    if (!auth_data || !auth_forward) {
875e1051a39Sopenharmony_ci        BIO_vfree(bio);
876e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_BIO, ERR_R_SYS_LIB,
877e1051a39Sopenharmony_ci                       "Ensure SCTP AUTH chunks are enabled on the "
878e1051a39Sopenharmony_ci                       "underlying socket");
879e1051a39Sopenharmony_ci        return NULL;
880e1051a39Sopenharmony_ci    }
881e1051a39Sopenharmony_ci
882e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
883e1051a39Sopenharmony_ci#   ifdef SCTP_EVENT
884e1051a39Sopenharmony_ci    memset(&event, 0, sizeof(event));
885e1051a39Sopenharmony_ci    event.se_assoc_id = 0;
886e1051a39Sopenharmony_ci    event.se_type = SCTP_AUTHENTICATION_EVENT;
887e1051a39Sopenharmony_ci    event.se_on = 1;
888e1051a39Sopenharmony_ci    ret =
889e1051a39Sopenharmony_ci        setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event,
890e1051a39Sopenharmony_ci                   sizeof(struct sctp_event));
891e1051a39Sopenharmony_ci    if (ret < 0) {
892e1051a39Sopenharmony_ci        BIO_vfree(bio);
893e1051a39Sopenharmony_ci        return NULL;
894e1051a39Sopenharmony_ci    }
895e1051a39Sopenharmony_ci#   else
896e1051a39Sopenharmony_ci    sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe);
897e1051a39Sopenharmony_ci    ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len);
898e1051a39Sopenharmony_ci    if (ret < 0) {
899e1051a39Sopenharmony_ci        BIO_vfree(bio);
900e1051a39Sopenharmony_ci        return NULL;
901e1051a39Sopenharmony_ci    }
902e1051a39Sopenharmony_ci
903e1051a39Sopenharmony_ci    event.sctp_authentication_event = 1;
904e1051a39Sopenharmony_ci
905e1051a39Sopenharmony_ci    ret =
906e1051a39Sopenharmony_ci        setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event,
907e1051a39Sopenharmony_ci                   sizeof(struct sctp_event_subscribe));
908e1051a39Sopenharmony_ci    if (ret < 0) {
909e1051a39Sopenharmony_ci        BIO_vfree(bio);
910e1051a39Sopenharmony_ci        return NULL;
911e1051a39Sopenharmony_ci    }
912e1051a39Sopenharmony_ci#   endif
913e1051a39Sopenharmony_ci#  endif
914e1051a39Sopenharmony_ci
915e1051a39Sopenharmony_ci    /*
916e1051a39Sopenharmony_ci     * Disable partial delivery by setting the min size larger than the max
917e1051a39Sopenharmony_ci     * record size of 2^14 + 2048 + 13
918e1051a39Sopenharmony_ci     */
919e1051a39Sopenharmony_ci    ret =
920e1051a39Sopenharmony_ci        setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval,
921e1051a39Sopenharmony_ci                   sizeof(optval));
922e1051a39Sopenharmony_ci    if (ret < 0) {
923e1051a39Sopenharmony_ci        BIO_vfree(bio);
924e1051a39Sopenharmony_ci        return NULL;
925e1051a39Sopenharmony_ci    }
926e1051a39Sopenharmony_ci
927e1051a39Sopenharmony_ci    return bio;
928e1051a39Sopenharmony_ci}
929e1051a39Sopenharmony_ci
930e1051a39Sopenharmony_ciint BIO_dgram_is_sctp(BIO *bio)
931e1051a39Sopenharmony_ci{
932e1051a39Sopenharmony_ci    return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP);
933e1051a39Sopenharmony_ci}
934e1051a39Sopenharmony_ci
935e1051a39Sopenharmony_cistatic int dgram_sctp_new(BIO *bi)
936e1051a39Sopenharmony_ci{
937e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = NULL;
938e1051a39Sopenharmony_ci
939e1051a39Sopenharmony_ci    bi->init = 0;
940e1051a39Sopenharmony_ci    bi->num = 0;
941e1051a39Sopenharmony_ci    if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) {
942e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
943e1051a39Sopenharmony_ci        return 0;
944e1051a39Sopenharmony_ci    }
945e1051a39Sopenharmony_ci#  ifdef SCTP_PR_SCTP_NONE
946e1051a39Sopenharmony_ci    data->prinfo.pr_policy = SCTP_PR_SCTP_NONE;
947e1051a39Sopenharmony_ci#  endif
948e1051a39Sopenharmony_ci    bi->ptr = data;
949e1051a39Sopenharmony_ci
950e1051a39Sopenharmony_ci    bi->flags = 0;
951e1051a39Sopenharmony_ci    return 1;
952e1051a39Sopenharmony_ci}
953e1051a39Sopenharmony_ci
954e1051a39Sopenharmony_cistatic int dgram_sctp_free(BIO *a)
955e1051a39Sopenharmony_ci{
956e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data;
957e1051a39Sopenharmony_ci
958e1051a39Sopenharmony_ci    if (a == NULL)
959e1051a39Sopenharmony_ci        return 0;
960e1051a39Sopenharmony_ci    if (!dgram_clear(a))
961e1051a39Sopenharmony_ci        return 0;
962e1051a39Sopenharmony_ci
963e1051a39Sopenharmony_ci    data = (bio_dgram_sctp_data *) a->ptr;
964e1051a39Sopenharmony_ci    if (data != NULL)
965e1051a39Sopenharmony_ci        OPENSSL_free(data);
966e1051a39Sopenharmony_ci
967e1051a39Sopenharmony_ci    return 1;
968e1051a39Sopenharmony_ci}
969e1051a39Sopenharmony_ci
970e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
971e1051a39Sopenharmony_civoid dgram_sctp_handle_auth_free_key_event(BIO *b,
972e1051a39Sopenharmony_ci                                           union sctp_notification *snp)
973e1051a39Sopenharmony_ci{
974e1051a39Sopenharmony_ci    int ret;
975e1051a39Sopenharmony_ci    struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event;
976e1051a39Sopenharmony_ci
977e1051a39Sopenharmony_ci    if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) {
978e1051a39Sopenharmony_ci        struct sctp_authkeyid authkeyid;
979e1051a39Sopenharmony_ci
980e1051a39Sopenharmony_ci        /* delete key */
981e1051a39Sopenharmony_ci        authkeyid.scact_keynumber = authkeyevent->auth_keynumber;
982e1051a39Sopenharmony_ci        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
983e1051a39Sopenharmony_ci                         &authkeyid, sizeof(struct sctp_authkeyid));
984e1051a39Sopenharmony_ci    }
985e1051a39Sopenharmony_ci}
986e1051a39Sopenharmony_ci#  endif
987e1051a39Sopenharmony_ci
988e1051a39Sopenharmony_cistatic int dgram_sctp_read(BIO *b, char *out, int outl)
989e1051a39Sopenharmony_ci{
990e1051a39Sopenharmony_ci    int ret = 0, n = 0, i, optval;
991e1051a39Sopenharmony_ci    socklen_t optlen;
992e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
993e1051a39Sopenharmony_ci    struct msghdr msg;
994e1051a39Sopenharmony_ci    struct iovec iov;
995e1051a39Sopenharmony_ci    struct cmsghdr *cmsg;
996e1051a39Sopenharmony_ci    char cmsgbuf[512];
997e1051a39Sopenharmony_ci
998e1051a39Sopenharmony_ci    if (out != NULL) {
999e1051a39Sopenharmony_ci        clear_socket_error();
1000e1051a39Sopenharmony_ci
1001e1051a39Sopenharmony_ci        do {
1002e1051a39Sopenharmony_ci            memset(&data->rcvinfo, 0, sizeof(data->rcvinfo));
1003e1051a39Sopenharmony_ci            iov.iov_base = out;
1004e1051a39Sopenharmony_ci            iov.iov_len = outl;
1005e1051a39Sopenharmony_ci            msg.msg_name = NULL;
1006e1051a39Sopenharmony_ci            msg.msg_namelen = 0;
1007e1051a39Sopenharmony_ci            msg.msg_iov = &iov;
1008e1051a39Sopenharmony_ci            msg.msg_iovlen = 1;
1009e1051a39Sopenharmony_ci            msg.msg_control = cmsgbuf;
1010e1051a39Sopenharmony_ci            msg.msg_controllen = 512;
1011e1051a39Sopenharmony_ci            msg.msg_flags = 0;
1012e1051a39Sopenharmony_ci            n = recvmsg(b->num, &msg, 0);
1013e1051a39Sopenharmony_ci
1014e1051a39Sopenharmony_ci            if (n <= 0) {
1015e1051a39Sopenharmony_ci                if (n < 0)
1016e1051a39Sopenharmony_ci                    ret = n;
1017e1051a39Sopenharmony_ci                break;
1018e1051a39Sopenharmony_ci            }
1019e1051a39Sopenharmony_ci
1020e1051a39Sopenharmony_ci            if (msg.msg_controllen > 0) {
1021e1051a39Sopenharmony_ci                for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
1022e1051a39Sopenharmony_ci                     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1023e1051a39Sopenharmony_ci                    if (cmsg->cmsg_level != IPPROTO_SCTP)
1024e1051a39Sopenharmony_ci                        continue;
1025e1051a39Sopenharmony_ci#  ifdef SCTP_RCVINFO
1026e1051a39Sopenharmony_ci                    if (cmsg->cmsg_type == SCTP_RCVINFO) {
1027e1051a39Sopenharmony_ci                        struct sctp_rcvinfo *rcvinfo;
1028e1051a39Sopenharmony_ci
1029e1051a39Sopenharmony_ci                        rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
1030e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_sid = rcvinfo->rcv_sid;
1031e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn;
1032e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_flags = rcvinfo->rcv_flags;
1033e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid;
1034e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn;
1035e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn;
1036e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_context = rcvinfo->rcv_context;
1037e1051a39Sopenharmony_ci                    }
1038e1051a39Sopenharmony_ci#  endif
1039e1051a39Sopenharmony_ci#  ifdef SCTP_SNDRCV
1040e1051a39Sopenharmony_ci                    if (cmsg->cmsg_type == SCTP_SNDRCV) {
1041e1051a39Sopenharmony_ci                        struct sctp_sndrcvinfo *sndrcvinfo;
1042e1051a39Sopenharmony_ci
1043e1051a39Sopenharmony_ci                        sndrcvinfo =
1044e1051a39Sopenharmony_ci                            (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
1045e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream;
1046e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn;
1047e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags;
1048e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid;
1049e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn;
1050e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn;
1051e1051a39Sopenharmony_ci                        data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context;
1052e1051a39Sopenharmony_ci                    }
1053e1051a39Sopenharmony_ci#  endif
1054e1051a39Sopenharmony_ci                }
1055e1051a39Sopenharmony_ci            }
1056e1051a39Sopenharmony_ci
1057e1051a39Sopenharmony_ci            if (msg.msg_flags & MSG_NOTIFICATION) {
1058e1051a39Sopenharmony_ci                union sctp_notification snp;
1059e1051a39Sopenharmony_ci
1060e1051a39Sopenharmony_ci                memcpy(&snp, out, sizeof(snp));
1061e1051a39Sopenharmony_ci                if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) {
1062e1051a39Sopenharmony_ci#  ifdef SCTP_EVENT
1063e1051a39Sopenharmony_ci                    struct sctp_event event;
1064e1051a39Sopenharmony_ci#  else
1065e1051a39Sopenharmony_ci                    struct sctp_event_subscribe event;
1066e1051a39Sopenharmony_ci                    socklen_t eventsize;
1067e1051a39Sopenharmony_ci#  endif
1068e1051a39Sopenharmony_ci
1069e1051a39Sopenharmony_ci                    /* disable sender dry event */
1070e1051a39Sopenharmony_ci#  ifdef SCTP_EVENT
1071e1051a39Sopenharmony_ci                    memset(&event, 0, sizeof(event));
1072e1051a39Sopenharmony_ci                    event.se_assoc_id = 0;
1073e1051a39Sopenharmony_ci                    event.se_type = SCTP_SENDER_DRY_EVENT;
1074e1051a39Sopenharmony_ci                    event.se_on = 0;
1075e1051a39Sopenharmony_ci                    i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
1076e1051a39Sopenharmony_ci                                   sizeof(struct sctp_event));
1077e1051a39Sopenharmony_ci                    if (i < 0) {
1078e1051a39Sopenharmony_ci                        ret = i;
1079e1051a39Sopenharmony_ci                        break;
1080e1051a39Sopenharmony_ci                    }
1081e1051a39Sopenharmony_ci#  else
1082e1051a39Sopenharmony_ci                    eventsize = sizeof(struct sctp_event_subscribe);
1083e1051a39Sopenharmony_ci                    i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
1084e1051a39Sopenharmony_ci                                   &eventsize);
1085e1051a39Sopenharmony_ci                    if (i < 0) {
1086e1051a39Sopenharmony_ci                        ret = i;
1087e1051a39Sopenharmony_ci                        break;
1088e1051a39Sopenharmony_ci                    }
1089e1051a39Sopenharmony_ci
1090e1051a39Sopenharmony_ci                    event.sctp_sender_dry_event = 0;
1091e1051a39Sopenharmony_ci
1092e1051a39Sopenharmony_ci                    i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
1093e1051a39Sopenharmony_ci                                   sizeof(struct sctp_event_subscribe));
1094e1051a39Sopenharmony_ci                    if (i < 0) {
1095e1051a39Sopenharmony_ci                        ret = i;
1096e1051a39Sopenharmony_ci                        break;
1097e1051a39Sopenharmony_ci                    }
1098e1051a39Sopenharmony_ci#  endif
1099e1051a39Sopenharmony_ci                }
1100e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
1101e1051a39Sopenharmony_ci                if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
1102e1051a39Sopenharmony_ci                    dgram_sctp_handle_auth_free_key_event(b, &snp);
1103e1051a39Sopenharmony_ci#  endif
1104e1051a39Sopenharmony_ci
1105e1051a39Sopenharmony_ci                if (data->handle_notifications != NULL)
1106e1051a39Sopenharmony_ci                    data->handle_notifications(b, data->notification_context,
1107e1051a39Sopenharmony_ci                                               (void *)out);
1108e1051a39Sopenharmony_ci
1109e1051a39Sopenharmony_ci                memset(&snp, 0, sizeof(snp));
1110e1051a39Sopenharmony_ci                memset(out, 0, outl);
1111e1051a39Sopenharmony_ci            } else {
1112e1051a39Sopenharmony_ci                ret += n;
1113e1051a39Sopenharmony_ci            }
1114e1051a39Sopenharmony_ci        }
1115e1051a39Sopenharmony_ci        while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR)
1116e1051a39Sopenharmony_ci               && (ret < outl));
1117e1051a39Sopenharmony_ci
1118e1051a39Sopenharmony_ci        if (ret > 0 && !(msg.msg_flags & MSG_EOR)) {
1119e1051a39Sopenharmony_ci            /* Partial message read, this should never happen! */
1120e1051a39Sopenharmony_ci
1121e1051a39Sopenharmony_ci            /*
1122e1051a39Sopenharmony_ci             * The buffer was too small, this means the peer sent a message
1123e1051a39Sopenharmony_ci             * that was larger than allowed.
1124e1051a39Sopenharmony_ci             */
1125e1051a39Sopenharmony_ci            if (ret == outl)
1126e1051a39Sopenharmony_ci                return -1;
1127e1051a39Sopenharmony_ci
1128e1051a39Sopenharmony_ci            /*
1129e1051a39Sopenharmony_ci             * Test if socket buffer can handle max record size (2^14 + 2048
1130e1051a39Sopenharmony_ci             * + 13)
1131e1051a39Sopenharmony_ci             */
1132e1051a39Sopenharmony_ci            optlen = (socklen_t) sizeof(int);
1133e1051a39Sopenharmony_ci            ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
1134e1051a39Sopenharmony_ci            if (ret >= 0)
1135e1051a39Sopenharmony_ci                OPENSSL_assert(optval >= 18445);
1136e1051a39Sopenharmony_ci
1137e1051a39Sopenharmony_ci            /*
1138e1051a39Sopenharmony_ci             * Test if SCTP doesn't partially deliver below max record size
1139e1051a39Sopenharmony_ci             * (2^14 + 2048 + 13)
1140e1051a39Sopenharmony_ci             */
1141e1051a39Sopenharmony_ci            optlen = (socklen_t) sizeof(int);
1142e1051a39Sopenharmony_ci            ret =
1143e1051a39Sopenharmony_ci                getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
1144e1051a39Sopenharmony_ci                           &optval, &optlen);
1145e1051a39Sopenharmony_ci            if (ret >= 0)
1146e1051a39Sopenharmony_ci                OPENSSL_assert(optval >= 18445);
1147e1051a39Sopenharmony_ci
1148e1051a39Sopenharmony_ci            /*
1149e1051a39Sopenharmony_ci             * Partially delivered notification??? Probably a bug....
1150e1051a39Sopenharmony_ci             */
1151e1051a39Sopenharmony_ci            OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION));
1152e1051a39Sopenharmony_ci
1153e1051a39Sopenharmony_ci            /*
1154e1051a39Sopenharmony_ci             * Everything seems ok till now, so it's most likely a message
1155e1051a39Sopenharmony_ci             * dropped by PR-SCTP.
1156e1051a39Sopenharmony_ci             */
1157e1051a39Sopenharmony_ci            memset(out, 0, outl);
1158e1051a39Sopenharmony_ci            BIO_set_retry_read(b);
1159e1051a39Sopenharmony_ci            return -1;
1160e1051a39Sopenharmony_ci        }
1161e1051a39Sopenharmony_ci
1162e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
1163e1051a39Sopenharmony_ci        if (ret < 0) {
1164e1051a39Sopenharmony_ci            if (BIO_dgram_should_retry(ret)) {
1165e1051a39Sopenharmony_ci                BIO_set_retry_read(b);
1166e1051a39Sopenharmony_ci                data->_errno = get_last_socket_error();
1167e1051a39Sopenharmony_ci            }
1168e1051a39Sopenharmony_ci        }
1169e1051a39Sopenharmony_ci
1170e1051a39Sopenharmony_ci        /* Test if peer uses SCTP-AUTH before continuing */
1171e1051a39Sopenharmony_ci        if (!data->peer_auth_tested) {
1172e1051a39Sopenharmony_ci            int ii, auth_data = 0, auth_forward = 0;
1173e1051a39Sopenharmony_ci            unsigned char *p;
1174e1051a39Sopenharmony_ci            struct sctp_authchunks *authchunks;
1175e1051a39Sopenharmony_ci
1176e1051a39Sopenharmony_ci            optlen =
1177e1051a39Sopenharmony_ci                (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
1178e1051a39Sopenharmony_ci            authchunks = OPENSSL_malloc(optlen);
1179e1051a39Sopenharmony_ci            if (authchunks == NULL) {
1180e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
1181e1051a39Sopenharmony_ci                return -1;
1182e1051a39Sopenharmony_ci            }
1183e1051a39Sopenharmony_ci            memset(authchunks, 0, optlen);
1184e1051a39Sopenharmony_ci            ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS,
1185e1051a39Sopenharmony_ci                            authchunks, &optlen);
1186e1051a39Sopenharmony_ci
1187e1051a39Sopenharmony_ci            if (ii >= 0)
1188e1051a39Sopenharmony_ci                for (p = (unsigned char *)authchunks->gauth_chunks;
1189e1051a39Sopenharmony_ci                     p < (unsigned char *)authchunks + optlen;
1190e1051a39Sopenharmony_ci                     p += sizeof(uint8_t)) {
1191e1051a39Sopenharmony_ci                    if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE)
1192e1051a39Sopenharmony_ci                        auth_data = 1;
1193e1051a39Sopenharmony_ci                    if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE)
1194e1051a39Sopenharmony_ci                        auth_forward = 1;
1195e1051a39Sopenharmony_ci                }
1196e1051a39Sopenharmony_ci
1197e1051a39Sopenharmony_ci            OPENSSL_free(authchunks);
1198e1051a39Sopenharmony_ci
1199e1051a39Sopenharmony_ci            if (!auth_data || !auth_forward) {
1200e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_CONNECT_ERROR);
1201e1051a39Sopenharmony_ci                return -1;
1202e1051a39Sopenharmony_ci            }
1203e1051a39Sopenharmony_ci
1204e1051a39Sopenharmony_ci            data->peer_auth_tested = 1;
1205e1051a39Sopenharmony_ci        }
1206e1051a39Sopenharmony_ci    }
1207e1051a39Sopenharmony_ci    return ret;
1208e1051a39Sopenharmony_ci}
1209e1051a39Sopenharmony_ci
1210e1051a39Sopenharmony_ci/*
1211e1051a39Sopenharmony_ci * dgram_sctp_write - send message on SCTP socket
1212e1051a39Sopenharmony_ci * @b: BIO to write to
1213e1051a39Sopenharmony_ci * @in: data to send
1214e1051a39Sopenharmony_ci * @inl: amount of bytes in @in to send
1215e1051a39Sopenharmony_ci *
1216e1051a39Sopenharmony_ci * Returns -1 on error or the sent amount of bytes on success
1217e1051a39Sopenharmony_ci */
1218e1051a39Sopenharmony_cistatic int dgram_sctp_write(BIO *b, const char *in, int inl)
1219e1051a39Sopenharmony_ci{
1220e1051a39Sopenharmony_ci    int ret;
1221e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
1222e1051a39Sopenharmony_ci    struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
1223e1051a39Sopenharmony_ci    struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
1224e1051a39Sopenharmony_ci    struct bio_dgram_sctp_sndinfo handshake_sinfo;
1225e1051a39Sopenharmony_ci    struct iovec iov[1];
1226e1051a39Sopenharmony_ci    struct msghdr msg;
1227e1051a39Sopenharmony_ci    struct cmsghdr *cmsg;
1228e1051a39Sopenharmony_ci#  if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
1229e1051a39Sopenharmony_ci    char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
1230e1051a39Sopenharmony_ci                 CMSG_SPACE(sizeof(struct sctp_prinfo))];
1231e1051a39Sopenharmony_ci    struct sctp_sndinfo *sndinfo;
1232e1051a39Sopenharmony_ci    struct sctp_prinfo *prinfo;
1233e1051a39Sopenharmony_ci#  else
1234e1051a39Sopenharmony_ci    char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
1235e1051a39Sopenharmony_ci    struct sctp_sndrcvinfo *sndrcvinfo;
1236e1051a39Sopenharmony_ci#  endif
1237e1051a39Sopenharmony_ci
1238e1051a39Sopenharmony_ci    clear_socket_error();
1239e1051a39Sopenharmony_ci
1240e1051a39Sopenharmony_ci    /*
1241e1051a39Sopenharmony_ci     * If we're send anything else than application data, disable all user
1242e1051a39Sopenharmony_ci     * parameters and flags.
1243e1051a39Sopenharmony_ci     */
1244e1051a39Sopenharmony_ci    if (in[0] != 23) {
1245e1051a39Sopenharmony_ci        memset(&handshake_sinfo, 0, sizeof(handshake_sinfo));
1246e1051a39Sopenharmony_ci#  ifdef SCTP_SACK_IMMEDIATELY
1247e1051a39Sopenharmony_ci        handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
1248e1051a39Sopenharmony_ci#  endif
1249e1051a39Sopenharmony_ci        sinfo = &handshake_sinfo;
1250e1051a39Sopenharmony_ci    }
1251e1051a39Sopenharmony_ci
1252e1051a39Sopenharmony_ci    /* We can only send a shutdown alert if the socket is dry */
1253e1051a39Sopenharmony_ci    if (data->save_shutdown) {
1254e1051a39Sopenharmony_ci        ret = BIO_dgram_sctp_wait_for_dry(b);
1255e1051a39Sopenharmony_ci        if (ret < 0)
1256e1051a39Sopenharmony_ci            return -1;
1257e1051a39Sopenharmony_ci        if (ret == 0) {
1258e1051a39Sopenharmony_ci            BIO_clear_retry_flags(b);
1259e1051a39Sopenharmony_ci            BIO_set_retry_write(b);
1260e1051a39Sopenharmony_ci            return -1;
1261e1051a39Sopenharmony_ci        }
1262e1051a39Sopenharmony_ci    }
1263e1051a39Sopenharmony_ci
1264e1051a39Sopenharmony_ci    iov[0].iov_base = (char *)in;
1265e1051a39Sopenharmony_ci    iov[0].iov_len = inl;
1266e1051a39Sopenharmony_ci    msg.msg_name = NULL;
1267e1051a39Sopenharmony_ci    msg.msg_namelen = 0;
1268e1051a39Sopenharmony_ci    msg.msg_iov = iov;
1269e1051a39Sopenharmony_ci    msg.msg_iovlen = 1;
1270e1051a39Sopenharmony_ci    msg.msg_control = (caddr_t) cmsgbuf;
1271e1051a39Sopenharmony_ci    msg.msg_controllen = 0;
1272e1051a39Sopenharmony_ci    msg.msg_flags = 0;
1273e1051a39Sopenharmony_ci#  if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
1274e1051a39Sopenharmony_ci    cmsg = (struct cmsghdr *)cmsgbuf;
1275e1051a39Sopenharmony_ci    cmsg->cmsg_level = IPPROTO_SCTP;
1276e1051a39Sopenharmony_ci    cmsg->cmsg_type = SCTP_SNDINFO;
1277e1051a39Sopenharmony_ci    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
1278e1051a39Sopenharmony_ci    sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
1279e1051a39Sopenharmony_ci    memset(sndinfo, 0, sizeof(*sndinfo));
1280e1051a39Sopenharmony_ci    sndinfo->snd_sid = sinfo->snd_sid;
1281e1051a39Sopenharmony_ci    sndinfo->snd_flags = sinfo->snd_flags;
1282e1051a39Sopenharmony_ci    sndinfo->snd_ppid = sinfo->snd_ppid;
1283e1051a39Sopenharmony_ci    sndinfo->snd_context = sinfo->snd_context;
1284e1051a39Sopenharmony_ci    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
1285e1051a39Sopenharmony_ci
1286e1051a39Sopenharmony_ci    cmsg =
1287e1051a39Sopenharmony_ci        (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
1288e1051a39Sopenharmony_ci    cmsg->cmsg_level = IPPROTO_SCTP;
1289e1051a39Sopenharmony_ci    cmsg->cmsg_type = SCTP_PRINFO;
1290e1051a39Sopenharmony_ci    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
1291e1051a39Sopenharmony_ci    prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
1292e1051a39Sopenharmony_ci    memset(prinfo, 0, sizeof(*prinfo));
1293e1051a39Sopenharmony_ci    prinfo->pr_policy = pinfo->pr_policy;
1294e1051a39Sopenharmony_ci    prinfo->pr_value = pinfo->pr_value;
1295e1051a39Sopenharmony_ci    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
1296e1051a39Sopenharmony_ci#  else
1297e1051a39Sopenharmony_ci    cmsg = (struct cmsghdr *)cmsgbuf;
1298e1051a39Sopenharmony_ci    cmsg->cmsg_level = IPPROTO_SCTP;
1299e1051a39Sopenharmony_ci    cmsg->cmsg_type = SCTP_SNDRCV;
1300e1051a39Sopenharmony_ci    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
1301e1051a39Sopenharmony_ci    sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
1302e1051a39Sopenharmony_ci    memset(sndrcvinfo, 0, sizeof(*sndrcvinfo));
1303e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_stream = sinfo->snd_sid;
1304e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_flags = sinfo->snd_flags;
1305e1051a39Sopenharmony_ci#   ifdef __FreeBSD__
1306e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
1307e1051a39Sopenharmony_ci#   endif
1308e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
1309e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_context = sinfo->snd_context;
1310e1051a39Sopenharmony_ci    sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
1311e1051a39Sopenharmony_ci    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
1312e1051a39Sopenharmony_ci#  endif
1313e1051a39Sopenharmony_ci
1314e1051a39Sopenharmony_ci    ret = sendmsg(b->num, &msg, 0);
1315e1051a39Sopenharmony_ci
1316e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
1317e1051a39Sopenharmony_ci    if (ret <= 0) {
1318e1051a39Sopenharmony_ci        if (BIO_dgram_should_retry(ret)) {
1319e1051a39Sopenharmony_ci            BIO_set_retry_write(b);
1320e1051a39Sopenharmony_ci            data->_errno = get_last_socket_error();
1321e1051a39Sopenharmony_ci        }
1322e1051a39Sopenharmony_ci    }
1323e1051a39Sopenharmony_ci    return ret;
1324e1051a39Sopenharmony_ci}
1325e1051a39Sopenharmony_ci
1326e1051a39Sopenharmony_cistatic long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr)
1327e1051a39Sopenharmony_ci{
1328e1051a39Sopenharmony_ci    long ret = 1;
1329e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = NULL;
1330e1051a39Sopenharmony_ci    socklen_t sockopt_len = 0;
1331e1051a39Sopenharmony_ci    struct sctp_authkeyid authkeyid;
1332e1051a39Sopenharmony_ci    struct sctp_authkey *authkey = NULL;
1333e1051a39Sopenharmony_ci
1334e1051a39Sopenharmony_ci    data = (bio_dgram_sctp_data *) b->ptr;
1335e1051a39Sopenharmony_ci
1336e1051a39Sopenharmony_ci    switch (cmd) {
1337e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_QUERY_MTU:
1338e1051a39Sopenharmony_ci        /*
1339e1051a39Sopenharmony_ci         * Set to maximum (2^14) and ignore user input to enable transport
1340e1051a39Sopenharmony_ci         * protocol fragmentation. Returns always 2^14.
1341e1051a39Sopenharmony_ci         */
1342e1051a39Sopenharmony_ci        data->mtu = 16384;
1343e1051a39Sopenharmony_ci        ret = data->mtu;
1344e1051a39Sopenharmony_ci        break;
1345e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_MTU:
1346e1051a39Sopenharmony_ci        /*
1347e1051a39Sopenharmony_ci         * Set to maximum (2^14) and ignore input to enable transport
1348e1051a39Sopenharmony_ci         * protocol fragmentation. Returns always 2^14.
1349e1051a39Sopenharmony_ci         */
1350e1051a39Sopenharmony_ci        data->mtu = 16384;
1351e1051a39Sopenharmony_ci        ret = data->mtu;
1352e1051a39Sopenharmony_ci        break;
1353e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_CONNECTED:
1354e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_CONNECT:
1355e1051a39Sopenharmony_ci        /* Returns always -1. */
1356e1051a39Sopenharmony_ci        ret = -1;
1357e1051a39Sopenharmony_ci        break;
1358e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
1359e1051a39Sopenharmony_ci        /*
1360e1051a39Sopenharmony_ci         * SCTP doesn't need the DTLS timer Returns always 1.
1361e1051a39Sopenharmony_ci         */
1362e1051a39Sopenharmony_ci        break;
1363e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
1364e1051a39Sopenharmony_ci        /*
1365e1051a39Sopenharmony_ci         * We allow transport protocol fragmentation so this is irrelevant
1366e1051a39Sopenharmony_ci         */
1367e1051a39Sopenharmony_ci        ret = 0;
1368e1051a39Sopenharmony_ci        break;
1369e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
1370e1051a39Sopenharmony_ci        if (num > 0)
1371e1051a39Sopenharmony_ci            data->in_handshake = 1;
1372e1051a39Sopenharmony_ci        else
1373e1051a39Sopenharmony_ci            data->in_handshake = 0;
1374e1051a39Sopenharmony_ci
1375e1051a39Sopenharmony_ci        ret =
1376e1051a39Sopenharmony_ci            setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY,
1377e1051a39Sopenharmony_ci                       &data->in_handshake, sizeof(int));
1378e1051a39Sopenharmony_ci        break;
1379e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY:
1380e1051a39Sopenharmony_ci        /*
1381e1051a39Sopenharmony_ci         * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise.
1382e1051a39Sopenharmony_ci         */
1383e1051a39Sopenharmony_ci
1384e1051a39Sopenharmony_ci        /* Get active key */
1385e1051a39Sopenharmony_ci        sockopt_len = sizeof(struct sctp_authkeyid);
1386e1051a39Sopenharmony_ci        ret =
1387e1051a39Sopenharmony_ci            getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid,
1388e1051a39Sopenharmony_ci                       &sockopt_len);
1389e1051a39Sopenharmony_ci        if (ret < 0)
1390e1051a39Sopenharmony_ci            break;
1391e1051a39Sopenharmony_ci
1392e1051a39Sopenharmony_ci        /* Add new key */
1393e1051a39Sopenharmony_ci        sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t);
1394e1051a39Sopenharmony_ci        authkey = OPENSSL_malloc(sockopt_len);
1395e1051a39Sopenharmony_ci        if (authkey == NULL) {
1396e1051a39Sopenharmony_ci            ret = -1;
1397e1051a39Sopenharmony_ci            break;
1398e1051a39Sopenharmony_ci        }
1399e1051a39Sopenharmony_ci        memset(authkey, 0, sockopt_len);
1400e1051a39Sopenharmony_ci        authkey->sca_keynumber = authkeyid.scact_keynumber + 1;
1401e1051a39Sopenharmony_ci#  ifndef __FreeBSD__
1402e1051a39Sopenharmony_ci        /*
1403e1051a39Sopenharmony_ci         * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3
1404e1051a39Sopenharmony_ci         * and higher work without it.
1405e1051a39Sopenharmony_ci         */
1406e1051a39Sopenharmony_ci        authkey->sca_keylength = 64;
1407e1051a39Sopenharmony_ci#  endif
1408e1051a39Sopenharmony_ci        memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t));
1409e1051a39Sopenharmony_ci
1410e1051a39Sopenharmony_ci        ret =
1411e1051a39Sopenharmony_ci            setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey,
1412e1051a39Sopenharmony_ci                       sockopt_len);
1413e1051a39Sopenharmony_ci        OPENSSL_free(authkey);
1414e1051a39Sopenharmony_ci        authkey = NULL;
1415e1051a39Sopenharmony_ci        if (ret < 0)
1416e1051a39Sopenharmony_ci            break;
1417e1051a39Sopenharmony_ci
1418e1051a39Sopenharmony_ci        /* Reset active key */
1419e1051a39Sopenharmony_ci        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
1420e1051a39Sopenharmony_ci                         &authkeyid, sizeof(struct sctp_authkeyid));
1421e1051a39Sopenharmony_ci        if (ret < 0)
1422e1051a39Sopenharmony_ci            break;
1423e1051a39Sopenharmony_ci
1424e1051a39Sopenharmony_ci        break;
1425e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY:
1426e1051a39Sopenharmony_ci        /* Returns 0 on success, -1 otherwise. */
1427e1051a39Sopenharmony_ci
1428e1051a39Sopenharmony_ci        /* Get active key */
1429e1051a39Sopenharmony_ci        sockopt_len = sizeof(struct sctp_authkeyid);
1430e1051a39Sopenharmony_ci        ret =
1431e1051a39Sopenharmony_ci            getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid,
1432e1051a39Sopenharmony_ci                       &sockopt_len);
1433e1051a39Sopenharmony_ci        if (ret < 0)
1434e1051a39Sopenharmony_ci            break;
1435e1051a39Sopenharmony_ci
1436e1051a39Sopenharmony_ci        /* Set active key */
1437e1051a39Sopenharmony_ci        authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1;
1438e1051a39Sopenharmony_ci        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
1439e1051a39Sopenharmony_ci                         &authkeyid, sizeof(struct sctp_authkeyid));
1440e1051a39Sopenharmony_ci        if (ret < 0)
1441e1051a39Sopenharmony_ci            break;
1442e1051a39Sopenharmony_ci
1443e1051a39Sopenharmony_ci        /*
1444e1051a39Sopenharmony_ci         * CCS has been sent, so remember that and fall through to check if
1445e1051a39Sopenharmony_ci         * we need to deactivate an old key
1446e1051a39Sopenharmony_ci         */
1447e1051a39Sopenharmony_ci        data->ccs_sent = 1;
1448e1051a39Sopenharmony_ci        /* fall-through */
1449e1051a39Sopenharmony_ci
1450e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD:
1451e1051a39Sopenharmony_ci        /* Returns 0 on success, -1 otherwise. */
1452e1051a39Sopenharmony_ci
1453e1051a39Sopenharmony_ci        /*
1454e1051a39Sopenharmony_ci         * Has this command really been called or is this just a
1455e1051a39Sopenharmony_ci         * fall-through?
1456e1051a39Sopenharmony_ci         */
1457e1051a39Sopenharmony_ci        if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD)
1458e1051a39Sopenharmony_ci            data->ccs_rcvd = 1;
1459e1051a39Sopenharmony_ci
1460e1051a39Sopenharmony_ci        /*
1461e1051a39Sopenharmony_ci         * CSS has been both, received and sent, so deactivate an old key
1462e1051a39Sopenharmony_ci         */
1463e1051a39Sopenharmony_ci        if (data->ccs_rcvd == 1 && data->ccs_sent == 1) {
1464e1051a39Sopenharmony_ci            /* Get active key */
1465e1051a39Sopenharmony_ci            sockopt_len = sizeof(struct sctp_authkeyid);
1466e1051a39Sopenharmony_ci            ret =
1467e1051a39Sopenharmony_ci                getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
1468e1051a39Sopenharmony_ci                           &authkeyid, &sockopt_len);
1469e1051a39Sopenharmony_ci            if (ret < 0)
1470e1051a39Sopenharmony_ci                break;
1471e1051a39Sopenharmony_ci
1472e1051a39Sopenharmony_ci            /*
1473e1051a39Sopenharmony_ci             * Deactivate key or delete second last key if
1474e1051a39Sopenharmony_ci             * SCTP_AUTHENTICATION_EVENT is not available.
1475e1051a39Sopenharmony_ci             */
1476e1051a39Sopenharmony_ci            authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
1477e1051a39Sopenharmony_ci#  ifdef SCTP_AUTH_DEACTIVATE_KEY
1478e1051a39Sopenharmony_ci            sockopt_len = sizeof(struct sctp_authkeyid);
1479e1051a39Sopenharmony_ci            ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY,
1480e1051a39Sopenharmony_ci                             &authkeyid, sockopt_len);
1481e1051a39Sopenharmony_ci            if (ret < 0)
1482e1051a39Sopenharmony_ci                break;
1483e1051a39Sopenharmony_ci#  endif
1484e1051a39Sopenharmony_ci#  ifndef SCTP_AUTHENTICATION_EVENT
1485e1051a39Sopenharmony_ci            if (authkeyid.scact_keynumber > 0) {
1486e1051a39Sopenharmony_ci                authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
1487e1051a39Sopenharmony_ci                ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
1488e1051a39Sopenharmony_ci                                 &authkeyid, sizeof(struct sctp_authkeyid));
1489e1051a39Sopenharmony_ci                if (ret < 0)
1490e1051a39Sopenharmony_ci                    break;
1491e1051a39Sopenharmony_ci            }
1492e1051a39Sopenharmony_ci#  endif
1493e1051a39Sopenharmony_ci
1494e1051a39Sopenharmony_ci            data->ccs_rcvd = 0;
1495e1051a39Sopenharmony_ci            data->ccs_sent = 0;
1496e1051a39Sopenharmony_ci        }
1497e1051a39Sopenharmony_ci        break;
1498e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO:
1499e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1500e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo))
1501e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_sndinfo);
1502e1051a39Sopenharmony_ci
1503e1051a39Sopenharmony_ci        memcpy(ptr, &(data->sndinfo), num);
1504e1051a39Sopenharmony_ci        ret = num;
1505e1051a39Sopenharmony_ci        break;
1506e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO:
1507e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1508e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo))
1509e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_sndinfo);
1510e1051a39Sopenharmony_ci
1511e1051a39Sopenharmony_ci        memcpy(&(data->sndinfo), ptr, num);
1512e1051a39Sopenharmony_ci        break;
1513e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO:
1514e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1515e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo))
1516e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_rcvinfo);
1517e1051a39Sopenharmony_ci
1518e1051a39Sopenharmony_ci        memcpy(ptr, &data->rcvinfo, num);
1519e1051a39Sopenharmony_ci
1520e1051a39Sopenharmony_ci        ret = num;
1521e1051a39Sopenharmony_ci        break;
1522e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO:
1523e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1524e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo))
1525e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_rcvinfo);
1526e1051a39Sopenharmony_ci
1527e1051a39Sopenharmony_ci        memcpy(&(data->rcvinfo), ptr, num);
1528e1051a39Sopenharmony_ci        break;
1529e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_GET_PRINFO:
1530e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1531e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_prinfo))
1532e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_prinfo);
1533e1051a39Sopenharmony_ci
1534e1051a39Sopenharmony_ci        memcpy(ptr, &(data->prinfo), num);
1535e1051a39Sopenharmony_ci        ret = num;
1536e1051a39Sopenharmony_ci        break;
1537e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SET_PRINFO:
1538e1051a39Sopenharmony_ci        /* Returns the size of the copied struct. */
1539e1051a39Sopenharmony_ci        if (num > (long)sizeof(struct bio_dgram_sctp_prinfo))
1540e1051a39Sopenharmony_ci            num = sizeof(struct bio_dgram_sctp_prinfo);
1541e1051a39Sopenharmony_ci
1542e1051a39Sopenharmony_ci        memcpy(&(data->prinfo), ptr, num);
1543e1051a39Sopenharmony_ci        break;
1544e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN:
1545e1051a39Sopenharmony_ci        /* Returns always 1. */
1546e1051a39Sopenharmony_ci        if (num > 0)
1547e1051a39Sopenharmony_ci            data->save_shutdown = 1;
1548e1051a39Sopenharmony_ci        else
1549e1051a39Sopenharmony_ci            data->save_shutdown = 0;
1550e1051a39Sopenharmony_ci        break;
1551e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_WAIT_FOR_DRY:
1552e1051a39Sopenharmony_ci        return dgram_sctp_wait_for_dry(b);
1553e1051a39Sopenharmony_ci    case BIO_CTRL_DGRAM_SCTP_MSG_WAITING:
1554e1051a39Sopenharmony_ci        return dgram_sctp_msg_waiting(b);
1555e1051a39Sopenharmony_ci
1556e1051a39Sopenharmony_ci    default:
1557e1051a39Sopenharmony_ci        /*
1558e1051a39Sopenharmony_ci         * Pass to default ctrl function to process SCTP unspecific commands
1559e1051a39Sopenharmony_ci         */
1560e1051a39Sopenharmony_ci        ret = dgram_ctrl(b, cmd, num, ptr);
1561e1051a39Sopenharmony_ci        break;
1562e1051a39Sopenharmony_ci    }
1563e1051a39Sopenharmony_ci    return ret;
1564e1051a39Sopenharmony_ci}
1565e1051a39Sopenharmony_ci
1566e1051a39Sopenharmony_ciint BIO_dgram_sctp_notification_cb(BIO *b,
1567e1051a39Sopenharmony_ci                BIO_dgram_sctp_notification_handler_fn handle_notifications,
1568e1051a39Sopenharmony_ci                void *context)
1569e1051a39Sopenharmony_ci{
1570e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
1571e1051a39Sopenharmony_ci
1572e1051a39Sopenharmony_ci    if (handle_notifications != NULL) {
1573e1051a39Sopenharmony_ci        data->handle_notifications = handle_notifications;
1574e1051a39Sopenharmony_ci        data->notification_context = context;
1575e1051a39Sopenharmony_ci    } else
1576e1051a39Sopenharmony_ci        return -1;
1577e1051a39Sopenharmony_ci
1578e1051a39Sopenharmony_ci    return 0;
1579e1051a39Sopenharmony_ci}
1580e1051a39Sopenharmony_ci
1581e1051a39Sopenharmony_ci/*
1582e1051a39Sopenharmony_ci * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event
1583e1051a39Sopenharmony_ci * @b: The BIO to check for the dry event
1584e1051a39Sopenharmony_ci *
1585e1051a39Sopenharmony_ci * Wait until the peer confirms all packets have been received, and so that
1586e1051a39Sopenharmony_ci * our kernel doesn't have anything to send anymore.  This is only received by
1587e1051a39Sopenharmony_ci * the peer's kernel, not the application.
1588e1051a39Sopenharmony_ci *
1589e1051a39Sopenharmony_ci * Returns:
1590e1051a39Sopenharmony_ci * -1 on error
1591e1051a39Sopenharmony_ci *  0 when not dry yet
1592e1051a39Sopenharmony_ci *  1 when dry
1593e1051a39Sopenharmony_ci */
1594e1051a39Sopenharmony_ciint BIO_dgram_sctp_wait_for_dry(BIO *b)
1595e1051a39Sopenharmony_ci{
1596e1051a39Sopenharmony_ci    return (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SCTP_WAIT_FOR_DRY, 0, NULL);
1597e1051a39Sopenharmony_ci}
1598e1051a39Sopenharmony_ci
1599e1051a39Sopenharmony_cistatic int dgram_sctp_wait_for_dry(BIO *b)
1600e1051a39Sopenharmony_ci{
1601e1051a39Sopenharmony_ci    int is_dry = 0;
1602e1051a39Sopenharmony_ci    int sockflags = 0;
1603e1051a39Sopenharmony_ci    int n, ret;
1604e1051a39Sopenharmony_ci    union sctp_notification snp;
1605e1051a39Sopenharmony_ci    struct msghdr msg;
1606e1051a39Sopenharmony_ci    struct iovec iov;
1607e1051a39Sopenharmony_ci#  ifdef SCTP_EVENT
1608e1051a39Sopenharmony_ci    struct sctp_event event;
1609e1051a39Sopenharmony_ci#  else
1610e1051a39Sopenharmony_ci    struct sctp_event_subscribe event;
1611e1051a39Sopenharmony_ci    socklen_t eventsize;
1612e1051a39Sopenharmony_ci#  endif
1613e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
1614e1051a39Sopenharmony_ci
1615e1051a39Sopenharmony_ci    /* set sender dry event */
1616e1051a39Sopenharmony_ci#  ifdef SCTP_EVENT
1617e1051a39Sopenharmony_ci    memset(&event, 0, sizeof(event));
1618e1051a39Sopenharmony_ci    event.se_assoc_id = 0;
1619e1051a39Sopenharmony_ci    event.se_type = SCTP_SENDER_DRY_EVENT;
1620e1051a39Sopenharmony_ci    event.se_on = 1;
1621e1051a39Sopenharmony_ci    ret =
1622e1051a39Sopenharmony_ci        setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
1623e1051a39Sopenharmony_ci                   sizeof(struct sctp_event));
1624e1051a39Sopenharmony_ci#  else
1625e1051a39Sopenharmony_ci    eventsize = sizeof(struct sctp_event_subscribe);
1626e1051a39Sopenharmony_ci    ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
1627e1051a39Sopenharmony_ci    if (ret < 0)
1628e1051a39Sopenharmony_ci        return -1;
1629e1051a39Sopenharmony_ci
1630e1051a39Sopenharmony_ci    event.sctp_sender_dry_event = 1;
1631e1051a39Sopenharmony_ci
1632e1051a39Sopenharmony_ci    ret =
1633e1051a39Sopenharmony_ci        setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
1634e1051a39Sopenharmony_ci                   sizeof(struct sctp_event_subscribe));
1635e1051a39Sopenharmony_ci#  endif
1636e1051a39Sopenharmony_ci    if (ret < 0)
1637e1051a39Sopenharmony_ci        return -1;
1638e1051a39Sopenharmony_ci
1639e1051a39Sopenharmony_ci    /* peek for notification */
1640e1051a39Sopenharmony_ci    memset(&snp, 0, sizeof(snp));
1641e1051a39Sopenharmony_ci    iov.iov_base = (char *)&snp;
1642e1051a39Sopenharmony_ci    iov.iov_len = sizeof(union sctp_notification);
1643e1051a39Sopenharmony_ci    msg.msg_name = NULL;
1644e1051a39Sopenharmony_ci    msg.msg_namelen = 0;
1645e1051a39Sopenharmony_ci    msg.msg_iov = &iov;
1646e1051a39Sopenharmony_ci    msg.msg_iovlen = 1;
1647e1051a39Sopenharmony_ci    msg.msg_control = NULL;
1648e1051a39Sopenharmony_ci    msg.msg_controllen = 0;
1649e1051a39Sopenharmony_ci    msg.msg_flags = 0;
1650e1051a39Sopenharmony_ci
1651e1051a39Sopenharmony_ci    n = recvmsg(b->num, &msg, MSG_PEEK);
1652e1051a39Sopenharmony_ci    if (n <= 0) {
1653e1051a39Sopenharmony_ci        if ((n < 0) && (get_last_socket_error() != EAGAIN)
1654e1051a39Sopenharmony_ci            && (get_last_socket_error() != EWOULDBLOCK))
1655e1051a39Sopenharmony_ci            return -1;
1656e1051a39Sopenharmony_ci        else
1657e1051a39Sopenharmony_ci            return 0;
1658e1051a39Sopenharmony_ci    }
1659e1051a39Sopenharmony_ci
1660e1051a39Sopenharmony_ci    /* if we find a notification, process it and try again if necessary */
1661e1051a39Sopenharmony_ci    while (msg.msg_flags & MSG_NOTIFICATION) {
1662e1051a39Sopenharmony_ci        memset(&snp, 0, sizeof(snp));
1663e1051a39Sopenharmony_ci        iov.iov_base = (char *)&snp;
1664e1051a39Sopenharmony_ci        iov.iov_len = sizeof(union sctp_notification);
1665e1051a39Sopenharmony_ci        msg.msg_name = NULL;
1666e1051a39Sopenharmony_ci        msg.msg_namelen = 0;
1667e1051a39Sopenharmony_ci        msg.msg_iov = &iov;
1668e1051a39Sopenharmony_ci        msg.msg_iovlen = 1;
1669e1051a39Sopenharmony_ci        msg.msg_control = NULL;
1670e1051a39Sopenharmony_ci        msg.msg_controllen = 0;
1671e1051a39Sopenharmony_ci        msg.msg_flags = 0;
1672e1051a39Sopenharmony_ci
1673e1051a39Sopenharmony_ci        n = recvmsg(b->num, &msg, 0);
1674e1051a39Sopenharmony_ci        if (n <= 0) {
1675e1051a39Sopenharmony_ci            if ((n < 0) && (get_last_socket_error() != EAGAIN)
1676e1051a39Sopenharmony_ci                && (get_last_socket_error() != EWOULDBLOCK))
1677e1051a39Sopenharmony_ci                return -1;
1678e1051a39Sopenharmony_ci            else
1679e1051a39Sopenharmony_ci                return is_dry;
1680e1051a39Sopenharmony_ci        }
1681e1051a39Sopenharmony_ci
1682e1051a39Sopenharmony_ci        if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) {
1683e1051a39Sopenharmony_ci            is_dry = 1;
1684e1051a39Sopenharmony_ci
1685e1051a39Sopenharmony_ci            /* disable sender dry event */
1686e1051a39Sopenharmony_ci#  ifdef SCTP_EVENT
1687e1051a39Sopenharmony_ci            memset(&event, 0, sizeof(event));
1688e1051a39Sopenharmony_ci            event.se_assoc_id = 0;
1689e1051a39Sopenharmony_ci            event.se_type = SCTP_SENDER_DRY_EVENT;
1690e1051a39Sopenharmony_ci            event.se_on = 0;
1691e1051a39Sopenharmony_ci            ret =
1692e1051a39Sopenharmony_ci                setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
1693e1051a39Sopenharmony_ci                           sizeof(struct sctp_event));
1694e1051a39Sopenharmony_ci#  else
1695e1051a39Sopenharmony_ci            eventsize = (socklen_t) sizeof(struct sctp_event_subscribe);
1696e1051a39Sopenharmony_ci            ret =
1697e1051a39Sopenharmony_ci                getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
1698e1051a39Sopenharmony_ci                           &eventsize);
1699e1051a39Sopenharmony_ci            if (ret < 0)
1700e1051a39Sopenharmony_ci                return -1;
1701e1051a39Sopenharmony_ci
1702e1051a39Sopenharmony_ci            event.sctp_sender_dry_event = 0;
1703e1051a39Sopenharmony_ci
1704e1051a39Sopenharmony_ci            ret =
1705e1051a39Sopenharmony_ci                setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
1706e1051a39Sopenharmony_ci                           sizeof(struct sctp_event_subscribe));
1707e1051a39Sopenharmony_ci#  endif
1708e1051a39Sopenharmony_ci            if (ret < 0)
1709e1051a39Sopenharmony_ci                return -1;
1710e1051a39Sopenharmony_ci        }
1711e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
1712e1051a39Sopenharmony_ci        if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
1713e1051a39Sopenharmony_ci            dgram_sctp_handle_auth_free_key_event(b, &snp);
1714e1051a39Sopenharmony_ci#  endif
1715e1051a39Sopenharmony_ci
1716e1051a39Sopenharmony_ci        if (data->handle_notifications != NULL)
1717e1051a39Sopenharmony_ci            data->handle_notifications(b, data->notification_context,
1718e1051a39Sopenharmony_ci                                       (void *)&snp);
1719e1051a39Sopenharmony_ci
1720e1051a39Sopenharmony_ci        /* found notification, peek again */
1721e1051a39Sopenharmony_ci        memset(&snp, 0, sizeof(snp));
1722e1051a39Sopenharmony_ci        iov.iov_base = (char *)&snp;
1723e1051a39Sopenharmony_ci        iov.iov_len = sizeof(union sctp_notification);
1724e1051a39Sopenharmony_ci        msg.msg_name = NULL;
1725e1051a39Sopenharmony_ci        msg.msg_namelen = 0;
1726e1051a39Sopenharmony_ci        msg.msg_iov = &iov;
1727e1051a39Sopenharmony_ci        msg.msg_iovlen = 1;
1728e1051a39Sopenharmony_ci        msg.msg_control = NULL;
1729e1051a39Sopenharmony_ci        msg.msg_controllen = 0;
1730e1051a39Sopenharmony_ci        msg.msg_flags = 0;
1731e1051a39Sopenharmony_ci
1732e1051a39Sopenharmony_ci        /* if we have seen the dry already, don't wait */
1733e1051a39Sopenharmony_ci        if (is_dry) {
1734e1051a39Sopenharmony_ci            sockflags = fcntl(b->num, F_GETFL, 0);
1735e1051a39Sopenharmony_ci            fcntl(b->num, F_SETFL, O_NONBLOCK);
1736e1051a39Sopenharmony_ci        }
1737e1051a39Sopenharmony_ci
1738e1051a39Sopenharmony_ci        n = recvmsg(b->num, &msg, MSG_PEEK);
1739e1051a39Sopenharmony_ci
1740e1051a39Sopenharmony_ci        if (is_dry) {
1741e1051a39Sopenharmony_ci            fcntl(b->num, F_SETFL, sockflags);
1742e1051a39Sopenharmony_ci        }
1743e1051a39Sopenharmony_ci
1744e1051a39Sopenharmony_ci        if (n <= 0) {
1745e1051a39Sopenharmony_ci            if ((n < 0) && (get_last_socket_error() != EAGAIN)
1746e1051a39Sopenharmony_ci                && (get_last_socket_error() != EWOULDBLOCK))
1747e1051a39Sopenharmony_ci                return -1;
1748e1051a39Sopenharmony_ci            else
1749e1051a39Sopenharmony_ci                return is_dry;
1750e1051a39Sopenharmony_ci        }
1751e1051a39Sopenharmony_ci    }
1752e1051a39Sopenharmony_ci
1753e1051a39Sopenharmony_ci    /* read anything else */
1754e1051a39Sopenharmony_ci    return is_dry;
1755e1051a39Sopenharmony_ci}
1756e1051a39Sopenharmony_ci
1757e1051a39Sopenharmony_ciint BIO_dgram_sctp_msg_waiting(BIO *b)
1758e1051a39Sopenharmony_ci{
1759e1051a39Sopenharmony_ci    return (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SCTP_MSG_WAITING, 0, NULL);
1760e1051a39Sopenharmony_ci}
1761e1051a39Sopenharmony_ci
1762e1051a39Sopenharmony_cistatic int dgram_sctp_msg_waiting(BIO *b)
1763e1051a39Sopenharmony_ci{
1764e1051a39Sopenharmony_ci    int n, sockflags;
1765e1051a39Sopenharmony_ci    union sctp_notification snp;
1766e1051a39Sopenharmony_ci    struct msghdr msg;
1767e1051a39Sopenharmony_ci    struct iovec iov;
1768e1051a39Sopenharmony_ci    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
1769e1051a39Sopenharmony_ci
1770e1051a39Sopenharmony_ci    /* Check if there are any messages waiting to be read */
1771e1051a39Sopenharmony_ci    do {
1772e1051a39Sopenharmony_ci        memset(&snp, 0, sizeof(snp));
1773e1051a39Sopenharmony_ci        iov.iov_base = (char *)&snp;
1774e1051a39Sopenharmony_ci        iov.iov_len = sizeof(union sctp_notification);
1775e1051a39Sopenharmony_ci        msg.msg_name = NULL;
1776e1051a39Sopenharmony_ci        msg.msg_namelen = 0;
1777e1051a39Sopenharmony_ci        msg.msg_iov = &iov;
1778e1051a39Sopenharmony_ci        msg.msg_iovlen = 1;
1779e1051a39Sopenharmony_ci        msg.msg_control = NULL;
1780e1051a39Sopenharmony_ci        msg.msg_controllen = 0;
1781e1051a39Sopenharmony_ci        msg.msg_flags = 0;
1782e1051a39Sopenharmony_ci
1783e1051a39Sopenharmony_ci        sockflags = fcntl(b->num, F_GETFL, 0);
1784e1051a39Sopenharmony_ci        fcntl(b->num, F_SETFL, O_NONBLOCK);
1785e1051a39Sopenharmony_ci        n = recvmsg(b->num, &msg, MSG_PEEK);
1786e1051a39Sopenharmony_ci        fcntl(b->num, F_SETFL, sockflags);
1787e1051a39Sopenharmony_ci
1788e1051a39Sopenharmony_ci        /* if notification, process and try again */
1789e1051a39Sopenharmony_ci        if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) {
1790e1051a39Sopenharmony_ci#  ifdef SCTP_AUTHENTICATION_EVENT
1791e1051a39Sopenharmony_ci            if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
1792e1051a39Sopenharmony_ci                dgram_sctp_handle_auth_free_key_event(b, &snp);
1793e1051a39Sopenharmony_ci#  endif
1794e1051a39Sopenharmony_ci
1795e1051a39Sopenharmony_ci            memset(&snp, 0, sizeof(snp));
1796e1051a39Sopenharmony_ci            iov.iov_base = (char *)&snp;
1797e1051a39Sopenharmony_ci            iov.iov_len = sizeof(union sctp_notification);
1798e1051a39Sopenharmony_ci            msg.msg_name = NULL;
1799e1051a39Sopenharmony_ci            msg.msg_namelen = 0;
1800e1051a39Sopenharmony_ci            msg.msg_iov = &iov;
1801e1051a39Sopenharmony_ci            msg.msg_iovlen = 1;
1802e1051a39Sopenharmony_ci            msg.msg_control = NULL;
1803e1051a39Sopenharmony_ci            msg.msg_controllen = 0;
1804e1051a39Sopenharmony_ci            msg.msg_flags = 0;
1805e1051a39Sopenharmony_ci            n = recvmsg(b->num, &msg, 0);
1806e1051a39Sopenharmony_ci
1807e1051a39Sopenharmony_ci            if (data->handle_notifications != NULL)
1808e1051a39Sopenharmony_ci                data->handle_notifications(b, data->notification_context,
1809e1051a39Sopenharmony_ci                                           (void *)&snp);
1810e1051a39Sopenharmony_ci        }
1811e1051a39Sopenharmony_ci
1812e1051a39Sopenharmony_ci    } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION));
1813e1051a39Sopenharmony_ci
1814e1051a39Sopenharmony_ci    /* Return 1 if there is a message to be read, return 0 otherwise. */
1815e1051a39Sopenharmony_ci    if (n > 0)
1816e1051a39Sopenharmony_ci        return 1;
1817e1051a39Sopenharmony_ci    else
1818e1051a39Sopenharmony_ci        return 0;
1819e1051a39Sopenharmony_ci}
1820e1051a39Sopenharmony_ci
1821e1051a39Sopenharmony_cistatic int dgram_sctp_puts(BIO *bp, const char *str)
1822e1051a39Sopenharmony_ci{
1823e1051a39Sopenharmony_ci    int n, ret;
1824e1051a39Sopenharmony_ci
1825e1051a39Sopenharmony_ci    n = strlen(str);
1826e1051a39Sopenharmony_ci    ret = dgram_sctp_write(bp, str, n);
1827e1051a39Sopenharmony_ci    return ret;
1828e1051a39Sopenharmony_ci}
1829e1051a39Sopenharmony_ci# endif
1830e1051a39Sopenharmony_ci
1831e1051a39Sopenharmony_cistatic int BIO_dgram_should_retry(int i)
1832e1051a39Sopenharmony_ci{
1833e1051a39Sopenharmony_ci    int err;
1834e1051a39Sopenharmony_ci
1835e1051a39Sopenharmony_ci    if ((i == 0) || (i == -1)) {
1836e1051a39Sopenharmony_ci        err = get_last_socket_error();
1837e1051a39Sopenharmony_ci
1838e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_WINDOWS)
1839e1051a39Sopenharmony_ci        /*
1840e1051a39Sopenharmony_ci         * If the socket return value (i) is -1 and err is unexpectedly 0 at
1841e1051a39Sopenharmony_ci         * this point, the error code was overwritten by another system call
1842e1051a39Sopenharmony_ci         * before this error handling is called.
1843e1051a39Sopenharmony_ci         */
1844e1051a39Sopenharmony_ci# endif
1845e1051a39Sopenharmony_ci
1846e1051a39Sopenharmony_ci        return BIO_dgram_non_fatal_error(err);
1847e1051a39Sopenharmony_ci    }
1848e1051a39Sopenharmony_ci    return 0;
1849e1051a39Sopenharmony_ci}
1850e1051a39Sopenharmony_ci
1851e1051a39Sopenharmony_ciint BIO_dgram_non_fatal_error(int err)
1852e1051a39Sopenharmony_ci{
1853e1051a39Sopenharmony_ci    switch (err) {
1854e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_WINDOWS)
1855e1051a39Sopenharmony_ci#  if defined(WSAEWOULDBLOCK)
1856e1051a39Sopenharmony_ci    case WSAEWOULDBLOCK:
1857e1051a39Sopenharmony_ci#  endif
1858e1051a39Sopenharmony_ci# endif
1859e1051a39Sopenharmony_ci
1860e1051a39Sopenharmony_ci# ifdef EWOULDBLOCK
1861e1051a39Sopenharmony_ci#  ifdef WSAEWOULDBLOCK
1862e1051a39Sopenharmony_ci#   if WSAEWOULDBLOCK != EWOULDBLOCK
1863e1051a39Sopenharmony_ci    case EWOULDBLOCK:
1864e1051a39Sopenharmony_ci#   endif
1865e1051a39Sopenharmony_ci#  else
1866e1051a39Sopenharmony_ci    case EWOULDBLOCK:
1867e1051a39Sopenharmony_ci#  endif
1868e1051a39Sopenharmony_ci# endif
1869e1051a39Sopenharmony_ci
1870e1051a39Sopenharmony_ci# ifdef EINTR
1871e1051a39Sopenharmony_ci    case EINTR:
1872e1051a39Sopenharmony_ci# endif
1873e1051a39Sopenharmony_ci
1874e1051a39Sopenharmony_ci# ifdef EAGAIN
1875e1051a39Sopenharmony_ci#  if EWOULDBLOCK != EAGAIN
1876e1051a39Sopenharmony_ci    case EAGAIN:
1877e1051a39Sopenharmony_ci#  endif
1878e1051a39Sopenharmony_ci# endif
1879e1051a39Sopenharmony_ci
1880e1051a39Sopenharmony_ci# ifdef EPROTO
1881e1051a39Sopenharmony_ci    case EPROTO:
1882e1051a39Sopenharmony_ci# endif
1883e1051a39Sopenharmony_ci
1884e1051a39Sopenharmony_ci# ifdef EINPROGRESS
1885e1051a39Sopenharmony_ci    case EINPROGRESS:
1886e1051a39Sopenharmony_ci# endif
1887e1051a39Sopenharmony_ci
1888e1051a39Sopenharmony_ci# ifdef EALREADY
1889e1051a39Sopenharmony_ci    case EALREADY:
1890e1051a39Sopenharmony_ci# endif
1891e1051a39Sopenharmony_ci
1892e1051a39Sopenharmony_ci        return 1;
1893e1051a39Sopenharmony_ci    default:
1894e1051a39Sopenharmony_ci        break;
1895e1051a39Sopenharmony_ci    }
1896e1051a39Sopenharmony_ci    return 0;
1897e1051a39Sopenharmony_ci}
1898e1051a39Sopenharmony_ci
1899e1051a39Sopenharmony_cistatic void get_current_time(struct timeval *t)
1900e1051a39Sopenharmony_ci{
1901e1051a39Sopenharmony_ci# if defined(_WIN32)
1902e1051a39Sopenharmony_ci    SYSTEMTIME st;
1903e1051a39Sopenharmony_ci    unsigned __int64 now_ul;
1904e1051a39Sopenharmony_ci    FILETIME now_ft;
1905e1051a39Sopenharmony_ci
1906e1051a39Sopenharmony_ci    GetSystemTime(&st);
1907e1051a39Sopenharmony_ci    SystemTimeToFileTime(&st, &now_ft);
1908e1051a39Sopenharmony_ci    now_ul = ((unsigned __int64)now_ft.dwHighDateTime << 32) | now_ft.dwLowDateTime;
1909e1051a39Sopenharmony_ci#  ifdef  __MINGW32__
1910e1051a39Sopenharmony_ci    now_ul -= 116444736000000000ULL;
1911e1051a39Sopenharmony_ci#  else
1912e1051a39Sopenharmony_ci    now_ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */
1913e1051a39Sopenharmony_ci#  endif
1914e1051a39Sopenharmony_ci    t->tv_sec = (long)(now_ul / 10000000);
1915e1051a39Sopenharmony_ci    t->tv_usec = ((int)(now_ul % 10000000)) / 10;
1916e1051a39Sopenharmony_ci# else
1917e1051a39Sopenharmony_ci    if (gettimeofday(t, NULL) < 0)
1918e1051a39Sopenharmony_ci        perror("gettimeofday");
1919e1051a39Sopenharmony_ci# endif
1920e1051a39Sopenharmony_ci}
1921e1051a39Sopenharmony_ci
1922e1051a39Sopenharmony_ci#endif
1923