Index: ssl/d1_both.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_both.c,v
retrieving revision 1.14.2.21.2.9
diff -u -r1.14.2.21.2.9 d1_both.c
--- ssl/d1_both.c	6 Mar 2012 13:47:27 -0000	1.14.2.21.2.9
+++ ssl/d1_both.c	28 Aug 2012 12:28:45 -0000
@@ -122,6 +122,12 @@
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#ifndef OPENSSL_NO_DTLSMOBILITY
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#endif
 
 #define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
 
@@ -247,7 +253,12 @@
 
 	fprintf(stderr, "using MTU = %d\n", mtu);
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH +
+	        DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE);
+#else
 	mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+#endif
 
 	curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
 
@@ -261,7 +272,12 @@
 		ret = BIO_flush(SSL_get_wbio(s));
 		if ( ret <= 0)
 			return ret;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH +
+		                    DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE);
+#else
 		mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+#endif
 		}
 #endif
 
@@ -285,8 +301,14 @@
 	frag_off = 0;
 	while( s->init_num)
 		{
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - 
+			DTLS1_RT_HEADER_LENGTH - DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE -
+			mac_size - blocksize;
+#else
 		curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - 
 			DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
+#endif
 
 		if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
 			{
@@ -294,8 +316,13 @@
 			ret = BIO_flush(SSL_get_wbio(s));
 			if ( ret <= 0)
 				return ret;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+			curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
+				DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE - mac_size - blocksize;
+#else
 			curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
 				mac_size - blocksize;
+#endif
 			}
 
 		if ( s->init_num > curr_mtu)
@@ -303,7 +330,6 @@
 		else
 			len = s->init_num;
 
-
 		/* XDTLS: this function is too long.  split out the CCS part */
 		if ( type == SSL3_RT_HANDSHAKE)
 			{
@@ -1451,6 +1477,14 @@
 	unsigned short hbtype;
 	unsigned int payload;
 	unsigned int padding = 16; /* Use minimum padding */
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	int fd, addr_len;
+	union	{
+		struct sockaddr sa;
+		struct sockaddr_in sa_in;
+		struct sockaddr_in6 sa_in6;
+	} new_addr;
+#endif
 
 	/* Read type and payload length first */
 	hbtype = *p++;
@@ -1509,6 +1543,42 @@
 			s->tlsext_hb_seq++;
 			s->tlsext_hb_pending = 0;
 			}
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		/* Check for mobility address verification */
+		pl -= 2;
+		n2l(pl, seq);
+		/* Check for magic bytes */
+		if (seq == 0x42424242)
+			{
+printf("DTLS Mobility: changing to verified address!\n");
+			memcpy(&new_addr, pl, sizeof(new_addr));
+
+	if (s->d1->mobility_verify_addr.sa.sa_family == AF_INET) {
+		char addrbuf[INET6_ADDRSTRLEN];
+		printf ("got hbres for addr: %s:%d\n",
+				inet_ntop(AF_INET, &new_addr.sa_in.sin_addr, addrbuf, INET_ADDRSTRLEN),
+				ntohs(new_addr.sa_in.sin_port));
+	}
+	else {
+		char addrbuf[INET6_ADDRSTRLEN];
+		printf ("got hbres for addr: %s:%d\n",
+				inet_ntop(AF_INET6, &new_addr.sa_in6.sin6_addr, addrbuf, INET6_ADDRSTRLEN),
+				ntohs(new_addr.sa_in6.sin6_port));
+	}
+
+			if (new_addr.sa.sa_family == AF_INET)
+				addr_len = sizeof(struct sockaddr_in);
+			else
+				addr_len = sizeof(struct sockaddr_in6);
+			
+			fd = BIO_get_fd(SSL_get_rbio(s), &fd);
+			if (connect(fd, (struct sockaddr *) &new_addr, addr_len) < 0)
+				perror("connect");
+
+			(void) BIO_dgram_set_peer(SSL_get_rbio(s), &new_addr);
+			}
+#endif
 		}
 
 	return 0;
