|  | @@ -596,7 +596,7 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
 | 
		
	
		
			
			| 596 | 596 |  
 | 
		
	
		
			
			| 597 | 597 |  /******************************************************************************
 | 
		
	
		
			
			| 598 | 598 |   *
 | 
		
	
		
			
			| 599 |  | - * TX state machine transitions
 | 
		
	
		
			
			|  | 599 | + * Record handling
 | 
		
	
		
			
			| 600 | 600 |   *
 | 
		
	
		
			
			| 601 | 601 |   ******************************************************************************
 | 
		
	
		
			
			| 602 | 602 |   */
 | 
		
	
	
		
			
			|  | @@ -610,53 +610,6 @@ static void tls_tx_resume ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 610 | 610 |  	process_add ( &tls->process );
 | 
		
	
		
			
			| 611 | 611 |  }
 | 
		
	
		
			
			| 612 | 612 |  
 | 
		
	
		
			
			| 613 |  | -/**
 | 
		
	
		
			
			| 614 |  | - * Enter TX state machine active state
 | 
		
	
		
			
			| 615 |  | - *
 | 
		
	
		
			
			| 616 |  | - * @v tls		TLS session
 | 
		
	
		
			
			| 617 |  | - * @v state		TX state
 | 
		
	
		
			
			| 618 |  | - */
 | 
		
	
		
			
			| 619 |  | -static void tls_tx_start ( struct tls_session *tls, enum tls_tx_state state ) {
 | 
		
	
		
			
			| 620 |  | -
 | 
		
	
		
			
			| 621 |  | -	/* Enter specified state */
 | 
		
	
		
			
			| 622 |  | -	tls->tx_state = state;
 | 
		
	
		
			
			| 623 |  | -
 | 
		
	
		
			
			| 624 |  | -	/* Resume state machine */
 | 
		
	
		
			
			| 625 |  | -	tls_tx_resume ( tls );
 | 
		
	
		
			
			| 626 |  | -}
 | 
		
	
		
			
			| 627 |  | -
 | 
		
	
		
			
			| 628 |  | -/**
 | 
		
	
		
			
			| 629 |  | - * Enter TX state machine idle state
 | 
		
	
		
			
			| 630 |  | - *
 | 
		
	
		
			
			| 631 |  | - * @v tls		TLS session
 | 
		
	
		
			
			| 632 |  | - */
 | 
		
	
		
			
			| 633 |  | -static void tls_tx_none ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 634 |  | -
 | 
		
	
		
			
			| 635 |  | -	/* Enter idle state */
 | 
		
	
		
			
			| 636 |  | -	tls->tx_state = TLS_TX_NONE;
 | 
		
	
		
			
			| 637 |  | -}
 | 
		
	
		
			
			| 638 |  | -
 | 
		
	
		
			
			| 639 |  | -/**
 | 
		
	
		
			
			| 640 |  | - * Enter TX state machine data state
 | 
		
	
		
			
			| 641 |  | - *
 | 
		
	
		
			
			| 642 |  | - * @v tls		TLS session
 | 
		
	
		
			
			| 643 |  | - */
 | 
		
	
		
			
			| 644 |  | -static void tls_tx_data ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 645 |  | -
 | 
		
	
		
			
			| 646 |  | -	/* Enter data state */
 | 
		
	
		
			
			| 647 |  | -	tls->tx_state = TLS_TX_DATA;
 | 
		
	
		
			
			| 648 |  | -
 | 
		
	
		
			
			| 649 |  | -	/* Send notification of a window change */
 | 
		
	
		
			
			| 650 |  | -	xfer_window_changed ( &tls->plainstream );
 | 
		
	
		
			
			| 651 |  | -}
 | 
		
	
		
			
			| 652 |  | -
 | 
		
	
		
			
			| 653 |  | -/******************************************************************************
 | 
		
	
		
			
			| 654 |  | - *
 | 
		
	
		
			
			| 655 |  | - * Record handling
 | 
		
	
		
			
			| 656 |  | - *
 | 
		
	
		
			
			| 657 |  | - ******************************************************************************
 | 
		
	
		
			
			| 658 |  | - */
 | 
		
	
		
			
			| 659 |  | -
 | 
		
	
		
			
			| 660 | 613 |  /**
 | 
		
	
		
			
			| 661 | 614 |   * Transmit Handshake record
 | 
		
	
		
			
			| 662 | 615 |   *
 | 
		
	
	
		
			
			|  | @@ -1025,15 +978,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
 | 
		
	
		
			
			| 1025 | 978 |  		return -EINVAL;
 | 
		
	
		
			
			| 1026 | 979 |  	}
 | 
		
	
		
			
			| 1027 | 980 |  
 | 
		
	
		
			
			| 1028 |  | -	/* Check that we are ready to send the Client Key Exchange */
 | 
		
	
		
			
			| 1029 |  | -	if ( tls->tx_state != TLS_TX_NONE ) {
 | 
		
	
		
			
			| 1030 |  | -		DBGC ( tls, "TLS %p received Server Hello Done while in "
 | 
		
	
		
			
			| 1031 |  | -		       "TX state %d\n", tls, tls->tx_state );
 | 
		
	
		
			
			| 1032 |  | -		return -EIO;
 | 
		
	
		
			
			| 1033 |  | -	}
 | 
		
	
		
			
			| 1034 |  | -
 | 
		
	
		
			
			| 1035 |  | -	/* Start sending the Client Key Exchange */
 | 
		
	
		
			
			| 1036 |  | -	tls_tx_start ( tls, TLS_TX_CLIENT_KEY_EXCHANGE );
 | 
		
	
		
			
			|  | 981 | +	/* Schedule Client Key Exchange, Change Cipher, and Finished */
 | 
		
	
		
			
			|  | 982 | +	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
 | 
		
	
		
			
			|  | 983 | +			     TLS_TX_CHANGE_CIPHER |
 | 
		
	
		
			
			|  | 984 | +			     TLS_TX_FINISHED );
 | 
		
	
		
			
			|  | 985 | +	tls_tx_resume ( tls );
 | 
		
	
		
			
			| 1037 | 986 |  
 | 
		
	
		
			
			| 1038 | 987 |  	return 0;
 | 
		
	
		
			
			| 1039 | 988 |  }
 | 
		
	
	
		
			
			|  | @@ -1050,10 +999,15 @@ static int tls_new_finished ( struct tls_session *tls,
 | 
		
	
		
			
			| 1050 | 999 |  			      void *data, size_t len ) {
 | 
		
	
		
			
			| 1051 | 1000 |  
 | 
		
	
		
			
			| 1052 | 1001 |  	/* FIXME: Handle this properly */
 | 
		
	
		
			
			| 1053 |  | -	tls_tx_data ( tls );
 | 
		
	
		
			
			| 1054 | 1002 |  	( void ) data;
 | 
		
	
		
			
			| 1055 | 1003 |  	( void ) len;
 | 
		
	
		
			
			| 1056 | 1004 |  
 | 
		
	
		
			
			|  | 1005 | +	/* Mark session as ready to transmit plaintext data */
 | 
		
	
		
			
			|  | 1006 | +	tls->tx_ready = 1;
 | 
		
	
		
			
			|  | 1007 | +
 | 
		
	
		
			
			|  | 1008 | +	/* Send notification of a window change */
 | 
		
	
		
			
			|  | 1009 | +	xfer_window_changed ( &tls->plainstream );
 | 
		
	
		
			
			|  | 1010 | +
 | 
		
	
		
			
			| 1057 | 1011 |  	return 0;
 | 
		
	
		
			
			| 1058 | 1012 |  }
 | 
		
	
		
			
			| 1059 | 1013 |  
 | 
		
	
	
		
			
			|  | @@ -1561,7 +1515,7 @@ static int tls_new_ciphertext ( struct tls_session *tls,
 | 
		
	
		
			
			| 1561 | 1515 |  static size_t tls_plainstream_window ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 1562 | 1516 |  
 | 
		
	
		
			
			| 1563 | 1517 |  	/* Block window unless we are ready to accept data */
 | 
		
	
		
			
			| 1564 |  | -	if ( tls->tx_state != TLS_TX_DATA )
 | 
		
	
		
			
			|  | 1518 | +	if ( ! tls->tx_ready )
 | 
		
	
		
			
			| 1565 | 1519 |  		return 0;
 | 
		
	
		
			
			| 1566 | 1520 |  
 | 
		
	
		
			
			| 1567 | 1521 |  	return xfer_window ( &tls->cipherstream );
 | 
		
	
	
		
			
			|  | @@ -1581,7 +1535,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls,
 | 
		
	
		
			
			| 1581 | 1535 |  	int rc;
 | 
		
	
		
			
			| 1582 | 1536 |  	
 | 
		
	
		
			
			| 1583 | 1537 |  	/* Refuse unless we are ready to accept data */
 | 
		
	
		
			
			| 1584 |  | -	if ( tls->tx_state != TLS_TX_DATA ) {
 | 
		
	
		
			
			|  | 1538 | +	if ( ! tls->tx_ready ) {
 | 
		
	
		
			
			| 1585 | 1539 |  		rc = -ENOTCONN;
 | 
		
	
		
			
			| 1586 | 1540 |  		goto done;
 | 
		
	
		
			
			| 1587 | 1541 |  	}
 | 
		
	
	
		
			
			|  | @@ -1757,29 +1711,24 @@ static void tls_tx_step ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 1757 | 1711 |  	if ( ! xfer_window ( &tls->cipherstream ) )
 | 
		
	
		
			
			| 1758 | 1712 |  		return;
 | 
		
	
		
			
			| 1759 | 1713 |  
 | 
		
	
		
			
			| 1760 |  | -	switch ( tls->tx_state ) {
 | 
		
	
		
			
			| 1761 |  | -	case TLS_TX_NONE:
 | 
		
	
		
			
			| 1762 |  | -		/* Nothing to do */
 | 
		
	
		
			
			| 1763 |  | -		break;
 | 
		
	
		
			
			| 1764 |  | -	case TLS_TX_CLIENT_HELLO:
 | 
		
	
		
			
			|  | 1714 | +	/* Send first pending transmission */
 | 
		
	
		
			
			|  | 1715 | +	if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
 | 
		
	
		
			
			| 1765 | 1716 |  		/* Send Client Hello */
 | 
		
	
		
			
			| 1766 | 1717 |  		if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
 | 
		
	
		
			
			| 1767 | 1718 |  			DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
 | 
		
	
		
			
			| 1768 | 1719 |  			       tls, strerror ( rc ) );
 | 
		
	
		
			
			| 1769 | 1720 |  			goto err;
 | 
		
	
		
			
			| 1770 | 1721 |  		}
 | 
		
	
		
			
			| 1771 |  | -		tls_tx_none ( tls );
 | 
		
	
		
			
			| 1772 |  | -		break;
 | 
		
	
		
			
			| 1773 |  | -	case TLS_TX_CLIENT_KEY_EXCHANGE:
 | 
		
	
		
			
			|  | 1722 | +		tls->tx_pending &= ~TLS_TX_CLIENT_HELLO;
 | 
		
	
		
			
			|  | 1723 | +	} else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) {
 | 
		
	
		
			
			| 1774 | 1724 |  		/* Send Client Key Exchange */
 | 
		
	
		
			
			| 1775 | 1725 |  		if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
 | 
		
	
		
			
			| 1776 | 1726 |  			DBGC ( tls, "TLS %p could send Client Key Exchange: "
 | 
		
	
		
			
			| 1777 | 1727 |  			       "%s\n", tls, strerror ( rc ) );
 | 
		
	
		
			
			| 1778 | 1728 |  			goto err;
 | 
		
	
		
			
			| 1779 | 1729 |  		}
 | 
		
	
		
			
			| 1780 |  | -		tls_tx_start ( tls, TLS_TX_CHANGE_CIPHER );
 | 
		
	
		
			
			| 1781 |  | -		break;
 | 
		
	
		
			
			| 1782 |  | -	case TLS_TX_CHANGE_CIPHER:
 | 
		
	
		
			
			|  | 1730 | +		tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE;
 | 
		
	
		
			
			|  | 1731 | +	} else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) {
 | 
		
	
		
			
			| 1783 | 1732 |  		/* Send Change Cipher, and then change the cipher in use */
 | 
		
	
		
			
			| 1784 | 1733 |  		if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
 | 
		
	
		
			
			| 1785 | 1734 |  			DBGC ( tls, "TLS %p could not send Change Cipher: "
 | 
		
	
	
		
			
			|  | @@ -1794,24 +1743,21 @@ static void tls_tx_step ( struct tls_session *tls ) {
 | 
		
	
		
			
			| 1794 | 1743 |  			goto err;
 | 
		
	
		
			
			| 1795 | 1744 |  		}
 | 
		
	
		
			
			| 1796 | 1745 |  		tls->tx_seq = 0;
 | 
		
	
		
			
			| 1797 |  | -		tls_tx_start ( tls, TLS_TX_FINISHED );
 | 
		
	
		
			
			| 1798 |  | -		break;
 | 
		
	
		
			
			| 1799 |  | -	case TLS_TX_FINISHED:
 | 
		
	
		
			
			|  | 1746 | +		tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER;
 | 
		
	
		
			
			|  | 1747 | +	} else if ( tls->tx_pending & TLS_TX_FINISHED ) {
 | 
		
	
		
			
			| 1800 | 1748 |  		/* Send Finished */
 | 
		
	
		
			
			| 1801 | 1749 |  		if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
 | 
		
	
		
			
			| 1802 | 1750 |  			DBGC ( tls, "TLS %p could not send Finished: %s\n",
 | 
		
	
		
			
			| 1803 | 1751 |  			       tls, strerror ( rc ) );
 | 
		
	
		
			
			| 1804 | 1752 |  			goto err;
 | 
		
	
		
			
			| 1805 | 1753 |  		}
 | 
		
	
		
			
			| 1806 |  | -		tls_tx_none ( tls );
 | 
		
	
		
			
			| 1807 |  | -		break;
 | 
		
	
		
			
			| 1808 |  | -	case TLS_TX_DATA:
 | 
		
	
		
			
			| 1809 |  | -		/* Nothing to do */
 | 
		
	
		
			
			| 1810 |  | -		break;
 | 
		
	
		
			
			| 1811 |  | -	default:
 | 
		
	
		
			
			| 1812 |  | -		assert ( 0 );
 | 
		
	
		
			
			|  | 1754 | +		tls->tx_pending &= ~TLS_TX_FINISHED;
 | 
		
	
		
			
			| 1813 | 1755 |  	}
 | 
		
	
		
			
			| 1814 | 1756 |  
 | 
		
	
		
			
			|  | 1757 | +	/* Reschedule process if pending transmissions remain */
 | 
		
	
		
			
			|  | 1758 | +	if ( tls->tx_pending )
 | 
		
	
		
			
			|  | 1759 | +		tls_tx_resume ( tls );
 | 
		
	
		
			
			|  | 1760 | +
 | 
		
	
		
			
			| 1815 | 1761 |  	return;
 | 
		
	
		
			
			| 1816 | 1762 |  
 | 
		
	
		
			
			| 1817 | 1763 |   err:
 | 
		
	
	
		
			
			|  | @@ -1862,8 +1808,8 @@ int add_tls ( struct interface *xfer, const char *name,
 | 
		
	
		
			
			| 1862 | 1808 |  	}
 | 
		
	
		
			
			| 1863 | 1809 |  	digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
 | 
		
	
		
			
			| 1864 | 1810 |  	digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
 | 
		
	
		
			
			| 1865 |  | -	process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt );
 | 
		
	
		
			
			| 1866 |  | -	tls_tx_start ( tls, TLS_TX_CLIENT_HELLO );
 | 
		
	
		
			
			|  | 1811 | +	tls->tx_pending = TLS_TX_CLIENT_HELLO;
 | 
		
	
		
			
			|  | 1812 | +	process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
 | 
		
	
		
			
			| 1867 | 1813 |  
 | 
		
	
		
			
			| 1868 | 1814 |  	/* Attach to parent interface, mortalise self, and return */
 | 
		
	
		
			
			| 1869 | 1815 |  	intf_plug_plug ( &tls->plainstream, xfer );
 |