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