@@ -1588,4 +1658,105 @@
 
 	return ret;
 	}
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+int
+dtls1_mobility_verification_heartbeat(SSL *s)
+	{
+	unsigned char *buf, *p;
+	int ret, fd, addr_len;
+	unsigned int payload;
+	unsigned int padding = 16; /* Use minimum padding */
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sa_in;
+		struct sockaddr_in6 sa_in6;
+	} old_address;
+
+	/* Only send if peer supports and accepts HB requests... */
+	if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+	    s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+		{
+		SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+		return -1;
+		}
+
+	/* ...and no handshake in progress. */
+	if (SSL_in_init(s) || s->in_handshake)
+		{
+		SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+		return -1;
+		}
+
+	/* Check if padding is too long, payload and padding
+	 * must not exceed 2^14 - 3 = 16381 bytes in total.
+	 */
+	OPENSSL_assert(payload + padding <= 16381);
+
+	/* Create HeartBeat message, we use four magic bytes and the to be
+	 * verified address as payload and add some random stuff.
+	 *  - Message Type, 1 byte
+	 *  - Payload Length, 2 bytes (unsigned int)
+	 *  - Payload, the sequence number (2 bytes uint)
+	 *  - Payload, random bytes (16 bytes uint)
+	 *  - Padding
+	 */
+	payload = 4 + sizeof(s->d1->mobility_verify_addr) + 16;
+	buf = OPENSSL_malloc(1 + 2 + payload + padding);
+	p = buf;
+	/* Message Type */
+	*p++ = TLS1_HB_REQUEST;
+	/* Payload length */
+	s2n(payload, p);
+	/* Magic bytes */
+	l2n(0x42424242, p);
+	/* The address that should be verified */
+	memcpy(p, &s->d1->mobility_verify_addr, sizeof(s->d1->mobility_verify_addr));
+	p += sizeof(s->d1->mobility_verify_addr);
+
+	if (s->d1->mobility_verify_addr.sa.sa_family == AF_INET) {
+		char addrbuf[INET6_ADDRSTRLEN];
+		printf ("send hbreq for addr: %s:%d\n",
+				inet_ntop(AF_INET, &s->d1->mobility_verify_addr.sa_in.sin_addr, addrbuf, INET_ADDRSTRLEN),
+				ntohs(s->d1->mobility_verify_addr.sa_in.sin_port));
+	}
+	else {
+		char addrbuf[INET6_ADDRSTRLEN];
+		printf ("send hbreq for addr: %s:%d\n",
+				inet_ntop(AF_INET6, &s->d1->mobility_verify_addr.sa_in6.sin6_addr, addrbuf, INET6_ADDRSTRLEN),
+				ntohs(s->d1->mobility_verify_addr.sa_in6.sin6_port));
+	}
+
+	/* 16 random bytes */
+	RAND_pseudo_bytes(p, 16);
+	p += 16;
+	/* Random padding */
+	RAND_pseudo_bytes(p, padding);
+
+	/* Store current address and set new one */
+	fd = BIO_get_fd(SSL_get_rbio(s), &fd);
+	addr_len = BIO_dgram_get_peer(SSL_get_rbio(s), &old_address);
+
+	if(s->d1->mobility_verify_addr.sa.sa_family == AF_INET)
+		connect(fd, (struct sockaddr *) &s->d1->mobility_verify_addr, sizeof(struct sockaddr_in));
+	else
+		connect(fd, (struct sockaddr *) &s->d1->mobility_verify_addr, sizeof(struct sockaddr_in6));
+
+	ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+	if (ret >= 0)
+		{
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+				buf, 3 + payload + padding,
+				s, s->msg_callback_arg);
+		}
+
+	/* Reset stored address */
+	connect(fd, (struct sockaddr *) &old_address, addr_len);
+
+	OPENSSL_free(buf);
+
+	return ret;
+	}
+#endif
 #endif
Index: ssl/d1_clnt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_clnt.c,v
retrieving revision 1.16.2.15.2.7
diff -u -r1.16.2.15.2.7 d1_clnt.c
--- ssl/d1_clnt.c	6 Mar 2012 13:24:16 -0000	1.16.2.15.2.7
+++ ssl/d1_clnt.c	28 Aug 2012 12:28:45 -0000
@@ -446,6 +446,14 @@
 				s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A;
 			s->init_num=0;
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+			if (s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED)
+				{
+				s->d1->mobility |= SSL_DTLSEXT_MOBILITY_IN_USE_BY_PEER;
+				dtls1_mobility_lookup_table_add(s, s->d1->mobility_remote_cid, CRYPTO_thread_id());
+				}
+#endif
+
 #ifndef OPENSSL_NO_SCTP			
 			if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
 			    state == SSL_ST_RENEGOTIATE)
