+
+ msg_hdr = &s->d1->r_msg_hdr;
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+again:
+ i = dtls1_get_message_fragment(s, st1, stn, max, ok);
+ if ( i == DTLS1_HM_BAD_FRAGMENT ||
+ i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
+ goto again;
+ else if ( i <= 0 && !*ok)
+ return i;
+
+ p = (unsigned char *)s->init_buf->data;
+ msg_len = msg_hdr->msg_len;
+
+ /* reconstruct message header */
+ *(p++) = msg_hdr->type;
+ l2n3(msg_len,p);
+ s2n (msg_hdr->seq,p);
+ l2n3(0,p);
+ l2n3(msg_len,p);
+ if (s->version != DTLS1_BAD_VER) {
+ p -= DTLS1_HM_HEADER_LENGTH;
+ msg_len += DTLS1_HM_HEADER_LENGTH;
+ }
+
+ ssl3_finish_mac(s, p, msg_len);
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ p, msg_len,
+ s, s->msg_callback_arg);
+
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+ s->d1->handshake_read_seq++;
+ /* we just read a handshake message from the other side:
+ * this means that we don't need to retransmit of the
+ * buffered messages.
+ * XDTLS: may be able clear out this
+ * buffer a little sooner (i.e if an out-of-order
+ * handshake message/record is received at the record
+ * layer.
+ * XDTLS: exception is that the server needs to
+ * know that change cipher spec and finished messages
+ * have been received by the client before clearing this
+ * buffer. this can simply be done by waiting for the
+ * first data segment, but is there a better way? */
+ dtls1_clear_record_buffer(s);
+
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ return s->init_num;
+
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ *ok = 0;
+ return -1;
+ }
+
+
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
+ {
+ size_t frag_off,frag_len,msg_len;
+
+ msg_len = msg_hdr->msg_len;
+ frag_off = msg_hdr->frag_off;
+ frag_len = msg_hdr->frag_len;
+
+ /* sanity checking */
+ if ( (frag_off+frag_len) > msg_len)
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ if ( (frag_off+frag_len) > (unsigned long)max)
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
+ {
+ /* msg_len is limited to 2^24, but is effectively checked
+ * against max above */
+ if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH))
+ {
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
+ return SSL_AD_INTERNAL_ERROR;
+ }
+
+ s->s3->tmp.message_size = msg_len;
+ s->d1->r_msg_hdr.msg_len = msg_len;
+ s->s3->tmp.message_type = msg_hdr->type;
+ s->d1->r_msg_hdr.type = msg_hdr->type;
+ s->d1->r_msg_hdr.seq = msg_hdr->seq;
+ }
+ else if (msg_len != s->d1->r_msg_hdr.msg_len)
+ {
+ /* They must be playing with us! BTW, failure to enforce
+ * upper limit would open possibility for buffer overrun. */
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return SSL_AD_ILLEGAL_PARAMETER;
+ }
+
+ return 0; /* no error */
+ }
+
+
+static int
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+ {
+ /* (0) check whether the desired fragment is available
+ * if so:
+ * (1) copy over the fragment to s->init_buf->data[]
+ * (2) update s->init_num
+ */
+ pitem *item;
+ hm_fragment *frag;
+ int al;
+
+ *ok = 0;
+ item = pqueue_peek(s->d1->buffered_messages);
+ if ( item == NULL)
+ return 0;
+
+ frag = (hm_fragment *)item->data;