1160814Ssimon/* crypto/bio/bio_dgram.c */ 2160814Ssimon/* 3160814Ssimon * DTLS implementation written by Nagendra Modadugu 4160814Ssimon * (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 14160814Ssimon * 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 61160814Ssimon#include <stdio.h> 62160814Ssimon#include <errno.h> 63160814Ssimon#define USE_SOCKETS 64160814Ssimon#include "cryptlib.h" 65160814Ssimon 66160814Ssimon#include <openssl/bio.h> 67237657Sjkim#ifndef OPENSSL_NO_DGRAM 68160814Ssimon 69205128Ssimon#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) 70205128Ssimon#include <sys/timeb.h> 71205128Ssimon#endif 72205128Ssimon 73238405Sjkim#ifndef OPENSSL_NO_SCTP 74238405Sjkim#include <netinet/sctp.h> 75238405Sjkim#include <fcntl.h> 76238405Sjkim#define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 77238405Sjkim#define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 78238405Sjkim#endif 79238405Sjkim 80246772Sjkim#if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU) 81160814Ssimon#define IP_MTU 14 /* linux is lame */ 82205128Ssimon#endif 83160814Ssimon 84246772Sjkim#if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED) 85246772Sjkim/* Standard definition causes type-punning problems. */ 86246772Sjkim#undef IN6_IS_ADDR_V4MAPPED 87246772Sjkim#define s6_addr32 __u6_addr.__u6_addr32 88246772Sjkim#define IN6_IS_ADDR_V4MAPPED(a) \ 89246772Sjkim (((a)->s6_addr32[0] == 0) && \ 90246772Sjkim ((a)->s6_addr32[1] == 0) && \ 91246772Sjkim ((a)->s6_addr32[2] == htonl(0x0000ffff))) 92246772Sjkim#endif 93246772Sjkim 94160814Ssimon#ifdef WATT32 95160814Ssimon#define sock_write SockWrite /* Watt-32 uses same names */ 96160814Ssimon#define sock_read SockRead 97160814Ssimon#define sock_puts SockPuts 98160814Ssimon#endif 99160814Ssimon 100160814Ssimonstatic int dgram_write(BIO *h, const char *buf, int num); 101160814Ssimonstatic int dgram_read(BIO *h, char *buf, int size); 102160814Ssimonstatic int dgram_puts(BIO *h, const char *str); 103160814Ssimonstatic long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); 104160814Ssimonstatic int dgram_new(BIO *h); 105160814Ssimonstatic int dgram_free(BIO *data); 106160814Ssimonstatic int dgram_clear(BIO *bio); 107160814Ssimon 108238405Sjkim#ifndef OPENSSL_NO_SCTP 109238405Sjkimstatic int dgram_sctp_write(BIO *h, const char *buf, int num); 110238405Sjkimstatic int dgram_sctp_read(BIO *h, char *buf, int size); 111238405Sjkimstatic int dgram_sctp_puts(BIO *h, const char *str); 112238405Sjkimstatic long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); 113238405Sjkimstatic int dgram_sctp_new(BIO *h); 114238405Sjkimstatic int dgram_sctp_free(BIO *data); 115238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 116238405Sjkimstatic void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp); 117238405Sjkim#endif 118238405Sjkim#endif 119238405Sjkim 120194206Ssimonstatic int BIO_dgram_should_retry(int s); 121160814Ssimon 122205128Ssimonstatic void get_current_time(struct timeval *t); 123205128Ssimon 124160814Ssimonstatic BIO_METHOD methods_dgramp= 125160814Ssimon { 126160814Ssimon BIO_TYPE_DGRAM, 127160814Ssimon "datagram socket", 128160814Ssimon dgram_write, 129160814Ssimon dgram_read, 130160814Ssimon dgram_puts, 131160814Ssimon NULL, /* dgram_gets, */ 132160814Ssimon dgram_ctrl, 133160814Ssimon dgram_new, 134160814Ssimon dgram_free, 135160814Ssimon NULL, 136160814Ssimon }; 137160814Ssimon 138238405Sjkim#ifndef OPENSSL_NO_SCTP 139238405Sjkimstatic BIO_METHOD methods_dgramp_sctp= 140238405Sjkim { 141238405Sjkim BIO_TYPE_DGRAM_SCTP, 142238405Sjkim "datagram sctp socket", 143238405Sjkim dgram_sctp_write, 144238405Sjkim dgram_sctp_read, 145238405Sjkim dgram_sctp_puts, 146238405Sjkim NULL, /* dgram_gets, */ 147238405Sjkim dgram_sctp_ctrl, 148238405Sjkim dgram_sctp_new, 149238405Sjkim dgram_sctp_free, 150238405Sjkim NULL, 151238405Sjkim }; 152238405Sjkim#endif 153238405Sjkim 154160814Ssimontypedef struct bio_dgram_data_st 155160814Ssimon { 156238405Sjkim union { 157238405Sjkim struct sockaddr sa; 158238405Sjkim struct sockaddr_in sa_in; 159238405Sjkim#if OPENSSL_USE_IPV6 160238405Sjkim struct sockaddr_in6 sa_in6; 161238405Sjkim#endif 162238405Sjkim } peer; 163160814Ssimon unsigned int connected; 164160814Ssimon unsigned int _errno; 165160814Ssimon unsigned int mtu; 166205128Ssimon struct timeval next_timeout; 167205128Ssimon struct timeval socket_timeout; 168160814Ssimon } bio_dgram_data; 169160814Ssimon 170238405Sjkim#ifndef OPENSSL_NO_SCTP 171238405Sjkimtypedef struct bio_dgram_sctp_save_message_st 172238405Sjkim { 173238405Sjkim BIO *bio; 174238405Sjkim char *data; 175238405Sjkim int length; 176238405Sjkim } bio_dgram_sctp_save_message; 177238405Sjkim 178238405Sjkimtypedef struct bio_dgram_sctp_data_st 179238405Sjkim { 180238405Sjkim union { 181238405Sjkim struct sockaddr sa; 182238405Sjkim struct sockaddr_in sa_in; 183238405Sjkim#if OPENSSL_USE_IPV6 184238405Sjkim struct sockaddr_in6 sa_in6; 185238405Sjkim#endif 186238405Sjkim } peer; 187238405Sjkim unsigned int connected; 188238405Sjkim unsigned int _errno; 189238405Sjkim unsigned int mtu; 190238405Sjkim struct bio_dgram_sctp_sndinfo sndinfo; 191238405Sjkim struct bio_dgram_sctp_rcvinfo rcvinfo; 192238405Sjkim struct bio_dgram_sctp_prinfo prinfo; 193238405Sjkim void (*handle_notifications)(BIO *bio, void *context, void *buf); 194238405Sjkim void* notification_context; 195238405Sjkim int in_handshake; 196238405Sjkim int ccs_rcvd; 197238405Sjkim int ccs_sent; 198238405Sjkim int save_shutdown; 199238405Sjkim int peer_auth_tested; 200238405Sjkim bio_dgram_sctp_save_message saved_message; 201238405Sjkim } bio_dgram_sctp_data; 202238405Sjkim#endif 203238405Sjkim 204160814SsimonBIO_METHOD *BIO_s_datagram(void) 205160814Ssimon { 206160814Ssimon return(&methods_dgramp); 207160814Ssimon } 208160814Ssimon 209160814SsimonBIO *BIO_new_dgram(int fd, int close_flag) 210160814Ssimon { 211160814Ssimon BIO *ret; 212160814Ssimon 213160814Ssimon ret=BIO_new(BIO_s_datagram()); 214160814Ssimon if (ret == NULL) return(NULL); 215160814Ssimon BIO_set_fd(ret,fd,close_flag); 216160814Ssimon return(ret); 217160814Ssimon } 218160814Ssimon 219160814Ssimonstatic int dgram_new(BIO *bi) 220160814Ssimon { 221160814Ssimon bio_dgram_data *data = NULL; 222160814Ssimon 223160814Ssimon bi->init=0; 224160814Ssimon bi->num=0; 225160814Ssimon data = OPENSSL_malloc(sizeof(bio_dgram_data)); 226160814Ssimon if (data == NULL) 227160814Ssimon return 0; 228160814Ssimon memset(data, 0x00, sizeof(bio_dgram_data)); 229160814Ssimon bi->ptr = data; 230160814Ssimon 231160814Ssimon bi->flags=0; 232160814Ssimon return(1); 233160814Ssimon } 234160814Ssimon 235160814Ssimonstatic int dgram_free(BIO *a) 236160814Ssimon { 237160814Ssimon bio_dgram_data *data; 238160814Ssimon 239160814Ssimon if (a == NULL) return(0); 240160814Ssimon if ( ! dgram_clear(a)) 241160814Ssimon return 0; 242160814Ssimon 243160814Ssimon data = (bio_dgram_data *)a->ptr; 244160814Ssimon if(data != NULL) OPENSSL_free(data); 245160814Ssimon 246160814Ssimon return(1); 247160814Ssimon } 248160814Ssimon 249160814Ssimonstatic int dgram_clear(BIO *a) 250160814Ssimon { 251160814Ssimon if (a == NULL) return(0); 252160814Ssimon if (a->shutdown) 253160814Ssimon { 254160814Ssimon if (a->init) 255160814Ssimon { 256160814Ssimon SHUTDOWN2(a->num); 257160814Ssimon } 258160814Ssimon a->init=0; 259160814Ssimon a->flags=0; 260160814Ssimon } 261160814Ssimon return(1); 262160814Ssimon } 263205128Ssimon 264205128Ssimonstatic void dgram_adjust_rcv_timeout(BIO *b) 265205128Ssimon { 266205128Ssimon#if defined(SO_RCVTIMEO) 267205128Ssimon bio_dgram_data *data = (bio_dgram_data *)b->ptr; 268246772Sjkim union { size_t s; int i; } sz = {0}; 269205128Ssimon 270205128Ssimon /* Is a timer active? */ 271205128Ssimon if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) 272205128Ssimon { 273205128Ssimon struct timeval timenow, timeleft; 274205128Ssimon 275205128Ssimon /* Read current socket timeout */ 276205128Ssimon#ifdef OPENSSL_SYS_WINDOWS 277205128Ssimon int timeout; 278246772Sjkim 279246772Sjkim sz.i = sizeof(timeout); 280205128Ssimon if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 281246772Sjkim (void*)&timeout, &sz.i) < 0) 282205128Ssimon { perror("getsockopt"); } 283205128Ssimon else 284205128Ssimon { 285205128Ssimon data->socket_timeout.tv_sec = timeout / 1000; 286205128Ssimon data->socket_timeout.tv_usec = (timeout % 1000) * 1000; 287205128Ssimon } 288205128Ssimon#else 289246772Sjkim sz.i = sizeof(data->socket_timeout); 290205128Ssimon if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 291205128Ssimon &(data->socket_timeout), (void *)&sz) < 0) 292205128Ssimon { perror("getsockopt"); } 293246772Sjkim else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 294246772Sjkim OPENSSL_assert(sz.s<=sizeof(data->socket_timeout)); 295205128Ssimon#endif 296205128Ssimon 297205128Ssimon /* Get current time */ 298205128Ssimon get_current_time(&timenow); 299205128Ssimon 300205128Ssimon /* Calculate time left until timer expires */ 301205128Ssimon memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); 302205128Ssimon timeleft.tv_sec -= timenow.tv_sec; 303205128Ssimon timeleft.tv_usec -= timenow.tv_usec; 304205128Ssimon if (timeleft.tv_usec < 0) 305205128Ssimon { 306205128Ssimon timeleft.tv_sec--; 307205128Ssimon timeleft.tv_usec += 1000000; 308205128Ssimon } 309205128Ssimon 310205128Ssimon if (timeleft.tv_sec < 0) 311205128Ssimon { 312205128Ssimon timeleft.tv_sec = 0; 313205128Ssimon timeleft.tv_usec = 1; 314205128Ssimon } 315205128Ssimon 316205128Ssimon /* Adjust socket timeout if next handhake message timer 317205128Ssimon * will expire earlier. 318205128Ssimon */ 319205128Ssimon if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) || 320205128Ssimon (data->socket_timeout.tv_sec > timeleft.tv_sec) || 321205128Ssimon (data->socket_timeout.tv_sec == timeleft.tv_sec && 322205128Ssimon data->socket_timeout.tv_usec >= timeleft.tv_usec)) 323205128Ssimon { 324205128Ssimon#ifdef OPENSSL_SYS_WINDOWS 325205128Ssimon timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; 326205128Ssimon if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 327205128Ssimon (void*)&timeout, sizeof(timeout)) < 0) 328205128Ssimon { perror("setsockopt"); } 329205128Ssimon#else 330205128Ssimon if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, 331205128Ssimon sizeof(struct timeval)) < 0) 332205128Ssimon { perror("setsockopt"); } 333205128Ssimon#endif 334205128Ssimon } 335205128Ssimon } 336205128Ssimon#endif 337205128Ssimon } 338205128Ssimon 339205128Ssimonstatic void dgram_reset_rcv_timeout(BIO *b) 340205128Ssimon { 341205128Ssimon#if defined(SO_RCVTIMEO) 342205128Ssimon bio_dgram_data *data = (bio_dgram_data *)b->ptr; 343205128Ssimon 344205128Ssimon /* Is a timer active? */ 345205128Ssimon if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) 346205128Ssimon { 347205128Ssimon#ifdef OPENSSL_SYS_WINDOWS 348205128Ssimon int timeout = data->socket_timeout.tv_sec * 1000 + 349205128Ssimon data->socket_timeout.tv_usec / 1000; 350205128Ssimon if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 351205128Ssimon (void*)&timeout, sizeof(timeout)) < 0) 352205128Ssimon { perror("setsockopt"); } 353205128Ssimon#else 354205128Ssimon if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), 355205128Ssimon sizeof(struct timeval)) < 0) 356205128Ssimon { perror("setsockopt"); } 357205128Ssimon#endif 358205128Ssimon } 359205128Ssimon#endif 360205128Ssimon } 361205128Ssimon 362160814Ssimonstatic int dgram_read(BIO *b, char *out, int outl) 363160814Ssimon { 364160814Ssimon int ret=0; 365160814Ssimon bio_dgram_data *data = (bio_dgram_data *)b->ptr; 366160814Ssimon 367238405Sjkim struct { 368238405Sjkim /* 369238405Sjkim * See commentary in b_sock.c. <appro> 370238405Sjkim */ 371238405Sjkim union { size_t s; int i; } len; 372238405Sjkim union { 373238405Sjkim struct sockaddr sa; 374238405Sjkim struct sockaddr_in sa_in; 375238405Sjkim#if OPENSSL_USE_IPV6 376238405Sjkim struct sockaddr_in6 sa_in6; 377238405Sjkim#endif 378238405Sjkim } peer; 379238405Sjkim } sa; 380160814Ssimon 381238405Sjkim sa.len.s=0; 382238405Sjkim sa.len.i=sizeof(sa.peer); 383238405Sjkim 384160814Ssimon if (out != NULL) 385160814Ssimon { 386160814Ssimon clear_socket_error(); 387238405Sjkim memset(&sa.peer, 0x00, sizeof(sa.peer)); 388205128Ssimon dgram_adjust_rcv_timeout(b); 389238405Sjkim ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len); 390238405Sjkim if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) 391238405Sjkim { 392238405Sjkim OPENSSL_assert(sa.len.s<=sizeof(sa.peer)); 393238405Sjkim sa.len.i = (int)sa.len.s; 394238405Sjkim } 395160814Ssimon 396205128Ssimon if ( ! data->connected && ret >= 0) 397238405Sjkim BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); 398160814Ssimon 399160814Ssimon BIO_clear_retry_flags(b); 400205128Ssimon if (ret < 0) 401160814Ssimon { 402160814Ssimon if (BIO_dgram_should_retry(ret)) 403160814Ssimon { 404160814Ssimon BIO_set_retry_read(b); 405160814Ssimon data->_errno = get_last_socket_error(); 406160814Ssimon } 407160814Ssimon } 408237657Sjkim 409237657Sjkim dgram_reset_rcv_timeout(b); 410160814Ssimon } 411160814Ssimon return(ret); 412160814Ssimon } 413160814Ssimon 414160814Ssimonstatic int dgram_write(BIO *b, const char *in, int inl) 415160814Ssimon { 416160814Ssimon int ret; 417160814Ssimon bio_dgram_data *data = (bio_dgram_data *)b->ptr; 418160814Ssimon clear_socket_error(); 419160814Ssimon 420238405Sjkim if ( data->connected ) 421238405Sjkim ret=writesocket(b->num,in,inl); 422238405Sjkim else 423238405Sjkim { 424238405Sjkim int peerlen = sizeof(data->peer); 425238405Sjkim 426238405Sjkim if (data->peer.sa.sa_family == AF_INET) 427238405Sjkim peerlen = sizeof(data->peer.sa_in); 428238405Sjkim#if OPENSSL_USE_IPV6 429238405Sjkim else if (data->peer.sa.sa_family == AF_INET6) 430238405Sjkim peerlen = sizeof(data->peer.sa_in6); 431238405Sjkim#endif 432194206Ssimon#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) 433238405Sjkim ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); 434194206Ssimon#else 435238405Sjkim ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); 436194206Ssimon#endif 437238405Sjkim } 438160814Ssimon 439160814Ssimon BIO_clear_retry_flags(b); 440160814Ssimon if (ret <= 0) 441160814Ssimon { 442205128Ssimon if (BIO_dgram_should_retry(ret)) 443160814Ssimon { 444160814Ssimon BIO_set_retry_write(b); 445160814Ssimon data->_errno = get_last_socket_error(); 446160814Ssimon 447160814Ssimon#if 0 /* higher layers are responsible for querying MTU, if necessary */ 448160814Ssimon if ( data->_errno == EMSGSIZE) 449160814Ssimon /* retrieve the new MTU */ 450160814Ssimon BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); 451160814Ssimon#endif 452160814Ssimon } 453160814Ssimon } 454160814Ssimon return(ret); 455160814Ssimon } 456160814Ssimon 457279264Sdelphijstatic long dgram_get_mtu_overhead(bio_dgram_data *data) 458279264Sdelphij { 459279264Sdelphij long ret; 460279264Sdelphij 461279264Sdelphij switch (data->peer.sa.sa_family) 462279264Sdelphij { 463279264Sdelphij case AF_INET: 464279264Sdelphij /* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */ 465279264Sdelphij ret = 28; 466279264Sdelphij break; 467279264Sdelphij#if OPENSSL_USE_IPV6 468279264Sdelphij case AF_INET6: 469279264Sdelphij#ifdef IN6_IS_ADDR_V4MAPPED 470279264Sdelphij if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 471279264Sdelphij /* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */ 472279264Sdelphij ret = 28; 473279264Sdelphij else 474279264Sdelphij#endif 475279264Sdelphij /* Assume this is UDP - 40 bytes for IP, 8 bytes for UDP */ 476279264Sdelphij ret = 48; 477279264Sdelphij break; 478279264Sdelphij#endif 479279264Sdelphij default: 480279264Sdelphij /* We don't know. Go with the historical default */ 481279264Sdelphij ret = 28; 482279264Sdelphij break; 483279264Sdelphij } 484279264Sdelphij return ret; 485279264Sdelphij } 486279264Sdelphij 487160814Ssimonstatic long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) 488160814Ssimon { 489160814Ssimon long ret=1; 490160814Ssimon int *ip; 491160814Ssimon struct sockaddr *to = NULL; 492160814Ssimon bio_dgram_data *data = NULL; 493246772Sjkim#if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) 494246772Sjkim int sockopt_val = 0; 495246772Sjkim socklen_t sockopt_len; /* assume that system supporting IP_MTU is 496246772Sjkim * modern enough to define socklen_t */ 497205128Ssimon socklen_t addr_len; 498238405Sjkim union { 499238405Sjkim struct sockaddr sa; 500238405Sjkim struct sockaddr_in s4; 501238405Sjkim#if OPENSSL_USE_IPV6 502238405Sjkim struct sockaddr_in6 s6; 503205128Ssimon#endif 504238405Sjkim } addr; 505238405Sjkim#endif 506160814Ssimon 507160814Ssimon data = (bio_dgram_data *)b->ptr; 508160814Ssimon 509160814Ssimon switch (cmd) 510160814Ssimon { 511160814Ssimon case BIO_CTRL_RESET: 512160814Ssimon num=0; 513160814Ssimon case BIO_C_FILE_SEEK: 514160814Ssimon ret=0; 515160814Ssimon break; 516160814Ssimon case BIO_C_FILE_TELL: 517160814Ssimon case BIO_CTRL_INFO: 518160814Ssimon ret=0; 519160814Ssimon break; 520160814Ssimon case BIO_C_SET_FD: 521160814Ssimon dgram_clear(b); 522160814Ssimon b->num= *((int *)ptr); 523160814Ssimon b->shutdown=(int)num; 524160814Ssimon b->init=1; 525160814Ssimon break; 526160814Ssimon case BIO_C_GET_FD: 527160814Ssimon if (b->init) 528160814Ssimon { 529160814Ssimon ip=(int *)ptr; 530160814Ssimon if (ip != NULL) *ip=b->num; 531160814Ssimon ret=b->num; 532160814Ssimon } 533160814Ssimon else 534160814Ssimon ret= -1; 535160814Ssimon break; 536160814Ssimon case BIO_CTRL_GET_CLOSE: 537160814Ssimon ret=b->shutdown; 538160814Ssimon break; 539160814Ssimon case BIO_CTRL_SET_CLOSE: 540160814Ssimon b->shutdown=(int)num; 541160814Ssimon break; 542160814Ssimon case BIO_CTRL_PENDING: 543160814Ssimon case BIO_CTRL_WPENDING: 544160814Ssimon ret=0; 545160814Ssimon break; 546160814Ssimon case BIO_CTRL_DUP: 547160814Ssimon case BIO_CTRL_FLUSH: 548160814Ssimon ret=1; 549160814Ssimon break; 550160814Ssimon case BIO_CTRL_DGRAM_CONNECT: 551160814Ssimon to = (struct sockaddr *)ptr; 552160814Ssimon#if 0 553160814Ssimon if (connect(b->num, to, sizeof(struct sockaddr)) < 0) 554160814Ssimon { perror("connect"); ret = 0; } 555160814Ssimon else 556160814Ssimon { 557160814Ssimon#endif 558238405Sjkim switch (to->sa_family) 559238405Sjkim { 560238405Sjkim case AF_INET: 561238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 562238405Sjkim break; 563238405Sjkim#if OPENSSL_USE_IPV6 564238405Sjkim case AF_INET6: 565238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 566238405Sjkim break; 567238405Sjkim#endif 568238405Sjkim default: 569238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa)); 570238405Sjkim break; 571238405Sjkim } 572160814Ssimon#if 0 573160814Ssimon } 574160814Ssimon#endif 575160814Ssimon break; 576160814Ssimon /* (Linux)kernel sets DF bit on outgoing IP packets */ 577160814Ssimon case BIO_CTRL_DGRAM_MTU_DISCOVER: 578246772Sjkim#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) 579238405Sjkim addr_len = (socklen_t)sizeof(addr); 580238405Sjkim memset((void *)&addr, 0, sizeof(addr)); 581238405Sjkim if (getsockname(b->num, &addr.sa, &addr_len) < 0) 582205128Ssimon { 583205128Ssimon ret = 0; 584205128Ssimon break; 585205128Ssimon } 586238405Sjkim switch (addr.sa.sa_family) 587205128Ssimon { 588205128Ssimon case AF_INET: 589205128Ssimon sockopt_val = IP_PMTUDISC_DO; 590205128Ssimon if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, 591205128Ssimon &sockopt_val, sizeof(sockopt_val))) < 0) 592205128Ssimon perror("setsockopt"); 593205128Ssimon break; 594246772Sjkim#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) 595205128Ssimon case AF_INET6: 596205128Ssimon sockopt_val = IPV6_PMTUDISC_DO; 597205128Ssimon if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, 598205128Ssimon &sockopt_val, sizeof(sockopt_val))) < 0) 599205128Ssimon perror("setsockopt"); 600205128Ssimon break; 601238405Sjkim#endif 602205128Ssimon default: 603205128Ssimon ret = -1; 604205128Ssimon break; 605205128Ssimon } 606205128Ssimon ret = -1; 607205128Ssimon#else 608160814Ssimon break; 609160814Ssimon#endif 610160814Ssimon case BIO_CTRL_DGRAM_QUERY_MTU: 611246772Sjkim#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) 612238405Sjkim addr_len = (socklen_t)sizeof(addr); 613238405Sjkim memset((void *)&addr, 0, sizeof(addr)); 614238405Sjkim if (getsockname(b->num, &addr.sa, &addr_len) < 0) 615160814Ssimon { 616205128Ssimon ret = 0; 617205128Ssimon break; 618160814Ssimon } 619205128Ssimon sockopt_len = sizeof(sockopt_val); 620238405Sjkim switch (addr.sa.sa_family) 621205128Ssimon { 622205128Ssimon case AF_INET: 623205128Ssimon if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, 624205128Ssimon &sockopt_len)) < 0 || sockopt_val < 0) 625205128Ssimon { 626205128Ssimon ret = 0; 627205128Ssimon } 628205128Ssimon else 629205128Ssimon { 630205128Ssimon /* we assume that the transport protocol is UDP and no 631205128Ssimon * IP options are used. 632205128Ssimon */ 633205128Ssimon data->mtu = sockopt_val - 8 - 20; 634205128Ssimon ret = data->mtu; 635205128Ssimon } 636205128Ssimon break; 637238405Sjkim#if OPENSSL_USE_IPV6 && defined(IPV6_MTU) 638205128Ssimon case AF_INET6: 639205128Ssimon if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, 640205128Ssimon &sockopt_len)) < 0 || sockopt_val < 0) 641205128Ssimon { 642205128Ssimon ret = 0; 643205128Ssimon } 644205128Ssimon else 645205128Ssimon { 646205128Ssimon /* we assume that the transport protocol is UDP and no 647205128Ssimon * IPV6 options are used. 648205128Ssimon */ 649205128Ssimon data->mtu = sockopt_val - 8 - 40; 650205128Ssimon ret = data->mtu; 651205128Ssimon } 652205128Ssimon break; 653238405Sjkim#endif 654205128Ssimon default: 655205128Ssimon ret = 0; 656205128Ssimon break; 657205128Ssimon } 658205128Ssimon#else 659205128Ssimon ret = 0; 660205128Ssimon#endif 661160814Ssimon break; 662237657Sjkim case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: 663279264Sdelphij ret = -dgram_get_mtu_overhead(data); 664238405Sjkim switch (data->peer.sa.sa_family) 665238405Sjkim { 666238405Sjkim case AF_INET: 667279264Sdelphij ret += 576; 668238405Sjkim break; 669238405Sjkim#if OPENSSL_USE_IPV6 670238405Sjkim case AF_INET6: 671238405Sjkim#ifdef IN6_IS_ADDR_V4MAPPED 672238405Sjkim if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 673279264Sdelphij ret += 576; 674238405Sjkim else 675238405Sjkim#endif 676279264Sdelphij ret += 1280; 677238405Sjkim break; 678238405Sjkim#endif 679238405Sjkim default: 680279264Sdelphij ret += 576; 681238405Sjkim break; 682238405Sjkim } 683237657Sjkim break; 684160814Ssimon case BIO_CTRL_DGRAM_GET_MTU: 685160814Ssimon return data->mtu; 686160814Ssimon break; 687160814Ssimon case BIO_CTRL_DGRAM_SET_MTU: 688160814Ssimon data->mtu = num; 689160814Ssimon ret = num; 690160814Ssimon break; 691160814Ssimon case BIO_CTRL_DGRAM_SET_CONNECTED: 692160814Ssimon to = (struct sockaddr *)ptr; 693160814Ssimon 694160814Ssimon if ( to != NULL) 695160814Ssimon { 696160814Ssimon data->connected = 1; 697238405Sjkim switch (to->sa_family) 698238405Sjkim { 699238405Sjkim case AF_INET: 700238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 701238405Sjkim break; 702238405Sjkim#if OPENSSL_USE_IPV6 703238405Sjkim case AF_INET6: 704238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 705238405Sjkim break; 706238405Sjkim#endif 707238405Sjkim default: 708238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa)); 709238405Sjkim break; 710238405Sjkim } 711160814Ssimon } 712160814Ssimon else 713160814Ssimon { 714160814Ssimon data->connected = 0; 715238405Sjkim memset(&(data->peer), 0x00, sizeof(data->peer)); 716160814Ssimon } 717160814Ssimon break; 718238405Sjkim case BIO_CTRL_DGRAM_GET_PEER: 719238405Sjkim switch (data->peer.sa.sa_family) 720238405Sjkim { 721238405Sjkim case AF_INET: 722238405Sjkim ret=sizeof(data->peer.sa_in); 723238405Sjkim break; 724238405Sjkim#if OPENSSL_USE_IPV6 725238405Sjkim case AF_INET6: 726238405Sjkim ret=sizeof(data->peer.sa_in6); 727238405Sjkim break; 728238405Sjkim#endif 729238405Sjkim default: 730238405Sjkim ret=sizeof(data->peer.sa); 731238405Sjkim break; 732238405Sjkim } 733238405Sjkim if (num==0 || num>ret) 734238405Sjkim num=ret; 735238405Sjkim memcpy(ptr,&data->peer,(ret=num)); 736238405Sjkim break; 737238405Sjkim case BIO_CTRL_DGRAM_SET_PEER: 738238405Sjkim to = (struct sockaddr *) ptr; 739238405Sjkim switch (to->sa_family) 740238405Sjkim { 741238405Sjkim case AF_INET: 742238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 743238405Sjkim break; 744238405Sjkim#if OPENSSL_USE_IPV6 745238405Sjkim case AF_INET6: 746238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 747238405Sjkim break; 748238405Sjkim#endif 749238405Sjkim default: 750238405Sjkim memcpy(&data->peer,to,sizeof(data->peer.sa)); 751238405Sjkim break; 752238405Sjkim } 753238405Sjkim break; 754205128Ssimon case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 755238405Sjkim memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); 756205128Ssimon break; 757194206Ssimon#if defined(SO_RCVTIMEO) 758160814Ssimon case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: 759194206Ssimon#ifdef OPENSSL_SYS_WINDOWS 760194206Ssimon { 761194206Ssimon struct timeval *tv = (struct timeval *)ptr; 762194206Ssimon int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 763194206Ssimon if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 764194206Ssimon (void*)&timeout, sizeof(timeout)) < 0) 765194206Ssimon { perror("setsockopt"); ret = -1; } 766194206Ssimon } 767194206Ssimon#else 768160814Ssimon if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, 769160814Ssimon sizeof(struct timeval)) < 0) 770160814Ssimon { perror("setsockopt"); ret = -1; } 771194206Ssimon#endif 772160814Ssimon break; 773160814Ssimon case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: 774246772Sjkim { 775246772Sjkim union { size_t s; int i; } sz = {0}; 776194206Ssimon#ifdef OPENSSL_SYS_WINDOWS 777246772Sjkim int timeout; 778194206Ssimon struct timeval *tv = (struct timeval *)ptr; 779246772Sjkim 780246772Sjkim sz.i = sizeof(timeout); 781194206Ssimon if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 782246772Sjkim (void*)&timeout, &sz.i) < 0) 783194206Ssimon { perror("getsockopt"); ret = -1; } 784194206Ssimon else 785194206Ssimon { 786194206Ssimon tv->tv_sec = timeout / 1000; 787194206Ssimon tv->tv_usec = (timeout % 1000) * 1000; 788194206Ssimon ret = sizeof(*tv); 789194206Ssimon } 790194206Ssimon#else 791246772Sjkim sz.i = sizeof(struct timeval); 792160814Ssimon if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 793246772Sjkim ptr, (void *)&sz) < 0) 794160814Ssimon { perror("getsockopt"); ret = -1; } 795246772Sjkim else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 796246772Sjkim { 797246772Sjkim OPENSSL_assert(sz.s<=sizeof(struct timeval)); 798246772Sjkim ret = (int)sz.s; 799246772Sjkim } 800246772Sjkim else 801246772Sjkim ret = sz.i; 802194206Ssimon#endif 803246772Sjkim } 804160814Ssimon break; 805194206Ssimon#endif 806194206Ssimon#if defined(SO_SNDTIMEO) 807160814Ssimon case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: 808194206Ssimon#ifdef OPENSSL_SYS_WINDOWS 809194206Ssimon { 810194206Ssimon struct timeval *tv = (struct timeval *)ptr; 811194206Ssimon int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 812194206Ssimon if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 813194206Ssimon (void*)&timeout, sizeof(timeout)) < 0) 814194206Ssimon { perror("setsockopt"); ret = -1; } 815194206Ssimon } 816194206Ssimon#else 817160814Ssimon if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, 818160814Ssimon sizeof(struct timeval)) < 0) 819160814Ssimon { perror("setsockopt"); ret = -1; } 820194206Ssimon#endif 821160814Ssimon break; 822160814Ssimon case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: 823246772Sjkim { 824246772Sjkim union { size_t s; int i; } sz = {0}; 825194206Ssimon#ifdef OPENSSL_SYS_WINDOWS 826246772Sjkim int timeout; 827194206Ssimon struct timeval *tv = (struct timeval *)ptr; 828246772Sjkim 829246772Sjkim sz.i = sizeof(timeout); 830194206Ssimon if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 831246772Sjkim (void*)&timeout, &sz.i) < 0) 832194206Ssimon { perror("getsockopt"); ret = -1; } 833194206Ssimon else 834194206Ssimon { 835194206Ssimon tv->tv_sec = timeout / 1000; 836194206Ssimon tv->tv_usec = (timeout % 1000) * 1000; 837194206Ssimon ret = sizeof(*tv); 838194206Ssimon } 839194206Ssimon#else 840246772Sjkim sz.i = sizeof(struct timeval); 841160814Ssimon if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 842246772Sjkim ptr, (void *)&sz) < 0) 843160814Ssimon { perror("getsockopt"); ret = -1; } 844246772Sjkim else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 845246772Sjkim { 846246772Sjkim OPENSSL_assert(sz.s<=sizeof(struct timeval)); 847246772Sjkim ret = (int)sz.s; 848246772Sjkim } 849246772Sjkim else 850246772Sjkim ret = sz.i; 851194206Ssimon#endif 852246772Sjkim } 853160814Ssimon break; 854194206Ssimon#endif 855160814Ssimon case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: 856160814Ssimon /* fall-through */ 857160814Ssimon case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: 858194206Ssimon#ifdef OPENSSL_SYS_WINDOWS 859194206Ssimon if ( data->_errno == WSAETIMEDOUT) 860194206Ssimon#else 861160814Ssimon if ( data->_errno == EAGAIN) 862194206Ssimon#endif 863160814Ssimon { 864160814Ssimon ret = 1; 865160814Ssimon data->_errno = 0; 866160814Ssimon } 867160814Ssimon else 868160814Ssimon ret = 0; 869160814Ssimon break; 870160814Ssimon#ifdef EMSGSIZE 871160814Ssimon case BIO_CTRL_DGRAM_MTU_EXCEEDED: 872160814Ssimon if ( data->_errno == EMSGSIZE) 873160814Ssimon { 874160814Ssimon ret = 1; 875160814Ssimon data->_errno = 0; 876160814Ssimon } 877160814Ssimon else 878160814Ssimon ret = 0; 879160814Ssimon break; 880160814Ssimon#endif 881279264Sdelphij case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 882279264Sdelphij ret = dgram_get_mtu_overhead(data); 883279264Sdelphij break; 884160814Ssimon default: 885160814Ssimon ret=0; 886160814Ssimon break; 887160814Ssimon } 888160814Ssimon return(ret); 889160814Ssimon } 890160814Ssimon 891160814Ssimonstatic int dgram_puts(BIO *bp, const char *str) 892160814Ssimon { 893160814Ssimon int n,ret; 894160814Ssimon 895160814Ssimon n=strlen(str); 896160814Ssimon ret=dgram_write(bp,str,n); 897160814Ssimon return(ret); 898160814Ssimon } 899160814Ssimon 900238405Sjkim#ifndef OPENSSL_NO_SCTP 901238405SjkimBIO_METHOD *BIO_s_datagram_sctp(void) 902238405Sjkim { 903238405Sjkim return(&methods_dgramp_sctp); 904238405Sjkim } 905238405Sjkim 906238405SjkimBIO *BIO_new_dgram_sctp(int fd, int close_flag) 907238405Sjkim { 908238405Sjkim BIO *bio; 909238405Sjkim int ret, optval = 20000; 910238405Sjkim int auth_data = 0, auth_forward = 0; 911238405Sjkim unsigned char *p; 912238405Sjkim struct sctp_authchunk auth; 913238405Sjkim struct sctp_authchunks *authchunks; 914238405Sjkim socklen_t sockopt_len; 915238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 916238405Sjkim#ifdef SCTP_EVENT 917238405Sjkim struct sctp_event event; 918238405Sjkim#else 919238405Sjkim struct sctp_event_subscribe event; 920238405Sjkim#endif 921238405Sjkim#endif 922238405Sjkim 923238405Sjkim bio=BIO_new(BIO_s_datagram_sctp()); 924238405Sjkim if (bio == NULL) return(NULL); 925238405Sjkim BIO_set_fd(bio,fd,close_flag); 926238405Sjkim 927238405Sjkim /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ 928238405Sjkim auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; 929238405Sjkim ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); 930279264Sdelphij if (ret < 0) 931279264Sdelphij { 932279264Sdelphij BIO_vfree(bio); 933279264Sdelphij return(NULL); 934279264Sdelphij } 935238405Sjkim auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; 936238405Sjkim ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); 937279264Sdelphij if (ret < 0) 938279264Sdelphij { 939279264Sdelphij BIO_vfree(bio); 940279264Sdelphij return(NULL); 941279264Sdelphij } 942238405Sjkim 943238405Sjkim /* Test if activation was successful. When using accept(), 944238405Sjkim * SCTP-AUTH has to be activated for the listening socket 945238405Sjkim * already, otherwise the connected socket won't use it. */ 946238405Sjkim sockopt_len = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); 947238405Sjkim authchunks = OPENSSL_malloc(sockopt_len); 948238405Sjkim memset(authchunks, 0, sizeof(sockopt_len)); 949238405Sjkim ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len); 950279264Sdelphij 951279264Sdelphij if (ret < 0) 952279264Sdelphij { 953279264Sdelphij OPENSSL_free(authchunks); 954279264Sdelphij BIO_vfree(bio); 955279264Sdelphij return(NULL); 956279264Sdelphij } 957279264Sdelphij 958279264Sdelphij for (p = (unsigned char*) authchunks->gauth_chunks; 959238405Sjkim p < (unsigned char*) authchunks + sockopt_len; 960238405Sjkim p += sizeof(uint8_t)) 961238405Sjkim { 962238405Sjkim if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1; 963238405Sjkim if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1; 964238405Sjkim } 965238405Sjkim 966238405Sjkim OPENSSL_free(authchunks); 967238405Sjkim 968238405Sjkim OPENSSL_assert(auth_data); 969238405Sjkim OPENSSL_assert(auth_forward); 970238405Sjkim 971238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 972238405Sjkim#ifdef SCTP_EVENT 973238405Sjkim memset(&event, 0, sizeof(struct sctp_event)); 974238405Sjkim event.se_assoc_id = 0; 975238405Sjkim event.se_type = SCTP_AUTHENTICATION_EVENT; 976238405Sjkim event.se_on = 1; 977238405Sjkim ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); 978279264Sdelphij if (ret < 0) 979279264Sdelphij { 980279264Sdelphij BIO_vfree(bio); 981279264Sdelphij return(NULL); 982279264Sdelphij } 983238405Sjkim#else 984238405Sjkim sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); 985238405Sjkim ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); 986279264Sdelphij if (ret < 0) 987279264Sdelphij { 988279264Sdelphij BIO_vfree(bio); 989279264Sdelphij return(NULL); 990279264Sdelphij } 991238405Sjkim 992238405Sjkim event.sctp_authentication_event = 1; 993238405Sjkim 994238405Sjkim ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); 995279264Sdelphij if (ret < 0) 996279264Sdelphij { 997279264Sdelphij BIO_vfree(bio); 998279264Sdelphij return(NULL); 999279264Sdelphij } 1000238405Sjkim#endif 1001238405Sjkim#endif 1002238405Sjkim 1003238405Sjkim /* Disable partial delivery by setting the min size 1004238405Sjkim * larger than the max record size of 2^14 + 2048 + 13 1005238405Sjkim */ 1006238405Sjkim ret = setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, sizeof(optval)); 1007279264Sdelphij if (ret < 0) 1008279264Sdelphij { 1009279264Sdelphij BIO_vfree(bio); 1010279264Sdelphij return(NULL); 1011279264Sdelphij } 1012238405Sjkim 1013238405Sjkim return(bio); 1014238405Sjkim } 1015238405Sjkim 1016238405Sjkimint BIO_dgram_is_sctp(BIO *bio) 1017238405Sjkim { 1018238405Sjkim return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); 1019238405Sjkim } 1020238405Sjkim 1021238405Sjkimstatic int dgram_sctp_new(BIO *bi) 1022238405Sjkim { 1023238405Sjkim bio_dgram_sctp_data *data = NULL; 1024238405Sjkim 1025238405Sjkim bi->init=0; 1026238405Sjkim bi->num=0; 1027238405Sjkim data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data)); 1028238405Sjkim if (data == NULL) 1029238405Sjkim return 0; 1030238405Sjkim memset(data, 0x00, sizeof(bio_dgram_sctp_data)); 1031238405Sjkim#ifdef SCTP_PR_SCTP_NONE 1032238405Sjkim data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; 1033238405Sjkim#endif 1034238405Sjkim bi->ptr = data; 1035238405Sjkim 1036238405Sjkim bi->flags=0; 1037238405Sjkim return(1); 1038238405Sjkim } 1039238405Sjkim 1040238405Sjkimstatic int dgram_sctp_free(BIO *a) 1041238405Sjkim { 1042238405Sjkim bio_dgram_sctp_data *data; 1043238405Sjkim 1044238405Sjkim if (a == NULL) return(0); 1045238405Sjkim if ( ! dgram_clear(a)) 1046238405Sjkim return 0; 1047238405Sjkim 1048238405Sjkim data = (bio_dgram_sctp_data *)a->ptr; 1049277195Sdelphij if(data != NULL) 1050277195Sdelphij { 1051277195Sdelphij if(data->saved_message.data != NULL) 1052277195Sdelphij OPENSSL_free(data->saved_message.data); 1053277195Sdelphij OPENSSL_free(data); 1054277195Sdelphij } 1055238405Sjkim 1056238405Sjkim return(1); 1057238405Sjkim } 1058238405Sjkim 1059238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 1060238405Sjkimvoid dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp) 1061238405Sjkim { 1062238405Sjkim int ret; 1063238405Sjkim struct sctp_authkey_event* authkeyevent = &snp->sn_auth_event; 1064238405Sjkim 1065238405Sjkim if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) 1066238405Sjkim { 1067238405Sjkim struct sctp_authkeyid authkeyid; 1068238405Sjkim 1069238405Sjkim /* delete key */ 1070238405Sjkim authkeyid.scact_keynumber = authkeyevent->auth_keynumber; 1071238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, 1072246772Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1073238405Sjkim } 1074238405Sjkim } 1075238405Sjkim#endif 1076238405Sjkim 1077238405Sjkimstatic int dgram_sctp_read(BIO *b, char *out, int outl) 1078238405Sjkim { 1079238405Sjkim int ret = 0, n = 0, i, optval; 1080238405Sjkim socklen_t optlen; 1081238405Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; 1082238405Sjkim union sctp_notification *snp; 1083238405Sjkim struct msghdr msg; 1084238405Sjkim struct iovec iov; 1085238405Sjkim struct cmsghdr *cmsg; 1086238405Sjkim char cmsgbuf[512]; 1087238405Sjkim 1088238405Sjkim if (out != NULL) 1089238405Sjkim { 1090238405Sjkim clear_socket_error(); 1091238405Sjkim 1092238405Sjkim do 1093238405Sjkim { 1094238405Sjkim memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo)); 1095238405Sjkim iov.iov_base = out; 1096238405Sjkim iov.iov_len = outl; 1097238405Sjkim msg.msg_name = NULL; 1098238405Sjkim msg.msg_namelen = 0; 1099238405Sjkim msg.msg_iov = &iov; 1100238405Sjkim msg.msg_iovlen = 1; 1101238405Sjkim msg.msg_control = cmsgbuf; 1102238405Sjkim msg.msg_controllen = 512; 1103238405Sjkim msg.msg_flags = 0; 1104238405Sjkim n = recvmsg(b->num, &msg, 0); 1105238405Sjkim 1106279264Sdelphij if (n <= 0) 1107279264Sdelphij { 1108279264Sdelphij if (n < 0) 1109279264Sdelphij ret = n; 1110279264Sdelphij break; 1111279264Sdelphij } 1112279264Sdelphij 1113238405Sjkim if (msg.msg_controllen > 0) 1114238405Sjkim { 1115238405Sjkim for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) 1116238405Sjkim { 1117238405Sjkim if (cmsg->cmsg_level != IPPROTO_SCTP) 1118238405Sjkim continue; 1119238405Sjkim#ifdef SCTP_RCVINFO 1120238405Sjkim if (cmsg->cmsg_type == SCTP_RCVINFO) 1121238405Sjkim { 1122238405Sjkim struct sctp_rcvinfo *rcvinfo; 1123238405Sjkim 1124238405Sjkim rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); 1125238405Sjkim data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; 1126238405Sjkim data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; 1127238405Sjkim data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; 1128238405Sjkim data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; 1129238405Sjkim data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; 1130238405Sjkim data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; 1131238405Sjkim data->rcvinfo.rcv_context = rcvinfo->rcv_context; 1132238405Sjkim } 1133238405Sjkim#endif 1134238405Sjkim#ifdef SCTP_SNDRCV 1135238405Sjkim if (cmsg->cmsg_type == SCTP_SNDRCV) 1136238405Sjkim { 1137238405Sjkim struct sctp_sndrcvinfo *sndrcvinfo; 1138238405Sjkim 1139238405Sjkim sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 1140238405Sjkim data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; 1141238405Sjkim data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; 1142238405Sjkim data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; 1143238405Sjkim data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; 1144238405Sjkim data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; 1145238405Sjkim data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; 1146238405Sjkim data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; 1147238405Sjkim } 1148238405Sjkim#endif 1149238405Sjkim } 1150238405Sjkim } 1151238405Sjkim 1152238405Sjkim if (msg.msg_flags & MSG_NOTIFICATION) 1153238405Sjkim { 1154238405Sjkim snp = (union sctp_notification*) out; 1155238405Sjkim if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) 1156238405Sjkim { 1157238405Sjkim#ifdef SCTP_EVENT 1158238405Sjkim struct sctp_event event; 1159238405Sjkim#else 1160238405Sjkim struct sctp_event_subscribe event; 1161238405Sjkim socklen_t eventsize; 1162238405Sjkim#endif 1163238405Sjkim /* If a message has been delayed until the socket 1164238405Sjkim * is dry, it can be sent now. 1165238405Sjkim */ 1166238405Sjkim if (data->saved_message.length > 0) 1167238405Sjkim { 1168238405Sjkim dgram_sctp_write(data->saved_message.bio, data->saved_message.data, 1169238405Sjkim data->saved_message.length); 1170238405Sjkim OPENSSL_free(data->saved_message.data); 1171277195Sdelphij data->saved_message.data = NULL; 1172238405Sjkim data->saved_message.length = 0; 1173238405Sjkim } 1174238405Sjkim 1175238405Sjkim /* disable sender dry event */ 1176238405Sjkim#ifdef SCTP_EVENT 1177238405Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1178238405Sjkim event.se_assoc_id = 0; 1179238405Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1180238405Sjkim event.se_on = 0; 1181238405Sjkim i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); 1182279264Sdelphij if (i < 0) 1183279264Sdelphij { 1184279264Sdelphij ret = i; 1185279264Sdelphij break; 1186279264Sdelphij } 1187238405Sjkim#else 1188238405Sjkim eventsize = sizeof(struct sctp_event_subscribe); 1189238405Sjkim i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); 1190279264Sdelphij if (i < 0) 1191279264Sdelphij { 1192279264Sdelphij ret = i; 1193279264Sdelphij break; 1194279264Sdelphij } 1195238405Sjkim 1196238405Sjkim event.sctp_sender_dry_event = 0; 1197238405Sjkim 1198238405Sjkim i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); 1199279264Sdelphij if (i < 0) 1200279264Sdelphij { 1201279264Sdelphij ret = i; 1202279264Sdelphij break; 1203279264Sdelphij } 1204238405Sjkim#endif 1205238405Sjkim } 1206238405Sjkim 1207238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 1208238405Sjkim if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1209238405Sjkim dgram_sctp_handle_auth_free_key_event(b, snp); 1210238405Sjkim#endif 1211238405Sjkim 1212238405Sjkim if (data->handle_notifications != NULL) 1213238405Sjkim data->handle_notifications(b, data->notification_context, (void*) out); 1214238405Sjkim 1215238405Sjkim memset(out, 0, outl); 1216238405Sjkim } 1217238405Sjkim else 1218238405Sjkim ret += n; 1219238405Sjkim } 1220238405Sjkim while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl)); 1221238405Sjkim 1222238405Sjkim if (ret > 0 && !(msg.msg_flags & MSG_EOR)) 1223238405Sjkim { 1224238405Sjkim /* Partial message read, this should never happen! */ 1225238405Sjkim 1226238405Sjkim /* The buffer was too small, this means the peer sent 1227238405Sjkim * a message that was larger than allowed. */ 1228238405Sjkim if (ret == outl) 1229238405Sjkim return -1; 1230238405Sjkim 1231238405Sjkim /* Test if socket buffer can handle max record 1232238405Sjkim * size (2^14 + 2048 + 13) 1233238405Sjkim */ 1234238405Sjkim optlen = (socklen_t) sizeof(int); 1235238405Sjkim ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); 1236279264Sdelphij if (ret >= 0) 1237279264Sdelphij OPENSSL_assert(optval >= 18445); 1238238405Sjkim 1239238405Sjkim /* Test if SCTP doesn't partially deliver below 1240238405Sjkim * max record size (2^14 + 2048 + 13) 1241238405Sjkim */ 1242238405Sjkim optlen = (socklen_t) sizeof(int); 1243238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, 1244238405Sjkim &optval, &optlen); 1245279264Sdelphij if (ret >= 0) 1246279264Sdelphij OPENSSL_assert(optval >= 18445); 1247238405Sjkim 1248238405Sjkim /* Partially delivered notification??? Probably a bug.... */ 1249238405Sjkim OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); 1250238405Sjkim 1251238405Sjkim /* Everything seems ok till now, so it's most likely 1252238405Sjkim * a message dropped by PR-SCTP. 1253238405Sjkim */ 1254238405Sjkim memset(out, 0, outl); 1255238405Sjkim BIO_set_retry_read(b); 1256238405Sjkim return -1; 1257238405Sjkim } 1258238405Sjkim 1259238405Sjkim BIO_clear_retry_flags(b); 1260238405Sjkim if (ret < 0) 1261238405Sjkim { 1262238405Sjkim if (BIO_dgram_should_retry(ret)) 1263238405Sjkim { 1264238405Sjkim BIO_set_retry_read(b); 1265238405Sjkim data->_errno = get_last_socket_error(); 1266238405Sjkim } 1267238405Sjkim } 1268238405Sjkim 1269238405Sjkim /* Test if peer uses SCTP-AUTH before continuing */ 1270238405Sjkim if (!data->peer_auth_tested) 1271238405Sjkim { 1272238405Sjkim int ii, auth_data = 0, auth_forward = 0; 1273238405Sjkim unsigned char *p; 1274238405Sjkim struct sctp_authchunks *authchunks; 1275238405Sjkim 1276238405Sjkim optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); 1277238405Sjkim authchunks = OPENSSL_malloc(optlen); 1278238405Sjkim memset(authchunks, 0, sizeof(optlen)); 1279238405Sjkim ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen); 1280238405Sjkim 1281279264Sdelphij if (ii >= 0) 1282279264Sdelphij for (p = (unsigned char*) authchunks->gauth_chunks; 1283279264Sdelphij p < (unsigned char*) authchunks + optlen; 1284279264Sdelphij p += sizeof(uint8_t)) 1285279264Sdelphij { 1286279264Sdelphij if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1; 1287279264Sdelphij if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1; 1288279264Sdelphij } 1289238405Sjkim 1290238405Sjkim OPENSSL_free(authchunks); 1291238405Sjkim 1292238405Sjkim if (!auth_data || !auth_forward) 1293238405Sjkim { 1294238405Sjkim BIOerr(BIO_F_DGRAM_SCTP_READ,BIO_R_CONNECT_ERROR); 1295238405Sjkim return -1; 1296238405Sjkim } 1297238405Sjkim 1298238405Sjkim data->peer_auth_tested = 1; 1299238405Sjkim } 1300238405Sjkim } 1301238405Sjkim return(ret); 1302238405Sjkim } 1303238405Sjkim 1304238405Sjkimstatic int dgram_sctp_write(BIO *b, const char *in, int inl) 1305238405Sjkim { 1306238405Sjkim int ret; 1307238405Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; 1308238405Sjkim struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); 1309238405Sjkim struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); 1310238405Sjkim struct bio_dgram_sctp_sndinfo handshake_sinfo; 1311238405Sjkim struct iovec iov[1]; 1312238405Sjkim struct msghdr msg; 1313238405Sjkim struct cmsghdr *cmsg; 1314238405Sjkim#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) 1315238405Sjkim char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))]; 1316238405Sjkim struct sctp_sndinfo *sndinfo; 1317238405Sjkim struct sctp_prinfo *prinfo; 1318238405Sjkim#else 1319238405Sjkim char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 1320238405Sjkim struct sctp_sndrcvinfo *sndrcvinfo; 1321238405Sjkim#endif 1322238405Sjkim 1323238405Sjkim clear_socket_error(); 1324238405Sjkim 1325238405Sjkim /* If we're send anything else than application data, 1326238405Sjkim * disable all user parameters and flags. 1327238405Sjkim */ 1328238405Sjkim if (in[0] != 23) { 1329238405Sjkim memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo)); 1330238405Sjkim#ifdef SCTP_SACK_IMMEDIATELY 1331238405Sjkim handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; 1332238405Sjkim#endif 1333238405Sjkim sinfo = &handshake_sinfo; 1334238405Sjkim } 1335238405Sjkim 1336238405Sjkim /* If we have to send a shutdown alert message and the 1337238405Sjkim * socket is not dry yet, we have to save it and send it 1338238405Sjkim * as soon as the socket gets dry. 1339238405Sjkim */ 1340238405Sjkim if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) 1341238405Sjkim { 1342238405Sjkim data->saved_message.bio = b; 1343277195Sdelphij if (data->saved_message.data) 1344277195Sdelphij OPENSSL_free(data->saved_message.data); 1345238405Sjkim data->saved_message.data = OPENSSL_malloc(inl); 1346238405Sjkim memcpy(data->saved_message.data, in, inl); 1347277195Sdelphij data->saved_message.length = inl; 1348238405Sjkim return inl; 1349238405Sjkim } 1350238405Sjkim 1351238405Sjkim iov[0].iov_base = (char *)in; 1352238405Sjkim iov[0].iov_len = inl; 1353238405Sjkim msg.msg_name = NULL; 1354238405Sjkim msg.msg_namelen = 0; 1355238405Sjkim msg.msg_iov = iov; 1356238405Sjkim msg.msg_iovlen = 1; 1357238405Sjkim msg.msg_control = (caddr_t)cmsgbuf; 1358238405Sjkim msg.msg_controllen = 0; 1359238405Sjkim msg.msg_flags = 0; 1360238405Sjkim#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) 1361238405Sjkim cmsg = (struct cmsghdr *)cmsgbuf; 1362238405Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1363238405Sjkim cmsg->cmsg_type = SCTP_SNDINFO; 1364238405Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); 1365238405Sjkim sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); 1366238405Sjkim memset(sndinfo, 0, sizeof(struct sctp_sndinfo)); 1367238405Sjkim sndinfo->snd_sid = sinfo->snd_sid; 1368238405Sjkim sndinfo->snd_flags = sinfo->snd_flags; 1369238405Sjkim sndinfo->snd_ppid = sinfo->snd_ppid; 1370238405Sjkim sndinfo->snd_context = sinfo->snd_context; 1371238405Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); 1372238405Sjkim 1373238405Sjkim cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; 1374238405Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1375238405Sjkim cmsg->cmsg_type = SCTP_PRINFO; 1376238405Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); 1377238405Sjkim prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); 1378238405Sjkim memset(prinfo, 0, sizeof(struct sctp_prinfo)); 1379238405Sjkim prinfo->pr_policy = pinfo->pr_policy; 1380238405Sjkim prinfo->pr_value = pinfo->pr_value; 1381238405Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); 1382238405Sjkim#else 1383238405Sjkim cmsg = (struct cmsghdr *)cmsgbuf; 1384238405Sjkim cmsg->cmsg_level = IPPROTO_SCTP; 1385238405Sjkim cmsg->cmsg_type = SCTP_SNDRCV; 1386238405Sjkim cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 1387238405Sjkim sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); 1388238405Sjkim memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); 1389238405Sjkim sndrcvinfo->sinfo_stream = sinfo->snd_sid; 1390238405Sjkim sndrcvinfo->sinfo_flags = sinfo->snd_flags; 1391238405Sjkim#ifdef __FreeBSD__ 1392238405Sjkim sndrcvinfo->sinfo_flags |= pinfo->pr_policy; 1393238405Sjkim#endif 1394238405Sjkim sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; 1395238405Sjkim sndrcvinfo->sinfo_context = sinfo->snd_context; 1396238405Sjkim sndrcvinfo->sinfo_timetolive = pinfo->pr_value; 1397238405Sjkim msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); 1398238405Sjkim#endif 1399238405Sjkim 1400238405Sjkim ret = sendmsg(b->num, &msg, 0); 1401238405Sjkim 1402238405Sjkim BIO_clear_retry_flags(b); 1403238405Sjkim if (ret <= 0) 1404238405Sjkim { 1405238405Sjkim if (BIO_dgram_should_retry(ret)) 1406238405Sjkim { 1407238405Sjkim BIO_set_retry_write(b); 1408238405Sjkim data->_errno = get_last_socket_error(); 1409238405Sjkim } 1410238405Sjkim } 1411238405Sjkim return(ret); 1412238405Sjkim } 1413238405Sjkim 1414238405Sjkimstatic long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) 1415238405Sjkim { 1416238405Sjkim long ret=1; 1417238405Sjkim bio_dgram_sctp_data *data = NULL; 1418246772Sjkim socklen_t sockopt_len = 0; 1419238405Sjkim struct sctp_authkeyid authkeyid; 1420279264Sdelphij struct sctp_authkey *authkey = NULL; 1421238405Sjkim 1422238405Sjkim data = (bio_dgram_sctp_data *)b->ptr; 1423238405Sjkim 1424238405Sjkim switch (cmd) 1425238405Sjkim { 1426238405Sjkim case BIO_CTRL_DGRAM_QUERY_MTU: 1427238405Sjkim /* Set to maximum (2^14) 1428238405Sjkim * and ignore user input to enable transport 1429238405Sjkim * protocol fragmentation. 1430238405Sjkim * Returns always 2^14. 1431238405Sjkim */ 1432238405Sjkim data->mtu = 16384; 1433238405Sjkim ret = data->mtu; 1434238405Sjkim break; 1435238405Sjkim case BIO_CTRL_DGRAM_SET_MTU: 1436238405Sjkim /* Set to maximum (2^14) 1437238405Sjkim * and ignore input to enable transport 1438238405Sjkim * protocol fragmentation. 1439238405Sjkim * Returns always 2^14. 1440238405Sjkim */ 1441238405Sjkim data->mtu = 16384; 1442238405Sjkim ret = data->mtu; 1443238405Sjkim break; 1444238405Sjkim case BIO_CTRL_DGRAM_SET_CONNECTED: 1445238405Sjkim case BIO_CTRL_DGRAM_CONNECT: 1446238405Sjkim /* Returns always -1. */ 1447238405Sjkim ret = -1; 1448238405Sjkim break; 1449238405Sjkim case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 1450238405Sjkim /* SCTP doesn't need the DTLS timer 1451238405Sjkim * Returns always 1. 1452238405Sjkim */ 1453238405Sjkim break; 1454279264Sdelphij case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 1455279264Sdelphij /* We allow transport protocol fragmentation so this is irrelevant */ 1456279264Sdelphij ret = 0; 1457279264Sdelphij break; 1458238405Sjkim case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: 1459238405Sjkim if (num > 0) 1460238405Sjkim data->in_handshake = 1; 1461238405Sjkim else 1462238405Sjkim data->in_handshake = 0; 1463238405Sjkim 1464238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, &data->in_handshake, sizeof(int)); 1465238405Sjkim break; 1466238405Sjkim case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: 1467238405Sjkim /* New shared key for SCTP AUTH. 1468238405Sjkim * Returns 0 on success, -1 otherwise. 1469238405Sjkim */ 1470238405Sjkim 1471238405Sjkim /* Get active key */ 1472238405Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1473238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); 1474238405Sjkim if (ret < 0) break; 1475238405Sjkim 1476238405Sjkim /* Add new key */ 1477238405Sjkim sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); 1478238405Sjkim authkey = OPENSSL_malloc(sockopt_len); 1479279264Sdelphij if (authkey == NULL) 1480279264Sdelphij { 1481279264Sdelphij ret = -1; 1482279264Sdelphij break; 1483279264Sdelphij } 1484238405Sjkim memset(authkey, 0x00, sockopt_len); 1485238405Sjkim authkey->sca_keynumber = authkeyid.scact_keynumber + 1; 1486238405Sjkim#ifndef __FreeBSD__ 1487238405Sjkim /* This field is missing in FreeBSD 8.2 and earlier, 1488238405Sjkim * and FreeBSD 8.3 and higher work without it. 1489238405Sjkim */ 1490238405Sjkim authkey->sca_keylength = 64; 1491238405Sjkim#endif 1492238405Sjkim memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); 1493238405Sjkim 1494238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, sockopt_len); 1495279264Sdelphij OPENSSL_free(authkey); 1496279264Sdelphij authkey = NULL; 1497238405Sjkim if (ret < 0) break; 1498238405Sjkim 1499238405Sjkim /* Reset active key */ 1500238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, 1501238405Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1502238405Sjkim if (ret < 0) break; 1503238405Sjkim 1504238405Sjkim break; 1505238405Sjkim case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: 1506238405Sjkim /* Returns 0 on success, -1 otherwise. */ 1507238405Sjkim 1508238405Sjkim /* Get active key */ 1509238405Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1510238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); 1511238405Sjkim if (ret < 0) break; 1512238405Sjkim 1513238405Sjkim /* Set active key */ 1514238405Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; 1515238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, 1516238405Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1517238405Sjkim if (ret < 0) break; 1518238405Sjkim 1519238405Sjkim /* CCS has been sent, so remember that and fall through 1520238405Sjkim * to check if we need to deactivate an old key 1521238405Sjkim */ 1522238405Sjkim data->ccs_sent = 1; 1523238405Sjkim 1524238405Sjkim case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: 1525238405Sjkim /* Returns 0 on success, -1 otherwise. */ 1526238405Sjkim 1527238405Sjkim /* Has this command really been called or is this just a fall-through? */ 1528238405Sjkim if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) 1529238405Sjkim data->ccs_rcvd = 1; 1530238405Sjkim 1531238405Sjkim /* CSS has been both, received and sent, so deactivate an old key */ 1532238405Sjkim if (data->ccs_rcvd == 1 && data->ccs_sent == 1) 1533238405Sjkim { 1534238405Sjkim /* Get active key */ 1535238405Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1536238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); 1537238405Sjkim if (ret < 0) break; 1538238405Sjkim 1539238405Sjkim /* Deactivate key or delete second last key if 1540238405Sjkim * SCTP_AUTHENTICATION_EVENT is not available. 1541238405Sjkim */ 1542238405Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; 1543238405Sjkim#ifdef SCTP_AUTH_DEACTIVATE_KEY 1544238405Sjkim sockopt_len = sizeof(struct sctp_authkeyid); 1545238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, 1546238405Sjkim &authkeyid, sockopt_len); 1547238405Sjkim if (ret < 0) break; 1548238405Sjkim#endif 1549238405Sjkim#ifndef SCTP_AUTHENTICATION_EVENT 1550238405Sjkim if (authkeyid.scact_keynumber > 0) 1551238405Sjkim { 1552238405Sjkim authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; 1553238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, 1554238405Sjkim &authkeyid, sizeof(struct sctp_authkeyid)); 1555238405Sjkim if (ret < 0) break; 1556238405Sjkim } 1557238405Sjkim#endif 1558238405Sjkim 1559238405Sjkim data->ccs_rcvd = 0; 1560238405Sjkim data->ccs_sent = 0; 1561238405Sjkim } 1562238405Sjkim break; 1563238405Sjkim case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: 1564238405Sjkim /* Returns the size of the copied struct. */ 1565238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo)) 1566238405Sjkim num = sizeof(struct bio_dgram_sctp_sndinfo); 1567238405Sjkim 1568238405Sjkim memcpy(ptr, &(data->sndinfo), num); 1569238405Sjkim ret = num; 1570238405Sjkim break; 1571238405Sjkim case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: 1572238405Sjkim /* Returns the size of the copied struct. */ 1573238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo)) 1574238405Sjkim num = sizeof(struct bio_dgram_sctp_sndinfo); 1575238405Sjkim 1576238405Sjkim memcpy(&(data->sndinfo), ptr, num); 1577238405Sjkim break; 1578238405Sjkim case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: 1579238405Sjkim /* Returns the size of the copied struct. */ 1580238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo)) 1581238405Sjkim num = sizeof(struct bio_dgram_sctp_rcvinfo); 1582238405Sjkim 1583238405Sjkim memcpy(ptr, &data->rcvinfo, num); 1584238405Sjkim 1585238405Sjkim ret = num; 1586238405Sjkim break; 1587238405Sjkim case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: 1588238405Sjkim /* Returns the size of the copied struct. */ 1589238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo)) 1590238405Sjkim num = sizeof(struct bio_dgram_sctp_rcvinfo); 1591238405Sjkim 1592238405Sjkim memcpy(&(data->rcvinfo), ptr, num); 1593238405Sjkim break; 1594238405Sjkim case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: 1595238405Sjkim /* Returns the size of the copied struct. */ 1596238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_prinfo)) 1597238405Sjkim num = sizeof(struct bio_dgram_sctp_prinfo); 1598238405Sjkim 1599238405Sjkim memcpy(ptr, &(data->prinfo), num); 1600238405Sjkim ret = num; 1601238405Sjkim break; 1602238405Sjkim case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: 1603238405Sjkim /* Returns the size of the copied struct. */ 1604238405Sjkim if (num > (long) sizeof(struct bio_dgram_sctp_prinfo)) 1605238405Sjkim num = sizeof(struct bio_dgram_sctp_prinfo); 1606238405Sjkim 1607238405Sjkim memcpy(&(data->prinfo), ptr, num); 1608238405Sjkim break; 1609238405Sjkim case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: 1610238405Sjkim /* Returns always 1. */ 1611238405Sjkim if (num > 0) 1612238405Sjkim data->save_shutdown = 1; 1613238405Sjkim else 1614238405Sjkim data->save_shutdown = 0; 1615238405Sjkim break; 1616238405Sjkim 1617238405Sjkim default: 1618238405Sjkim /* Pass to default ctrl function to 1619238405Sjkim * process SCTP unspecific commands 1620238405Sjkim */ 1621238405Sjkim ret=dgram_ctrl(b, cmd, num, ptr); 1622238405Sjkim break; 1623238405Sjkim } 1624238405Sjkim return(ret); 1625238405Sjkim } 1626238405Sjkim 1627238405Sjkimint BIO_dgram_sctp_notification_cb(BIO *b, 1628238405Sjkim void (*handle_notifications)(BIO *bio, void *context, void *buf), 1629238405Sjkim void *context) 1630238405Sjkim { 1631238405Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; 1632238405Sjkim 1633238405Sjkim if (handle_notifications != NULL) 1634238405Sjkim { 1635238405Sjkim data->handle_notifications = handle_notifications; 1636238405Sjkim data->notification_context = context; 1637238405Sjkim } 1638238405Sjkim else 1639238405Sjkim return -1; 1640238405Sjkim 1641238405Sjkim return 0; 1642238405Sjkim } 1643238405Sjkim 1644238405Sjkimint BIO_dgram_sctp_wait_for_dry(BIO *b) 1645238405Sjkim{ 1646238405Sjkim int is_dry = 0; 1647238405Sjkim int n, sockflags, ret; 1648238405Sjkim union sctp_notification snp; 1649238405Sjkim struct msghdr msg; 1650238405Sjkim struct iovec iov; 1651238405Sjkim#ifdef SCTP_EVENT 1652238405Sjkim struct sctp_event event; 1653238405Sjkim#else 1654238405Sjkim struct sctp_event_subscribe event; 1655238405Sjkim socklen_t eventsize; 1656238405Sjkim#endif 1657238405Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; 1658238405Sjkim 1659238405Sjkim /* set sender dry event */ 1660238405Sjkim#ifdef SCTP_EVENT 1661238405Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1662238405Sjkim event.se_assoc_id = 0; 1663238405Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1664238405Sjkim event.se_on = 1; 1665238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); 1666238405Sjkim#else 1667238405Sjkim eventsize = sizeof(struct sctp_event_subscribe); 1668238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); 1669238405Sjkim if (ret < 0) 1670238405Sjkim return -1; 1671238405Sjkim 1672238405Sjkim event.sctp_sender_dry_event = 1; 1673238405Sjkim 1674238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); 1675238405Sjkim#endif 1676238405Sjkim if (ret < 0) 1677238405Sjkim return -1; 1678238405Sjkim 1679238405Sjkim /* peek for notification */ 1680238405Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1681238405Sjkim iov.iov_base = (char *)&snp; 1682238405Sjkim iov.iov_len = sizeof(union sctp_notification); 1683238405Sjkim msg.msg_name = NULL; 1684238405Sjkim msg.msg_namelen = 0; 1685238405Sjkim msg.msg_iov = &iov; 1686238405Sjkim msg.msg_iovlen = 1; 1687238405Sjkim msg.msg_control = NULL; 1688238405Sjkim msg.msg_controllen = 0; 1689238405Sjkim msg.msg_flags = 0; 1690238405Sjkim 1691238405Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1692238405Sjkim if (n <= 0) 1693238405Sjkim { 1694238405Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) 1695238405Sjkim return -1; 1696238405Sjkim else 1697238405Sjkim return 0; 1698238405Sjkim } 1699238405Sjkim 1700238405Sjkim /* if we find a notification, process it and try again if necessary */ 1701238405Sjkim while (msg.msg_flags & MSG_NOTIFICATION) 1702238405Sjkim { 1703238405Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1704238405Sjkim iov.iov_base = (char *)&snp; 1705238405Sjkim iov.iov_len = sizeof(union sctp_notification); 1706238405Sjkim msg.msg_name = NULL; 1707238405Sjkim msg.msg_namelen = 0; 1708238405Sjkim msg.msg_iov = &iov; 1709238405Sjkim msg.msg_iovlen = 1; 1710238405Sjkim msg.msg_control = NULL; 1711238405Sjkim msg.msg_controllen = 0; 1712238405Sjkim msg.msg_flags = 0; 1713238405Sjkim 1714238405Sjkim n = recvmsg(b->num, &msg, 0); 1715238405Sjkim if (n <= 0) 1716238405Sjkim { 1717238405Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) 1718238405Sjkim return -1; 1719238405Sjkim else 1720238405Sjkim return is_dry; 1721238405Sjkim } 1722238405Sjkim 1723238405Sjkim if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) 1724238405Sjkim { 1725238405Sjkim is_dry = 1; 1726238405Sjkim 1727238405Sjkim /* disable sender dry event */ 1728238405Sjkim#ifdef SCTP_EVENT 1729238405Sjkim memset(&event, 0, sizeof(struct sctp_event)); 1730238405Sjkim event.se_assoc_id = 0; 1731238405Sjkim event.se_type = SCTP_SENDER_DRY_EVENT; 1732238405Sjkim event.se_on = 0; 1733238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); 1734238405Sjkim#else 1735238405Sjkim eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); 1736238405Sjkim ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); 1737238405Sjkim if (ret < 0) 1738238405Sjkim return -1; 1739238405Sjkim 1740238405Sjkim event.sctp_sender_dry_event = 0; 1741238405Sjkim 1742238405Sjkim ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); 1743238405Sjkim#endif 1744238405Sjkim if (ret < 0) 1745238405Sjkim return -1; 1746238405Sjkim } 1747238405Sjkim 1748238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 1749238405Sjkim if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1750238405Sjkim dgram_sctp_handle_auth_free_key_event(b, &snp); 1751238405Sjkim#endif 1752238405Sjkim 1753238405Sjkim if (data->handle_notifications != NULL) 1754238405Sjkim data->handle_notifications(b, data->notification_context, (void*) &snp); 1755238405Sjkim 1756238405Sjkim /* found notification, peek again */ 1757238405Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1758238405Sjkim iov.iov_base = (char *)&snp; 1759238405Sjkim iov.iov_len = sizeof(union sctp_notification); 1760238405Sjkim msg.msg_name = NULL; 1761238405Sjkim msg.msg_namelen = 0; 1762238405Sjkim msg.msg_iov = &iov; 1763238405Sjkim msg.msg_iovlen = 1; 1764238405Sjkim msg.msg_control = NULL; 1765238405Sjkim msg.msg_controllen = 0; 1766238405Sjkim msg.msg_flags = 0; 1767238405Sjkim 1768238405Sjkim /* if we have seen the dry already, don't wait */ 1769238405Sjkim if (is_dry) 1770238405Sjkim { 1771238405Sjkim sockflags = fcntl(b->num, F_GETFL, 0); 1772238405Sjkim fcntl(b->num, F_SETFL, O_NONBLOCK); 1773238405Sjkim } 1774238405Sjkim 1775238405Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1776238405Sjkim 1777238405Sjkim if (is_dry) 1778238405Sjkim { 1779238405Sjkim fcntl(b->num, F_SETFL, sockflags); 1780238405Sjkim } 1781238405Sjkim 1782238405Sjkim if (n <= 0) 1783238405Sjkim { 1784238405Sjkim if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) 1785238405Sjkim return -1; 1786238405Sjkim else 1787238405Sjkim return is_dry; 1788238405Sjkim } 1789238405Sjkim } 1790238405Sjkim 1791238405Sjkim /* read anything else */ 1792238405Sjkim return is_dry; 1793238405Sjkim} 1794238405Sjkim 1795238405Sjkimint BIO_dgram_sctp_msg_waiting(BIO *b) 1796238405Sjkim { 1797238405Sjkim int n, sockflags; 1798238405Sjkim union sctp_notification snp; 1799238405Sjkim struct msghdr msg; 1800238405Sjkim struct iovec iov; 1801238405Sjkim bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; 1802238405Sjkim 1803238405Sjkim /* Check if there are any messages waiting to be read */ 1804238405Sjkim do 1805238405Sjkim { 1806238405Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1807238405Sjkim iov.iov_base = (char *)&snp; 1808238405Sjkim iov.iov_len = sizeof(union sctp_notification); 1809238405Sjkim msg.msg_name = NULL; 1810238405Sjkim msg.msg_namelen = 0; 1811238405Sjkim msg.msg_iov = &iov; 1812238405Sjkim msg.msg_iovlen = 1; 1813238405Sjkim msg.msg_control = NULL; 1814238405Sjkim msg.msg_controllen = 0; 1815238405Sjkim msg.msg_flags = 0; 1816238405Sjkim 1817238405Sjkim sockflags = fcntl(b->num, F_GETFL, 0); 1818238405Sjkim fcntl(b->num, F_SETFL, O_NONBLOCK); 1819238405Sjkim n = recvmsg(b->num, &msg, MSG_PEEK); 1820238405Sjkim fcntl(b->num, F_SETFL, sockflags); 1821238405Sjkim 1822238405Sjkim /* if notification, process and try again */ 1823238405Sjkim if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) 1824238405Sjkim { 1825238405Sjkim#ifdef SCTP_AUTHENTICATION_EVENT 1826238405Sjkim if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) 1827238405Sjkim dgram_sctp_handle_auth_free_key_event(b, &snp); 1828238405Sjkim#endif 1829238405Sjkim 1830238405Sjkim memset(&snp, 0x00, sizeof(union sctp_notification)); 1831238405Sjkim iov.iov_base = (char *)&snp; 1832238405Sjkim iov.iov_len = sizeof(union sctp_notification); 1833238405Sjkim msg.msg_name = NULL; 1834238405Sjkim msg.msg_namelen = 0; 1835238405Sjkim msg.msg_iov = &iov; 1836238405Sjkim msg.msg_iovlen = 1; 1837238405Sjkim msg.msg_control = NULL; 1838238405Sjkim msg.msg_controllen = 0; 1839238405Sjkim msg.msg_flags = 0; 1840238405Sjkim n = recvmsg(b->num, &msg, 0); 1841238405Sjkim 1842238405Sjkim if (data->handle_notifications != NULL) 1843238405Sjkim data->handle_notifications(b, data->notification_context, (void*) &snp); 1844238405Sjkim } 1845238405Sjkim 1846238405Sjkim } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); 1847238405Sjkim 1848238405Sjkim /* Return 1 if there is a message to be read, return 0 otherwise. */ 1849238405Sjkim if (n > 0) 1850238405Sjkim return 1; 1851238405Sjkim else 1852238405Sjkim return 0; 1853238405Sjkim } 1854238405Sjkim 1855238405Sjkimstatic int dgram_sctp_puts(BIO *bp, const char *str) 1856238405Sjkim { 1857238405Sjkim int n,ret; 1858238405Sjkim 1859238405Sjkim n=strlen(str); 1860238405Sjkim ret=dgram_sctp_write(bp,str,n); 1861238405Sjkim return(ret); 1862238405Sjkim } 1863238405Sjkim#endif 1864238405Sjkim 1865194206Ssimonstatic int BIO_dgram_should_retry(int i) 1866160814Ssimon { 1867160814Ssimon int err; 1868160814Ssimon 1869160814Ssimon if ((i == 0) || (i == -1)) 1870160814Ssimon { 1871160814Ssimon err=get_last_socket_error(); 1872160814Ssimon 1873237657Sjkim#if defined(OPENSSL_SYS_WINDOWS) 1874237657Sjkim /* If the socket return value (i) is -1 1875237657Sjkim * and err is unexpectedly 0 at this point, 1876237657Sjkim * the error code was overwritten by 1877237657Sjkim * another system call before this error 1878237657Sjkim * handling is called. 1879237657Sjkim */ 1880160814Ssimon#endif 1881160814Ssimon 1882160814Ssimon return(BIO_dgram_non_fatal_error(err)); 1883160814Ssimon } 1884160814Ssimon return(0); 1885160814Ssimon } 1886160814Ssimon 1887160814Ssimonint BIO_dgram_non_fatal_error(int err) 1888160814Ssimon { 1889160814Ssimon switch (err) 1890160814Ssimon { 1891160814Ssimon#if defined(OPENSSL_SYS_WINDOWS) 1892160814Ssimon# if defined(WSAEWOULDBLOCK) 1893160814Ssimon case WSAEWOULDBLOCK: 1894160814Ssimon# endif 1895160814Ssimon 1896160814Ssimon# if 0 /* This appears to always be an error */ 1897160814Ssimon# if defined(WSAENOTCONN) 1898160814Ssimon case WSAENOTCONN: 1899160814Ssimon# endif 1900160814Ssimon# endif 1901160814Ssimon#endif 1902160814Ssimon 1903160814Ssimon#ifdef EWOULDBLOCK 1904160814Ssimon# ifdef WSAEWOULDBLOCK 1905160814Ssimon# if WSAEWOULDBLOCK != EWOULDBLOCK 1906160814Ssimon case EWOULDBLOCK: 1907160814Ssimon# endif 1908160814Ssimon# else 1909160814Ssimon case EWOULDBLOCK: 1910160814Ssimon# endif 1911160814Ssimon#endif 1912160814Ssimon 1913160814Ssimon#ifdef EINTR 1914160814Ssimon case EINTR: 1915160814Ssimon#endif 1916160814Ssimon 1917160814Ssimon#ifdef EAGAIN 1918160814Ssimon#if EWOULDBLOCK != EAGAIN 1919160814Ssimon case EAGAIN: 1920160814Ssimon# endif 1921160814Ssimon#endif 1922160814Ssimon 1923160814Ssimon#ifdef EPROTO 1924160814Ssimon case EPROTO: 1925160814Ssimon#endif 1926160814Ssimon 1927160814Ssimon#ifdef EINPROGRESS 1928160814Ssimon case EINPROGRESS: 1929160814Ssimon#endif 1930160814Ssimon 1931160814Ssimon#ifdef EALREADY 1932160814Ssimon case EALREADY: 1933160814Ssimon#endif 1934160814Ssimon 1935160814Ssimon return(1); 1936160814Ssimon /* break; */ 1937160814Ssimon default: 1938160814Ssimon break; 1939160814Ssimon } 1940160814Ssimon return(0); 1941160814Ssimon } 1942205128Ssimon 1943205128Ssimonstatic void get_current_time(struct timeval *t) 1944205128Ssimon { 1945205128Ssimon#ifdef OPENSSL_SYS_WIN32 1946205128Ssimon struct _timeb tb; 1947205128Ssimon _ftime(&tb); 1948205128Ssimon t->tv_sec = (long)tb.time; 1949205128Ssimon t->tv_usec = (long)tb.millitm * 1000; 1950205128Ssimon#elif defined(OPENSSL_SYS_VMS) 1951205128Ssimon struct timeb tb; 1952205128Ssimon ftime(&tb); 1953205128Ssimon t->tv_sec = (long)tb.time; 1954205128Ssimon t->tv_usec = (long)tb.millitm * 1000; 1955205128Ssimon#else 1956205128Ssimon gettimeofday(t, NULL); 1957205128Ssimon#endif 1958205128Ssimon } 1959237657Sjkim 1960237657Sjkim#endif 1961