Index: ssl/d1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_lib.c,v
retrieving revision 1.8.2.13.2.11
diff -u -r1.8.2.13.2.11 d1_lib.c
--- ssl/d1_lib.c	18 Apr 2012 14:53:48 -0000	1.8.2.13.2.11
+++ ssl/d1_lib.c	28 Aug 2012 12:28:45 -0000
@@ -60,6 +60,7 @@
 #include <stdio.h>
 #define USE_SOCKETS
 #include <openssl/objects.h>
+#include <openssl/rand.h>
 #include "ssl_locl.h"
 
 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
@@ -107,6 +108,9 @@
 	d1->buffered_messages = pqueue_new();
 	d1->sent_messages=pqueue_new();
 	d1->buffered_app_data.q=pqueue_new();
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	d1->mobility_rcds.q=pqueue_new();
+#endif
 
 	if ( s->server)
 		{
@@ -114,6 +118,9 @@
 		}
 
 	if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+        || ! d1->mobility_rcds.q
+#endif
         || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q)
 		{
         if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
@@ -121,10 +128,23 @@
         if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
 		if ( d1->sent_messages) pqueue_free(d1->sent_messages);
 		if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q);
+#ifndef OPENSSL_NO_DTLSMOBILITY
+        if ( d1->mobility_rcds.q) pqueue_free(d1->mobility_rcds.q);
+#endif
 		OPENSSL_free(d1);
 		return (0);
 		}
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		do
+			{
+			RAND_pseudo_bytes((unsigned char*) &d1->mobility_remote_cid,
+							  sizeof(d1->mobility_remote_cid));
+			}
+		while(dtls1_mobility_lookup_table_find(s,
+		      d1->mobility_remote_cid) != NULL);
+#endif
+
 	s->d1=d1;
 	s->method->ssl_clear(s);
 	return(1);
@@ -181,6 +201,19 @@
 		OPENSSL_free(frag);
 		pitem_free(item);
 		}
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+    while( (item = pqueue_pop(s->d1->mobility_rcds.q)) != NULL)
+        {
+		rdata = (DTLS1_RECORD_DATA *) item->data;
+		if (rdata->rbuf.buf)
+			{
+			OPENSSL_free(rdata->rbuf.buf);
+			}
+        OPENSSL_free(item->data);
+        pitem_free(item);
+        }
+#endif
 	}
 
 void dtls1_free(SSL *s)
@@ -194,6 +227,11 @@
     pqueue_free(s->d1->buffered_messages);
 	pqueue_free(s->d1->sent_messages);
 	pqueue_free(s->d1->buffered_app_data.q);
+#ifndef OPENSSL_NO_DTLSMOBILITY
+    pqueue_free(s->d1->mobility_rcds.q);
+
+	dtls1_mobility_lookup_table_remove(s);
+#endif
 
 	OPENSSL_free(s->d1);
 	}
@@ -205,6 +243,10 @@
     pqueue buffered_messages;
 	pqueue sent_messages;
 	pqueue buffered_app_data;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+    pqueue mobility_rcds;
+	unsigned int dtlsext_mobility_remote_cid;
+#endif
 	unsigned int mtu;
 
 	if (s->d1)
@@ -215,6 +257,10 @@
 		sent_messages = s->d1->sent_messages;
 		buffered_app_data = s->d1->buffered_app_data.q;
 		mtu = s->d1->mtu;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		mobility_rcds = s->d1->mobility_rcds.q;
+		dtlsext_mobility_remote_cid = s->d1->mobility_remote_cid;
+#endif
 
 		dtls1_clear_queues(s);
 
@@ -235,6 +281,10 @@
 		s->d1->buffered_messages = buffered_messages;
 		s->d1->sent_messages = sent_messages;
 		s->d1->buffered_app_data.q = buffered_app_data;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		s->d1->mobility_rcds.q = mobility_rcds;
+		s->d1->mobility_remote_cid = dtlsext_mobility_remote_cid;
+#endif
 		}
 
 	ssl3_clear(s);
