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