diff options
Diffstat (limited to 'src/lib/libcrypto/bio/bss_dgram.c')
-rw-r--r-- | src/lib/libcrypto/bio/bss_dgram.c | 996 |
1 files changed, 996 insertions, 0 deletions
diff --git a/src/lib/libcrypto/bio/bss_dgram.c b/src/lib/libcrypto/bio/bss_dgram.c index 71ebe987b6..1b1e4bec81 100644 --- a/src/lib/libcrypto/bio/bss_dgram.c +++ b/src/lib/libcrypto/bio/bss_dgram.c | |||
@@ -70,6 +70,13 @@ | |||
70 | #include <sys/timeb.h> | 70 | #include <sys/timeb.h> |
71 | #endif | 71 | #endif |
72 | 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 | |||
73 | #ifdef OPENSSL_SYS_LINUX | 80 | #ifdef OPENSSL_SYS_LINUX |
74 | #define IP_MTU 14 /* linux is lame */ | 81 | #define IP_MTU 14 /* linux is lame */ |
75 | #endif | 82 | #endif |
@@ -88,6 +95,18 @@ static int dgram_new(BIO *h); | |||
88 | static int dgram_free(BIO *data); | 95 | static int dgram_free(BIO *data); |
89 | static int dgram_clear(BIO *bio); | 96 | static int dgram_clear(BIO *bio); |
90 | 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 | |||
91 | static int BIO_dgram_should_retry(int s); | 110 | static int BIO_dgram_should_retry(int s); |
92 | 111 | ||
93 | static void get_current_time(struct timeval *t); | 112 | static void get_current_time(struct timeval *t); |
@@ -106,6 +125,22 @@ static BIO_METHOD methods_dgramp= | |||
106 | NULL, | 125 | NULL, |
107 | }; | 126 | }; |
108 | 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 | |||
109 | typedef struct bio_dgram_data_st | 144 | typedef struct bio_dgram_data_st |
110 | { | 145 | { |
111 | union { | 146 | union { |
@@ -122,6 +157,40 @@ typedef struct bio_dgram_data_st | |||
122 | struct timeval socket_timeout; | 157 | struct timeval socket_timeout; |
123 | } bio_dgram_data; | 158 | } bio_dgram_data; |
124 | 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 | |||
125 | BIO_METHOD *BIO_s_datagram(void) | 194 | BIO_METHOD *BIO_s_datagram(void) |
126 | { | 195 | { |
127 | return(&methods_dgramp); | 196 | return(&methods_dgramp); |
@@ -547,6 +616,27 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) | |||
547 | ret = 0; | 616 | ret = 0; |
548 | #endif | 617 | #endif |
549 | break; | 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; | ||
550 | case BIO_CTRL_DGRAM_GET_MTU: | 640 | case BIO_CTRL_DGRAM_GET_MTU: |
551 | return data->mtu; | 641 | return data->mtu; |
552 | break; | 642 | break; |
@@ -738,6 +828,912 @@ static int dgram_puts(BIO *bp, const char *str) | |||
738 | return(ret); | 828 | return(ret); |
739 | } | 829 | } |
740 | 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 | |||
741 | static int BIO_dgram_should_retry(int i) | 1737 | static int BIO_dgram_should_retry(int i) |
742 | { | 1738 | { |
743 | int err; | 1739 | int err; |