@@ -480,3 +530,102 @@
 	(void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
 	return 1;
 	}
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+#if 0
+void dtls1_mobility_lookup_table_print(SSL *s)
+	{
+	struct dtls1_mobility_lookup_table *tmp;
+
+	printf("DTLS Mobility lookup table:\n");
+	printf("CID\t\t|\tSSL Object\t\t|\tTID\n");
+
+	tmp = s->ctx->dtls1_mobility_table;
+	while (tmp != NULL)
+		{
+		printf("%u\t|\t%p\t\t|\t%lx\n", tmp->cid, tmp->ssl, tmp->tid);
+		tmp = tmp->next;
+		}
+	}
+#endif
+
+int dtls1_mobility_lookup_table_add(SSL *s, unsigned int cid, unsigned long tid)
+	{
+	struct dtls1_mobility_lookup_table *new;
+
+	if (dtls1_mobility_lookup_table_find(s, cid) != NULL)
+		return 0;
+
+	new = OPENSSL_malloc(sizeof(struct dtls1_mobility_lookup_table));
+	if (new == NULL) {
+		return -1;
+	}
+
+	new->cid = cid;
+	new->ssl = s;
+	new->tid = tid;
+	new->next = s->ctx->dtls1_mobility_table;
+	s->ctx->dtls1_mobility_table = new;
+
+#if 0
+	dtls1_mobility_lookup_table_print(s);
+#endif
+
+	return 1;
+	}
+
+int dtls1_mobility_lookup_table_remove(SSL *s)
+	{
+	struct dtls1_mobility_lookup_table *tmp, *old;
+
+	if (s->ctx->dtls1_mobility_table == NULL)
+		return 0;
+
+	tmp = s->ctx->dtls1_mobility_table;
+
+	if (tmp != NULL && tmp->ssl == s)
+		{
+		s->ctx->dtls1_mobility_table = tmp->next;
+		OPENSSL_free(tmp);
+		}
+	else
+		{
+		while (tmp->next != NULL && tmp->next->ssl != s)
+			tmp = tmp->next;
+			
+		if (tmp->next != NULL && tmp->next->ssl == s)
+			{
+			old = tmp->next;
+			tmp->next = tmp->next->next;
+			OPENSSL_free(old);
+			}
+		}
+
+	return 1;
+	}
+
+int dtls1_mobility_lookup_table_clear(SSL_CTX *ctx)
+	{
+	struct dtls1_mobility_lookup_table *tmp;
+
+	while (ctx->dtls1_mobility_table != NULL)
+		{
+		tmp = ctx->dtls1_mobility_table;
+		ctx->dtls1_mobility_table = ctx->dtls1_mobility_table->next;
+		OPENSSL_free(tmp);
+		}
+
+	return 1;
+	}
+
+struct dtls1_mobility_lookup_table* dtls1_mobility_lookup_table_find(SSL *s, unsigned int cid)
+	{
+	struct dtls1_mobility_lookup_table *tmp;
+
+	tmp = s->ctx->dtls1_mobility_table;
+	while(tmp != NULL && tmp->cid != cid)
+		tmp = tmp->next;
+		
+	return tmp;
+	}
+#endif
Index: ssl/d1_pkt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_pkt.c,v
retrieving revision 1.27.2.25.2.10
diff -u -r1.27.2.25.2.10 d1_pkt.c
--- ssl/d1_pkt.c	9 Mar 2012 15:52:20 -0000	1.27.2.25.2.10
+++ ssl/d1_pkt.c	28 Aug 2012 12:28:45 -0000
@@ -121,6 +121,9 @@
 #include <openssl/buffer.h>
 #include <openssl/pqueue.h>
 #include <openssl/rand.h>
+#ifndef OPENSSL_NO_DTLSMOBILITY
+#include <pthread.h>
+#endif
 
 /* mod 128 saturating subtract of two 64-bit values in big-endian order */
 static int satsub64be(const unsigned char *v1,const unsigned char *v2)
@@ -198,7 +201,16 @@
 	
 	/* Set proper sequence number for mac calculation */
 	memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
-    
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if (s->d1->mobility_verify == 1)
+		{
+		memcpy(&s->d1->mobility_verify_addr, &rdata->mobility_addr,
+		       sizeof(rdata->mobility_addr));
+		s->d1->mobility_verify = 2;
+		}
+#endif
+
     return(1);
     }
 
@@ -239,6 +251,14 @@
 	}
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if (s->d1->mobility_new_addr)
+		{
+		(void) BIO_dgram_get_peer(SSL_get_rbio(s), &rdata->mobility_addr);
+		s->d1->mobility_new_addr = 0;
+		}
+#endif
+
 	/* insert should not fail, since duplicates are dropped */
 	if (pqueue_insert(queue->q, item) == NULL)
 		{
@@ -299,7 +319,7 @@
 dtls1_process_buffered_records(SSL *s)
     {
     pitem *item;
-    
+
     item = pqueue_peek(s->d1->unprocessed_rcds.q);
     if (item)
         {
@@ -326,6 +346,29 @@
     return(1);
     }
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+static int
+dtls1_process_buffered_mobility_records(SSL *s)
+    {
+    pitem *item;
+
+    item = pqueue_peek(s->d1->mobility_rcds.q);
+    if (item)
+        {
+        /* Process all the records. Should only be a single one anyway. */
+        while (pqueue_peek(s->d1->mobility_rcds.q))
+            {
+            dtls1_retrieve_buffered_record(s, &(s->d1->mobility_rcds));
+            if ( ! dtls1_process_record(s))
+                return(0);
+            dtls1_buffer_record(s, &(s->d1->processed_rcds), 
+                s->s3->rrec.seq_num);
+            }
+        }
+
+    return(1);
+    }
+#endif
 
 #if 0
 
@@ -392,7 +435,11 @@
 	/* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
 	 * and we have that many bytes in s->packet
 	 */
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_MOBILITY_LENGTH_READ]);
+#else
 	rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
