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