2010-12-16 18:56:54 -07: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 .
*
*/
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/poll.h>
# include <sys/utsname.h>
# include <linux/types.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <arpa/inet.h>
# include <linux/connector.h>
2012-02-02 16:56:49 -08:00
# include <linux/hyperv.h>
2010-12-16 18:56:54 -07:00
# include <linux/netlink.h>
# include <ifaddrs.h>
# include <netdb.h>
# include <syslog.h>
2012-03-16 08:02:26 -07:00
# include <sys/stat.h>
# include <fcntl.h>
2010-12-16 18:56:54 -07:00
/*
* KVP protocol : The user mode component first registers with the
* the kernel component . Subsequently , the kernel component requests , data
* for the specified keys . In response to this message the user mode component
* fills in the value corresponding to the specified key . We overload the
* sequence field in the cn_msg header to define our KVP message types .
*
* We use this infrastructure for also supporting queries from user mode
* application for state that may be maintained in the KVP kernel component .
*
*/
enum key_index {
FullyQualifiedDomainName = 0 ,
IntegrationServicesVersion , /*This key is serviced in the kernel*/
NetworkAddressIPv4 ,
NetworkAddressIPv6 ,
OSBuildNumber ,
OSName ,
OSMajorVersion ,
OSMinorVersion ,
OSVersion ,
ProcessorArchitecture
} ;
static char kvp_send_buffer [ 4096 ] ;
static char kvp_recv_buffer [ 4096 ] ;
static struct sockaddr_nl addr ;
2011-03-22 10:02:17 +01:00
static char * os_name = " " ;
static char * os_major = " " ;
static char * os_minor = " " ;
static char * processor_arch ;
static char * os_build ;
2010-12-16 18:56:54 -07:00
static char * lic_version ;
2011-03-22 10:02:17 +01:00
static struct utsname uts_buf ;
2010-12-16 18:56:54 -07:00
2012-03-16 08:02:26 -07:00
# define MAX_FILE_NAME 100
# define ENTRIES_PER_BLOCK 50
struct kvp_record {
__u8 key [ HV_KVP_EXCHANGE_MAX_KEY_SIZE ] ;
__u8 value [ HV_KVP_EXCHANGE_MAX_VALUE_SIZE ] ;
} ;
struct kvp_file_state {
int fd ;
int num_blocks ;
struct kvp_record * records ;
int num_records ;
__u8 fname [ MAX_FILE_NAME ] ;
} ;
static struct kvp_file_state kvp_file_info [ KVP_POOL_COUNT ] ;
static void kvp_acquire_lock ( int pool )
{
struct flock fl = { F_WRLCK , SEEK_SET , 0 , 0 , 0 } ;
fl . l_pid = getpid ( ) ;
if ( fcntl ( kvp_file_info [ pool ] . fd , F_SETLKW , & fl ) = = - 1 ) {
syslog ( LOG_ERR , " Failed to acquire the lock pool: %d " , pool ) ;
exit ( - 1 ) ;
}
}
static void kvp_release_lock ( int pool )
{
struct flock fl = { F_UNLCK , SEEK_SET , 0 , 0 , 0 } ;
fl . l_pid = getpid ( ) ;
if ( fcntl ( kvp_file_info [ pool ] . fd , F_SETLK , & fl ) = = - 1 ) {
perror ( " fcntl " ) ;
syslog ( LOG_ERR , " Failed to release the lock pool: %d " , pool ) ;
exit ( - 1 ) ;
}
}
static void kvp_update_file ( int pool )
{
FILE * filep ;
size_t bytes_written ;
/*
* We are going to write our in - memory registry out to
* disk ; acquire the lock first .
*/
kvp_acquire_lock ( pool ) ;
filep = fopen ( kvp_file_info [ pool ] . fname , " w " ) ;
if ( ! filep ) {
kvp_release_lock ( pool ) ;
syslog ( LOG_ERR , " Failed to open file, pool: %d " , pool ) ;
exit ( - 1 ) ;
}
bytes_written = fwrite ( kvp_file_info [ pool ] . records ,
sizeof ( struct kvp_record ) ,
kvp_file_info [ pool ] . num_records , filep ) ;
fflush ( filep ) ;
kvp_release_lock ( pool ) ;
}
2012-03-16 08:02:27 -07:00
static void kvp_update_mem_state ( int pool )
{
FILE * filep ;
size_t records_read = 0 ;
struct kvp_record * record = kvp_file_info [ pool ] . records ;
struct kvp_record * readp ;
int num_blocks = kvp_file_info [ pool ] . num_blocks ;
int alloc_unit = sizeof ( struct kvp_record ) * ENTRIES_PER_BLOCK ;
kvp_acquire_lock ( pool ) ;
filep = fopen ( kvp_file_info [ pool ] . fname , " r " ) ;
if ( ! filep ) {
kvp_release_lock ( pool ) ;
syslog ( LOG_ERR , " Failed to open file, pool: %d " , pool ) ;
exit ( - 1 ) ;
}
while ( ! feof ( filep ) ) {
readp = & record [ records_read ] ;
records_read + = fread ( readp , sizeof ( struct kvp_record ) ,
ENTRIES_PER_BLOCK * num_blocks ,
filep ) ;
if ( ! feof ( filep ) ) {
/*
* We have more data to read .
*/
num_blocks + + ;
record = realloc ( record , alloc_unit * num_blocks ) ;
if ( record = = NULL ) {
syslog ( LOG_ERR , " malloc failed " ) ;
exit ( - 1 ) ;
}
continue ;
}
break ;
}
kvp_file_info [ pool ] . num_blocks = num_blocks ;
kvp_file_info [ pool ] . records = record ;
kvp_file_info [ pool ] . num_records = records_read ;
kvp_release_lock ( pool ) ;
}
2012-03-16 08:02:26 -07:00
static int kvp_file_init ( void )
{
int ret , fd ;
FILE * filep ;
size_t records_read ;
__u8 * fname ;
struct kvp_record * record ;
struct kvp_record * readp ;
int num_blocks ;
int i ;
int alloc_unit = sizeof ( struct kvp_record ) * ENTRIES_PER_BLOCK ;
if ( access ( " /var/opt/hyperv " , F_OK ) ) {
if ( mkdir ( " /var/opt/hyperv " , S_IRUSR | S_IWUSR | S_IROTH ) ) {
syslog ( LOG_ERR , " Failed to create /var/opt/hyperv " ) ;
exit ( - 1 ) ;
}
}
for ( i = 0 ; i < KVP_POOL_COUNT ; i + + ) {
fname = kvp_file_info [ i ] . fname ;
records_read = 0 ;
num_blocks = 1 ;
sprintf ( fname , " /var/opt/hyperv/.kvp_pool_%d " , i ) ;
fd = open ( fname , O_RDWR | O_CREAT , S_IRUSR | S_IWUSR | S_IROTH ) ;
if ( fd = = - 1 )
return 1 ;
filep = fopen ( fname , " r " ) ;
if ( ! filep )
return 1 ;
record = malloc ( alloc_unit * num_blocks ) ;
if ( record = = NULL ) {
fclose ( filep ) ;
return 1 ;
}
while ( ! feof ( filep ) ) {
readp = & record [ records_read ] ;
records_read + = fread ( readp , sizeof ( struct kvp_record ) ,
ENTRIES_PER_BLOCK ,
filep ) ;
if ( ! feof ( filep ) ) {
/*
* We have more data to read .
*/
num_blocks + + ;
record = realloc ( record , alloc_unit *
num_blocks ) ;
if ( record = = NULL ) {
fclose ( filep ) ;
return 1 ;
}
continue ;
}
break ;
}
kvp_file_info [ i ] . fd = fd ;
kvp_file_info [ i ] . num_blocks = num_blocks ;
kvp_file_info [ i ] . records = record ;
kvp_file_info [ i ] . num_records = records_read ;
fclose ( filep ) ;
}
return 0 ;
}
static int kvp_key_delete ( int pool , __u8 * key , int key_size )
{
int i ;
int j , k ;
2012-03-16 08:02:27 -07:00
int num_records ;
struct kvp_record * record ;
/*
* First update the in - memory state .
*/
kvp_update_mem_state ( pool ) ;
num_records = kvp_file_info [ pool ] . num_records ;
record = kvp_file_info [ pool ] . records ;
2012-03-16 08:02:26 -07:00
for ( i = 0 ; i < num_records ; i + + ) {
if ( memcmp ( key , record [ i ] . key , key_size ) )
continue ;
/*
* Found a match ; just move the remaining
* entries up .
*/
if ( i = = num_records ) {
kvp_file_info [ pool ] . num_records - - ;
kvp_update_file ( pool ) ;
return 0 ;
}
j = i ;
k = j + 1 ;
for ( ; k < num_records ; k + + ) {
strcpy ( record [ j ] . key , record [ k ] . key ) ;
strcpy ( record [ j ] . value , record [ k ] . value ) ;
j + + ;
}
kvp_file_info [ pool ] . num_records - - ;
kvp_update_file ( pool ) ;
return 0 ;
}
return 1 ;
}
static int kvp_key_add_or_modify ( int pool , __u8 * key , int key_size , __u8 * value ,
int value_size )
{
int i ;
int j , k ;
2012-03-16 08:02:27 -07:00
int num_records ;
struct kvp_record * record ;
int num_blocks ;
2012-03-16 08:02:26 -07:00
if ( ( key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE ) | |
( value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) )
return 1 ;
2012-03-16 08:02:27 -07:00
/*
* First update the in - memory state .
*/
kvp_update_mem_state ( pool ) ;
num_records = kvp_file_info [ pool ] . num_records ;
record = kvp_file_info [ pool ] . records ;
num_blocks = kvp_file_info [ pool ] . num_blocks ;
2012-03-16 08:02:26 -07:00
for ( i = 0 ; i < num_records ; i + + ) {
if ( memcmp ( key , record [ i ] . key , key_size ) )
continue ;
/*
* Found a match ; just update the value -
* this is the modify case .
*/
memcpy ( record [ i ] . value , value , value_size ) ;
kvp_update_file ( pool ) ;
return 0 ;
}
/*
* Need to add a new entry ;
*/
if ( num_records = = ( ENTRIES_PER_BLOCK * num_blocks ) ) {
/* Need to allocate a larger array for reg entries. */
record = realloc ( record , sizeof ( struct kvp_record ) *
ENTRIES_PER_BLOCK * ( num_blocks + 1 ) ) ;
if ( record = = NULL )
return 1 ;
kvp_file_info [ pool ] . num_blocks + + ;
}
memcpy ( record [ i ] . value , value , value_size ) ;
memcpy ( record [ i ] . key , key , key_size ) ;
kvp_file_info [ pool ] . records = record ;
kvp_file_info [ pool ] . num_records + + ;
kvp_update_file ( pool ) ;
return 0 ;
}
static int kvp_get_value ( int pool , __u8 * key , int key_size , __u8 * value ,
int value_size )
{
int i ;
2012-03-16 08:02:27 -07:00
int num_records ;
struct kvp_record * record ;
2012-03-16 08:02:26 -07:00
if ( ( key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE ) | |
( value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) )
return 1 ;
2012-03-16 08:02:27 -07:00
/*
* First update the in - memory state .
*/
kvp_update_mem_state ( pool ) ;
num_records = kvp_file_info [ pool ] . num_records ;
record = kvp_file_info [ pool ] . records ;
2012-03-16 08:02:26 -07:00
for ( i = 0 ; i < num_records ; i + + ) {
if ( memcmp ( key , record [ i ] . key , key_size ) )
continue ;
/*
* Found a match ; just copy the value out .
*/
memcpy ( value , record [ i ] . value , value_size ) ;
return 0 ;
}
return 1 ;
}
2012-03-16 08:02:27 -07:00
static void kvp_pool_enumerate ( int pool , int index , __u8 * key , int key_size ,
__u8 * value , int value_size )
{
struct kvp_record * record ;
/*
* First update our in - memory database .
*/
kvp_update_mem_state ( pool ) ;
record = kvp_file_info [ pool ] . records ;
if ( index > = kvp_file_info [ pool ] . num_records ) {
/*
* This is an invalid index ; terminate enumeration ;
* - a NULL value will do the trick .
*/
strcpy ( value , " " ) ;
return ;
}
memcpy ( key , record [ index ] . key , key_size ) ;
memcpy ( value , record [ index ] . value , value_size ) ;
}
2010-12-16 18:56:54 -07:00
void kvp_get_os_info ( void )
{
FILE * file ;
2011-03-22 10:02:17 +01:00
char * p , buf [ 512 ] ;
2010-12-16 18:56:54 -07:00
2011-03-22 10:02:17 +01:00
uname ( & uts_buf ) ;
os_build = uts_buf . release ;
2011-07-19 11:44:20 -07:00
processor_arch = uts_buf . machine ;
2010-12-16 18:56:54 -07:00
2011-07-22 10:14:31 -07:00
/*
* The current windows host ( win7 ) expects the build
* string to be of the form : x . y . z
* Strip additional information we may have .
*/
p = strchr ( os_build , ' - ' ) ;
if ( p )
* p = ' \0 ' ;
2010-12-16 18:56:54 -07:00
file = fopen ( " /etc/SuSE-release " , " r " ) ;
if ( file ! = NULL )
goto kvp_osinfo_found ;
file = fopen ( " /etc/redhat-release " , " r " ) ;
if ( file ! = NULL )
goto kvp_osinfo_found ;
/*
* Add code for other supported platforms .
*/
/*
* We don ' t have information about the os .
*/
2011-03-22 10:02:17 +01:00
os_name = uts_buf . sysname ;
2010-12-16 18:56:54 -07:00
return ;
kvp_osinfo_found :
2011-03-22 10:02:17 +01:00
/* up to three lines */
p = fgets ( buf , sizeof ( buf ) , file ) ;
if ( p ) {
p = strchr ( buf , ' \n ' ) ;
if ( p )
* p = ' \0 ' ;
p = strdup ( buf ) ;
if ( ! p )
goto done ;
os_name = p ;
/* second line */
p = fgets ( buf , sizeof ( buf ) , file ) ;
if ( p ) {
p = strchr ( buf , ' \n ' ) ;
if ( p )
* p = ' \0 ' ;
p = strdup ( buf ) ;
if ( ! p )
goto done ;
os_major = p ;
/* third line */
p = fgets ( buf , sizeof ( buf ) , file ) ;
if ( p ) {
p = strchr ( buf , ' \n ' ) ;
if ( p )
* p = ' \0 ' ;
p = strdup ( buf ) ;
if ( p )
os_minor = p ;
}
}
}
done :
2010-12-16 18:56:54 -07:00
fclose ( file ) ;
return ;
}
static int
kvp_get_ip_address ( int family , char * buffer , int length )
{
struct ifaddrs * ifap ;
struct ifaddrs * curp ;
int ipv4_len = strlen ( " 255.255.255.255 " ) + 1 ;
int ipv6_len = strlen ( " ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff " ) + 1 ;
int offset = 0 ;
const char * str ;
char tmp [ 50 ] ;
int error = 0 ;
/*
* On entry into this function , the buffer is capable of holding the
* maximum key value ( 2048 bytes ) .
*/
if ( getifaddrs ( & ifap ) ) {
strcpy ( buffer , " getifaddrs failed \n " ) ;
return 1 ;
}
curp = ifap ;
while ( curp ! = NULL ) {
if ( ( curp - > ifa_addr ! = NULL ) & &
( curp - > ifa_addr - > sa_family = = family ) ) {
if ( family = = AF_INET ) {
struct sockaddr_in * addr =
( struct sockaddr_in * ) curp - > ifa_addr ;
str = inet_ntop ( family , & addr - > sin_addr ,
tmp , 50 ) ;
if ( str = = NULL ) {
strcpy ( buffer , " inet_ntop failed \n " ) ;
error = 1 ;
goto getaddr_done ;
}
if ( offset = = 0 )
strcpy ( buffer , tmp ) ;
else
strcat ( buffer , tmp ) ;
strcat ( buffer , " ; " ) ;
offset + = strlen ( str ) + 1 ;
if ( ( length - offset ) < ( ipv4_len + 1 ) )
goto getaddr_done ;
} else {
/*
* We only support AF_INET and AF_INET6
2011-03-30 22:57:33 -03:00
* and the list of addresses is separated by a " ; " .
2010-12-16 18:56:54 -07:00
*/
struct sockaddr_in6 * addr =
( struct sockaddr_in6 * ) curp - > ifa_addr ;
str = inet_ntop ( family ,
& addr - > sin6_addr . s6_addr ,
tmp , 50 ) ;
if ( str = = NULL ) {
strcpy ( buffer , " inet_ntop failed \n " ) ;
error = 1 ;
goto getaddr_done ;
}
if ( offset = = 0 )
strcpy ( buffer , tmp ) ;
else
strcat ( buffer , tmp ) ;
strcat ( buffer , " ; " ) ;
offset + = strlen ( str ) + 1 ;
if ( ( length - offset ) < ( ipv6_len + 1 ) )
goto getaddr_done ;
}
}
curp = curp - > ifa_next ;
}
getaddr_done :
freeifaddrs ( ifap ) ;
return error ;
}
static int
kvp_get_domain_name ( char * buffer , int length )
{
struct addrinfo hints , * info ;
int error = 0 ;
2011-07-26 11:03:10 -07:00
gethostname ( buffer , length ) ;
2010-12-16 18:56:54 -07:00
memset ( & hints , 0 , sizeof ( hints ) ) ;
hints . ai_family = AF_INET ; /*Get only ipv4 addrinfo. */
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = AI_CANONNAME ;
2011-07-26 11:03:10 -07:00
error = getaddrinfo ( buffer , NULL , & hints , & info ) ;
2010-12-16 18:56:54 -07:00
if ( error ! = 0 ) {
strcpy ( buffer , " getaddrinfo failed \n " ) ;
2011-07-26 11:03:10 -07:00
return error ;
2010-12-16 18:56:54 -07:00
}
strcpy ( buffer , info - > ai_canonname ) ;
freeaddrinfo ( info ) ;
return error ;
}
static int
netlink_send ( int fd , struct cn_msg * msg )
{
struct nlmsghdr * nlh ;
unsigned int size ;
struct msghdr message ;
char buffer [ 64 ] ;
struct iovec iov [ 2 ] ;
size = NLMSG_SPACE ( sizeof ( struct cn_msg ) + msg - > len ) ;
nlh = ( struct nlmsghdr * ) buffer ;
nlh - > nlmsg_seq = 0 ;
nlh - > nlmsg_pid = getpid ( ) ;
nlh - > nlmsg_type = NLMSG_DONE ;
nlh - > nlmsg_len = NLMSG_LENGTH ( size - sizeof ( * nlh ) ) ;
nlh - > nlmsg_flags = 0 ;
iov [ 0 ] . iov_base = nlh ;
iov [ 0 ] . iov_len = sizeof ( * nlh ) ;
iov [ 1 ] . iov_base = msg ;
iov [ 1 ] . iov_len = size ;
memset ( & message , 0 , sizeof ( message ) ) ;
message . msg_name = & addr ;
message . msg_namelen = sizeof ( addr ) ;
message . msg_iov = iov ;
message . msg_iovlen = 2 ;
return sendmsg ( fd , & message , 0 ) ;
}
2011-03-22 10:02:17 +01:00
int main ( void )
2010-12-16 18:56:54 -07:00
{
int fd , len , sock_opt ;
int error ;
struct cn_msg * message ;
struct pollfd pfd ;
struct nlmsghdr * incoming_msg ;
struct cn_msg * incoming_cn_msg ;
2012-02-02 16:56:50 -08:00
struct hv_kvp_msg * hv_msg ;
2011-03-22 10:02:17 +01:00
char * p ;
2010-12-16 18:56:54 -07:00
char * key_value ;
char * key_name ;
daemon ( 1 , 0 ) ;
openlog ( " KVP " , 0 , LOG_USER ) ;
syslog ( LOG_INFO , " KVP starting; pid is:%d " , getpid ( ) ) ;
/*
* Retrieve OS release information .
*/
kvp_get_os_info ( ) ;
2012-03-16 08:02:26 -07:00
if ( kvp_file_init ( ) ) {
syslog ( LOG_ERR , " Failed to initialize the pools " ) ;
exit ( - 1 ) ;
}
2010-12-16 18:56:54 -07:00
fd = socket ( AF_NETLINK , SOCK_DGRAM , NETLINK_CONNECTOR ) ;
if ( fd < 0 ) {
syslog ( LOG_ERR , " netlink socket creation failed; error:%d " , fd ) ;
exit ( - 1 ) ;
}
addr . nl_family = AF_NETLINK ;
addr . nl_pad = 0 ;
addr . nl_pid = 0 ;
addr . nl_groups = CN_KVP_IDX ;
error = bind ( fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( error < 0 ) {
syslog ( LOG_ERR , " bind failed; error:%d " , error ) ;
close ( fd ) ;
exit ( - 1 ) ;
}
sock_opt = addr . nl_groups ;
setsockopt ( fd , 270 , 1 , & sock_opt , sizeof ( sock_opt ) ) ;
/*
* Register ourselves with the kernel .
*/
message = ( struct cn_msg * ) kvp_send_buffer ;
message - > id . idx = CN_KVP_IDX ;
message - > id . val = CN_KVP_VAL ;
2012-02-02 16:56:50 -08:00
hv_msg = ( struct hv_kvp_msg * ) message - > data ;
hv_msg - > kvp_hdr . operation = KVP_OP_REGISTER ;
2010-12-16 18:56:54 -07:00
message - > ack = 0 ;
2012-02-02 16:56:50 -08:00
message - > len = sizeof ( struct hv_kvp_msg ) ;
2010-12-16 18:56:54 -07:00
len = netlink_send ( fd , message ) ;
if ( len < 0 ) {
syslog ( LOG_ERR , " netlink_send failed; error:%d " , len ) ;
close ( fd ) ;
exit ( - 1 ) ;
}
pfd . fd = fd ;
while ( 1 ) {
2012-05-31 16:40:06 +02:00
struct sockaddr * addr_p = ( struct sockaddr * ) & addr ;
socklen_t addr_l = sizeof ( addr ) ;
2010-12-16 18:56:54 -07:00
pfd . events = POLLIN ;
pfd . revents = 0 ;
poll ( & pfd , 1 , - 1 ) ;
2012-05-31 16:40:06 +02:00
len = recvfrom ( fd , kvp_recv_buffer , sizeof ( kvp_recv_buffer ) , 0 ,
addr_p , & addr_l ) ;
2010-12-16 18:56:54 -07:00
2012-05-31 16:40:06 +02:00
if ( len < 0 | | addr . nl_pid ) {
syslog ( LOG_ERR , " recvfrom failed; pid:%u error:%d %s " ,
addr . nl_pid , errno , strerror ( errno ) ) ;
2010-12-16 18:56:54 -07:00
close ( fd ) ;
return - 1 ;
}
incoming_msg = ( struct nlmsghdr * ) kvp_recv_buffer ;
incoming_cn_msg = ( struct cn_msg * ) NLMSG_DATA ( incoming_msg ) ;
2012-02-02 16:56:50 -08:00
hv_msg = ( struct hv_kvp_msg * ) incoming_cn_msg - > data ;
2010-12-16 18:56:54 -07:00
2012-02-02 16:56:50 -08:00
switch ( hv_msg - > kvp_hdr . operation ) {
case KVP_OP_REGISTER :
2010-12-16 18:56:54 -07:00
/*
* Driver is registering with us ; stash away the version
* information .
*/
2012-03-10 15:32:08 -08:00
p = ( char * ) hv_msg - > body . kvp_register . version ;
2011-03-22 10:02:17 +01:00
lic_version = malloc ( strlen ( p ) + 1 ) ;
2010-12-16 18:56:54 -07:00
if ( lic_version ) {
2011-03-22 10:02:17 +01:00
strcpy ( lic_version , p ) ;
2010-12-16 18:56:54 -07:00
syslog ( LOG_INFO , " KVP LIC Version: %s " ,
lic_version ) ;
} else {
syslog ( LOG_ERR , " malloc failed " ) ;
}
continue ;
2012-03-16 08:02:26 -07:00
/*
* The current protocol with the kernel component uses a
* NULL key name to pass an error condition .
* For the SET , GET and DELETE operations ,
* use the existing protocol to pass back error .
*/
2012-03-16 08:02:25 -07:00
case KVP_OP_SET :
2012-03-16 08:02:26 -07:00
if ( kvp_key_add_or_modify ( hv_msg - > kvp_hdr . pool ,
hv_msg - > body . kvp_set . data . key ,
hv_msg - > body . kvp_set . data . key_size ,
hv_msg - > body . kvp_set . data . value ,
hv_msg - > body . kvp_set . data . value_size ) )
strcpy ( hv_msg - > body . kvp_set . data . key , " " ) ;
break ;
2012-03-16 08:02:25 -07:00
case KVP_OP_GET :
2012-03-16 08:02:26 -07:00
if ( kvp_get_value ( hv_msg - > kvp_hdr . pool ,
hv_msg - > body . kvp_set . data . key ,
hv_msg - > body . kvp_set . data . key_size ,
hv_msg - > body . kvp_set . data . value ,
hv_msg - > body . kvp_set . data . value_size ) )
strcpy ( hv_msg - > body . kvp_set . data . key , " " ) ;
break ;
2012-03-16 08:02:25 -07:00
case KVP_OP_DELETE :
2012-03-16 08:02:26 -07:00
if ( kvp_key_delete ( hv_msg - > kvp_hdr . pool ,
hv_msg - > body . kvp_delete . key ,
hv_msg - > body . kvp_delete . key_size ) )
strcpy ( hv_msg - > body . kvp_delete . key , " " ) ;
break ;
2010-12-16 18:56:54 -07:00
default :
2012-02-02 16:56:50 -08:00
break ;
2010-12-16 18:56:54 -07:00
}
2012-03-16 08:02:25 -07:00
if ( hv_msg - > kvp_hdr . operation ! = KVP_OP_ENUMERATE )
goto kvp_done ;
2012-03-16 08:02:27 -07:00
/*
* If the pool is KVP_POOL_AUTO , dynamically generate
* both the key and the value ; if not read from the
* appropriate pool .
*/
if ( hv_msg - > kvp_hdr . pool ! = KVP_POOL_AUTO ) {
kvp_pool_enumerate ( hv_msg - > kvp_hdr . pool ,
hv_msg - > body . kvp_enum_data . index ,
hv_msg - > body . kvp_enum_data . data . key ,
HV_KVP_EXCHANGE_MAX_KEY_SIZE ,
hv_msg - > body . kvp_enum_data . data . value ,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) ;
goto kvp_done ;
}
2012-02-02 16:56:50 -08:00
hv_msg = ( struct hv_kvp_msg * ) incoming_cn_msg - > data ;
key_name = ( char * ) hv_msg - > body . kvp_enum_data . data . key ;
key_value = ( char * ) hv_msg - > body . kvp_enum_data . data . value ;
2010-12-16 18:56:54 -07:00
2012-02-02 16:56:50 -08:00
switch ( hv_msg - > body . kvp_enum_data . index ) {
2010-12-16 18:56:54 -07:00
case FullyQualifiedDomainName :
kvp_get_domain_name ( key_value ,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) ;
strcpy ( key_name , " FullyQualifiedDomainName " ) ;
break ;
case IntegrationServicesVersion :
strcpy ( key_name , " IntegrationServicesVersion " ) ;
strcpy ( key_value , lic_version ) ;
break ;
case NetworkAddressIPv4 :
kvp_get_ip_address ( AF_INET , key_value ,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) ;
strcpy ( key_name , " NetworkAddressIPv4 " ) ;
break ;
case NetworkAddressIPv6 :
kvp_get_ip_address ( AF_INET6 , key_value ,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE ) ;
strcpy ( key_name , " NetworkAddressIPv6 " ) ;
break ;
case OSBuildNumber :
strcpy ( key_value , os_build ) ;
strcpy ( key_name , " OSBuildNumber " ) ;
break ;
case OSName :
strcpy ( key_value , os_name ) ;
strcpy ( key_name , " OSName " ) ;
break ;
case OSMajorVersion :
strcpy ( key_value , os_major ) ;
strcpy ( key_name , " OSMajorVersion " ) ;
break ;
case OSMinorVersion :
strcpy ( key_value , os_minor ) ;
strcpy ( key_name , " OSMinorVersion " ) ;
break ;
case OSVersion :
strcpy ( key_value , os_build ) ;
strcpy ( key_name , " OSVersion " ) ;
break ;
case ProcessorArchitecture :
strcpy ( key_value , processor_arch ) ;
strcpy ( key_name , " ProcessorArchitecture " ) ;
break ;
default :
strcpy ( key_value , " Unknown Key " ) ;
/*
* We use a null key name to terminate enumeration .
*/
strcpy ( key_name , " " ) ;
break ;
}
/*
* Send the value back to the kernel . The response is
* already in the receive buffer . Update the cn_msg header to
* reflect the key value that has been added to the message
*/
2012-03-16 08:02:25 -07:00
kvp_done :
2010-12-16 18:56:54 -07:00
incoming_cn_msg - > id . idx = CN_KVP_IDX ;
incoming_cn_msg - > id . val = CN_KVP_VAL ;
incoming_cn_msg - > ack = 0 ;
2012-02-02 16:56:50 -08:00
incoming_cn_msg - > len = sizeof ( struct hv_kvp_msg ) ;
2010-12-16 18:56:54 -07:00
len = netlink_send ( fd , incoming_cn_msg ) ;
if ( len < 0 ) {
syslog ( LOG_ERR , " net_link send failed; error:%d " , len ) ;
exit ( - 1 ) ;
}
}
}