+#endif
 
 	/* ok, we can now read from 's->packet' data into 'rr'
 	 * rr->input points at rr->length bytes, which
@@ -513,6 +560,16 @@
 	/* we have pulled in a full packet so zero things */
 	s->packet_length=0;
 	dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if (s->d1->mobility_verify == 2)
+		{
+		printf("DTLS Mobility: this packet has a new address!\n");
+		dtls1_mobility_verification_heartbeat(s);
+		s->d1->mobility_verify = 0;
+		}
+#endif
+
 	return(1);
 
 f_err:
@@ -521,7 +578,6 @@
 	return(0);
 }
 
-
 /* Call this to get a new input record.
  * It will return <= 0 if more data is needed, normally due to an error
  * or non-blocking IO.
@@ -540,6 +596,10 @@
 	unsigned short version;
 	DTLS1_BITMAP *bitmap;
 	unsigned int is_next_epoch;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	unsigned int remote_cid;
+	struct dtls1_mobility_lookup_table *mobility_entry;
+#endif
 
 	rr= &(s->s3->rrec);
 
@@ -547,6 +607,11 @@
 	 * pending records.  This is a non-blocking operation. */
 	dtls1_process_buffered_records(s);
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	/* There may be records due to address changes */
+	dtls1_process_buffered_mobility_records(s);
+#endif
+
 	/* if we're renegotiating, then there may be buffered records */
 	if (dtls1_get_processed_record(s))
 		return 1;
@@ -554,15 +619,28 @@
 	/* get something from the wire */
 again:
 	/* check if we have the header */
-	if (	(s->rstate != SSL_ST_READ_BODY) ||
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if ((s->rstate != SSL_ST_READ_BODY) ||
+		(s->packet_length < DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_MOBILITY_LENGTH_READ)) 
+		{
+		mobility_entry = NULL;
+		n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH +
+		              DTLS1_RT_HEADER_MOBILITY_LENGTH_READ, s->s3->rbuf.len, 0);
+#else
+	if ((s->rstate != SSL_ST_READ_BODY) ||
 		(s->packet_length < DTLS1_RT_HEADER_LENGTH)) 
 		{
 		n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+#endif
 		/* read timeout is handled by dtls1_read_bytes */
 		if (n <= 0) return(n); /* error or non-blocking */
 
 		/* this packet contained a partial record, dump it */
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		if (s->packet_length != DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_MOBILITY_LENGTH_READ)
+#else
 		if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
+#endif
 			{
 			s->packet_length = 0;
 			goto again;
@@ -584,6 +662,44 @@
 		memcpy(&(s->s3->read_sequence[2]), p, 6);
 		p+=6;
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		if ((s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED) &&
+		    (s->d1->mobility & SSL_DTLSEXT_MOBILITY_IN_USE_BY_PEER))
+			{
+			n2l(p, remote_cid);
+			if (remote_cid != s->d1->mobility_remote_cid)
+				{
+				/* wrong connection identifier, silently discard */
+				rr->length = 0;
+				s->packet_length = 0;
+				goto again;
+				}
+			}
+
+		/* While listening, everything but ClientHellos is dropped anyway, so
+		 * otherwise just assume an address change with mobility occured.
+		 */
+		if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE)
+			{
+			/* Read missing 4 bytes for extended header*/
+			n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH_MOBILITY, DTLS1_RT_HEADER_LENGTH_MOBILITY, 1);
+			if (n <= 0) return(n); /* error or non-blocking io */
+
+			n2l(p, remote_cid);
+
+			mobility_entry = dtls1_mobility_lookup_table_find(s, remote_cid);
+
+			/* Ignore if the connection still has a verification
+			 * in progress and it's not a heartbeat.
+			 */
+			if (mobility_entry != NULL && rr->type != TLS1_RT_HEARTBEAT &&
+			    mobility_entry->ssl->d1->mobility_verify != 0)
+				{
+				mobility_entry = NULL;
+				}
+			}
+#endif
+
 		n2s(p,rr->length);
 
 		/* Lets check version */
@@ -619,7 +735,12 @@
 
 	/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH -
+	    DTLS1_RT_HEADER_MOBILITY_LENGTH_READ)
+#else
 	if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
