2010-12-17 04:54:16 +03:00
/*
* An implementation of key value pair ( KVP ) functionality for Linux .
*
*
* Copyright ( C ) 2010 , Novell , Inc .
* Author : K . Y . Srinivasan < ksrinivasan @ novell . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
*/
2011-03-30 00:58:49 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2010-12-17 04:54:16 +03:00
# include <linux/net.h>
# include <linux/nls.h>
# include <linux/connector.h>
# include <linux/workqueue.h>
2011-10-04 23:29:52 +04:00
# include <linux/hyperv.h>
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:39 +03:00
# include "hyperv_vmbus.h"
2015-04-12 04:07:54 +03:00
# include "hv_utils_transport.h"
2010-12-17 04:54:16 +03:00
2013-07-02 21:31:30 +04:00
/*
* Pre win8 version numbers used in ws2008 and ws 2008 r2 ( win7 )
*/
2013-09-06 22:49:56 +04:00
# define WS2008_SRV_MAJOR 1
# define WS2008_SRV_MINOR 0
# define WS2008_SRV_VERSION (WS2008_SRV_MAJOR << 16 | WS2008_SRV_MINOR)
2013-07-02 21:31:30 +04:00
# define WIN7_SRV_MAJOR 3
# define WIN7_SRV_MINOR 0
2013-09-06 22:49:56 +04:00
# define WIN7_SRV_VERSION (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
2013-07-02 21:31:30 +04:00
# define WIN8_SRV_MAJOR 4
# define WIN8_SRV_MINOR 0
2013-09-06 22:49:56 +04:00
# define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
2010-12-17 04:54:16 +03:00
2017-01-28 22:37:17 +03:00
# define KVP_VER_COUNT 3
static const int kvp_versions [ ] = {
WIN8_SRV_VERSION ,
WIN7_SRV_VERSION ,
WS2008_SRV_VERSION
} ;
# define FW_VER_COUNT 2
static const int fw_versions [ ] = {
UTIL_FW_VERSION ,
UTIL_WS2K8_FW_VERSION
} ;
2010-12-17 04:54:16 +03:00
/*
2015-04-12 04:07:47 +03:00
* Global state maintained for transaction that is being processed . For a class
* of integration services , including the " KVP service " , the specified protocol
* is a " request/response " protocol which means that there can only be single
* outstanding transaction from the host at any given point in time . We use
* this to simplify memory management in this driver - we cache and process
* only one message at a time .
2010-12-17 04:54:16 +03:00
*
2015-04-12 04:07:47 +03:00
* While the request / response protocol is guaranteed by the host , we further
* ensure this by serializing packet processing in this driver - we do not
* read additional packets from the VMBUs until the current packet is fully
* handled .
2010-12-17 04:54:16 +03:00
*/
static struct {
2015-04-12 04:07:47 +03:00
int state ; /* hvutil_device_state */
2010-12-17 04:54:16 +03:00
int recv_len ; /* number of bytes received. */
2012-03-16 19:02:25 +04:00
struct hv_kvp_msg * kvp_msg ; /* current message */
2010-12-17 04:54:16 +03:00
struct vmbus_channel * recv_channel ; /* chn we got the request */
u64 recv_req_id ; /* request ID. */
} kvp_transaction ;
2012-08-13 21:06:52 +04:00
/*
* This state maintains the version number registered by the daemon .
*/
static int dm_reg_value ;
2011-10-10 06:42:28 +04:00
static void kvp_send_key ( struct work_struct * dummy ) ;
2010-12-17 04:54:16 +03:00
2011-10-05 01:00:02 +04:00
2012-08-17 05:32:12 +04:00
static void kvp_respond_to_host ( struct hv_kvp_msg * msg , int error ) ;
2015-04-12 04:07:44 +03:00
static void kvp_timeout_func ( struct work_struct * dummy ) ;
2016-05-01 05:21:33 +03:00
static void kvp_host_handshake_func ( struct work_struct * dummy ) ;
2012-08-13 21:06:52 +04:00
static void kvp_register ( int ) ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:44 +03:00
static DECLARE_DELAYED_WORK ( kvp_timeout_work , kvp_timeout_func ) ;
2016-05-01 05:21:33 +03:00
static DECLARE_DELAYED_WORK ( kvp_host_handshake_work , kvp_host_handshake_func ) ;
2011-10-10 06:42:28 +04:00
static DECLARE_WORK ( kvp_sendkey_work , kvp_send_key ) ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:54 +03:00
static const char kvp_devname [ ] = " vmbus/hv_kvp " ;
2010-12-17 04:54:16 +03:00
static u8 * recv_buffer ;
2015-04-12 04:07:54 +03:00
static struct hvutil_transport * hvt ;
2016-12-23 03:54:01 +03:00
static struct completion release_event ;
2010-12-17 04:54:16 +03:00
/*
* Register the kernel component with the user - level daemon .
* As part of this registration , pass the LIC version number .
2013-05-29 13:29:07 +04:00
* This number has no meaning , it satisfies the registration protocol .
2010-12-17 04:54:16 +03:00
*/
2013-05-29 13:29:07 +04:00
# define HV_DRV_VERSION "3.1"
2010-12-17 04:54:16 +03:00
2015-12-15 03:01:33 +03:00
static void kvp_poll_wrapper ( void * channel )
{
/* Transaction is finished, reset the state here to avoid races. */
kvp_transaction . state = HVUTIL_READY ;
hv_kvp_onchannelcallback ( channel ) ;
}
2016-06-10 03:08:57 +03:00
static void kvp_register_done ( void )
{
/*
* If we ' re still negotiating with the host cancel the timeout
* work to not poll the channel twice .
*/
pr_debug ( " KVP: userspace daemon registered \n " ) ;
cancel_delayed_work_sync ( & kvp_host_handshake_work ) ;
hv_poll_channel ( kvp_transaction . recv_channel , kvp_poll_wrapper ) ;
}
2010-12-17 04:54:16 +03:00
static void
2012-08-13 21:06:52 +04:00
kvp_register ( int reg_value )
2010-12-17 04:54:16 +03:00
{
2012-02-03 04:56:50 +04:00
struct hv_kvp_msg * kvp_msg ;
char * version ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:54 +03:00
kvp_msg = kzalloc ( sizeof ( * kvp_msg ) , GFP_KERNEL ) ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:54 +03:00
if ( kvp_msg ) {
2012-03-11 03:32:08 +04:00
version = kvp_msg - > body . kvp_register . version ;
2012-08-13 21:06:52 +04:00
kvp_msg - > kvp_hdr . operation = reg_value ;
2012-02-03 04:56:50 +04:00
strcpy ( version , HV_DRV_VERSION ) ;
2015-04-12 04:07:54 +03:00
2016-06-10 03:08:57 +03:00
hvutil_transport_send ( hvt , kvp_msg , sizeof ( * kvp_msg ) ,
kvp_register_done ) ;
2015-04-12 04:07:54 +03:00
kfree ( kvp_msg ) ;
2010-12-17 04:54:16 +03:00
}
}
2015-04-12 04:07:44 +03:00
static void kvp_timeout_func ( struct work_struct * dummy )
2010-12-17 04:54:16 +03:00
{
/*
* If the timer fires , the user - mode component has not responded ;
* process the pending transaction .
*/
2012-08-17 05:32:12 +04:00
kvp_respond_to_host ( NULL , HV_E_FAIL ) ;
2015-04-12 04:07:47 +03:00
2015-12-15 03:01:33 +03:00
hv_poll_channel ( kvp_transaction . recv_channel , kvp_poll_wrapper ) ;
2012-08-13 21:06:52 +04:00
}
2016-05-01 05:21:33 +03:00
static void kvp_host_handshake_func ( struct work_struct * dummy )
{
hv_poll_channel ( kvp_transaction . recv_channel , hv_kvp_onchannelcallback ) ;
}
2012-08-13 21:06:52 +04:00
static int kvp_handle_handshake ( struct hv_kvp_msg * msg )
{
switch ( msg - > kvp_hdr . operation ) {
case KVP_OP_REGISTER :
dm_reg_value = KVP_OP_REGISTER ;
pr_info ( " KVP: IP injection functionality not available \n " ) ;
pr_info ( " KVP: Upgrade the KVP daemon \n " ) ;
break ;
case KVP_OP_REGISTER1 :
dm_reg_value = KVP_OP_REGISTER1 ;
break ;
default :
pr_info ( " KVP: incompatible daemon \n " ) ;
pr_info ( " KVP: KVP version: %d, Daemon version: %d \n " ,
KVP_OP_REGISTER1 , msg - > kvp_hdr . operation ) ;
2015-04-12 04:07:54 +03:00
return - EINVAL ;
2012-08-13 21:06:52 +04:00
}
2015-04-12 04:07:54 +03:00
/*
* We have a compatible daemon ; complete the handshake .
*/
2016-06-10 03:08:57 +03:00
pr_debug ( " KVP: userspace daemon ver. %d connected \n " ,
msg - > kvp_hdr . operation ) ;
2015-04-12 04:07:54 +03:00
kvp_register ( dm_reg_value ) ;
2016-05-01 05:21:33 +03:00
2015-04-12 04:07:54 +03:00
return 0 ;
2010-12-17 04:54:16 +03:00
}
2012-08-13 21:06:52 +04:00
2010-12-17 04:54:16 +03:00
/*
* Callback when data is received from user mode .
*/
2015-04-12 04:07:54 +03:00
static int kvp_on_msg ( void * msg , int len )
2010-12-17 04:54:16 +03:00
{
2015-04-12 04:07:54 +03:00
struct hv_kvp_msg * message = ( struct hv_kvp_msg * ) msg ;
2012-02-03 04:56:50 +04:00
struct hv_kvp_msg_enumerate * data ;
2012-08-13 21:06:52 +04:00
int error = 0 ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:54 +03:00
if ( len < sizeof ( * message ) )
return - EINVAL ;
2012-08-13 21:06:52 +04:00
/*
* If we are negotiating the version information
* with the daemon ; handle that first .
*/
2015-04-12 04:07:47 +03:00
if ( kvp_transaction . state < HVUTIL_READY ) {
2015-04-12 04:07:54 +03:00
return kvp_handle_handshake ( message ) ;
2012-08-13 21:06:52 +04:00
}
2015-04-12 04:07:47 +03:00
/* We didn't send anything to userspace so the reply is spurious */
if ( kvp_transaction . state < HVUTIL_USERSPACE_REQ )
2015-04-12 04:07:54 +03:00
return - EINVAL ;
2015-04-12 04:07:47 +03:00
kvp_transaction . state = HVUTIL_USERSPACE_RECV ;
2012-08-13 21:06:52 +04:00
/*
* Based on the version of the daemon , we propagate errors from the
* daemon differently .
*/
data = & message - > body . kvp_enum_data ;
switch ( dm_reg_value ) {
2012-03-16 19:02:25 +04:00
case KVP_OP_REGISTER :
2012-08-13 21:06:52 +04:00
/*
* Null string is used to pass back error condition .
*/
if ( data - > data . key [ 0 ] = = 0 )
error = HV_S_CONT ;
2012-03-16 19:02:25 +04:00
break ;
2010-12-17 04:54:16 +03:00
2012-08-13 21:06:52 +04:00
case KVP_OP_REGISTER1 :
2010-12-17 04:54:16 +03:00
/*
2012-08-13 21:06:52 +04:00
* We use the message header information from
* the user level daemon to transmit errors .
2010-12-17 04:54:16 +03:00
*/
2012-08-13 21:06:52 +04:00
error = message - > error ;
break ;
2010-12-17 04:54:16 +03:00
}
2012-08-13 21:06:52 +04:00
/*
* Complete the transaction by forwarding the key value
* to the host . But first , cancel the timeout .
*/
2015-04-12 04:07:47 +03:00
if ( cancel_delayed_work_sync ( & kvp_timeout_work ) ) {
2012-08-17 05:32:12 +04:00
kvp_respond_to_host ( message , error ) ;
2015-12-15 03:01:33 +03:00
hv_poll_channel ( kvp_transaction . recv_channel , kvp_poll_wrapper ) ;
2015-04-12 04:07:47 +03:00
}
2015-04-12 04:07:54 +03:00
return 0 ;
2010-12-17 04:54:16 +03:00
}
2012-08-17 05:32:12 +04:00
static int process_ob_ipinfo ( void * in_msg , void * out_msg , int op )
{
struct hv_kvp_msg * in = in_msg ;
struct hv_kvp_ip_msg * out = out_msg ;
int len ;
switch ( op ) {
case KVP_OP_GET_IP_INFO :
/*
* Transform all parameters into utf16 encoding .
*/
len = utf8s_to_utf16s ( ( char * ) in - > body . kvp_ip_val . ip_addr ,
strlen ( ( char * ) in - > body . kvp_ip_val . ip_addr ) ,
UTF16_HOST_ENDIAN ,
( wchar_t * ) out - > kvp_ip_val . ip_addr ,
MAX_IP_ADDR_SIZE ) ;
if ( len < 0 )
return len ;
len = utf8s_to_utf16s ( ( char * ) in - > body . kvp_ip_val . sub_net ,
strlen ( ( char * ) in - > body . kvp_ip_val . sub_net ) ,
UTF16_HOST_ENDIAN ,
( wchar_t * ) out - > kvp_ip_val . sub_net ,
MAX_IP_ADDR_SIZE ) ;
if ( len < 0 )
return len ;
len = utf8s_to_utf16s ( ( char * ) in - > body . kvp_ip_val . gate_way ,
strlen ( ( char * ) in - > body . kvp_ip_val . gate_way ) ,
UTF16_HOST_ENDIAN ,
( wchar_t * ) out - > kvp_ip_val . gate_way ,
MAX_GATEWAY_SIZE ) ;
if ( len < 0 )
return len ;
len = utf8s_to_utf16s ( ( char * ) in - > body . kvp_ip_val . dns_addr ,
strlen ( ( char * ) in - > body . kvp_ip_val . dns_addr ) ,
UTF16_HOST_ENDIAN ,
( wchar_t * ) out - > kvp_ip_val . dns_addr ,
MAX_IP_ADDR_SIZE ) ;
if ( len < 0 )
return len ;
len = utf8s_to_utf16s ( ( char * ) in - > body . kvp_ip_val . adapter_id ,
strlen ( ( char * ) in - > body . kvp_ip_val . adapter_id ) ,
UTF16_HOST_ENDIAN ,
( wchar_t * ) out - > kvp_ip_val . adapter_id ,
MAX_IP_ADDR_SIZE ) ;
if ( len < 0 )
return len ;
out - > kvp_ip_val . dhcp_enabled =
in - > body . kvp_ip_val . dhcp_enabled ;
2012-09-05 04:54:13 +04:00
out - > kvp_ip_val . addr_family =
in - > body . kvp_ip_val . addr_family ;
2012-08-17 05:32:12 +04:00
}
return 0 ;
}
static void process_ib_ipinfo ( void * in_msg , void * out_msg , int op )
{
struct hv_kvp_ip_msg * in = in_msg ;
struct hv_kvp_msg * out = out_msg ;
switch ( op ) {
case KVP_OP_SET_IP_INFO :
/*
* Transform all parameters into utf8 encoding .
*/
utf16s_to_utf8s ( ( wchar_t * ) in - > kvp_ip_val . ip_addr ,
MAX_IP_ADDR_SIZE ,
UTF16_LITTLE_ENDIAN ,
( __u8 * ) out - > body . kvp_ip_val . ip_addr ,
MAX_IP_ADDR_SIZE ) ;
utf16s_to_utf8s ( ( wchar_t * ) in - > kvp_ip_val . sub_net ,
MAX_IP_ADDR_SIZE ,
UTF16_LITTLE_ENDIAN ,
( __u8 * ) out - > body . kvp_ip_val . sub_net ,
MAX_IP_ADDR_SIZE ) ;
utf16s_to_utf8s ( ( wchar_t * ) in - > kvp_ip_val . gate_way ,
MAX_GATEWAY_SIZE ,
UTF16_LITTLE_ENDIAN ,
( __u8 * ) out - > body . kvp_ip_val . gate_way ,
MAX_GATEWAY_SIZE ) ;
utf16s_to_utf8s ( ( wchar_t * ) in - > kvp_ip_val . dns_addr ,
MAX_IP_ADDR_SIZE ,
UTF16_LITTLE_ENDIAN ,
( __u8 * ) out - > body . kvp_ip_val . dns_addr ,
MAX_IP_ADDR_SIZE ) ;
out - > body . kvp_ip_val . dhcp_enabled = in - > kvp_ip_val . dhcp_enabled ;
default :
utf16s_to_utf8s ( ( wchar_t * ) in - > kvp_ip_val . adapter_id ,
MAX_ADAPTER_ID_SIZE ,
UTF16_LITTLE_ENDIAN ,
( __u8 * ) out - > body . kvp_ip_val . adapter_id ,
MAX_ADAPTER_ID_SIZE ) ;
out - > body . kvp_ip_val . addr_family = in - > kvp_ip_val . addr_family ;
}
}
2011-10-10 06:42:28 +04:00
static void
kvp_send_key ( struct work_struct * dummy )
2010-12-17 04:54:16 +03:00
{
2012-02-03 04:56:50 +04:00
struct hv_kvp_msg * message ;
2012-03-16 19:02:25 +04:00
struct hv_kvp_msg * in_msg ;
__u8 operation = kvp_transaction . kvp_msg - > kvp_hdr . operation ;
__u8 pool = kvp_transaction . kvp_msg - > kvp_hdr . pool ;
__u32 val32 ;
__u64 val64 ;
2014-11-06 20:21:25 +03:00
int rc ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:47 +03:00
/* The transaction state is wrong. */
if ( kvp_transaction . state ! = HVUTIL_HOSTMSG_RECEIVED )
return ;
2015-04-12 04:07:54 +03:00
message = kzalloc ( sizeof ( * message ) , GFP_KERNEL ) ;
2015-08-02 02:08:11 +03:00
if ( ! message )
return ;
2012-03-16 19:02:25 +04:00
message - > kvp_hdr . operation = operation ;
message - > kvp_hdr . pool = pool ;
in_msg = kvp_transaction . kvp_msg ;
/*
* The key / value strings sent from the host are encoded in
* in utf16 ; convert it to utf8 strings .
* The host assures us that the utf16 strings will not exceed
* the max lengths specified . We will however , reserve room
* for the string terminating character - in the utf16s_utf8s ( )
* function we limit the size of the buffer where the converted
* string is placed to HV_KVP_EXCHANGE_MAX_ * _SIZE - 1 to gaurantee
* that the strings can be properly terminated !
*/
switch ( message - > kvp_hdr . operation ) {
2012-08-17 05:32:12 +04:00
case KVP_OP_SET_IP_INFO :
process_ib_ipinfo ( in_msg , message , KVP_OP_SET_IP_INFO ) ;
break ;
case KVP_OP_GET_IP_INFO :
process_ib_ipinfo ( in_msg , message , KVP_OP_GET_IP_INFO ) ;
break ;
2012-03-16 19:02:25 +04:00
case KVP_OP_SET :
switch ( in_msg - > body . kvp_set . data . value_type ) {
case REG_SZ :
/*
* The value is a string - utf16 encoding .
*/
message - > body . kvp_set . data . value_size =
utf16s_to_utf8s (
( wchar_t * ) in_msg - > body . kvp_set . data . value ,
in_msg - > body . kvp_set . data . value_size ,
UTF16_LITTLE_ENDIAN ,
message - > body . kvp_set . data . value ,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1 ) + 1 ;
break ;
case REG_U32 :
/*
* The value is a 32 bit scalar .
* We save this as a utf8 string .
*/
val32 = in_msg - > body . kvp_set . data . value_u32 ;
message - > body . kvp_set . data . value_size =
sprintf ( message - > body . kvp_set . data . value ,
" %d " , val32 ) + 1 ;
break ;
case REG_U64 :
/*
* The value is a 64 bit scalar .
* We save this as a utf8 string .
*/
val64 = in_msg - > body . kvp_set . data . value_u64 ;
message - > body . kvp_set . data . value_size =
sprintf ( message - > body . kvp_set . data . value ,
" %llu " , val64 ) + 1 ;
break ;
}
case KVP_OP_GET :
message - > body . kvp_set . data . key_size =
utf16s_to_utf8s (
( wchar_t * ) in_msg - > body . kvp_set . data . key ,
in_msg - > body . kvp_set . data . key_size ,
UTF16_LITTLE_ENDIAN ,
message - > body . kvp_set . data . key ,
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1 ) + 1 ;
break ;
case KVP_OP_DELETE :
message - > body . kvp_delete . key_size =
utf16s_to_utf8s (
( wchar_t * ) in_msg - > body . kvp_delete . key ,
in_msg - > body . kvp_delete . key_size ,
UTF16_LITTLE_ENDIAN ,
message - > body . kvp_delete . key ,
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1 ) + 1 ;
break ;
case KVP_OP_ENUMERATE :
message - > body . kvp_enum_data . index =
in_msg - > body . kvp_enum_data . index ;
break ;
2010-12-17 04:54:16 +03:00
}
2012-03-16 19:02:25 +04:00
2015-04-12 04:07:47 +03:00
kvp_transaction . state = HVUTIL_USERSPACE_REQ ;
2016-06-10 03:08:57 +03:00
rc = hvutil_transport_send ( hvt , message , sizeof ( * message ) , NULL ) ;
2014-11-06 20:21:25 +03:00
if ( rc ) {
pr_debug ( " KVP: failed to communicate to the daemon: %d \n " , rc ) ;
2015-04-12 04:07:47 +03:00
if ( cancel_delayed_work_sync ( & kvp_timeout_work ) ) {
2014-11-06 20:21:25 +03:00
kvp_respond_to_host ( message , HV_E_FAIL ) ;
2015-04-12 04:07:47 +03:00
kvp_transaction . state = HVUTIL_READY ;
}
2014-11-06 20:21:25 +03:00
}
2015-04-12 04:07:54 +03:00
kfree ( message ) ;
2012-03-16 19:02:25 +04:00
2011-10-10 06:42:28 +04:00
return ;
2010-12-17 04:54:16 +03:00
}
/*
* Send a response back to the host .
*/
static void
2012-08-17 05:32:12 +04:00
kvp_respond_to_host ( struct hv_kvp_msg * msg_to_host , int error )
2010-12-17 04:54:16 +03:00
{
struct hv_kvp_msg * kvp_msg ;
2012-03-16 19:02:25 +04:00
struct hv_kvp_exchg_msg_value * kvp_data ;
2010-12-17 04:54:16 +03:00
char * key_name ;
2012-08-17 05:32:12 +04:00
char * value ;
2010-12-17 04:54:16 +03:00
struct icmsg_hdr * icmsghdrp ;
2012-03-16 19:02:25 +04:00
int keylen = 0 ;
int valuelen = 0 ;
2010-12-17 04:54:16 +03:00
u32 buf_len ;
struct vmbus_channel * channel ;
u64 req_id ;
2012-08-17 05:32:12 +04:00
int ret ;
2010-12-17 04:54:16 +03:00
/*
* Copy the global state for completing the transaction . Note that
* only one transaction can be active at a time .
*/
buf_len = kvp_transaction . recv_len ;
channel = kvp_transaction . recv_channel ;
req_id = kvp_transaction . recv_req_id ;
2012-03-16 19:02:25 +04:00
icmsghdrp = ( struct icmsg_hdr * )
& recv_buffer [ sizeof ( struct vmbuspipe_hdr ) ] ;
2011-09-18 21:31:34 +04:00
if ( channel - > onchannel_callback = = NULL )
/*
* We have raced with util driver being unloaded ;
* silently return .
*/
return ;
2012-08-13 21:06:52 +04:00
icmsghdrp - > status = error ;
2010-12-17 04:54:16 +03:00
/*
2012-03-16 19:02:27 +04:00
* If the error parameter is set , terminate the host ' s enumeration
* on this pool .
2010-12-17 04:54:16 +03:00
*/
if ( error ) {
/*
2012-08-13 21:06:52 +04:00
* Something failed or we have timedout ;
* terminate the current host - side iteration .
2010-12-17 04:54:16 +03:00
*/
goto response_done ;
}
2012-03-16 19:02:25 +04:00
kvp_msg = ( struct hv_kvp_msg * )
& recv_buffer [ sizeof ( struct vmbuspipe_hdr ) +
sizeof ( struct icmsg_hdr ) ] ;
switch ( kvp_transaction . kvp_msg - > kvp_hdr . operation ) {
2012-08-17 05:32:12 +04:00
case KVP_OP_GET_IP_INFO :
ret = process_ob_ipinfo ( msg_to_host ,
( struct hv_kvp_ip_msg * ) kvp_msg ,
KVP_OP_GET_IP_INFO ) ;
if ( ret < 0 )
icmsghdrp - > status = HV_E_FAIL ;
goto response_done ;
case KVP_OP_SET_IP_INFO :
goto response_done ;
2012-03-16 19:02:25 +04:00
case KVP_OP_GET :
kvp_data = & kvp_msg - > body . kvp_get . data ;
goto copy_value ;
case KVP_OP_SET :
case KVP_OP_DELETE :
goto response_done ;
default :
break ;
}
kvp_data = & kvp_msg - > body . kvp_enum_data . data ;
2012-08-17 05:32:12 +04:00
key_name = msg_to_host - > body . kvp_enum_data . data . key ;
2012-03-16 19:02:25 +04:00
2010-12-17 04:54:16 +03:00
/*
* The windows host expects the key / value pair to be encoded
2012-03-16 19:02:25 +04:00
* in utf16 . Ensure that the key / value size reported to the host
* will be less than or equal to the MAX size ( including the
* terminating character ) .
2010-12-17 04:54:16 +03:00
*/
2011-11-18 01:42:19 +04:00
keylen = utf8s_to_utf16s ( key_name , strlen ( key_name ) , UTF16_HOST_ENDIAN ,
2012-03-16 19:02:25 +04:00
( wchar_t * ) kvp_data - > key ,
( HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2 ) - 2 ) ;
kvp_data - > key_size = 2 * ( keylen + 1 ) ; /* utf16 encoding */
copy_value :
2012-08-17 05:32:12 +04:00
value = msg_to_host - > body . kvp_enum_data . data . value ;
2011-11-18 01:42:19 +04:00
valuelen = utf8s_to_utf16s ( value , strlen ( value ) , UTF16_HOST_ENDIAN ,
2012-03-16 19:02:25 +04:00
( wchar_t * ) kvp_data - > value ,
( HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2 ) - 2 ) ;
kvp_data - > value_size = 2 * ( valuelen + 1 ) ; /* utf16 encoding */
2010-12-17 04:54:16 +03:00
2012-03-16 19:02:25 +04:00
/*
* If the utf8s to utf16s conversion failed ; notify host
* of the error .
*/
if ( ( keylen < 0 ) | | ( valuelen < 0 ) )
icmsghdrp - > status = HV_E_FAIL ;
kvp_data - > value_type = REG_SZ ; /* all our values are strings */
2010-12-17 04:54:16 +03:00
response_done :
icmsghdrp - > icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE ;
vmbus_sendpacket ( channel , recv_buffer , buf_len , req_id ,
2011-01-26 23:12:13 +03:00
VM_PKT_DATA_INBAND , 0 ) ;
2010-12-17 04:54:16 +03:00
}
/*
* This callback is invoked when we get a KVP message from the host .
* The host ensures that only one KVP transaction can be active at a time .
* KVP implementation in Linux needs to forward the key to a user - mde
* component to retrive the corresponding value . Consequently , we cannot
* respond to the host in the conext of this callback . Since the host
* guarantees that at most only one transaction can be active at a time ,
* we stash away the transaction state in a set of global variables .
*/
void hv_kvp_onchannelcallback ( void * context )
{
struct vmbus_channel * channel = context ;
u32 recvlen ;
u64 requestid ;
struct hv_kvp_msg * kvp_msg ;
struct icmsg_hdr * icmsghdrp ;
2013-09-06 22:49:56 +04:00
int kvp_srv_version ;
2016-05-01 05:21:33 +03:00
static enum { NEGO_NOT_STARTED ,
NEGO_IN_PROGRESS ,
NEGO_FINISHED } host_negotiatied = NEGO_NOT_STARTED ;
2010-12-17 04:54:16 +03:00
2016-05-01 05:21:33 +03:00
if ( host_negotiatied = = NEGO_NOT_STARTED & &
kvp_transaction . state < HVUTIL_READY ) {
/*
* If userspace daemon is not connected and host is asking
* us to negotiate we need to delay to not lose messages .
* This is important for Failover IP setting .
*/
host_negotiatied = NEGO_IN_PROGRESS ;
schedule_delayed_work ( & kvp_host_handshake_work ,
HV_UTIL_NEGO_TIMEOUT * HZ ) ;
return ;
}
2015-12-15 03:01:33 +03:00
if ( kvp_transaction . state > HVUTIL_READY )
2012-03-16 19:02:25 +04:00
return ;
2010-12-17 04:54:16 +03:00
2014-07-08 03:34:25 +04:00
vmbus_recvpacket ( channel , recv_buffer , PAGE_SIZE * 4 , & recvlen ,
2012-08-17 05:32:12 +04:00
& requestid ) ;
2010-12-17 04:54:16 +03:00
if ( recvlen > 0 ) {
icmsghdrp = ( struct icmsg_hdr * ) & recv_buffer [
sizeof ( struct vmbuspipe_hdr ) ] ;
if ( icmsghdrp - > icmsgtype = = ICMSGTYPE_NEGOTIATE ) {
2017-01-28 22:37:17 +03:00
vmbus_prep_negotiate_resp ( icmsghdrp ,
recv_buffer , fw_versions , FW_VER_COUNT ,
kvp_versions , KVP_VER_COUNT ,
NULL , & kvp_srv_version ) ;
2010-12-17 04:54:16 +03:00
} else {
kvp_msg = ( struct hv_kvp_msg * ) & recv_buffer [
sizeof ( struct vmbuspipe_hdr ) +
sizeof ( struct icmsg_hdr ) ] ;
/*
* Stash away this global state for completing the
* transaction ; note transactions are serialized .
*/
2012-03-16 19:02:25 +04:00
2010-12-17 04:54:16 +03:00
kvp_transaction . recv_len = recvlen ;
kvp_transaction . recv_req_id = requestid ;
2012-03-16 19:02:25 +04:00
kvp_transaction . kvp_msg = kvp_msg ;
2010-12-17 04:54:16 +03:00
2015-04-12 04:07:47 +03:00
if ( kvp_transaction . state < HVUTIL_READY ) {
/* Userspace is not registered yet */
kvp_respond_to_host ( NULL , HV_E_FAIL ) ;
return ;
}
kvp_transaction . state = HVUTIL_HOSTMSG_RECEIVED ;
2010-12-17 04:54:16 +03:00
/*
* Get the information from the
* user - mode component .
* component . This transaction will be
* completed when we get the value from
* the user - mode component .
* Set a timeout to deal with
* user - mode not responding .
*/
2011-10-10 06:42:28 +04:00
schedule_work ( & kvp_sendkey_work ) ;
2015-12-15 03:01:32 +03:00
schedule_delayed_work ( & kvp_timeout_work ,
HV_UTIL_TIMEOUT * HZ ) ;
2010-12-17 04:54:16 +03:00
return ;
}
icmsghdrp - > icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE ;
vmbus_sendpacket ( channel , recv_buffer ,
recvlen , requestid ,
2011-01-26 23:12:13 +03:00
VM_PKT_DATA_INBAND , 0 ) ;
2016-05-01 05:21:33 +03:00
host_negotiatied = NEGO_FINISHED ;
2010-12-17 04:54:16 +03:00
}
}
2015-04-12 04:07:54 +03:00
static void kvp_on_reset ( void )
{
if ( cancel_delayed_work_sync ( & kvp_timeout_work ) )
kvp_respond_to_host ( NULL , HV_E_FAIL ) ;
kvp_transaction . state = HVUTIL_DEVICE_INIT ;
2016-12-23 03:54:01 +03:00
complete ( & release_event ) ;
2015-04-12 04:07:54 +03:00
}
2010-12-17 04:54:16 +03:00
int
2011-09-18 21:31:33 +04:00
hv_kvp_init ( struct hv_util_service * srv )
2010-12-17 04:54:16 +03:00
{
2011-09-18 21:31:33 +04:00
recv_buffer = srv - > recv_buffer ;
2016-02-27 02:13:19 +03:00
kvp_transaction . recv_channel = srv - > channel ;
2010-12-17 04:54:16 +03:00
2016-12-23 03:54:01 +03:00
init_completion ( & release_event ) ;
2012-03-16 19:02:25 +04:00
/*
* When this driver loads , the user level daemon that
* processes the host requests may not yet be running .
* Defer processing channel callbacks until the daemon
* has registered .
*/
2015-04-12 04:07:47 +03:00
kvp_transaction . state = HVUTIL_DEVICE_INIT ;
2012-03-16 19:02:25 +04:00
2015-04-12 04:07:54 +03:00
hvt = hvutil_transport_init ( kvp_devname , CN_KVP_IDX , CN_KVP_VAL ,
kvp_on_msg , kvp_on_reset ) ;
if ( ! hvt )
return - EFAULT ;
2010-12-17 04:54:16 +03:00
return 0 ;
}
void hv_kvp_deinit ( void )
{
2015-04-12 04:07:47 +03:00
kvp_transaction . state = HVUTIL_DEVICE_DYING ;
2016-05-01 05:21:33 +03:00
cancel_delayed_work_sync ( & kvp_host_handshake_work ) ;
2015-04-12 04:07:44 +03:00
cancel_delayed_work_sync ( & kvp_timeout_work ) ;
2011-10-10 06:42:28 +04:00
cancel_work_sync ( & kvp_sendkey_work ) ;
2015-04-12 04:07:54 +03:00
hvutil_transport_destroy ( hvt ) ;
2016-12-23 03:54:01 +03:00
wait_for_completion ( & release_event ) ;
2010-12-17 04:54:16 +03:00
}