#!/bin/bash
# ===================================================================
# 
# Copyright (c) 2005, Intel Corp.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions 
# are met:
#
#   * Redistributions of source code must retain the above copyright 
#     notice, this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above 
#     copyright notice, this list of conditions and the following 
#     disclaimer in the documentation and/or other materials provided 
#     with the distribution.
#   * Neither the name of Intel Corporation nor the names of its 
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
# ===================================================================

#            |        SRC        |    TAG  |      CMD SIZE     |        ORD       |mtype|strt
TPM_CMD_OPEN=\\x00\\x00\\x00\\x00\\x01\\xc1\\x00\\x00\\x00\\x11\\x01\\x00\\x00\\x01\\x01\\x01
TPM_CMD_RESM=\\x00\\x00\\x00\\x00\\x01\\xc1\\x00\\x00\\x00\\x11\\x01\\x00\\x00\\x01\\x01\\x02
TPM_CMD_CLOS=\\x00\\x00\\x00\\x00\\x01\\xc1\\x00\\x00\\x00\\x0e\\x01\\x00\\x00\\x02
TPM_CMD_DELE=\\x00\\x00\\x00\\x00\\x01\\xc1\\x00\\x00\\x00\\x0e\\x01\\x00\\x00\\x03

TPM_TYPE_PVM=\\x01
TPM_TYPE_HVM=\\x02

TPM_SUCCESS=00000000

TX_VTPM_MANAGER=/var/vtpm/fifos/from_console.fifo
RX_VTPM_MANAGER=/var/vtpm/fifos/to_console.fifo

VTPM_MIG=/usr/bin/vtpm_migrator

# -------------------- Helpers for binary streams -----------

function str_to_hex32() {
 printf "%0.8x" $1
}

function hex32_to_bin() {
 local inst=$(str_to_hex32 $1);
 
 local n1=`echo $inst | sed 's/\(..\)....../\\\\x\1/'`
 local n2=`echo $inst | sed 's/..\(..\)..../\\\\x\1/'`
 local n3=`echo $inst | sed 's/....\(..\)../\\\\x\1/'`
 local n4=`echo $inst | sed 's/......\(..\)/\\\\x\1/'`

 echo "$n1$n2$n3$n4"
}

function vtpm_manager_cmd() {
 local cmd=$1;
 local inst=$2;
 local inst_bin=$(hex32_to_bin $inst);

 claim_lock vtpm_mgr

 #send cmd to vtpm_manager
 printf "$cmd$inst_bin" > $TX_VTPM_MANAGER

 #recv response
 set +e
 local resp_hex=`dd skip=10 bs=1 count=4 if=$RX_VTPM_MANAGER 2> /dev/null | xxd -ps`
 set -e

 release_lock vtpm_mgr

 #return whether the command was successful
 if [ $resp_hex -ne $TPM_SUCCESS ]; then
   vtpm_fatal_error=1
   false
  else
   true
 fi
}

# Helper to get vm type to pass to vtpm_manager open/resume
function vtpm_get_type() {
 local inst=$(xenstore_read $XENBUS_PATH/frontend-id)
 local vm=$(xenstore_read /local/domain/$inst/vm)
 if [ "$vm" != "" ]; then
  local ostype=$(xenstore-read $vm/image/ostype)
  if [ "$ostype" == "hvm" ]; then
   echo $TPM_TYPE_HVM;
  else
   echo $TPM_TYPE_PVM;
  fi
 fi
}

# ------------------ Command handlers -----------------

# Create new vtpm instance & set it up for use
function vtpm_create () {
 # Creation is handled implicitly by the manager on first setup
 # so just set it up for use
 $(vtpm_start $1)
}

# Setup vtpm instance for use.
function vtpm_start() {
 local vmtype=$(vtpm_get_type);
 $(vtpm_manager_cmd $TPM_CMD_OPEN$vmtype $1)
}

function vtpm_resume() {
 local vmtype=$(vtpm_get_type);
 $(vtpm_manager_cmd $TPM_CMD_RESM$vmtype $1)
}

# Reset the vtpm AKA clear PCRs
function vtpm_reset() {
 #not used by current implemenation
 true
}

# Shutdown the vtpm while the vm is down
# This could be a suspend of shutdown
# we cannot distinquish, so save the state
# and decide on startup if we should keep is
function vtpm_suspend() {
 $(vtpm_manager_cmd $TPM_CMD_CLOS $1)
}


function vtpm_delete() {
 local inst=$1
 if $(vtpm_manager_cmd $TPM_CMD_DELE $inst); then
   rm -f /var/vtpm/vtpm_dm_$1.data
   true
 else 
   vtpm_fatal_error=1
   false
 fi
}

# Perform a migration step. This function differentiates between migration
# to the local host or to a remote machine.
# Parameters:
# 1st: destination host to migrate to
# 2nd: name of the domain to migrate
# 3rd: the migration step to perform
function vtpm_migrate() {
 local instance res

 instance=$(vtpmdb_find_instance $2)
 if [ "$instance" == "" ]; then
  log err "VTPM Migratoin failed. Unable to translation of domain name"
  echo "Error: VTPM Migration failed while looking up instance number"
 fi

 case "$3" in
  0)
   #Incicate migration supported
   echo "0" 
  ;;

  1)
   # Get Public Key from Destination
   # Call vtpm_manager's migration part 1
   claim_lock vtpm_mgr
   $VTPM_MIG $1 $2 $instance $3
   release_lock vtpm_mgr
  ;;

  2)
   # Call manager's migration step 2 and send result to destination
   # If successful remove from db
   claim_lock vtpm_mgr
   $VTPM_MIG $1 $2 $instance $3
   release_lock vtpm_mgr
  ;;

  3)
   if `ps x | grep "$VTPM_MIG $1"`; then
    log err "VTPM Migration failed to complete."
    echo "Error: VTPM Migration failed to complete."
   fi
  ;;
 esac
 
}


function vtpm_migrate_recover() {
 echo "Error: Recovery not supported yet" 
}

function vtpm_migrate_local() {
 echo "Error: local vTPM migration not supported"
}