+#endif
 		{
 		/* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
 		i=rr->length;
@@ -639,6 +760,31 @@
 		}
 	s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	/* If this is an mobility packet after a possible address change, process it */
+	if (mobility_entry != NULL)
+		{
+
+		CRYPTO_r_lock(CRYPTO_LOCK_SSL);
+
+		s->d1->mobility_new_addr = 1;
+		dtls1_buffer_record(s, &(mobility_entry->ssl->d1->mobility_rcds), rr->seq_num);
+
+		mobility_entry->ssl->d1->mobility_verify = 1;
+
+		CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+
+		/* Notify thread to end blocking calls, if necessary */
+		pthread_kill((pthread_t) mobility_entry->tid, SIGALRM);
+
+		mobility_entry = NULL;
+
+		rr->length = 0;
+		s->packet_length = 0;
+		goto again;   /* get another record */
+		}
+#endif
+
 	/* match epochs.  NULL means the packet is dropped on the floor */
 	bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
 	if ( bitmap == NULL)
@@ -1534,7 +1680,11 @@
 
 	/* field where we are to write out packet epoch, seq num and len */
 	pseq=p; 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	p+=10 + DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE;
+#else
 	p+=10;
+#endif
 
 	/* lets setup the record stuff. */
 
@@ -1610,13 +1760,26 @@
 
 	memcpy(pseq, &(s->s3->write_sequence[2]), 6);
 	pseq+=6;
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if ((s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED) &&
+	    (s->d1->mobility & SSL_DTLSEXT_MOBILITY_IN_USE))
+		{
+		l2n(s->d1->mobility_local_cid, pseq);
+		}
+#endif
+
 	s2n(wr->length,pseq);
 
 	/* we should now have
 	 * wr->data pointing to the encrypted data, which is
 	 * wr->length long */
 	wr->type=type; /* not needed but helps for debugging */
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	wr->length+=DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE;
+#else
 	wr->length+=DTLS1_RT_HEADER_LENGTH;
+#endif
 
 #if 0  /* this is now done at the message layer */
 	/* buffer the record, making it easy to handle retransmits */
Index: ssl/d1_srvr.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_srvr.c,v
retrieving revision 1.20.2.16.2.15
diff -u -r1.20.2.16.2.15 d1_srvr.c
--- ssl/d1_srvr.c	31 Mar 2012 18:02:43 -0000	1.20.2.16.2.15
+++ ssl/d1_srvr.c	28 Aug 2012 12:28:45 -0000
@@ -562,6 +562,13 @@
 			dtls1_start_timer(s);
 			ret=dtls1_send_server_done(s);
 			if (ret <= 0) goto end;
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+				if (s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED)
+					dtls1_mobility_lookup_table_add(s, s->d1->mobility_remote_cid,
+					                                CRYPTO_thread_id());
+#endif
+
 			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
 			s->state=SSL3_ST_SW_FLUSH;
 			s->init_num=0;
@@ -601,6 +608,10 @@
 				 * have not asked for it :-) */
 				ret=ssl3_get_client_certificate(s);
 				if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_DTLSMOBILITY
+				if (s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED)
+					s->d1->mobility |= SSL_DTLSEXT_MOBILITY_IN_USE;
+#endif
 				s->init_num=0;
 				s->state=SSL3_ST_SR_KEY_EXCH_A;
 			}
@@ -625,6 +636,11 @@
 			         sizeof(sctpauthkey), sctpauthkey);
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+			if (s->d1->mobility & SSL_DTLSEXT_MOBILITY_ENABLED)
+				s->d1->mobility |= SSL_DTLSEXT_MOBILITY_IN_USE;
+#endif
+
 			s->state=SSL3_ST_SR_CERT_VRFY_A;
 			s->init_num=0;
 
Index: ssl/dtls1.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/dtls1.h,v
retrieving revision 1.12.2.16.2.4
diff -u -r1.12.2.16.2.4 dtls1.h
--- ssl/dtls1.h	8 Jun 2012 09:18:46 -0000	1.12.2.16.2.4
+++ ssl/dtls1.h	28 Aug 2012 12:28:45 -0000
@@ -77,6 +77,9 @@
 #else
 #include <sys/time.h>
 #endif
