Index: /pjproject/trunk/pjnath/include/pjnath/errno.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1140)
+++ /pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1141)
@@ -145,4 +145,11 @@
 /**
  * @hideinitializer
+ * Source address mismatch. This error occurs if the source address
+ * of the response for ICE connectivity check is different than
+ * the destination address of the request.
+ */
+#define PJNATH_EICEINSRCADDR	    (PJNATH_ERRNO_START+88) /* 370088 */
+/**
+ * @hideinitializer
  * Missing ICE SDP attribute
  */
Index: /pjproject/trunk/pjnath/include/pjnath/ice_session.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice_session.h	(revision 1140)
+++ /pjproject/trunk/pjnath/include/pjnath/ice_session.h	(revision 1141)
@@ -401,4 +401,9 @@
 typedef enum pj_ice_sess_role
 {
+    /**
+     * The ICE agent is in controlled role.
+     */
+    PJ_ICE_SESS_ROLE_UNKNOWN,
+
     /**
      * The ICE agent is in controlled role.
Index: /pjproject/trunk/pjnath/include/pjnath/stun_session.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/stun_session.h	(revision 1140)
+++ /pjproject/trunk/pjnath/include/pjnath/stun_session.h	(revision 1141)
@@ -110,11 +110,23 @@
      *			    or other error has occurred, and the response
      *			    argument may be NULL.
+     *			    Note that when the status is not success, the
+     *			    response may contain non-NULL value if the 
+     *			    response contains STUN ERROR-CODE attribute.
      * @param request	    The original STUN request.
-     * @param response	    The response message, on successful transaction.
+     * @param response	    The response message, on successful transaction,
+     *			    or otherwise MAY BE NULL if status is not success.
+     *			    Note that when the status is not success, this
+     *			    argument may contain non-NULL value if the 
+     *			    response contains STUN ERROR-CODE attribute.
+     * @param src_addr	    The source address where the response was 
+     *			    received, or NULL if the response is NULL.
+     * @param src_addr_len  The length of the source  address.
      */
     void (*on_request_complete)(pj_stun_session *sess,
 			        pj_status_t status,
 			        pj_stun_tx_data *tdata,
-			        const pj_stun_msg *response);
+			        const pj_stun_msg *response,
+				const pj_sockaddr_t *src_addr,
+				unsigned src_addr_len);
 
 
Index: /pjproject/trunk/pjnath/include/pjnath/stun_transaction.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/stun_transaction.h	(revision 1140)
+++ /pjproject/trunk/pjnath/include/pjnath/stun_transaction.h	(revision 1141)
@@ -71,8 +71,13 @@
      * @param response	    The STUN response, which value may be NULL if
      *			    \a status is not PJ_SUCCESS.
+     * @param src_addr	    The source address of the response, if response 
+     *			    is not NULL.
+     * @param src_addr_len  The length of the source address.
      */
     void	(*on_complete)(pj_stun_client_tsx *tsx,
 			       pj_status_t status, 
-			       const pj_stun_msg *response);
+			       const pj_stun_msg *response,
+			       const pj_sockaddr_t *src_addr,
+			       unsigned src_addr_len);
 
     /**
@@ -229,9 +234,13 @@
  * @param tsx		The STUN client transaction instance.
  * @param msg		The incoming STUN message.
+ * @param src_addr	The source address of the packet.
+ * @param src_addr_len	The length of the source address.
  *
  * @return		PJ_SUCCESS on success or the appropriate error code.
  */
 PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
-						  const pj_stun_msg *msg);
+						  const pj_stun_msg *msg,
+						  const pj_sockaddr_t*src_addr,
+						  unsigned src_addr_len);
 
 
Index: /pjproject/trunk/pjnath/src/pjnath/errno.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1141)
@@ -57,4 +57,5 @@
     PJ_BUILD_ERR( PJNATH_EICEINCOMPID,	    "Invalid ICE component ID"),
     PJ_BUILD_ERR( PJNATH_EICEINCANDID,	    "Invalid ICE candidate ID"),
+    PJ_BUILD_ERR( PJNATH_EICEINSRCADDR,	    "Source address mismatch"),
     PJ_BUILD_ERR( PJNATH_EICEMISSINGSDP,    "Missing ICE SDP attribute"),
     PJ_BUILD_ERR( PJNATH_EICEINCANDSDP,	    "Invalid SDP \"candidate\" attribute"),
Index: /pjproject/trunk/pjnath/src/pjnath/ice_session.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1141)
@@ -116,5 +116,7 @@
 				     pj_status_t status,
 				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response);
+				     const pj_stun_msg *response,
+				     const pj_sockaddr_t *src_addr,
+				     unsigned src_addr_len);
 static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
 					 const pj_uint8_t *pkt,
@@ -1207,10 +1209,22 @@
 			      PJ_STUN_ATTR_PRIORITY, prio);
 
