1160814Ssimon/* crypto/bio/bio_dgram.c */ 2280304Sjkim/* 3160814Ssimon * DTLS implementation written by Nagendra Modadugu 4280304Sjkim * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 5160814Ssimon */ 6160814Ssimon/* ==================================================================== 7160814Ssimon * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. 8160814Ssimon * 9160814Ssimon * Redistribution and use in source and binary forms, with or without 10160814Ssimon * modification, are permitted provided that the following conditions 11160814Ssimon * are met: 12160814Ssimon * 13160814Ssimon * 1. Redistributions of source code must retain the above copyright 14280304Sjkim * notice, this list of conditions and the following disclaimer. 15160814Ssimon * 16160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright 17160814Ssimon * notice, this list of conditions and the following disclaimer in 18160814Ssimon * the documentation and/or other materials provided with the 19160814Ssimon * distribution. 20160814Ssimon * 21160814Ssimon * 3. All advertising materials mentioning features or use of this 22160814Ssimon * software must display the following acknowledgment: 23160814Ssimon * "This product includes software developed by the OpenSSL Project 24160814Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25160814Ssimon * 26160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27160814Ssimon * endorse or promote products derived from this software without 28160814Ssimon * prior written permission. For written permission, please contact 29160814Ssimon * openssl-core@OpenSSL.org. 30160814Ssimon * 31160814Ssimon * 5. Products derived from this software may not be called "OpenSSL" 32160814Ssimon * nor may "OpenSSL" appear in their names without prior written 33160814Ssimon * permission of the OpenSSL Project. 34160814Ssimon * 35160814Ssimon * 6. Redistributions of any form whatsoever must retain the following 36160814Ssimon * acknowledgment: 37160814Ssimon * "This product includes software developed by the OpenSSL Project 38160814Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39160814Ssimon * 40160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43160814Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 52160814Ssimon * ==================================================================== 53160814Ssimon * 54160814Ssimon * This product includes cryptographic software written by Eric Young 55160814Ssimon * (eay@cryptsoft.com). This product includes software written by Tim 56160814Ssimon * Hudson (tjh@cryptsoft.com). 57160814Ssimon * 58160814Ssimon */ 59160814Ssimon 60160814Ssimon#include <stdio.h> 61160814Ssimon#include <errno.h> 62160814Ssimon#define USE_SOCKETS 63160814Ssimon#include "cryptlib.h" 64160814Ssimon 65160814Ssimon#include <openssl/bio.h> 66237657Sjkim#ifndef OPENSSL_NO_DGRAM 67160814Ssimon 68280304Sjkim# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) 69280304Sjkim# include <sys/timeb.h> 70280304Sjkim# endif 71205128Ssimon 72280304Sjkim# ifndef OPENSSL_NO_SCTP 73280304Sjkim# include <netinet/sctp.h> 74280304Sjkim# include <fcntl.h> 75280304Sjkim# define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 76280304Sjkim# define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 77280304Sjkim# endif 78238405Sjkim 79280304Sjkim# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU) 80280304Sjkim# define IP_MTU 14 /* linux is lame */ 81280304Sjkim# endif 82160814Ssimon 83280304Sjkim# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED) 84246772Sjkim/* Standard definition causes type-punning problems. */ 85280304Sjkim# undef IN6_IS_ADDR_V4MAPPED 86280304Sjkim# define s6_addr32 __u6_addr.__u6_addr32 87280304Sjkim# define IN6_IS_ADDR_V4MAPPED(a) \ 88246772Sjkim (((a)->s6_addr32[0] == 0) && \ 89246772Sjkim ((a)->s6_addr32[1] == 0) && \ 90246772Sjkim ((a)->s6_addr32[2] == htonl(0x0000ffff))) 91280304Sjkim# endif 92246772Sjkim 93280304Sjkim# ifdef WATT32 94280304Sjkim# define sock_write SockWrite /* Watt-32 uses same names */ 95280304Sjkim# define sock_read SockRead 96280304Sjkim# define sock_puts SockPuts 97280304Sjkim# endif 98160814Ssimon 99160814Ssimonstatic int dgram_write(BIO *h, const char *buf, int num); 100160814Ssimonstatic int dgram_read(BIO *h, char *buf, int size); 101160814Ssimonstatic int dgram_puts(BIO *h, const char *str); 102160814Ssimonstatic long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); 103160814Ssimonstatic int dgram_new(BIO *h); 104160814Ssimonstatic int dgram_free(BIO *data); 105160814Ssimonstatic int dgram_clear(BIO *bio); 106160814Ssimon 107280304Sjkim# ifndef OPENSSL_NO_SCTP 108238405Sjkimstatic int dgram_sctp_write(BIO *h, const char *buf, int num); 109238405Sjkimstatic int dgram_sctp_read(BIO *h, char *buf, int size); 110238405Sjkimstatic int dgram_sctp_puts(BIO *h, const char *str); 111238405Sjkimstatic long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); 112238405Sjkimstatic int dgram_sctp_new(BIO *h); 113238405Sjkimstatic int dgram_sctp_free(BIO *data); 114280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 115280304Sjkimstatic void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification 116280304Sjkim *snp); 117280304Sjkim# endif 118280304Sjkim# endif 119238405Sjkim 120194206Ssimonstatic int BIO_dgram_should_retry(int s); 121160814Ssimon 122205128Ssimonstatic void get_current_time(struct timeval *t); 123205128Ssimon 124280304Sjkimstatic BIO_METHOD methods_dgramp = { 125280304Sjkim BIO_TYPE_DGRAM, 126280304Sjkim "datagram socket", 127280304Sjkim dgram_write, 128280304Sjkim dgram_read, 129280304Sjkim dgram_puts, 130280304Sjkim NULL, /* dgram_gets, */ 131280304Sjkim dgram_ctrl, 132280304Sjkim dgram_new, 133280304Sjkim dgram_free, 134280304Sjkim NULL, 135280304Sjkim}; 136160814Ssimon 137280304Sjkim# ifndef OPENSSL_NO_SCTP 138280304Sjkimstatic BIO_METHOD methods_dgramp_sctp = { 139280304Sjkim BIO_TYPE_DGRAM_SCTP, 140280304Sjkim "datagram sctp socket", 141280304Sjkim dgram_sctp_write, 142280304Sjkim dgram_sctp_read, 143280304Sjkim dgram_sctp_puts, 144280304Sjkim NULL, /* dgram_gets, */ 145280304Sjkim dgram_sctp_ctrl, 146280304Sjkim dgram_sctp_new, 147280304Sjkim dgram_sctp_free, 148280304Sjkim NULL, 149280304Sjkim}; 150280304Sjkim# endif 151238405Sjkim 152280304Sjkimtypedef struct bio_dgram_data_st { 153280304Sjkim union { 154280304Sjkim struct sockaddr sa; 155280304Sjkim struct sockaddr_in sa_in; 156280304Sjkim# if OPENSSL_USE_IPV6 157280304Sjkim struct sockaddr_in6 sa_in6; 158280304Sjkim# endif 159280304Sjkim } peer; 160280304Sjkim unsigned int connected; 161280304Sjkim unsigned int _errno; 162280304Sjkim unsigned int mtu; 163280304Sjkim struct timeval next_timeout; 164280304Sjkim struct timeval socket_timeout; 165280304Sjkim} bio_dgram_data; 166160814Ssimon 167280304Sjkim# ifndef OPENSSL_NO_SCTP 168280304Sjkimtypedef struct bio_dgram_sctp_save_message_st { 169280304Sjkim BIO *bio; 170280304Sjkim char *data; 171280304Sjkim int length; 172280304Sjkim} bio_dgram_sctp_save_message; 173238405Sjkim 174280304Sjkimtypedef struct bio_dgram_sctp_data_st { 175280304Sjkim union { 176280304Sjkim struct sockaddr sa; 177280304Sjkim struct sockaddr_in sa_in; 178280304Sjkim# if OPENSSL_USE_IPV6 179280304Sjkim struct sockaddr_in6 sa_in6; 180280304Sjkim# endif 181280304Sjkim } peer; 182280304Sjkim unsigned int connected; 183280304Sjkim unsigned int _errno; 184280304Sjkim unsigned int mtu; 185280304Sjkim struct bio_dgram_sctp_sndinfo sndinfo; 186280304Sjkim struct bio_dgram_sctp_rcvinfo rcvinfo; 187280304Sjkim struct bio_dgram_sctp_prinfo prinfo; 188280304Sjkim void (*handle_notifications) (BIO *bio, void *context, void *buf); 189280304Sjkim void *notification_context; 190280304Sjkim int in_handshake; 191280304Sjkim int ccs_rcvd; 192280304Sjkim int ccs_sent; 193280304Sjkim int save_shutdown; 194280304Sjkim int peer_auth_tested; 195280304Sjkim bio_dgram_sctp_save_message saved_message; 196280304Sjkim} bio_dgram_sctp_data; 197280304Sjkim# endif 198238405Sjkim 199160814SsimonBIO_METHOD *BIO_s_datagram(void) 200280304Sjkim{ 201280304Sjkim return (&methods_dgramp); 202280304Sjkim} 203160814Ssimon 204160814SsimonBIO *BIO_new_dgram(int fd, int close_flag) 205280304Sjkim{ 206280304Sjkim BIO *ret; 207160814Ssimon 208280304Sjkim ret = BIO_new(BIO_s_datagram()); 209280304Sjkim if (ret == NULL) 210280304Sjkim return (NULL); 211280304Sjkim BIO_set_fd(ret, fd, close_flag); 212280304Sjkim return (ret); 213280304Sjkim} 214160814Ssimon 215160814Ssimonstatic int dgram_new(BIO *bi) 216280304Sjkim{ 217280304Sjkim bio_dgram_data *data = NULL; 218160814Ssimon 219280304Sjkim bi->init = 0; 220280304Sjkim bi->num = 0; 221280304Sjkim data = OPENSSL_malloc(sizeof(bio_dgram_data)); 222280304Sjkim if (data == NULL) 223280304Sjkim return 0; 224280304Sjkim memset(data, 0x00, sizeof(bio_dgram_data)); 225160814Ssimon bi->ptr = data; 226160814Ssimon 227280304Sjkim bi->flags = 0; 228280304Sjkim return (1); 229280304Sjkim} 230160814Ssimon 231160814Ssimonstatic int dgram_free(BIO *a) 232280304Sjkim{ 233280304Sjkim bio_dgram_data *data; 234160814Ssimon 235280304Sjkim if (a == NULL) 236280304Sjkim return (0); 237280304Sjkim if (!dgram_clear(a)) 238280304Sjkim return 0; 239160814Ssimon 240280304Sjkim data = (bio_dgram_data *)a->ptr; 241280304Sjkim if (data != NULL) 242280304Sjkim OPENSSL_free(data); 243160814Ssimon 244280304Sjkim return (1); 245280304Sjkim} 246160814Ssimon 247160814Ssimonstatic int dgram_clear(BIO *a) 248280304Sjkim{ 249280304Sjkim if (a == NULL) 250280304Sjkim return (0); 251280304Sjkim if (a->shutdown) { 252280304Sjkim if (a->init) { 253280304Sjkim SHUTDOWN2(a->num); 254280304Sjkim } 255280304Sjkim a->init = 0; 256280304Sjkim a->flags = 0; 257280304Sjkim } 258280304Sjkim return (1); 259280304Sjkim} 260205128Ssimon 261205128Ssimonstatic void dgram_adjust_rcv_timeout(BIO *b) 262280304Sjkim{ 263280304Sjkim# if defined(SO_RCVTIMEO) 264280304Sjkim bio_dgram_data *data = (bio_dgram_data *)b->ptr; 265280304Sjkim union { 266280304Sjkim size_t s; 267280304Sjkim int i; 268280304Sjkim } sz = { 269280304Sjkim 0 270280304Sjkim }; 271205128Ssimon 272280304Sjkim /* Is a timer active? */ 273280304Sjkim if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { 274280304Sjkim struct timeval timenow, timeleft; 275205128Ssimon 276280304Sjkim /* Read current socket timeout */ 277280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 278280304Sjkim int timeout; 279246772Sjkim 280280304Sjkim sz.i = sizeof(timeout); 281280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 282280304Sjkim (void *)&timeout, &sz.i) < 0) { 283280304Sjkim perror("getsockopt"); 284280304Sjkim } else { 285280304Sjkim data->socket_timeout.tv_sec = timeout / 1000; 286280304Sjkim data->socket_timeout.tv_usec = (timeout % 1000) * 1000; 287280304Sjkim } 288280304Sjkim# else 289280304Sjkim sz.i = sizeof(data->socket_timeout); 290280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 291280304Sjkim &(data->socket_timeout), (void *)&sz) < 0) { 292280304Sjkim perror("getsockopt"); 293280304Sjkim } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) 294280304Sjkim OPENSSL_assert(sz.s <= sizeof(data->socket_timeout)); 295280304Sjkim# endif 296205128Ssimon 297280304Sjkim /* Get current time */ 298280304Sjkim get_current_time(&timenow); 299205128Ssimon 300280304Sjkim /* Calculate time left until timer expires */ 301280304Sjkim memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); 302284285Sjkim if (timeleft.tv_usec < timenow.tv_usec) { 303284285Sjkim timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec; 304280304Sjkim timeleft.tv_sec--; 305284285Sjkim } else { 306284285Sjkim timeleft.tv_usec -= timenow.tv_usec; 307280304Sjkim } 308284285Sjkim if (timeleft.tv_sec < timenow.tv_sec) { 309280304Sjkim timeleft.tv_sec = 0; 310280304Sjkim timeleft.tv_usec = 1; 311284285Sjkim } else { 312284285Sjkim timeleft.tv_sec -= timenow.tv_sec; 313280304Sjkim } 314205128Ssimon 315280304Sjkim /* 316280304Sjkim * Adjust socket timeout if next handhake message timer will expire 317280304Sjkim * earlier. 318280304Sjkim */ 319280304Sjkim if ((data->socket_timeout.tv_sec == 0 320280304Sjkim && data->socket_timeout.tv_usec == 0) 321280304Sjkim || (data->socket_timeout.tv_sec > timeleft.tv_sec) 322280304Sjkim || (data->socket_timeout.tv_sec == timeleft.tv_sec 323280304Sjkim && data->socket_timeout.tv_usec >= timeleft.tv_usec)) { 324280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 325280304Sjkim timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; 326280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 327280304Sjkim (void *)&timeout, sizeof(timeout)) < 0) { 328280304Sjkim perror("setsockopt"); 329280304Sjkim } 330280304Sjkim# else 331280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, 332280304Sjkim sizeof(struct timeval)) < 0) { 333280304Sjkim perror("setsockopt"); 334280304Sjkim } 335280304Sjkim# endif 336280304Sjkim } 337280304Sjkim } 338280304Sjkim# endif 339280304Sjkim} 340205128Ssimon 341205128Ssimonstatic void dgram_reset_rcv_timeout(BIO *b) 342280304Sjkim{ 343280304Sjkim# if defined(SO_RCVTIMEO) 344280304Sjkim bio_dgram_data *data = (bio_dgram_data *)b->ptr; 345205128Ssimon 346280304Sjkim /* Is a timer active? */ 347280304Sjkim if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { 348280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 349280304Sjkim int timeout = data->socket_timeout.tv_sec * 1000 + 350280304Sjkim data->socket_timeout.tv_usec / 1000; 351280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 352280304Sjkim (void *)&timeout, sizeof(timeout)) < 0) { 353280304Sjkim perror("setsockopt"); 354280304Sjkim } 355280304Sjkim# else 356280304Sjkim if (setsockopt 357280304Sjkim (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), 358280304Sjkim sizeof(struct timeval)) < 0) { 359280304Sjkim perror("setsockopt"); 360280304Sjkim } 361280304Sjkim# endif 362280304Sjkim } 363280304Sjkim# endif 364280304Sjkim} 365205128Ssimon 366160814Ssimonstatic int dgram_read(BIO *b, char *out, int outl) 367280304Sjkim{ 368280304Sjkim int ret = 0; 369280304Sjkim bio_dgram_data *data = (bio_dgram_data *)b->ptr; 370160814Ssimon 371280304Sjkim struct { 372280304Sjkim /* 373280304Sjkim * See commentary in b_sock.c. <appro> 374280304Sjkim */ 375280304Sjkim union { 376280304Sjkim size_t s; 377280304Sjkim int i; 378280304Sjkim } len; 379280304Sjkim union { 380280304Sjkim struct sockaddr sa; 381280304Sjkim struct sockaddr_in sa_in; 382280304Sjkim# if OPENSSL_USE_IPV6 383280304Sjkim struct sockaddr_in6 sa_in6; 384280304Sjkim# endif 385280304Sjkim } peer; 386280304Sjkim } sa; 387160814Ssimon 388280304Sjkim sa.len.s = 0; 389280304Sjkim sa.len.i = sizeof(sa.peer); 390238405Sjkim 391280304Sjkim if (out != NULL) { 392280304Sjkim clear_socket_error(); 393280304Sjkim memset(&sa.peer, 0x00, sizeof(sa.peer)); 394280304Sjkim dgram_adjust_rcv_timeout(b); 395280304Sjkim ret = recvfrom(b->num, out, outl, 0, &sa.peer.sa, (void *)&sa.len); 396280304Sjkim if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) { 397280304Sjkim OPENSSL_assert(sa.len.s <= sizeof(sa.peer)); 398280304Sjkim sa.len.i = (int)sa.len.s; 399280304Sjkim } 400160814Ssimon 401280304Sjkim if (!data->connected && ret >= 0) 402280304Sjkim BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); 403160814Ssimon 404280304Sjkim BIO_clear_retry_flags(b); 405280304Sjkim if (ret < 0) { 406280304Sjkim if (BIO_dgram_should_retry(ret)) { 407280304Sjkim BIO_set_retry_read(b); 408280304Sjkim data->_errno = get_last_socket_error(); 409280304Sjkim } 410280304Sjkim } 411237657Sjkim 412280304Sjkim dgram_reset_rcv_timeout(b); 413280304Sjkim } 414280304Sjkim return (ret); 415280304Sjkim} 416160814Ssimon 417160814Ssimonstatic int dgram_write(BIO *b, const char *in, int inl) 418280304Sjkim{ 419280304Sjkim int ret; 420280304Sjkim bio_dgram_data *data = (bio_dgram_data *)b->ptr; 421280304Sjkim clear_socket_error(); 422160814Ssimon 423280304Sjkim if (data->connected) 424280304Sjkim ret = writesocket(b->num, in, inl); 425280304Sjkim else { 426280304Sjkim int peerlen = sizeof(data->peer); 427238405Sjkim 428280304Sjkim if (data->peer.sa.sa_family == AF_INET) 429280304Sjkim peerlen = sizeof(data->peer.sa_in); 430280304Sjkim# if OPENSSL_USE_IPV6 431280304Sjkim else if (data->peer.sa.sa_family == AF_INET6) 432280304Sjkim peerlen = sizeof(data->peer.sa_in6); 433280304Sjkim# endif 434280304Sjkim# if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) 435280304Sjkim ret = sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); 436280304Sjkim# else 437280304Sjkim ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); 438280304Sjkim# endif 439280304Sjkim } 440160814Ssimon 441280304Sjkim BIO_clear_retry_flags(b); 442280304Sjkim if (ret <= 0) { 443280304Sjkim if (BIO_dgram_should_retry(ret)) { 444280304Sjkim BIO_set_retry_write(b); 445280304Sjkim data->_errno = get_last_socket_error(); 446160814Ssimon 447280304Sjkim# if 0 /* higher layers are responsible for querying 448280304Sjkim * MTU, if necessary */ 449280304Sjkim if (data->_errno == EMSGSIZE) 450280304Sjkim /* retrieve the new MTU */ 451280304Sjkim BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); 452280304Sjkim# endif 453280304Sjkim } 454280304Sjkim } 455280304Sjkim return (ret); 456280304Sjkim} 457160814Ssimon 458276864Sjkimstatic long dgram_get_mtu_overhead(bio_dgram_data *data) 459280304Sjkim{ 460280304Sjkim long ret; 461276864Sjkim 462280304Sjkim switch (data->peer.sa.sa_family) { 463280304Sjkim case AF_INET: 464280304Sjkim /* 465280304Sjkim * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP 466280304Sjkim */ 467280304Sjkim ret = 28; 468280304Sjkim break; 469280304Sjkim# if OPENSSL_USE_IPV6 470280304Sjkim case AF_INET6: 471280304Sjkim# ifdef IN6_IS_ADDR_V4MAPPED 472280304Sjkim if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 473280304Sjkim /* 474280304Sjkim * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP 475280304Sjkim */ 476280304Sjkim ret = 28; 477280304Sjkim else 478280304Sjkim# endif 479280304Sjkim /* 480280304Sjkim * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP 481280304Sjkim */ 482280304Sjkim ret = 48; 483280304Sjkim break; 484280304Sjkim# endif 485280304Sjkim default: 486280304Sjkim /* We don't know. Go with the historical default */ 487280304Sjkim ret = 28; 488280304Sjkim break; 489280304Sjkim } 490280304Sjkim return ret; 491280304Sjkim} 492276864Sjkim 493160814Ssimonstatic long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) 494280304Sjkim{ 495280304Sjkim long ret = 1; 496280304Sjkim int *ip; 497280304Sjkim struct sockaddr *to = NULL; 498280304Sjkim bio_dgram_data *data = NULL; 499280304Sjkim# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) 500280304Sjkim int sockopt_val = 0; 501280304Sjkim socklen_t sockopt_len; /* assume that system supporting IP_MTU is 502280304Sjkim * modern enough to define socklen_t */ 503280304Sjkim socklen_t addr_len; 504280304Sjkim union { 505280304Sjkim struct sockaddr sa; 506280304Sjkim struct sockaddr_in s4; 507280304Sjkim# if OPENSSL_USE_IPV6 508280304Sjkim struct sockaddr_in6 s6; 509280304Sjkim# endif 510280304Sjkim } addr; 511280304Sjkim# endif 512160814Ssimon 513280304Sjkim data = (bio_dgram_data *)b->ptr; 514160814Ssimon 515280304Sjkim switch (cmd) { 516280304Sjkim case BIO_CTRL_RESET: 517280304Sjkim num = 0; 518280304Sjkim ret = 0; 519280304Sjkim break; 520280304Sjkim case BIO_CTRL_INFO: 521280304Sjkim ret = 0; 522280304Sjkim break; 523280304Sjkim case BIO_C_SET_FD: 524280304Sjkim dgram_clear(b); 525280304Sjkim b->num = *((int *)ptr); 526280304Sjkim b->shutdown = (int)num; 527280304Sjkim b->init = 1; 528280304Sjkim break; 529280304Sjkim case BIO_C_GET_FD: 530280304Sjkim if (b->init) { 531280304Sjkim ip = (int *)ptr; 532280304Sjkim if (ip != NULL) 533280304Sjkim *ip = b->num; 534280304Sjkim ret = b->num; 535280304Sjkim } else 536280304Sjkim ret = -1; 537280304Sjkim break; 538280304Sjkim case BIO_CTRL_GET_CLOSE: 539280304Sjkim ret = b->shutdown; 540280304Sjkim break; 541280304Sjkim case BIO_CTRL_SET_CLOSE: 542280304Sjkim b->shutdown = (int)num; 543280304Sjkim break; 544280304Sjkim case BIO_CTRL_PENDING: 545280304Sjkim case BIO_CTRL_WPENDING: 546280304Sjkim ret = 0; 547280304Sjkim break; 548280304Sjkim case BIO_CTRL_DUP: 549280304Sjkim case BIO_CTRL_FLUSH: 550280304Sjkim ret = 1; 551280304Sjkim break; 552280304Sjkim case BIO_CTRL_DGRAM_CONNECT: 553280304Sjkim to = (struct sockaddr *)ptr; 554280304Sjkim# if 0 555280304Sjkim if (connect(b->num, to, sizeof(struct sockaddr)) < 0) { 556280304Sjkim perror("connect"); 557280304Sjkim ret = 0; 558280304Sjkim } else { 559280304Sjkim# endif 560280304Sjkim switch (to->sa_family) { 561280304Sjkim case AF_INET: 562280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in)); 563280304Sjkim break; 564280304Sjkim# if OPENSSL_USE_IPV6 565280304Sjkim case AF_INET6: 566280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); 567280304Sjkim break; 568280304Sjkim# endif 569280304Sjkim default: 570280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa)); 571280304Sjkim break; 572280304Sjkim } 573280304Sjkim# if 0 574280304Sjkim } 575280304Sjkim# endif 576280304Sjkim break; 577280304Sjkim /* (Linux)kernel sets DF bit on outgoing IP packets */ 578280304Sjkim case BIO_CTRL_DGRAM_MTU_DISCOVER: 579280304Sjkim# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) 580280304Sjkim addr_len = (socklen_t) sizeof(addr); 581280304Sjkim memset((void *)&addr, 0, sizeof(addr)); 582280304Sjkim if (getsockname(b->num, &addr.sa, &addr_len) < 0) { 583280304Sjkim ret = 0; 584280304Sjkim break; 585280304Sjkim } 586280304Sjkim switch (addr.sa.sa_family) { 587280304Sjkim case AF_INET: 588280304Sjkim sockopt_val = IP_PMTUDISC_DO; 589280304Sjkim if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, 590280304Sjkim &sockopt_val, sizeof(sockopt_val))) < 0) 591280304Sjkim perror("setsockopt"); 592280304Sjkim break; 593280304Sjkim# if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) 594280304Sjkim case AF_INET6: 595280304Sjkim sockopt_val = IPV6_PMTUDISC_DO; 596280304Sjkim if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, 597280304Sjkim &sockopt_val, sizeof(sockopt_val))) < 0) 598280304Sjkim perror("setsockopt"); 599280304Sjkim break; 600280304Sjkim# endif 601280304Sjkim default: 602280304Sjkim ret = -1; 603280304Sjkim break; 604280304Sjkim } 605280304Sjkim ret = -1; 606280304Sjkim# else 607280304Sjkim break; 608280304Sjkim# endif 609280304Sjkim case BIO_CTRL_DGRAM_QUERY_MTU: 610280304Sjkim# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) 611280304Sjkim addr_len = (socklen_t) sizeof(addr); 612280304Sjkim memset((void *)&addr, 0, sizeof(addr)); 613280304Sjkim if (getsockname(b->num, &addr.sa, &addr_len) < 0) { 614280304Sjkim ret = 0; 615280304Sjkim break; 616280304Sjkim } 617280304Sjkim sockopt_len = sizeof(sockopt_val); 618280304Sjkim switch (addr.sa.sa_family) { 619280304Sjkim case AF_INET: 620280304Sjkim if ((ret = 621280304Sjkim getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, 622280304Sjkim &sockopt_len)) < 0 || sockopt_val < 0) { 623280304Sjkim ret = 0; 624280304Sjkim } else { 625280304Sjkim /* 626280304Sjkim * we assume that the transport protocol is UDP and no IP 627280304Sjkim * options are used. 628280304Sjkim */ 629280304Sjkim data->mtu = sockopt_val - 8 - 20; 630280304Sjkim ret = data->mtu; 631280304Sjkim } 632280304Sjkim break; 633280304Sjkim# if OPENSSL_USE_IPV6 && defined(IPV6_MTU) 634280304Sjkim case AF_INET6: 635280304Sjkim if ((ret = 636280304Sjkim getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, 637280304Sjkim (void *)&sockopt_val, &sockopt_len)) < 0 638280304Sjkim || sockopt_val < 0) { 639280304Sjkim ret = 0; 640280304Sjkim } else { 641280304Sjkim /* 642280304Sjkim * we assume that the transport protocol is UDP and no IPV6 643280304Sjkim * options are used. 644280304Sjkim */ 645280304Sjkim data->mtu = sockopt_val - 8 - 40; 646280304Sjkim ret = data->mtu; 647280304Sjkim } 648280304Sjkim break; 649280304Sjkim# endif 650280304Sjkim default: 651280304Sjkim ret = 0; 652280304Sjkim break; 653280304Sjkim } 654280304Sjkim# else 655280304Sjkim ret = 0; 656280304Sjkim# endif 657280304Sjkim break; 658280304Sjkim case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: 659280304Sjkim ret = -dgram_get_mtu_overhead(data); 660280304Sjkim switch (data->peer.sa.sa_family) { 661280304Sjkim case AF_INET: 662280304Sjkim ret += 576; 663280304Sjkim break; 664280304Sjkim# if OPENSSL_USE_IPV6 665280304Sjkim case AF_INET6: 666280304Sjkim# ifdef IN6_IS_ADDR_V4MAPPED 667280304Sjkim if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 668280304Sjkim ret += 576; 669280304Sjkim else 670280304Sjkim# endif 671280304Sjkim ret += 1280; 672280304Sjkim break; 673280304Sjkim# endif 674280304Sjkim default: 675280304Sjkim ret += 576; 676280304Sjkim break; 677280304Sjkim } 678280304Sjkim break; 679280304Sjkim case BIO_CTRL_DGRAM_GET_MTU: 680280304Sjkim return data->mtu; 681280304Sjkim break; 682280304Sjkim case BIO_CTRL_DGRAM_SET_MTU: 683280304Sjkim data->mtu = num; 684280304Sjkim ret = num; 685280304Sjkim break; 686280304Sjkim case BIO_CTRL_DGRAM_SET_CONNECTED: 687280304Sjkim to = (struct sockaddr *)ptr; 688160814Ssimon 689280304Sjkim if (to != NULL) { 690280304Sjkim data->connected = 1; 691280304Sjkim switch (to->sa_family) { 692280304Sjkim case AF_INET: 693280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in)); 694280304Sjkim break; 695280304Sjkim# if OPENSSL_USE_IPV6 696280304Sjkim case AF_INET6: 697280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); 698280304Sjkim break; 699280304Sjkim# endif 700280304Sjkim default: 701280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa)); 702280304Sjkim break; 703280304Sjkim } 704280304Sjkim } else { 705280304Sjkim data->connected = 0; 706280304Sjkim memset(&(data->peer), 0x00, sizeof(data->peer)); 707280304Sjkim } 708280304Sjkim break; 709280304Sjkim case BIO_CTRL_DGRAM_GET_PEER: 710280304Sjkim switch (data->peer.sa.sa_family) { 711280304Sjkim case AF_INET: 712280304Sjkim ret = sizeof(data->peer.sa_in); 713280304Sjkim break; 714280304Sjkim# if OPENSSL_USE_IPV6 715280304Sjkim case AF_INET6: 716280304Sjkim ret = sizeof(data->peer.sa_in6); 717280304Sjkim break; 718280304Sjkim# endif 719280304Sjkim default: 720280304Sjkim ret = sizeof(data->peer.sa); 721280304Sjkim break; 722280304Sjkim } 723280304Sjkim if (num == 0 || num > ret) 724280304Sjkim num = ret; 725280304Sjkim memcpy(ptr, &data->peer, (ret = num)); 726280304Sjkim break; 727280304Sjkim case BIO_CTRL_DGRAM_SET_PEER: 728280304Sjkim to = (struct sockaddr *)ptr; 729280304Sjkim switch (to->sa_family) { 730280304Sjkim case AF_INET: 731280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in)); 732280304Sjkim break; 733280304Sjkim# if OPENSSL_USE_IPV6 734280304Sjkim case AF_INET6: 735280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); 736280304Sjkim break; 737280304Sjkim# endif 738280304Sjkim default: 739280304Sjkim memcpy(&data->peer, to, sizeof(data->peer.sa)); 740280304Sjkim break; 741280304Sjkim } 742280304Sjkim break; 743280304Sjkim case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 744280304Sjkim memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); 745280304Sjkim break; 746280304Sjkim# if defined(SO_RCVTIMEO) 747280304Sjkim case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: 748280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 749280304Sjkim { 750280304Sjkim struct timeval *tv = (struct timeval *)ptr; 751280304Sjkim int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; 752280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 753280304Sjkim (void *)&timeout, sizeof(timeout)) < 0) { 754280304Sjkim perror("setsockopt"); 755280304Sjkim ret = -1; 756280304Sjkim } 757280304Sjkim } 758280304Sjkim# else 759280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, 760280304Sjkim sizeof(struct timeval)) < 0) { 761280304Sjkim perror("setsockopt"); 762280304Sjkim ret = -1; 763280304Sjkim } 764280304Sjkim# endif 765280304Sjkim break; 766280304Sjkim case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: 767280304Sjkim { 768280304Sjkim union { 769280304Sjkim size_t s; 770280304Sjkim int i; 771280304Sjkim } sz = { 772280304Sjkim 0 773280304Sjkim }; 774280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 775280304Sjkim int timeout; 776280304Sjkim struct timeval *tv = (struct timeval *)ptr; 777246772Sjkim 778280304Sjkim sz.i = sizeof(timeout); 779280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 780280304Sjkim (void *)&timeout, &sz.i) < 0) { 781280304Sjkim perror("getsockopt"); 782280304Sjkim ret = -1; 783280304Sjkim } else { 784280304Sjkim tv->tv_sec = timeout / 1000; 785280304Sjkim tv->tv_usec = (timeout % 1000) * 1000; 786280304Sjkim ret = sizeof(*tv); 787280304Sjkim } 788280304Sjkim# else 789280304Sjkim sz.i = sizeof(struct timeval); 790280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 791280304Sjkim ptr, (void *)&sz) < 0) { 792280304Sjkim perror("getsockopt"); 793280304Sjkim ret = -1; 794280304Sjkim } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { 795280304Sjkim OPENSSL_assert(sz.s <= sizeof(struct timeval)); 796280304Sjkim ret = (int)sz.s; 797280304Sjkim } else 798280304Sjkim ret = sz.i; 799280304Sjkim# endif 800280304Sjkim } 801280304Sjkim break; 802280304Sjkim# endif 803280304Sjkim# if defined(SO_SNDTIMEO) 804280304Sjkim case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: 805280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 806280304Sjkim { 807280304Sjkim struct timeval *tv = (struct timeval *)ptr; 808280304Sjkim int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; 809280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 810280304Sjkim (void *)&timeout, sizeof(timeout)) < 0) { 811280304Sjkim perror("setsockopt"); 812280304Sjkim ret = -1; 813280304Sjkim } 814280304Sjkim } 815280304Sjkim# else 816280304Sjkim if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, 817280304Sjkim sizeof(struct timeval)) < 0) { 818280304Sjkim perror("setsockopt"); 819280304Sjkim ret = -1; 820280304Sjkim } 821280304Sjkim# endif 822280304Sjkim break; 823280304Sjkim case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: 824280304Sjkim { 825280304Sjkim union { 826280304Sjkim size_t s; 827280304Sjkim int i; 828280304Sjkim } sz = { 829280304Sjkim 0 830280304Sjkim }; 831280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 832280304Sjkim int timeout; 833280304Sjkim struct timeval *tv = (struct timeval *)ptr; 834246772Sjkim 835280304Sjkim sz.i = sizeof(timeout); 836280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 837280304Sjkim (void *)&timeout, &sz.i) < 0) { 838280304Sjkim perror("getsockopt"); 839280304Sjkim ret = -1; 840280304Sjkim } else { 841280304Sjkim tv->tv_sec = timeout / 1000; 842280304Sjkim tv->tv_usec = (timeout % 1000) * 1000; 843280304Sjkim ret = sizeof(*tv); 844280304Sjkim } 845280304Sjkim# else 846280304Sjkim sz.i = sizeof(struct timeval); 847280304Sjkim if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 848280304Sjkim ptr, (void *)&sz) < 0) { 849280304Sjkim perror("getsockopt"); 850280304Sjkim ret = -1; 851280304Sjkim } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { 852280304Sjkim OPENSSL_assert(sz.s <= sizeof(struct timeval)); 853280304Sjkim ret = (int)sz.s; 854280304Sjkim } else 855280304Sjkim ret = sz.i; 856280304Sjkim# endif 857280304Sjkim } 858280304Sjkim break; 859280304Sjkim# endif 860280304Sjkim case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: 861280304Sjkim /* fall-through */ 862280304Sjkim case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: 863280304Sjkim# ifdef OPENSSL_SYS_WINDOWS 864280304Sjkim if (data->_errno == WSAETIMEDOUT) 865280304Sjkim# else 866280304Sjkim if (data->_errno == EAGAIN) 867280304Sjkim# endif 868280304Sjkim { 869280304Sjkim ret = 1; 870280304Sjkim data->_errno = 0; 871280304Sjkim } else 872280304Sjkim ret = 0; 873280304Sjkim break; 874280304Sjkim# ifdef EMSGSIZE 875280304Sjkim case BIO_CTRL_DGRAM_MTU_EXCEEDED: 876280304Sjkim if (data->_errno == EMSGSIZE) { 877280304Sjkim ret = 1; 878280304Sjkim data->_errno = 0; 879280304Sjkim } else 880280304Sjkim ret = 0; 881280304Sjkim break; 882280304Sjkim# endif 883280304Sjkim case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 884280304Sjkim ret = dgram_get_mtu_overhead(data); 885280304Sjkim break; 886280304Sjkim default: 887280304Sjkim ret = 0; 888280304Sjkim break; 889280304Sjkim } 890280304Sjkim return (ret); 891280304Sjkim} 892160814Ssimon 893160814Ssimonstatic int dgram_puts(BIO *bp, const char *str) 894280304Sjkim{ 895280304Sjkim int n, ret; 896160814Ssimon 897280304Sjkim n = strlen(str); 898280304Sjkim ret = dgram_write(bp, str, n); 899280304Sjkim return (ret); 900280304Sjkim} 901160814Ssimon 902280304Sjkim# ifndef OPENSSL_NO_SCTP 903238405SjkimBIO_METHOD *BIO_s_datagram_sctp(void) 904280304Sjkim{ 905280304Sjkim return (&methods_dgramp_sctp); 906280304Sjkim} 907238405Sjkim 908238405SjkimBIO *BIO_new_dgram_sctp(int fd, int close_flag) 909280304Sjkim{ 910280304Sjkim BIO *bio; 911280304Sjkim int ret, optval = 20000; 912280304Sjkim int auth_data = 0, auth_forward = 0; 913280304Sjkim unsigned char *p; 914280304Sjkim struct sctp_authchunk auth; 915280304Sjkim struct sctp_authchunks *authchunks; 916280304Sjkim socklen_t sockopt_len; 917280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 918280304Sjkim# ifdef SCTP_EVENT 919280304Sjkim struct sctp_event event; 920280304Sjkim# else 921280304Sjkim struct sctp_event_subscribe event; 922280304Sjkim# endif 923280304Sjkim# endif 924238405Sjkim 925280304Sjkim bio = BIO_new(BIO_s_datagram_sctp()); 926280304Sjkim if (bio == NULL) 927280304Sjkim return (NULL); 928280304Sjkim BIO_set_fd(bio, fd, close_flag); 929238405Sjkim 930280304Sjkim /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ 931280304Sjkim auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; 932280304Sjkim ret = 933280304Sjkim setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, 934280304Sjkim sizeof(struct sctp_authchunk)); 935280304Sjkim if (ret < 0) { 936280304Sjkim BIO_vfree(bio); 937280304Sjkim return (NULL); 938280304Sjkim } 939280304Sjkim auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; 940280304Sjkim ret = 941280304Sjkim setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, 942280304Sjkim sizeof(struct sctp_authchunk)); 943280304Sjkim if (ret < 0) { 944280304Sjkim BIO_vfree(bio); 945280304Sjkim return (NULL); 946280304Sjkim } 947238405Sjkim 948280304Sjkim /* 949280304Sjkim * Test if activation was successful. When using accept(), SCTP-AUTH has 950280304Sjkim * to be activated for the listening socket already, otherwise the 951280304Sjkim * connected socket won't use it. 952280304Sjkim */ 953280304Sjkim sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); 954280304Sjkim authchunks = OPENSSL_malloc(sockopt_len); 955284285Sjkim if (!authchunks) { 956280304Sjkim BIO_vfree(bio); 957280304Sjkim return (NULL); 958280304Sjkim } 959280304Sjkim memset(authchunks, 0, sizeof(sockopt_len)); 960280304Sjkim ret = 961280304Sjkim getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, 962280304Sjkim &sockopt_len); 963264331Sjkim 964280304Sjkim if (ret < 0) { 965280304Sjkim OPENSSL_free(authchunks); 966280304Sjkim BIO_vfree(bio); 967280304Sjkim return (NULL); 968280304Sjkim } 969276864Sjkim 970280304Sjkim for (p = (unsigned char *)authchunks->gauth_chunks; 971280304Sjkim p < (unsigned char *)authchunks + sockopt_len; 972280304Sjkim p += sizeof(uint8_t)) { 973280304Sjkim if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) 974280304Sjkim auth_data = 1; 975280304Sjkim if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) 976280304Sjkim auth_forward = 1; 977280304Sjkim } 978238405Sjkim 979280304Sjkim OPENSSL_free(authchunks); 980238405Sjkim 981280304Sjkim OPENSSL_assert(auth_data); 982280304Sjkim OPENSSL_assert(auth_forward); 983238405Sjkim 984280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 985280304Sjkim# ifdef SCTP_EVENT 986280304Sjkim memset(&event, 0, sizeof(struct sctp_event)); 987280304Sjkim event.se_assoc_id = 0; 988280304Sjkim event.se_type = SCTP_AUTHENTICATION_EVENT; 989280304Sjkim event.se_on = 1; 990280304Sjkim ret = 991280304Sjkim setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, 992280304Sjkim sizeof(struct sctp_event)); 993280304Sjkim if (ret < 0) { 994280304Sjkim BIO_vfree(bio); 995280304Sjkim return (NULL); 996280304Sjkim } 997280304Sjkim# else 998280304Sjkim sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); 999280304Sjkim ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); 1000280304Sjkim if (ret < 0) { 1001280304Sjkim BIO_vfree(bio); 1002280304Sjkim return (NULL); 1003280304Sjkim } 1004238405Sjkim 1005280304Sjkim event.sctp_authentication_event = 1; 1006238405Sjkim 1007280304Sjkim ret = 1008280304Sjkim setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, 1009280304Sjkim sizeof(struct sctp_event_subscribe)); 1010280304Sjkim if (ret < 0) { 1011280304Sjkim BIO_vfree(bio); 1012280304Sjkim return (NULL); 1013280304Sjkim } 1014280304Sjkim# endif 1015280304Sjkim# endif 1016238405Sjkim 1017280304Sjkim /* 1018280304Sjkim * Disable partial delivery by setting the min size larger than the max 1019280304Sjkim * record size of 2^14 + 2048 + 13 1020280304Sjkim */ 1021280304Sjkim ret = 1022280304Sjkim setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, 1023280304Sjkim sizeof(optval)); 1024280304Sjkim if (ret < 0) { 1025280304Sjkim BIO_vfree(bio); 1026280304Sjkim return (NULL); 1027280304Sjkim } 1028238405Sjkim 1029280304Sjkim return (bio); 1030280304Sjkim} 1031280304Sjkim 1032238405Sjkimint BIO_dgram_is_sctp(BIO *bio) 1033280304Sjkim{ 1034280304Sjkim return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); 1035280304Sjkim} 1036238405Sjkim 1037238405Sjkimstatic int dgram_sctp_new(BIO *bi) 1038280304Sjkim{ 1039280304Sjkim bio_dgram_sctp_data *data = NULL; 1040238405Sjkim 1041280304Sjkim bi->init = 0; 1042280304Sjkim bi->num = 0; 1043280304Sjkim data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data)); 1044280304Sjkim if (data == NULL) 1045280304Sjkim return 0; 1046280304Sjkim memset(data, 0x00, sizeof(bio_dgram_sctp_data)); 1047280304Sjkim# ifdef SCTP_PR_SCTP_NONE 1048280304Sjkim data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; 1049280304Sjkim# endif 1050238405Sjkim bi->ptr = data; 1051238405Sjkim 1052280304Sjkim bi->flags = 0; 1053280304Sjkim return (1); 1054280304Sjkim} 1055238405Sjkim 1056238405Sjkimstatic int dgram_sctp_free(BIO *a) 1057280304Sjkim{ 1058280304Sjkim bio_dgram_sctp_data *data; 1059238405Sjkim 1060280304Sjkim if (a == NULL) 1061280304Sjkim return (0); 1062280304Sjkim if (!dgram_clear(a)) 1063280304Sjkim return 0; 1064238405Sjkim 1065280304Sjkim data = (bio_dgram_sctp_data *) a->ptr; 1066280304Sjkim if (data != NULL) { 1067280304Sjkim if (data->saved_message.data != NULL) 1068280304Sjkim OPENSSL_free(data->saved_message.data); 1069280304Sjkim OPENSSL_free(data); 1070280304Sjkim } 1071238405Sjkim 1072280304Sjkim return (1); 1073280304Sjkim} 1074238405Sjkim 1075280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 1076280304Sjkimvoid dgram_sctp_handle_auth_free_key_event(BIO *b, 1077280304Sjkim union sctp_notification *snp) 1078280304Sjkim{ 1079280304Sjkim int ret; 1080280304Sjkim struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event; 1081238405Sjkim 1082280304Sjkim if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) { 1083280304Sjkim struct sctp_authkeyid authkeyid; 1084238405Sjkim 1085280304Sjkim /* delete key */ 1086280304Sjkim authkeyid.scact_keynumber = authkeyevent->auth_keynumber; 1087280304Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, 1088280304Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1089280304Sjkim } 1090280304Sjkim} 1091280304Sjkim# endif 1092238405Sjkim 1093238405Sjkimstatic int dgram_sctp_read(BIO *b, char *out, int outl) 1094280304Sjkim{ 1095280304Sjkim int ret = 0, n = 0, i, optval; 1096280304Sjkim socklen_t optlen; 1097280304Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1098280304Sjkim union sctp_notification *snp; 1099280304Sjkim struct msghdr msg; 1100280304Sjkim struct iovec iov; 1101280304Sjkim struct cmsghdr *cmsg; 1102280304Sjkim char cmsgbuf[512]; 1103238405Sjkim 1104280304Sjkim if (out != NULL) { 1105280304Sjkim clear_socket_error(); 1106238405Sjkim 1107280304Sjkim do { 1108280304Sjkim memset(&data->rcvinfo, 0x00, 1109280304Sjkim sizeof(struct bio_dgram_sctp_rcvinfo)); 1110280304Sjkim iov.iov_base = out; 1111280304Sjkim iov.iov_len = outl; 1112280304Sjkim msg.msg_name = NULL; 1113280304Sjkim msg.msg_namelen = 0; 1114280304Sjkim msg.msg_iov = &iov; 1115280304Sjkim msg.msg_iovlen = 1; 1116280304Sjkim msg.msg_control = cmsgbuf; 1117280304Sjkim msg.msg_controllen = 512; 1118280304Sjkim msg.msg_flags = 0; 1119280304Sjkim n = recvmsg(b->num, &msg, 0); 1120238405Sjkim 1121280304Sjkim if (n <= 0) { 1122280304Sjkim if (n < 0) 1123280304Sjkim ret = n; 1124280304Sjkim break; 1125280304Sjkim } 1126276864Sjkim 1127280304Sjkim if (msg.msg_controllen > 0) { 1128280304Sjkim for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; 1129280304Sjkim cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1130280304Sjkim if (cmsg->cmsg_level != IPPROTO_SCTP) 1131280304Sjkim continue; 1132280304Sjkim# ifdef SCTP_RCVINFO 1133280304Sjkim if (cmsg->cmsg_type == SCTP_RCVINFO) { 1134280304Sjkim struct sctp_rcvinfo *rcvinfo; 1135238405Sjkim 1136280304Sjkim rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 1137280304Sjkim data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; 1138280304Sjkim data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; 1139280304Sjkim data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; 1140280304Sjkim data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; 1141280304Sjkim data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; 1142280304Sjkim data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; 1143280304Sjkim data->rcvinfo.rcv_context = rcvinfo->rcv_context; 1144280304Sjkim } 1145280304Sjkim# endif 1146280304Sjkim# ifdef SCTP_SNDRCV 1147280304Sjkim if (cmsg->cmsg_type == SCTP_SNDRCV) { 1148280304Sjkim struct sctp_sndrcvinfo *sndrcvinfo; 1149238405Sjkim 1150280304Sjkim sndrcvinfo = 1151280304Sjkim (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 1152280304Sjkim data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; 1153280304Sjkim data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; 1154280304Sjkim data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; 1155280304Sjkim data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; 1156280304Sjkim data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; 1157280304Sjkim data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; 1158280304Sjkim data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; 1159280304Sjkim } 1160280304Sjkim# endif 1161280304Sjkim } 1162280304Sjkim } 1163238405Sjkim 1164280304Sjkim if (msg.msg_flags & MSG_NOTIFICATION) { 1165280304Sjkim snp = (union sctp_notification *)out; 1166280304Sjkim if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { 1167280304Sjkim# ifdef SCTP_EVENT 1168280304Sjkim struct sctp_event event; 1169280304Sjkim# else 1170280304Sjkim struct sctp_event_subscribe event; 1171280304Sjkim socklen_t eventsize; 1172280304Sjkim# endif 1173280304Sjkim /* 1174280304Sjkim * If a message has been delayed until the socket is dry, 1175280304Sjkim * it can be sent now. 1176280304Sjkim */ 1177280304Sjkim if (data->saved_message.length > 0) { 1178280304Sjkim dgram_sctp_write(data->saved_message.bio, 1179280304Sjkim data->saved_message.data, 1180280304Sjkim data->saved_message.length); 1181280304Sjkim OPENSSL_free(data->saved_message.data); 1182280304Sjkim data->saved_message.data = NULL; 1183280304Sjkim data->saved_message.length = 0; 1184280304Sjkim } 1185238405Sjkim 1186280304Sjkim /* disable sender dry event */ 1187280304Sjkim# ifdef SCTP_EVENT 1188280304Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1189280304Sjkim event.se_assoc_id = 0; 1190280304Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1191280304Sjkim event.se_on = 0; 1192280304Sjkim i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, 1193280304Sjkim sizeof(struct sctp_event)); 1194280304Sjkim if (i < 0) { 1195280304Sjkim ret = i; 1196280304Sjkim break; 1197280304Sjkim } 1198280304Sjkim# else 1199280304Sjkim eventsize = sizeof(struct sctp_event_subscribe); 1200280304Sjkim i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, 1201280304Sjkim &eventsize); 1202280304Sjkim if (i < 0) { 1203280304Sjkim ret = i; 1204280304Sjkim break; 1205280304Sjkim } 1206238405Sjkim 1207280304Sjkim event.sctp_sender_dry_event = 0; 1208238405Sjkim 1209280304Sjkim i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, 1210280304Sjkim sizeof(struct sctp_event_subscribe)); 1211280304Sjkim if (i < 0) { 1212280304Sjkim ret = i; 1213280304Sjkim break; 1214280304Sjkim } 1215280304Sjkim# endif 1216280304Sjkim } 1217280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 1218280304Sjkim if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1219280304Sjkim dgram_sctp_handle_auth_free_key_event(b, snp); 1220280304Sjkim# endif 1221238405Sjkim 1222280304Sjkim if (data->handle_notifications != NULL) 1223280304Sjkim data->handle_notifications(b, data->notification_context, 1224280304Sjkim (void *)out); 1225238405Sjkim 1226280304Sjkim memset(out, 0, outl); 1227280304Sjkim } else 1228280304Sjkim ret += n; 1229280304Sjkim } 1230280304Sjkim while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) 1231280304Sjkim && (ret < outl)); 1232238405Sjkim 1233280304Sjkim if (ret > 0 && !(msg.msg_flags & MSG_EOR)) { 1234280304Sjkim /* Partial message read, this should never happen! */ 1235238405Sjkim 1236280304Sjkim /* 1237280304Sjkim * The buffer was too small, this means the peer sent a message 1238280304Sjkim * that was larger than allowed. 1239280304Sjkim */ 1240280304Sjkim if (ret == outl) 1241280304Sjkim return -1; 1242238405Sjkim 1243280304Sjkim /* 1244280304Sjkim * Test if socket buffer can handle max record size (2^14 + 2048 1245280304Sjkim * + 13) 1246280304Sjkim */ 1247280304Sjkim optlen = (socklen_t) sizeof(int); 1248280304Sjkim ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); 1249280304Sjkim if (ret >= 0) 1250280304Sjkim OPENSSL_assert(optval >= 18445); 1251238405Sjkim 1252280304Sjkim /* 1253280304Sjkim * Test if SCTP doesn't partially deliver below max record size 1254280304Sjkim * (2^14 + 2048 + 13) 1255280304Sjkim */ 1256280304Sjkim optlen = (socklen_t) sizeof(int); 1257280304Sjkim ret = 1258280304Sjkim getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, 1259280304Sjkim &optval, &optlen); 1260280304Sjkim if (ret >= 0) 1261280304Sjkim OPENSSL_assert(optval >= 18445); 1262238405Sjkim 1263280304Sjkim /* 1264280304Sjkim * Partially delivered notification??? Probably a bug.... 1265280304Sjkim */ 1266280304Sjkim OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); 1267238405Sjkim 1268280304Sjkim /* 1269280304Sjkim * Everything seems ok till now, so it's most likely a message 1270280304Sjkim * dropped by PR-SCTP. 1271280304Sjkim */ 1272280304Sjkim memset(out, 0, outl); 1273280304Sjkim BIO_set_retry_read(b); 1274280304Sjkim return -1; 1275280304Sjkim } 1276238405Sjkim 1277280304Sjkim BIO_clear_retry_flags(b); 1278280304Sjkim if (ret < 0) { 1279280304Sjkim if (BIO_dgram_should_retry(ret)) { 1280280304Sjkim BIO_set_retry_read(b); 1281280304Sjkim data->_errno = get_last_socket_error(); 1282280304Sjkim } 1283280304Sjkim } 1284238405Sjkim 1285280304Sjkim /* Test if peer uses SCTP-AUTH before continuing */ 1286280304Sjkim if (!data->peer_auth_tested) { 1287280304Sjkim int ii, auth_data = 0, auth_forward = 0; 1288280304Sjkim unsigned char *p; 1289280304Sjkim struct sctp_authchunks *authchunks; 1290238405Sjkim 1291280304Sjkim optlen = 1292280304Sjkim (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); 1293280304Sjkim authchunks = OPENSSL_malloc(optlen); 1294280304Sjkim if (!authchunks) { 1295284285Sjkim BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE); 1296280304Sjkim return -1; 1297280304Sjkim } 1298280304Sjkim memset(authchunks, 0, sizeof(optlen)); 1299280304Sjkim ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, 1300280304Sjkim authchunks, &optlen); 1301238405Sjkim 1302280304Sjkim if (ii >= 0) 1303280304Sjkim for (p = (unsigned char *)authchunks->gauth_chunks; 1304280304Sjkim p < (unsigned char *)authchunks + optlen; 1305280304Sjkim p += sizeof(uint8_t)) { 1306280304Sjkim if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) 1307280304Sjkim auth_data = 1; 1308280304Sjkim if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) 1309280304Sjkim auth_forward = 1; 1310280304Sjkim } 1311238405Sjkim 1312280304Sjkim OPENSSL_free(authchunks); 1313238405Sjkim 1314280304Sjkim if (!auth_data || !auth_forward) { 1315280304Sjkim BIOerr(BIO_F_DGRAM_SCTP_READ, BIO_R_CONNECT_ERROR); 1316280304Sjkim return -1; 1317280304Sjkim } 1318238405Sjkim 1319280304Sjkim data->peer_auth_tested = 1; 1320280304Sjkim } 1321280304Sjkim } 1322280304Sjkim return (ret); 1323280304Sjkim} 1324238405Sjkim 1325238405Sjkimstatic int dgram_sctp_write(BIO *b, const char *in, int inl) 1326280304Sjkim{ 1327280304Sjkim int ret; 1328280304Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1329280304Sjkim struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); 1330280304Sjkim struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); 1331280304Sjkim struct bio_dgram_sctp_sndinfo handshake_sinfo; 1332280304Sjkim struct iovec iov[1]; 1333280304Sjkim struct msghdr msg; 1334280304Sjkim struct cmsghdr *cmsg; 1335280304Sjkim# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) 1336280304Sjkim char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + 1337280304Sjkim CMSG_SPACE(sizeof(struct sctp_prinfo))]; 1338280304Sjkim struct sctp_sndinfo *sndinfo; 1339280304Sjkim struct sctp_prinfo *prinfo; 1340280304Sjkim# else 1341280304Sjkim char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 1342280304Sjkim struct sctp_sndrcvinfo *sndrcvinfo; 1343280304Sjkim# endif 1344238405Sjkim 1345280304Sjkim clear_socket_error(); 1346238405Sjkim 1347280304Sjkim /* 1348280304Sjkim * If we're send anything else than application data, disable all user 1349280304Sjkim * parameters and flags. 1350280304Sjkim */ 1351280304Sjkim if (in[0] != 23) { 1352280304Sjkim memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo)); 1353280304Sjkim# ifdef SCTP_SACK_IMMEDIATELY 1354280304Sjkim handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; 1355280304Sjkim# endif 1356280304Sjkim sinfo = &handshake_sinfo; 1357280304Sjkim } 1358238405Sjkim 1359280304Sjkim /* 1360280304Sjkim * If we have to send a shutdown alert message and the socket is not dry 1361280304Sjkim * yet, we have to save it and send it as soon as the socket gets dry. 1362280304Sjkim */ 1363280304Sjkim if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) { 1364280304Sjkim char *tmp; 1365280304Sjkim data->saved_message.bio = b; 1366284285Sjkim if (!(tmp = OPENSSL_malloc(inl))) { 1367284285Sjkim BIOerr(BIO_F_DGRAM_SCTP_WRITE, ERR_R_MALLOC_FAILURE); 1368280304Sjkim return -1; 1369280304Sjkim } 1370280304Sjkim if (data->saved_message.data) 1371280304Sjkim OPENSSL_free(data->saved_message.data); 1372280304Sjkim data->saved_message.data = tmp; 1373280304Sjkim memcpy(data->saved_message.data, in, inl); 1374280304Sjkim data->saved_message.length = inl; 1375280304Sjkim return inl; 1376280304Sjkim } 1377238405Sjkim 1378280304Sjkim iov[0].iov_base = (char *)in; 1379280304Sjkim iov[0].iov_len = inl; 1380280304Sjkim msg.msg_name = NULL; 1381280304Sjkim msg.msg_namelen = 0; 1382280304Sjkim msg.msg_iov = iov; 1383280304Sjkim msg.msg_iovlen = 1; 1384280304Sjkim msg.msg_control = (caddr_t) cmsgbuf; 1385280304Sjkim msg.msg_controllen = 0; 1386280304Sjkim msg.msg_flags = 0; 1387280304Sjkim# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) 1388280304Sjkim cmsg = (struct cmsghdr *)cmsgbuf; 1389280304Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1390280304Sjkim cmsg->cmsg_type = SCTP_SNDINFO; 1391280304Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1392280304Sjkim sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); 1393280304Sjkim memset(sndinfo, 0, sizeof(struct sctp_sndinfo)); 1394280304Sjkim sndinfo->snd_sid = sinfo->snd_sid; 1395280304Sjkim sndinfo->snd_flags = sinfo->snd_flags; 1396280304Sjkim sndinfo->snd_ppid = sinfo->snd_ppid; 1397280304Sjkim sndinfo->snd_context = sinfo->snd_context; 1398280304Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1399238405Sjkim 1400280304Sjkim cmsg = 1401280304Sjkim (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; 1402280304Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1403280304Sjkim cmsg->cmsg_type = SCTP_PRINFO; 1404280304Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1405280304Sjkim prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); 1406280304Sjkim memset(prinfo, 0, sizeof(struct sctp_prinfo)); 1407280304Sjkim prinfo->pr_policy = pinfo->pr_policy; 1408280304Sjkim prinfo->pr_value = pinfo->pr_value; 1409280304Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1410280304Sjkim# else 1411280304Sjkim cmsg = (struct cmsghdr *)cmsgbuf; 1412280304Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1413280304Sjkim cmsg->cmsg_type = SCTP_SNDRCV; 1414280304Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 1415280304Sjkim sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 1416280304Sjkim memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); 1417280304Sjkim sndrcvinfo->sinfo_stream = sinfo->snd_sid; 1418280304Sjkim sndrcvinfo->sinfo_flags = sinfo->snd_flags; 1419280304Sjkim# ifdef __FreeBSD__ 1420280304Sjkim sndrcvinfo->sinfo_flags |= pinfo->pr_policy; 1421280304Sjkim# endif 1422280304Sjkim sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; 1423280304Sjkim sndrcvinfo->sinfo_context = sinfo->snd_context; 1424280304Sjkim sndrcvinfo->sinfo_timetolive = pinfo->pr_value; 1425280304Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 1426280304Sjkim# endif 1427238405Sjkim 1428280304Sjkim ret = sendmsg(b->num, &msg, 0); 1429238405Sjkim 1430280304Sjkim BIO_clear_retry_flags(b); 1431280304Sjkim if (ret <= 0) { 1432280304Sjkim if (BIO_dgram_should_retry(ret)) { 1433280304Sjkim BIO_set_retry_write(b); 1434280304Sjkim data->_errno = get_last_socket_error(); 1435280304Sjkim } 1436280304Sjkim } 1437280304Sjkim return (ret); 1438280304Sjkim} 1439238405Sjkim 1440238405Sjkimstatic long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) 1441280304Sjkim{ 1442280304Sjkim long ret = 1; 1443280304Sjkim bio_dgram_sctp_data *data = NULL; 1444280304Sjkim socklen_t sockopt_len = 0; 1445280304Sjkim struct sctp_authkeyid authkeyid; 1446280304Sjkim struct sctp_authkey *authkey = NULL; 1447238405Sjkim 1448280304Sjkim data = (bio_dgram_sctp_data *) b->ptr; 1449238405Sjkim 1450280304Sjkim switch (cmd) { 1451280304Sjkim case BIO_CTRL_DGRAM_QUERY_MTU: 1452280304Sjkim /* 1453280304Sjkim * Set to maximum (2^14) and ignore user input to enable transport 1454280304Sjkim * protocol fragmentation. Returns always 2^14. 1455280304Sjkim */ 1456280304Sjkim data->mtu = 16384; 1457280304Sjkim ret = data->mtu; 1458280304Sjkim break; 1459280304Sjkim case BIO_CTRL_DGRAM_SET_MTU: 1460280304Sjkim /* 1461280304Sjkim * Set to maximum (2^14) and ignore input to enable transport 1462280304Sjkim * protocol fragmentation. Returns always 2^14. 1463280304Sjkim */ 1464280304Sjkim data->mtu = 16384; 1465280304Sjkim ret = data->mtu; 1466280304Sjkim break; 1467280304Sjkim case BIO_CTRL_DGRAM_SET_CONNECTED: 1468280304Sjkim case BIO_CTRL_DGRAM_CONNECT: 1469280304Sjkim /* Returns always -1. */ 1470280304Sjkim ret = -1; 1471280304Sjkim break; 1472280304Sjkim case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 1473280304Sjkim /* 1474280304Sjkim * SCTP doesn't need the DTLS timer Returns always 1. 1475280304Sjkim */ 1476280304Sjkim break; 1477280304Sjkim case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 1478280304Sjkim /* 1479280304Sjkim * We allow transport protocol fragmentation so this is irrelevant 1480280304Sjkim */ 1481280304Sjkim ret = 0; 1482280304Sjkim break; 1483280304Sjkim case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: 1484280304Sjkim if (num > 0) 1485280304Sjkim data->in_handshake = 1; 1486280304Sjkim else 1487280304Sjkim data->in_handshake = 0; 1488238405Sjkim 1489280304Sjkim ret = 1490280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, 1491280304Sjkim &data->in_handshake, sizeof(int)); 1492280304Sjkim break; 1493280304Sjkim case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: 1494280304Sjkim /* 1495280304Sjkim * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise. 1496280304Sjkim */ 1497238405Sjkim 1498280304Sjkim /* Get active key */ 1499280304Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1500280304Sjkim ret = 1501280304Sjkim getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, 1502280304Sjkim &sockopt_len); 1503280304Sjkim if (ret < 0) 1504280304Sjkim break; 1505238405Sjkim 1506280304Sjkim /* Add new key */ 1507280304Sjkim sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); 1508280304Sjkim authkey = OPENSSL_malloc(sockopt_len); 1509280304Sjkim if (authkey == NULL) { 1510280304Sjkim ret = -1; 1511280304Sjkim break; 1512280304Sjkim } 1513280304Sjkim memset(authkey, 0x00, sockopt_len); 1514280304Sjkim authkey->sca_keynumber = authkeyid.scact_keynumber + 1; 1515280304Sjkim# ifndef __FreeBSD__ 1516280304Sjkim /* 1517280304Sjkim * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3 1518280304Sjkim * and higher work without it. 1519280304Sjkim */ 1520280304Sjkim authkey->sca_keylength = 64; 1521280304Sjkim# endif 1522280304Sjkim memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); 1523238405Sjkim 1524280304Sjkim ret = 1525280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, 1526280304Sjkim sockopt_len); 1527280304Sjkim OPENSSL_free(authkey); 1528280304Sjkim authkey = NULL; 1529280304Sjkim if (ret < 0) 1530280304Sjkim break; 1531238405Sjkim 1532280304Sjkim /* Reset active key */ 1533280304Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, 1534280304Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1535280304Sjkim if (ret < 0) 1536280304Sjkim break; 1537238405Sjkim 1538280304Sjkim break; 1539280304Sjkim case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: 1540280304Sjkim /* Returns 0 on success, -1 otherwise. */ 1541238405Sjkim 1542280304Sjkim /* Get active key */ 1543280304Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1544280304Sjkim ret = 1545280304Sjkim getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, 1546280304Sjkim &sockopt_len); 1547280304Sjkim if (ret < 0) 1548280304Sjkim break; 1549238405Sjkim 1550280304Sjkim /* Set active key */ 1551280304Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; 1552280304Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, 1553280304Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1554280304Sjkim if (ret < 0) 1555280304Sjkim break; 1556238405Sjkim 1557280304Sjkim /* 1558280304Sjkim * CCS has been sent, so remember that and fall through to check if 1559280304Sjkim * we need to deactivate an old key 1560280304Sjkim */ 1561280304Sjkim data->ccs_sent = 1; 1562238405Sjkim 1563280304Sjkim case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: 1564280304Sjkim /* Returns 0 on success, -1 otherwise. */ 1565238405Sjkim 1566280304Sjkim /* 1567280304Sjkim * Has this command really been called or is this just a 1568280304Sjkim * fall-through? 1569280304Sjkim */ 1570280304Sjkim if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) 1571280304Sjkim data->ccs_rcvd = 1; 1572238405Sjkim 1573280304Sjkim /* 1574280304Sjkim * CSS has been both, received and sent, so deactivate an old key 1575280304Sjkim */ 1576280304Sjkim if (data->ccs_rcvd == 1 && data->ccs_sent == 1) { 1577280304Sjkim /* Get active key */ 1578280304Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1579280304Sjkim ret = 1580280304Sjkim getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, 1581280304Sjkim &authkeyid, &sockopt_len); 1582280304Sjkim if (ret < 0) 1583280304Sjkim break; 1584238405Sjkim 1585280304Sjkim /* 1586280304Sjkim * Deactivate key or delete second last key if 1587280304Sjkim * SCTP_AUTHENTICATION_EVENT is not available. 1588280304Sjkim */ 1589280304Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; 1590280304Sjkim# ifdef SCTP_AUTH_DEACTIVATE_KEY 1591280304Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1592280304Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, 1593280304Sjkim &authkeyid, sockopt_len); 1594280304Sjkim if (ret < 0) 1595280304Sjkim break; 1596280304Sjkim# endif 1597280304Sjkim# ifndef SCTP_AUTHENTICATION_EVENT 1598280304Sjkim if (authkeyid.scact_keynumber > 0) { 1599280304Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; 1600280304Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, 1601280304Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1602280304Sjkim if (ret < 0) 1603280304Sjkim break; 1604280304Sjkim } 1605280304Sjkim# endif 1606238405Sjkim 1607280304Sjkim data->ccs_rcvd = 0; 1608280304Sjkim data->ccs_sent = 0; 1609280304Sjkim } 1610280304Sjkim break; 1611280304Sjkim case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: 1612280304Sjkim /* Returns the size of the copied struct. */ 1613280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) 1614280304Sjkim num = sizeof(struct bio_dgram_sctp_sndinfo); 1615238405Sjkim 1616280304Sjkim memcpy(ptr, &(data->sndinfo), num); 1617280304Sjkim ret = num; 1618280304Sjkim break; 1619280304Sjkim case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: 1620280304Sjkim /* Returns the size of the copied struct. */ 1621280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) 1622280304Sjkim num = sizeof(struct bio_dgram_sctp_sndinfo); 1623238405Sjkim 1624280304Sjkim memcpy(&(data->sndinfo), ptr, num); 1625280304Sjkim break; 1626280304Sjkim case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: 1627280304Sjkim /* Returns the size of the copied struct. */ 1628280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) 1629280304Sjkim num = sizeof(struct bio_dgram_sctp_rcvinfo); 1630238405Sjkim 1631280304Sjkim memcpy(ptr, &data->rcvinfo, num); 1632238405Sjkim 1633280304Sjkim ret = num; 1634280304Sjkim break; 1635280304Sjkim case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: 1636280304Sjkim /* Returns the size of the copied struct. */ 1637280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) 1638280304Sjkim num = sizeof(struct bio_dgram_sctp_rcvinfo); 1639238405Sjkim 1640280304Sjkim memcpy(&(data->rcvinfo), ptr, num); 1641280304Sjkim break; 1642280304Sjkim case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: 1643280304Sjkim /* Returns the size of the copied struct. */ 1644280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) 1645280304Sjkim num = sizeof(struct bio_dgram_sctp_prinfo); 1646238405Sjkim 1647280304Sjkim memcpy(ptr, &(data->prinfo), num); 1648280304Sjkim ret = num; 1649280304Sjkim break; 1650280304Sjkim case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: 1651280304Sjkim /* Returns the size of the copied struct. */ 1652280304Sjkim if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) 1653280304Sjkim num = sizeof(struct bio_dgram_sctp_prinfo); 1654238405Sjkim 1655280304Sjkim memcpy(&(data->prinfo), ptr, num); 1656280304Sjkim break; 1657280304Sjkim case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: 1658280304Sjkim /* Returns always 1. */ 1659280304Sjkim if (num > 0) 1660280304Sjkim data->save_shutdown = 1; 1661280304Sjkim else 1662280304Sjkim data->save_shutdown = 0; 1663280304Sjkim break; 1664238405Sjkim 1665280304Sjkim default: 1666280304Sjkim /* 1667280304Sjkim * Pass to default ctrl function to process SCTP unspecific commands 1668280304Sjkim */ 1669280304Sjkim ret = dgram_ctrl(b, cmd, num, ptr); 1670280304Sjkim break; 1671280304Sjkim } 1672280304Sjkim return (ret); 1673280304Sjkim} 1674238405Sjkim 1675238405Sjkimint BIO_dgram_sctp_notification_cb(BIO *b, 1676280304Sjkim void (*handle_notifications) (BIO *bio, 1677280304Sjkim void 1678280304Sjkim *context, 1679280304Sjkim void *buf), 1680238405Sjkim void *context) 1681280304Sjkim{ 1682280304Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1683238405Sjkim 1684280304Sjkim if (handle_notifications != NULL) { 1685280304Sjkim data->handle_notifications = handle_notifications; 1686280304Sjkim data->notification_context = context; 1687280304Sjkim } else 1688280304Sjkim return -1; 1689238405Sjkim 1690280304Sjkim return 0; 1691280304Sjkim} 1692238405Sjkim 1693238405Sjkimint BIO_dgram_sctp_wait_for_dry(BIO *b) 1694238405Sjkim{ 1695280304Sjkim int is_dry = 0; 1696280304Sjkim int n, sockflags, ret; 1697280304Sjkim union sctp_notification snp; 1698280304Sjkim struct msghdr msg; 1699280304Sjkim struct iovec iov; 1700280304Sjkim# ifdef SCTP_EVENT 1701280304Sjkim struct sctp_event event; 1702280304Sjkim# else 1703280304Sjkim struct sctp_event_subscribe event; 1704280304Sjkim socklen_t eventsize; 1705280304Sjkim# endif 1706280304Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1707238405Sjkim 1708280304Sjkim /* set sender dry event */ 1709280304Sjkim# ifdef SCTP_EVENT 1710280304Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1711280304Sjkim event.se_assoc_id = 0; 1712280304Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1713280304Sjkim event.se_on = 1; 1714280304Sjkim ret = 1715280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, 1716280304Sjkim sizeof(struct sctp_event)); 1717280304Sjkim# else 1718280304Sjkim eventsize = sizeof(struct sctp_event_subscribe); 1719280304Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); 1720280304Sjkim if (ret < 0) 1721280304Sjkim return -1; 1722238405Sjkim 1723280304Sjkim event.sctp_sender_dry_event = 1; 1724238405Sjkim 1725280304Sjkim ret = 1726280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, 1727280304Sjkim sizeof(struct sctp_event_subscribe)); 1728280304Sjkim# endif 1729280304Sjkim if (ret < 0) 1730280304Sjkim return -1; 1731238405Sjkim 1732280304Sjkim /* peek for notification */ 1733280304Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1734280304Sjkim iov.iov_base = (char *)&snp; 1735280304Sjkim iov.iov_len = sizeof(union sctp_notification); 1736280304Sjkim msg.msg_name = NULL; 1737280304Sjkim msg.msg_namelen = 0; 1738280304Sjkim msg.msg_iov = &iov; 1739280304Sjkim msg.msg_iovlen = 1; 1740280304Sjkim msg.msg_control = NULL; 1741280304Sjkim msg.msg_controllen = 0; 1742280304Sjkim msg.msg_flags = 0; 1743238405Sjkim 1744280304Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1745280304Sjkim if (n <= 0) { 1746280304Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) 1747280304Sjkim && (get_last_socket_error() != EWOULDBLOCK)) 1748280304Sjkim return -1; 1749280304Sjkim else 1750280304Sjkim return 0; 1751280304Sjkim } 1752238405Sjkim 1753280304Sjkim /* if we find a notification, process it and try again if necessary */ 1754280304Sjkim while (msg.msg_flags & MSG_NOTIFICATION) { 1755280304Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1756280304Sjkim iov.iov_base = (char *)&snp; 1757280304Sjkim iov.iov_len = sizeof(union sctp_notification); 1758280304Sjkim msg.msg_name = NULL; 1759280304Sjkim msg.msg_namelen = 0; 1760280304Sjkim msg.msg_iov = &iov; 1761280304Sjkim msg.msg_iovlen = 1; 1762280304Sjkim msg.msg_control = NULL; 1763280304Sjkim msg.msg_controllen = 0; 1764280304Sjkim msg.msg_flags = 0; 1765238405Sjkim 1766280304Sjkim n = recvmsg(b->num, &msg, 0); 1767280304Sjkim if (n <= 0) { 1768280304Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) 1769280304Sjkim && (get_last_socket_error() != EWOULDBLOCK)) 1770280304Sjkim return -1; 1771280304Sjkim else 1772280304Sjkim return is_dry; 1773280304Sjkim } 1774238405Sjkim 1775280304Sjkim if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { 1776280304Sjkim is_dry = 1; 1777238405Sjkim 1778280304Sjkim /* disable sender dry event */ 1779280304Sjkim# ifdef SCTP_EVENT 1780280304Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1781280304Sjkim event.se_assoc_id = 0; 1782280304Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1783280304Sjkim event.se_on = 0; 1784280304Sjkim ret = 1785280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, 1786280304Sjkim sizeof(struct sctp_event)); 1787280304Sjkim# else 1788280304Sjkim eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); 1789280304Sjkim ret = 1790280304Sjkim getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, 1791280304Sjkim &eventsize); 1792280304Sjkim if (ret < 0) 1793280304Sjkim return -1; 1794238405Sjkim 1795280304Sjkim event.sctp_sender_dry_event = 0; 1796238405Sjkim 1797280304Sjkim ret = 1798280304Sjkim setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, 1799280304Sjkim sizeof(struct sctp_event_subscribe)); 1800280304Sjkim# endif 1801280304Sjkim if (ret < 0) 1802280304Sjkim return -1; 1803280304Sjkim } 1804280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 1805280304Sjkim if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1806280304Sjkim dgram_sctp_handle_auth_free_key_event(b, &snp); 1807280304Sjkim# endif 1808238405Sjkim 1809280304Sjkim if (data->handle_notifications != NULL) 1810280304Sjkim data->handle_notifications(b, data->notification_context, 1811280304Sjkim (void *)&snp); 1812238405Sjkim 1813280304Sjkim /* found notification, peek again */ 1814280304Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1815280304Sjkim iov.iov_base = (char *)&snp; 1816280304Sjkim iov.iov_len = sizeof(union sctp_notification); 1817280304Sjkim msg.msg_name = NULL; 1818280304Sjkim msg.msg_namelen = 0; 1819280304Sjkim msg.msg_iov = &iov; 1820280304Sjkim msg.msg_iovlen = 1; 1821280304Sjkim msg.msg_control = NULL; 1822280304Sjkim msg.msg_controllen = 0; 1823280304Sjkim msg.msg_flags = 0; 1824238405Sjkim 1825280304Sjkim /* if we have seen the dry already, don't wait */ 1826280304Sjkim if (is_dry) { 1827280304Sjkim sockflags = fcntl(b->num, F_GETFL, 0); 1828280304Sjkim fcntl(b->num, F_SETFL, O_NONBLOCK); 1829280304Sjkim } 1830238405Sjkim 1831280304Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1832238405Sjkim 1833280304Sjkim if (is_dry) { 1834280304Sjkim fcntl(b->num, F_SETFL, sockflags); 1835280304Sjkim } 1836280304Sjkim 1837280304Sjkim if (n <= 0) { 1838280304Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) 1839280304Sjkim && (get_last_socket_error() != EWOULDBLOCK)) 1840280304Sjkim return -1; 1841280304Sjkim else 1842280304Sjkim return is_dry; 1843280304Sjkim } 1844280304Sjkim } 1845280304Sjkim 1846280304Sjkim /* read anything else */ 1847280304Sjkim return is_dry; 1848238405Sjkim} 1849238405Sjkim 1850238405Sjkimint BIO_dgram_sctp_msg_waiting(BIO *b) 1851280304Sjkim{ 1852280304Sjkim int n, sockflags; 1853280304Sjkim union sctp_notification snp; 1854280304Sjkim struct msghdr msg; 1855280304Sjkim struct iovec iov; 1856280304Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1857238405Sjkim 1858280304Sjkim /* Check if there are any messages waiting to be read */ 1859280304Sjkim do { 1860280304Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1861280304Sjkim iov.iov_base = (char *)&snp; 1862280304Sjkim iov.iov_len = sizeof(union sctp_notification); 1863280304Sjkim msg.msg_name = NULL; 1864280304Sjkim msg.msg_namelen = 0; 1865280304Sjkim msg.msg_iov = &iov; 1866280304Sjkim msg.msg_iovlen = 1; 1867280304Sjkim msg.msg_control = NULL; 1868280304Sjkim msg.msg_controllen = 0; 1869280304Sjkim msg.msg_flags = 0; 1870238405Sjkim 1871280304Sjkim sockflags = fcntl(b->num, F_GETFL, 0); 1872280304Sjkim fcntl(b->num, F_SETFL, O_NONBLOCK); 1873280304Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1874280304Sjkim fcntl(b->num, F_SETFL, sockflags); 1875238405Sjkim 1876280304Sjkim /* if notification, process and try again */ 1877280304Sjkim if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) { 1878280304Sjkim# ifdef SCTP_AUTHENTICATION_EVENT 1879280304Sjkim if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1880280304Sjkim dgram_sctp_handle_auth_free_key_event(b, &snp); 1881280304Sjkim# endif 1882238405Sjkim 1883280304Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1884280304Sjkim iov.iov_base = (char *)&snp; 1885280304Sjkim iov.iov_len = sizeof(union sctp_notification); 1886280304Sjkim msg.msg_name = NULL; 1887280304Sjkim msg.msg_namelen = 0; 1888280304Sjkim msg.msg_iov = &iov; 1889280304Sjkim msg.msg_iovlen = 1; 1890280304Sjkim msg.msg_control = NULL; 1891280304Sjkim msg.msg_controllen = 0; 1892280304Sjkim msg.msg_flags = 0; 1893280304Sjkim n = recvmsg(b->num, &msg, 0); 1894238405Sjkim 1895280304Sjkim if (data->handle_notifications != NULL) 1896280304Sjkim data->handle_notifications(b, data->notification_context, 1897280304Sjkim (void *)&snp); 1898280304Sjkim } 1899238405Sjkim 1900280304Sjkim } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); 1901238405Sjkim 1902280304Sjkim /* Return 1 if there is a message to be read, return 0 otherwise. */ 1903280304Sjkim if (n > 0) 1904280304Sjkim return 1; 1905280304Sjkim else 1906280304Sjkim return 0; 1907280304Sjkim} 1908238405Sjkim 1909238405Sjkimstatic int dgram_sctp_puts(BIO *bp, const char *str) 1910280304Sjkim{ 1911280304Sjkim int n, ret; 1912238405Sjkim 1913280304Sjkim n = strlen(str); 1914280304Sjkim ret = dgram_sctp_write(bp, str, n); 1915280304Sjkim return (ret); 1916280304Sjkim} 1917280304Sjkim# endif 1918238405Sjkim 1919194206Ssimonstatic int BIO_dgram_should_retry(int i) 1920280304Sjkim{ 1921280304Sjkim int err; 1922160814Ssimon 1923280304Sjkim if ((i == 0) || (i == -1)) { 1924280304Sjkim err = get_last_socket_error(); 1925160814Ssimon 1926280304Sjkim# if defined(OPENSSL_SYS_WINDOWS) 1927280304Sjkim /* 1928280304Sjkim * If the socket return value (i) is -1 and err is unexpectedly 0 at 1929280304Sjkim * this point, the error code was overwritten by another system call 1930280304Sjkim * before this error handling is called. 1931280304Sjkim */ 1932280304Sjkim# endif 1933160814Ssimon 1934280304Sjkim return (BIO_dgram_non_fatal_error(err)); 1935280304Sjkim } 1936280304Sjkim return (0); 1937280304Sjkim} 1938160814Ssimon 1939160814Ssimonint BIO_dgram_non_fatal_error(int err) 1940280304Sjkim{ 1941280304Sjkim switch (err) { 1942280304Sjkim# if defined(OPENSSL_SYS_WINDOWS) 1943280304Sjkim# if defined(WSAEWOULDBLOCK) 1944280304Sjkim case WSAEWOULDBLOCK: 1945280304Sjkim# endif 1946160814Ssimon 1947280304Sjkim# if 0 /* This appears to always be an error */ 1948280304Sjkim# if defined(WSAENOTCONN) 1949280304Sjkim case WSAENOTCONN: 1950280304Sjkim# endif 1951160814Ssimon# endif 1952160814Ssimon# endif 1953160814Ssimon 1954280304Sjkim# ifdef EWOULDBLOCK 1955280304Sjkim# ifdef WSAEWOULDBLOCK 1956280304Sjkim# if WSAEWOULDBLOCK != EWOULDBLOCK 1957280304Sjkim case EWOULDBLOCK: 1958280304Sjkim# endif 1959280304Sjkim# else 1960280304Sjkim case EWOULDBLOCK: 1961160814Ssimon# endif 1962160814Ssimon# endif 1963160814Ssimon 1964280304Sjkim# ifdef EINTR 1965280304Sjkim case EINTR: 1966280304Sjkim# endif 1967160814Ssimon 1968280304Sjkim# ifdef EAGAIN 1969280304Sjkim# if EWOULDBLOCK != EAGAIN 1970280304Sjkim case EAGAIN: 1971280304Sjkim# endif 1972160814Ssimon# endif 1973160814Ssimon 1974280304Sjkim# ifdef EPROTO 1975280304Sjkim case EPROTO: 1976280304Sjkim# endif 1977160814Ssimon 1978280304Sjkim# ifdef EINPROGRESS 1979280304Sjkim case EINPROGRESS: 1980280304Sjkim# endif 1981160814Ssimon 1982280304Sjkim# ifdef EALREADY 1983280304Sjkim case EALREADY: 1984280304Sjkim# endif 1985160814Ssimon 1986280304Sjkim return (1); 1987280304Sjkim /* break; */ 1988280304Sjkim default: 1989280304Sjkim break; 1990280304Sjkim } 1991280304Sjkim return (0); 1992280304Sjkim} 1993205128Ssimon 1994205128Ssimonstatic void get_current_time(struct timeval *t) 1995280304Sjkim{ 1996280304Sjkim# ifdef OPENSSL_SYS_WIN32 1997280304Sjkim struct _timeb tb; 1998280304Sjkim _ftime(&tb); 1999280304Sjkim t->tv_sec = (long)tb.time; 2000280304Sjkim t->tv_usec = (long)tb.millitm * 1000; 2001280304Sjkim# elif defined(OPENSSL_SYS_VMS) 2002280304Sjkim struct timeb tb; 2003280304Sjkim ftime(&tb); 2004280304Sjkim t->tv_sec = (long)tb.time; 2005280304Sjkim t->tv_usec = (long)tb.millitm * 1000; 2006280304Sjkim# else 2007280304Sjkim gettimeofday(t, NULL); 2008280304Sjkim# endif 2009280304Sjkim} 2010237657Sjkim 2011237657Sjkim#endif 2012