+#ifndef OPENSSL_NO_DTLSMOBILITY
+#include <netinet/in.h>
+#endif
 #endif
 
 #ifdef  __cplusplus
@@ -109,6 +112,26 @@
 #define DTLS1_AL_HEADER_LENGTH                   2
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+#define DTLSEXT_TYPE_mobility					16
+
+#define SSL_DTLSEXT_MOBILITY_ENABLED			0x01
+#define SSL_DTLSEXT_MOBILITY_IN_USE_BY_PEER		0x02
+#define SSL_DTLSEXT_MOBILITY_IN_USE				0x04
+
+#define DTLS1_RT_HEADER_LENGTH_MOBILITY			4
+#define DTLS1_RT_HEADER_MOBILITY_LENGTH_READ	(((s->d1->mobility & \
+												  SSL_DTLSEXT_MOBILITY_ENABLED) && \
+												  (s->d1->mobility & \
+  												  SSL_DTLSEXT_MOBILITY_IN_USE_BY_PEER)) ? \
+												  4 : 0)
+#define DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE	(((s->d1->mobility & \
+												  SSL_DTLSEXT_MOBILITY_ENABLED) && \
+												  (s->d1->mobility & \
+  												  SSL_DTLSEXT_MOBILITY_IN_USE)) ? \
+												  4 : 0)
+#endif
+
 #ifndef OPENSSL_NO_SSL_INTERN
 
 #ifndef OPENSSL_NO_SCTP
@@ -259,6 +282,21 @@
 	int shutdown_received;
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	unsigned int mobility;
+
+	unsigned int mobility_local_cid;
+	unsigned int mobility_remote_cid;
+	unsigned int mobility_new_addr;
+	unsigned int mobility_verify;
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sa_in;
+		struct sockaddr_in6 sa_in6;
+	} mobility_verify_addr;
+	record_pqueue mobility_rcds;
+#endif
+
 	} DTLS1_STATE;
 
 typedef struct dtls1_record_data_st
@@ -270,8 +308,22 @@
 #ifndef OPENSSL_NO_SCTP
 	struct bio_dgram_sctp_rcvinfo recordinfo;
 #endif
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sa_in;
+		struct sockaddr_in6 sa_in6;
+	} mobility_addr;
+#endif
 	} DTLS1_RECORD_DATA;
 
+struct dtls1_mobility_lookup_table
+	{
+	unsigned int cid;
+	SSL *ssl;
+	unsigned long tid;
+	struct dtls1_mobility_lookup_table *next;
+	};
 #endif
 
 /* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
Index: ssl/s3_both.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_both.c,v
retrieving revision 1.49.2.5.2.2
diff -u -r1.49.2.5.2.2 s3_both.c
--- ssl/s3_both.c	8 Jun 2012 09:18:46 -0000	1.49.2.5.2.2
+++ ssl/s3_both.c	28 Aug 2012 12:28:45 -0000
@@ -739,7 +739,11 @@
 	size_t len,align=0,headerlen;
 	
 	if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		headerlen = DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH_MOBILITY;
+#else
 		headerlen = DTLS1_RT_HEADER_LENGTH;
+#endif
 	else
 		headerlen = SSL3_RT_HEADER_LENGTH;
 
@@ -781,7 +785,11 @@
 	size_t len,align=0,headerlen;
 
 	if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		headerlen = DTLS1_RT_HEADER_LENGTH + DTLS1_RT_HEADER_MOBILITY_LENGTH_WRITE + 1;
+#else
 		headerlen = DTLS1_RT_HEADER_LENGTH + 1;
+#endif
 	else
 		headerlen = SSL3_RT_HEADER_LENGTH;
 
Index: ssl/ssl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl.h,v
retrieving revision 1.221.2.24.2.32
diff -u -r1.221.2.24.2.32 ssl.h
--- ssl/ssl.h	8 Jun 2012 09:18:46 -0000	1.221.2.24.2.32
+++ ssl/ssl.h	28 Aug 2012 12:28:45 -0000
@@ -977,6 +977,10 @@
 # endif
         /* SRTP profiles we are willing to do from RFC 5764 */
         STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;  
+
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	struct dtls1_mobility_lookup_table *dtls1_mobility_table;
+#endif
 #endif
 	};
 
