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