-    /* Add USE-CANDIDATE and set this check to nominated */
+    /* Add USE-CANDIDATE and set this check to nominated.
+     * Also add ICE-CONTROLLING or ICE-CONTROLLED
+     */
     if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
 	pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg, 
 				   PJ_STUN_ATTR_USE_CANDIDATE);
 	check->nominated = PJ_TRUE;
-    }
+
+	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
+				    PJ_STUN_ATTR_ICE_CONTROLLING,
+				    &ice->tie_breaker);
+
+    } else {
+	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
+				    PJ_STUN_ATTR_ICE_CONTROLLED,
+				    &ice->tie_breaker);
+    }
+
 
     /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the 
@@ -1429,5 +1443,7 @@
 				     pj_status_t status,
 				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response)
+				     const pj_stun_msg *response,
+				     const pj_sockaddr_t *src_addr,
+				     unsigned src_addr_len)
 {
     struct req_data *rd = (struct req_data*) tdata->user_data;
@@ -1441,4 +1457,5 @@
 
     PJ_UNUSED_ARG(stun_sess);
+    PJ_UNUSED_ARG(src_addr_len);
 
     ice = rd->ice;
@@ -1457,11 +1474,53 @@
     lcand = NULL;
 
-    LOG4((ice->obj_name, 
-	 "Check %s%s: connectivity check %s",
-	 dump_check(buffer, sizeof(buffer), &ice->clist, check),
-	 (check->nominated ? " (nominated)" : " (not nominated)"),
-	 (status==PJ_SUCCESS ? "SUCCESS" : "FAILED")));
-
     if (status != PJ_SUCCESS) {
+	char errmsg[PJ_ERR_MSG_SIZE];
+
+	if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
+	    /* Role conclict response.
+	     * 7.1.2.1.  Failure Cases:
+	     * If the request had contained the ICE-CONTROLLED attribute, 
+	     * the agent MUST switch to the controlling role if it has not
+	     * already done so.  If the request had contained the 
+	     * ICE-CONTROLLING attribute, the agent MUST switch to the 
+	     * controlled role if it has not already done so.  Once it has
+	     * switched, the agent MUST immediately retry the request with
+	     * the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting 
+	     * its new role.
+	     */
+	    pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
+	    pj_stun_msg *req = tdata->msg;
+
+	    if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
+		new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
+	    } else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED, 
+					     0)) {
+		new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
+	    } else {
+		pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
+		new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
+	    }
+
+	    if (new_role != ice->role) {
+		LOG4((ice->obj_name, 
+		      "Changing role because of role conflict"));
+		pj_ice_sess_change_role(ice, new_role);
+	    }
+
+	    /* Resend request */
+	    LOG4((ice->obj_name, "Resending check because of role conflict"));
+	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
+	    perform_check(ice, clist, rd->ckid);
+	    pj_mutex_unlock(ice->mutex);
+	    return;
+	}
+
+	pj_strerror(status, errmsg, sizeof(errmsg));
+	LOG4((ice->obj_name, 
+	     "Check %s%s: connectivity check FAILED: %s",
+	     dump_check(buffer, sizeof(buffer), &ice->clist, check),
+	     (check->nominated ? " (nominated)" : " (not nominated)"),
+	     errmsg));
+
 	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
 	on_check_complete(ice, check);
@@ -1469,4 +1528,5 @@
 	return;
     }
+
 
     /* The agent MUST check that the source IP address and port of the
@@ -1476,5 +1536,20 @@
      * Request was sent from.
      */
-    PJ_TODO(ICE_CHECK_RESPONSE_SOURCE_ADDRESS);
+    if (sockaddr_cmp(&check->rcand->addr, src_addr) != 0) {
+	status = PJNATH_EICEINSRCADDR;
+	LOG4((ice->obj_name, 
+	     "Check %s%s: connectivity check FAILED: source address mismatch",
+	     dump_check(buffer, sizeof(buffer), &ice->clist, check),
+	     (check->nominated ? " (nominated)" : " (not nominated)")));
+	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
+	on_check_complete(ice, check);
+	pj_mutex_unlock(ice->mutex);
+	return;
+    }
+
+    LOG4((ice->obj_name, 
+	 "Check %s%s: connectivity check SUCCESS",
+	 dump_check(buffer, sizeof(buffer), &ice->clist, check),
+	 (check->nominated ? " (nominated)" : " (not nominated)")));
 
     /* Get the STUN XOR-MAPPED-ADDRESS attribute. */
Index: /pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1141)
@@ -67,5 +67,7 @@
 				     pj_status_t status,
 				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response);
+				     const pj_stun_msg *response,
+				     const pj_sockaddr_t *src_addr,
+				     unsigned src_addr_len);
 
 /* Keep-alive timer */