Index: ssl/ssl_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_lib.c,v
retrieving revision 1.176.2.19.2.25
diff -u -r1.176.2.19.2.25 ssl_lib.c
--- ssl/ssl_lib.c	8 Jun 2012 09:18:46 -0000	1.176.2.19.2.25
+++ ssl/ssl_lib.c	28 Aug 2012 12:28:45 -0000
@@ -1862,6 +1862,9 @@
 	}
 #endif
 #endif
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	ret->dtls1_mobility_table = NULL;
+#endif
 	/* Default is to connect to non-RI servers. When RI is more widely
 	 * deployed might change this.
 	 */
@@ -1974,6 +1977,10 @@
 		ssl_buf_freelist_free(a->rbuf_freelist);
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	dtls1_mobility_lookup_table_clear(a);
+#endif
+
 	OPENSSL_free(a);
 	}
 
Index: ssl/ssl_locl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_locl.h,v
retrieving revision 1.100.2.10.2.17
diff -u -r1.100.2.10.2.17 ssl_locl.h
--- ssl/ssl_locl.h	9 Mar 2012 15:52:20 -0000	1.100.2.10.2.17
+++ ssl/ssl_locl.h	28 Aug 2012 12:28:45 -0000
@@ -1098,6 +1098,14 @@
 int dtls1_process_heartbeat(SSL *s);
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+int dtls1_mobility_lookup_table_add(SSL *s, unsigned int cid, unsigned long tid);
+int dtls1_mobility_lookup_table_remove(SSL *s);
+int dtls1_mobility_lookup_table_clear(SSL_CTX *s);
+struct dtls1_mobility_lookup_table* dtls1_mobility_lookup_table_find(SSL *s, unsigned int cid);
+int dtls1_mobility_verification_heartbeat(SSL *s);
+#endif
+
 #ifdef OPENSSL_NO_SHA256
 #define tlsext_tick_md	EVP_sha1
 #else
Index: ssl/t1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/t1_lib.c,v
retrieving revision 1.64.2.14.2.33
diff -u -r1.64.2.14.2.33 t1_lib.c
--- ssl/t1_lib.c	27 Jun 2012 14:11:40 -0000	1.64.2.14.2.33
+++ ssl/t1_lib.c	28 Aug 2012 12:28:45 -0000
@@ -637,6 +637,16 @@
 		*(ret++) = SSL_TLSEXT_HB_ENABLED;
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	if (s->version == DTLS1_VERSION)
+		{
+		/* Add DTLS Mobility extension */
+		s2n(DTLSEXT_TYPE_mobility, ret);
+		s2n(4,ret);
+		l2n(s->d1->mobility_remote_cid, ret);
+		}
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
 	if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
 		{
@@ -833,6 +843,16 @@
 		}
 #endif
 
+#ifndef OPENSSL_NO_DTLSMOBILITY
+	/* Add DTLS Mobility extension if we've received one */
+	if (s->version == DTLS1_VERSION && s->d1->mobility)
+		{
+		s2n(DTLSEXT_TYPE_mobility, ret);
+		s2n(4,ret);
+		l2n(s->d1->mobility_remote_cid, ret);
+		}
+#endif
+
 #ifndef OPENSSL_NO_NEXTPROTONEG
 	next_proto_neg_seen = s->s3->next_proto_neg_seen;
 	s->s3->next_proto_neg_seen = 0;
@@ -1304,6 +1324,15 @@
 				}
 			}
 #endif
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		else if (type == DTLSEXT_TYPE_mobility)
+			{
+			n2l(data, s->d1->mobility_local_cid);
+			data -= 4;
+			s->d1->mobility = SSL_DTLSEXT_MOBILITY_ENABLED |
+			                          SSL_DTLSEXT_MOBILITY_IN_USE_BY_PEER;
+			}
+#endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
 		else if (type == TLSEXT_TYPE_next_proto_neg &&
 			 s->s3->tmp.finish_md_len == 0)
@@ -1577,6 +1606,15 @@
 				}
 			}
 #endif
+#ifndef OPENSSL_NO_DTLSMOBILITY
+		else if (type == DTLSEXT_TYPE_mobility)
+			{
+			n2l(data, s->d1->mobility_local_cid);
+			data -= 4;
+			s->d1->mobility = SSL_DTLSEXT_MOBILITY_ENABLED |
+			                          SSL_DTLSEXT_MOBILITY_IN_USE;
+			}
+#endif
 		else if (type == TLSEXT_TYPE_use_srtp)
                         {
                         if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