@@ -1046,5 +1048,7 @@
 				     pj_status_t status,
 				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response)
+				     const pj_stun_msg *response,
+				     const pj_sockaddr_t *src_addr,
+				     unsigned src_addr_len)
 {
     pj_ice_strans_comp *comp;
@@ -1056,4 +1060,7 @@
     comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess);
     cand = (pj_ice_strans_cand*) tdata->user_data;
+
+    PJ_UNUSED_ARG(src_addr);
+    PJ_UNUSED_ARG(src_addr_len);
 
     if (cand == NULL) {
Index: /pjproject/trunk/pjnath/src/pjnath/stun_msg.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1141)
@@ -1096,5 +1096,5 @@
 
     attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
-    INIT_ATTR(attr, attr_type, 4);
+    INIT_ATTR(attr, attr_type, 8);
 
     if (value) {
@@ -1155,5 +1155,5 @@
 
     PUTVAL16H(buf, 0, ca->hdr.type);
-    PUTVAL16H(buf, 2, ca->hdr.length);
+    PUTVAL16H(buf, 2, (pj_uint16_t)8);
     PUTVAL64H(buf, 4, &ca->value);
 
Index: /pjproject/trunk/pjnath/src/pjnath/stun_session.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1141)
@@ -52,5 +52,7 @@
 static void stun_tsx_on_complete(pj_stun_client_tsx *tsx,
 				 pj_status_t status, 
-				 const pj_stun_msg *response);
+				 const pj_stun_msg *response,
+				 const pj_sockaddr_t *src_addr,
+				 unsigned src_addr_len);
 static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx,
 					const void *stun_pkt,
@@ -326,5 +328,7 @@
 static void stun_tsx_on_complete(pj_stun_client_tsx *tsx,
 				 pj_status_t status, 
-				 const pj_stun_msg *response)
+				 const pj_stun_msg *response,
+				 const pj_sockaddr_t *src_addr,
+				 unsigned src_addr_len)
 {
     pj_stun_tx_data *tdata;
@@ -334,5 +338,6 @@
     if (tdata->sess->cb.on_request_complete) {
 	(*tdata->sess->cb.on_request_complete)(tdata->sess, status, tdata, 
-					       response);
+					       response, 
+					       src_addr, src_addr_len);
     }
 }
@@ -697,5 +702,6 @@
 
     if (notify) {
-	(sess->cb.on_request_complete)(sess, notify_status, tdata, NULL);
+	(sess->cb.on_request_complete)(sess, notify_status, tdata, NULL,
+				       NULL, 0);
     }
 
@@ -776,5 +782,7 @@
 /* Handle incoming response */
 static pj_status_t on_incoming_response(pj_stun_session *sess,
-					pj_stun_msg *msg)
+					pj_stun_msg *msg,
+					const pj_sockaddr_t *src_addr,
+					unsigned src_addr_len)
 {
     pj_stun_tx_data *tdata;
@@ -793,5 +801,6 @@
      * and this will call the session callback too.
      */
-    status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg);
+    status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg, 
+					  src_addr, src_addr_len);
     if (status != PJ_SUCCESS) {
 	return status;
@@ -959,5 +968,5 @@
 	PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
     {
-	status = on_incoming_response(sess, msg);
+	status = on_incoming_response(sess, msg, src_addr, src_addr_len);
 
     } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
Index: /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1140)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1141)
@@ -276,5 +276,5 @@
 	    tsx->complete = PJ_TRUE;
 	    if (tsx->cb.on_complete) {
-		tsx->cb.on_complete(tsx, PJNATH_ESTUNTIMEDOUT, NULL);
+		tsx->cb.on_complete(tsx, PJNATH_ESTUNTIMEDOUT, NULL, NULL, 0);
 	    }
 	}
@@ -289,5 +289,5 @@
 	    tsx->complete = PJ_TRUE;
 	    if (tsx->cb.on_complete) {
-		tsx->cb.on_complete(tsx, status, NULL);
+		tsx->cb.on_complete(tsx, status, NULL, NULL, 0);
 	    }
 	}
@@ -314,5 +314,7 @@
  */
 PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
-						 const pj_stun_msg *msg)
+						 const pj_stun_msg *msg,
+						 const pj_sockaddr_t *src_addr,
+						 unsigned src_addr_len)
 {
     pj_stun_errcode_attr *err_attr;
@@ -364,10 +366,10 @@
 	tsx->complete = PJ_TRUE;
 	if (tsx->cb.on_complete) {
-	    tsx->cb.on_complete(tsx, status, msg);
-	}
-    }
-
-    return PJ_SUCCESS;
-
-}
-
+	    tsx->cb.on_complete(tsx, status, msg, src_addr, src_addr_len);
+	}
+    }
+
+    return PJ_SUCCESS;
+
+}
+
