cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hv_kvp_daemon.c (36571B)


      1/*
      2 * An implementation of key value pair (KVP) functionality for Linux.
      3 *
      4 *
      5 * Copyright (C) 2010, Novell, Inc.
      6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
      7 *
      8 * This program is free software; you can redistribute it and/or modify it
      9 * under the terms of the GNU General Public License version 2 as published
     10 * by the Free Software Foundation.
     11 *
     12 * This program is distributed in the hope that it will be useful, but
     13 * WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
     15 * NON INFRINGEMENT.  See the GNU General Public License for more
     16 * details.
     17 *
     18 * You should have received a copy of the GNU General Public License
     19 * along with this program; if not, write to the Free Software
     20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21 *
     22 */
     23
     24
     25#include <sys/poll.h>
     26#include <sys/utsname.h>
     27#include <stdio.h>
     28#include <stdlib.h>
     29#include <unistd.h>
     30#include <string.h>
     31#include <ctype.h>
     32#include <errno.h>
     33#include <arpa/inet.h>
     34#include <linux/hyperv.h>
     35#include <ifaddrs.h>
     36#include <netdb.h>
     37#include <syslog.h>
     38#include <sys/stat.h>
     39#include <fcntl.h>
     40#include <dirent.h>
     41#include <net/if.h>
     42#include <limits.h>
     43#include <getopt.h>
     44
     45/*
     46 * KVP protocol: The user mode component first registers with the
     47 * the kernel component. Subsequently, the kernel component requests, data
     48 * for the specified keys. In response to this message the user mode component
     49 * fills in the value corresponding to the specified key. We overload the
     50 * sequence field in the cn_msg header to define our KVP message types.
     51 *
     52 * We use this infrastructure for also supporting queries from user mode
     53 * application for state that may be maintained in the KVP kernel component.
     54 *
     55 */
     56
     57
     58enum key_index {
     59	FullyQualifiedDomainName = 0,
     60	IntegrationServicesVersion, /*This key is serviced in the kernel*/
     61	NetworkAddressIPv4,
     62	NetworkAddressIPv6,
     63	OSBuildNumber,
     64	OSName,
     65	OSMajorVersion,
     66	OSMinorVersion,
     67	OSVersion,
     68	ProcessorArchitecture
     69};
     70
     71
     72enum {
     73	IPADDR = 0,
     74	NETMASK,
     75	GATEWAY,
     76	DNS
     77};
     78
     79static int in_hand_shake;
     80
     81static char *os_name = "";
     82static char *os_major = "";
     83static char *os_minor = "";
     84static char *processor_arch;
     85static char *os_build;
     86static char *os_version;
     87static char *lic_version = "Unknown version";
     88static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
     89static struct utsname uts_buf;
     90
     91/*
     92 * The location of the interface configuration file.
     93 */
     94
     95#define KVP_CONFIG_LOC	"/var/lib/hyperv"
     96
     97#ifndef KVP_SCRIPTS_PATH
     98#define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
     99#endif
    100
    101#define KVP_NET_DIR "/sys/class/net/"
    102
    103#define MAX_FILE_NAME 100
    104#define ENTRIES_PER_BLOCK 50
    105
    106struct kvp_record {
    107	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
    108	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
    109};
    110
    111struct kvp_file_state {
    112	int fd;
    113	int num_blocks;
    114	struct kvp_record *records;
    115	int num_records;
    116	char fname[MAX_FILE_NAME];
    117};
    118
    119static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
    120
    121static void kvp_acquire_lock(int pool)
    122{
    123	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
    124	fl.l_pid = getpid();
    125
    126	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
    127		syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
    128				errno, strerror(errno));
    129		exit(EXIT_FAILURE);
    130	}
    131}
    132
    133static void kvp_release_lock(int pool)
    134{
    135	struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
    136	fl.l_pid = getpid();
    137
    138	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
    139		syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
    140				errno, strerror(errno));
    141		exit(EXIT_FAILURE);
    142	}
    143}
    144
    145static void kvp_update_file(int pool)
    146{
    147	FILE *filep;
    148
    149	/*
    150	 * We are going to write our in-memory registry out to
    151	 * disk; acquire the lock first.
    152	 */
    153	kvp_acquire_lock(pool);
    154
    155	filep = fopen(kvp_file_info[pool].fname, "we");
    156	if (!filep) {
    157		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
    158				errno, strerror(errno));
    159		kvp_release_lock(pool);
    160		exit(EXIT_FAILURE);
    161	}
    162
    163	fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
    164				kvp_file_info[pool].num_records, filep);
    165
    166	if (ferror(filep) || fclose(filep)) {
    167		kvp_release_lock(pool);
    168		syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
    169		exit(EXIT_FAILURE);
    170	}
    171
    172	kvp_release_lock(pool);
    173}
    174
    175static void kvp_update_mem_state(int pool)
    176{
    177	FILE *filep;
    178	size_t records_read = 0;
    179	struct kvp_record *record = kvp_file_info[pool].records;
    180	struct kvp_record *readp;
    181	int num_blocks = kvp_file_info[pool].num_blocks;
    182	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
    183
    184	kvp_acquire_lock(pool);
    185
    186	filep = fopen(kvp_file_info[pool].fname, "re");
    187	if (!filep) {
    188		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
    189				errno, strerror(errno));
    190		kvp_release_lock(pool);
    191		exit(EXIT_FAILURE);
    192	}
    193	for (;;) {
    194		readp = &record[records_read];
    195		records_read += fread(readp, sizeof(struct kvp_record),
    196				ENTRIES_PER_BLOCK * num_blocks - records_read,
    197				filep);
    198
    199		if (ferror(filep)) {
    200			syslog(LOG_ERR,
    201				"Failed to read file, pool: %d; error: %d %s",
    202				 pool, errno, strerror(errno));
    203			kvp_release_lock(pool);
    204			exit(EXIT_FAILURE);
    205		}
    206
    207		if (!feof(filep)) {
    208			/*
    209			 * We have more data to read.
    210			 */
    211			num_blocks++;
    212			record = realloc(record, alloc_unit * num_blocks);
    213
    214			if (record == NULL) {
    215				syslog(LOG_ERR, "malloc failed");
    216				kvp_release_lock(pool);
    217				exit(EXIT_FAILURE);
    218			}
    219			continue;
    220		}
    221		break;
    222	}
    223
    224	kvp_file_info[pool].num_blocks = num_blocks;
    225	kvp_file_info[pool].records = record;
    226	kvp_file_info[pool].num_records = records_read;
    227
    228	fclose(filep);
    229	kvp_release_lock(pool);
    230}
    231
    232static int kvp_file_init(void)
    233{
    234	int  fd;
    235	char *fname;
    236	int i;
    237	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
    238
    239	if (access(KVP_CONFIG_LOC, F_OK)) {
    240		if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
    241			syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
    242					errno, strerror(errno));
    243			exit(EXIT_FAILURE);
    244		}
    245	}
    246
    247	for (i = 0; i < KVP_POOL_COUNT; i++) {
    248		fname = kvp_file_info[i].fname;
    249		sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
    250		fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
    251
    252		if (fd == -1)
    253			return 1;
    254
    255		kvp_file_info[i].fd = fd;
    256		kvp_file_info[i].num_blocks = 1;
    257		kvp_file_info[i].records = malloc(alloc_unit);
    258		if (kvp_file_info[i].records == NULL)
    259			return 1;
    260		kvp_file_info[i].num_records = 0;
    261		kvp_update_mem_state(i);
    262	}
    263
    264	return 0;
    265}
    266
    267static int kvp_key_delete(int pool, const __u8 *key, int key_size)
    268{
    269	int i;
    270	int j, k;
    271	int num_records;
    272	struct kvp_record *record;
    273
    274	/*
    275	 * First update the in-memory state.
    276	 */
    277	kvp_update_mem_state(pool);
    278
    279	num_records = kvp_file_info[pool].num_records;
    280	record = kvp_file_info[pool].records;
    281
    282	for (i = 0; i < num_records; i++) {
    283		if (memcmp(key, record[i].key, key_size))
    284			continue;
    285		/*
    286		 * Found a match; just move the remaining
    287		 * entries up.
    288		 */
    289		if (i == (num_records - 1)) {
    290			kvp_file_info[pool].num_records--;
    291			kvp_update_file(pool);
    292			return 0;
    293		}
    294
    295		j = i;
    296		k = j + 1;
    297		for (; k < num_records; k++) {
    298			strcpy(record[j].key, record[k].key);
    299			strcpy(record[j].value, record[k].value);
    300			j++;
    301		}
    302
    303		kvp_file_info[pool].num_records--;
    304		kvp_update_file(pool);
    305		return 0;
    306	}
    307	return 1;
    308}
    309
    310static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
    311				 const __u8 *value, int value_size)
    312{
    313	int i;
    314	int num_records;
    315	struct kvp_record *record;
    316	int num_blocks;
    317
    318	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
    319		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
    320		return 1;
    321
    322	/*
    323	 * First update the in-memory state.
    324	 */
    325	kvp_update_mem_state(pool);
    326
    327	num_records = kvp_file_info[pool].num_records;
    328	record = kvp_file_info[pool].records;
    329	num_blocks = kvp_file_info[pool].num_blocks;
    330
    331	for (i = 0; i < num_records; i++) {
    332		if (memcmp(key, record[i].key, key_size))
    333			continue;
    334		/*
    335		 * Found a match; just update the value -
    336		 * this is the modify case.
    337		 */
    338		memcpy(record[i].value, value, value_size);
    339		kvp_update_file(pool);
    340		return 0;
    341	}
    342
    343	/*
    344	 * Need to add a new entry;
    345	 */
    346	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
    347		/* Need to allocate a larger array for reg entries. */
    348		record = realloc(record, sizeof(struct kvp_record) *
    349			 ENTRIES_PER_BLOCK * (num_blocks + 1));
    350
    351		if (record == NULL)
    352			return 1;
    353		kvp_file_info[pool].num_blocks++;
    354
    355	}
    356	memcpy(record[i].value, value, value_size);
    357	memcpy(record[i].key, key, key_size);
    358	kvp_file_info[pool].records = record;
    359	kvp_file_info[pool].num_records++;
    360	kvp_update_file(pool);
    361	return 0;
    362}
    363
    364static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
    365			int value_size)
    366{
    367	int i;
    368	int num_records;
    369	struct kvp_record *record;
    370
    371	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
    372		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
    373		return 1;
    374
    375	/*
    376	 * First update the in-memory state.
    377	 */
    378	kvp_update_mem_state(pool);
    379
    380	num_records = kvp_file_info[pool].num_records;
    381	record = kvp_file_info[pool].records;
    382
    383	for (i = 0; i < num_records; i++) {
    384		if (memcmp(key, record[i].key, key_size))
    385			continue;
    386		/*
    387		 * Found a match; just copy the value out.
    388		 */
    389		memcpy(value, record[i].value, value_size);
    390		return 0;
    391	}
    392
    393	return 1;
    394}
    395
    396static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
    397				__u8 *value, int value_size)
    398{
    399	struct kvp_record *record;
    400
    401	/*
    402	 * First update our in-memory database.
    403	 */
    404	kvp_update_mem_state(pool);
    405	record = kvp_file_info[pool].records;
    406
    407	if (index >= kvp_file_info[pool].num_records) {
    408		return 1;
    409	}
    410
    411	memcpy(key, record[index].key, key_size);
    412	memcpy(value, record[index].value, value_size);
    413	return 0;
    414}
    415
    416
    417void kvp_get_os_info(void)
    418{
    419	FILE	*file;
    420	char	*p, buf[512];
    421
    422	uname(&uts_buf);
    423	os_version = uts_buf.release;
    424	os_build = strdup(uts_buf.release);
    425
    426	os_name = uts_buf.sysname;
    427	processor_arch = uts_buf.machine;
    428
    429	/*
    430	 * The current windows host (win7) expects the build
    431	 * string to be of the form: x.y.z
    432	 * Strip additional information we may have.
    433	 */
    434	p = strchr(os_version, '-');
    435	if (p)
    436		*p = '\0';
    437
    438	/*
    439	 * Parse the /etc/os-release file if present:
    440	 * https://www.freedesktop.org/software/systemd/man/os-release.html
    441	 */
    442	file = fopen("/etc/os-release", "r");
    443	if (file != NULL) {
    444		while (fgets(buf, sizeof(buf), file)) {
    445			char *value, *q;
    446
    447			/* Ignore comments */
    448			if (buf[0] == '#')
    449				continue;
    450
    451			/* Split into name=value */
    452			p = strchr(buf, '=');
    453			if (!p)
    454				continue;
    455			*p++ = 0;
    456
    457			/* Remove quotes and newline; un-escape */
    458			value = p;
    459			q = p;
    460			while (*p) {
    461				if (*p == '\\') {
    462					++p;
    463					if (!*p)
    464						break;
    465					*q++ = *p++;
    466				} else if (*p == '\'' || *p == '"' ||
    467					   *p == '\n') {
    468					++p;
    469				} else {
    470					*q++ = *p++;
    471				}
    472			}
    473			*q = 0;
    474
    475			if (!strcmp(buf, "NAME")) {
    476				p = strdup(value);
    477				if (!p)
    478					break;
    479				os_name = p;
    480			} else if (!strcmp(buf, "VERSION_ID")) {
    481				p = strdup(value);
    482				if (!p)
    483					break;
    484				os_major = p;
    485			}
    486		}
    487		fclose(file);
    488		return;
    489	}
    490
    491	/* Fallback for older RH/SUSE releases */
    492	file = fopen("/etc/SuSE-release", "r");
    493	if (file != NULL)
    494		goto kvp_osinfo_found;
    495	file  = fopen("/etc/redhat-release", "r");
    496	if (file != NULL)
    497		goto kvp_osinfo_found;
    498
    499	/*
    500	 * We don't have information about the os.
    501	 */
    502	return;
    503
    504kvp_osinfo_found:
    505	/* up to three lines */
    506	p = fgets(buf, sizeof(buf), file);
    507	if (p) {
    508		p = strchr(buf, '\n');
    509		if (p)
    510			*p = '\0';
    511		p = strdup(buf);
    512		if (!p)
    513			goto done;
    514		os_name = p;
    515
    516		/* second line */
    517		p = fgets(buf, sizeof(buf), file);
    518		if (p) {
    519			p = strchr(buf, '\n');
    520			if (p)
    521				*p = '\0';
    522			p = strdup(buf);
    523			if (!p)
    524				goto done;
    525			os_major = p;
    526
    527			/* third line */
    528			p = fgets(buf, sizeof(buf), file);
    529			if (p)  {
    530				p = strchr(buf, '\n');
    531				if (p)
    532					*p = '\0';
    533				p = strdup(buf);
    534				if (p)
    535					os_minor = p;
    536			}
    537		}
    538	}
    539
    540done:
    541	fclose(file);
    542	return;
    543}
    544
    545
    546
    547/*
    548 * Retrieve an interface name corresponding to the specified guid.
    549 * If there is a match, the function returns a pointer
    550 * to the interface name and if not, a NULL is returned.
    551 * If a match is found, the caller is responsible for
    552 * freeing the memory.
    553 */
    554
    555static char *kvp_get_if_name(char *guid)
    556{
    557	DIR *dir;
    558	struct dirent *entry;
    559	FILE    *file;
    560	char    *p, *x;
    561	char    *if_name = NULL;
    562	char    buf[256];
    563	char dev_id[PATH_MAX];
    564
    565	dir = opendir(KVP_NET_DIR);
    566	if (dir == NULL)
    567		return NULL;
    568
    569	while ((entry = readdir(dir)) != NULL) {
    570		/*
    571		 * Set the state for the next pass.
    572		 */
    573		snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
    574			 KVP_NET_DIR, entry->d_name);
    575
    576		file = fopen(dev_id, "r");
    577		if (file == NULL)
    578			continue;
    579
    580		p = fgets(buf, sizeof(buf), file);
    581		if (p) {
    582			x = strchr(p, '\n');
    583			if (x)
    584				*x = '\0';
    585
    586			if (!strcmp(p, guid)) {
    587				/*
    588				 * Found the guid match; return the interface
    589				 * name. The caller will free the memory.
    590				 */
    591				if_name = strdup(entry->d_name);
    592				fclose(file);
    593				break;
    594			}
    595		}
    596		fclose(file);
    597	}
    598
    599	closedir(dir);
    600	return if_name;
    601}
    602
    603/*
    604 * Retrieve the MAC address given the interface name.
    605 */
    606
    607static char *kvp_if_name_to_mac(char *if_name)
    608{
    609	FILE    *file;
    610	char    *p, *x;
    611	char    buf[256];
    612	char addr_file[PATH_MAX];
    613	unsigned int i;
    614	char *mac_addr = NULL;
    615
    616	snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
    617		 if_name, "/address");
    618
    619	file = fopen(addr_file, "r");
    620	if (file == NULL)
    621		return NULL;
    622
    623	p = fgets(buf, sizeof(buf), file);
    624	if (p) {
    625		x = strchr(p, '\n');
    626		if (x)
    627			*x = '\0';
    628		for (i = 0; i < strlen(p); i++)
    629			p[i] = toupper(p[i]);
    630		mac_addr = strdup(p);
    631	}
    632
    633	fclose(file);
    634	return mac_addr;
    635}
    636
    637static void kvp_process_ipconfig_file(char *cmd,
    638					char *config_buf, unsigned int len,
    639					int element_size, int offset)
    640{
    641	char buf[256];
    642	char *p;
    643	char *x;
    644	FILE *file;
    645
    646	/*
    647	 * First execute the command.
    648	 */
    649	file = popen(cmd, "r");
    650	if (file == NULL)
    651		return;
    652
    653	if (offset == 0)
    654		memset(config_buf, 0, len);
    655	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
    656		if (len < strlen(config_buf) + element_size + 1)
    657			break;
    658
    659		x = strchr(p, '\n');
    660		if (x)
    661			*x = '\0';
    662
    663		strcat(config_buf, p);
    664		strcat(config_buf, ";");
    665	}
    666	pclose(file);
    667}
    668
    669static void kvp_get_ipconfig_info(char *if_name,
    670				 struct hv_kvp_ipaddr_value *buffer)
    671{
    672	char cmd[512];
    673	char dhcp_info[128];
    674	char *p;
    675	FILE *file;
    676
    677	/*
    678	 * Get the address of default gateway (ipv4).
    679	 */
    680	sprintf(cmd, "%s %s", "ip route show dev", if_name);
    681	strcat(cmd, " | awk '/default/ {print $3 }'");
    682
    683	/*
    684	 * Execute the command to gather gateway info.
    685	 */
    686	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
    687				(MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
    688
    689	/*
    690	 * Get the address of default gateway (ipv6).
    691	 */
    692	sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
    693	strcat(cmd, " | awk '/default/ {print $3 }'");
    694
    695	/*
    696	 * Execute the command to gather gateway info (ipv6).
    697	 */
    698	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
    699				(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
    700
    701
    702	/*
    703	 * Gather the DNS state.
    704	 * Since there is no standard way to get this information
    705	 * across various distributions of interest; we just invoke
    706	 * an external script that needs to be ported across distros
    707	 * of interest.
    708	 *
    709	 * Following is the expected format of the information from the script:
    710	 *
    711	 * ipaddr1 (nameserver1)
    712	 * ipaddr2 (nameserver2)
    713	 * .
    714	 * .
    715	 */
    716
    717	sprintf(cmd, KVP_SCRIPTS_PATH "%s",  "hv_get_dns_info");
    718
    719	/*
    720	 * Execute the command to gather DNS info.
    721	 */
    722	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
    723				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
    724
    725	/*
    726	 * Gather the DHCP state.
    727	 * We will gather this state by invoking an external script.
    728	 * The parameter to the script is the interface name.
    729	 * Here is the expected output:
    730	 *
    731	 * Enabled: DHCP enabled.
    732	 */
    733
    734	sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name);
    735
    736	file = popen(cmd, "r");
    737	if (file == NULL)
    738		return;
    739
    740	p = fgets(dhcp_info, sizeof(dhcp_info), file);
    741	if (p == NULL) {
    742		pclose(file);
    743		return;
    744	}
    745
    746	if (!strncmp(p, "Enabled", 7))
    747		buffer->dhcp_enabled = 1;
    748	else
    749		buffer->dhcp_enabled = 0;
    750
    751	pclose(file);
    752}
    753
    754
    755static unsigned int hweight32(unsigned int *w)
    756{
    757	unsigned int res = *w - ((*w >> 1) & 0x55555555);
    758	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
    759	res = (res + (res >> 4)) & 0x0F0F0F0F;
    760	res = res + (res >> 8);
    761	return (res + (res >> 16)) & 0x000000FF;
    762}
    763
    764static int kvp_process_ip_address(void *addrp,
    765				int family, char *buffer,
    766				int length,  int *offset)
    767{
    768	struct sockaddr_in *addr;
    769	struct sockaddr_in6 *addr6;
    770	int addr_length;
    771	char tmp[50];
    772	const char *str;
    773
    774	if (family == AF_INET) {
    775		addr = (struct sockaddr_in *)addrp;
    776		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
    777		addr_length = INET_ADDRSTRLEN;
    778	} else {
    779		addr6 = (struct sockaddr_in6 *)addrp;
    780		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
    781		addr_length = INET6_ADDRSTRLEN;
    782	}
    783
    784	if ((length - *offset) < addr_length + 2)
    785		return HV_E_FAIL;
    786	if (str == NULL) {
    787		strcpy(buffer, "inet_ntop failed\n");
    788		return HV_E_FAIL;
    789	}
    790	if (*offset == 0)
    791		strcpy(buffer, tmp);
    792	else {
    793		strcat(buffer, ";");
    794		strcat(buffer, tmp);
    795	}
    796
    797	*offset += strlen(str) + 1;
    798
    799	return 0;
    800}
    801
    802static int
    803kvp_get_ip_info(int family, char *if_name, int op,
    804		 void  *out_buffer, unsigned int length)
    805{
    806	struct ifaddrs *ifap;
    807	struct ifaddrs *curp;
    808	int offset = 0;
    809	int sn_offset = 0;
    810	int error = 0;
    811	char *buffer;
    812	struct hv_kvp_ipaddr_value *ip_buffer = NULL;
    813	char cidr_mask[5]; /* /xyz */
    814	int weight;
    815	int i;
    816	unsigned int *w;
    817	char *sn_str;
    818	struct sockaddr_in6 *addr6;
    819
    820	if (op == KVP_OP_ENUMERATE) {
    821		buffer = out_buffer;
    822	} else {
    823		ip_buffer = out_buffer;
    824		buffer = (char *)ip_buffer->ip_addr;
    825		ip_buffer->addr_family = 0;
    826	}
    827	/*
    828	 * On entry into this function, the buffer is capable of holding the
    829	 * maximum key value.
    830	 */
    831
    832	if (getifaddrs(&ifap)) {
    833		strcpy(buffer, "getifaddrs failed\n");
    834		return HV_E_FAIL;
    835	}
    836
    837	curp = ifap;
    838	while (curp != NULL) {
    839		if (curp->ifa_addr == NULL) {
    840			curp = curp->ifa_next;
    841			continue;
    842		}
    843
    844		if ((if_name != NULL) &&
    845			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
    846			/*
    847			 * We want info about a specific interface;
    848			 * just continue.
    849			 */
    850			curp = curp->ifa_next;
    851			continue;
    852		}
    853
    854		/*
    855		 * We only support two address families: AF_INET and AF_INET6.
    856		 * If a family value of 0 is specified, we collect both
    857		 * supported address families; if not we gather info on
    858		 * the specified address family.
    859		 */
    860		if ((((family != 0) &&
    861			 (curp->ifa_addr->sa_family != family))) ||
    862			 (curp->ifa_flags & IFF_LOOPBACK)) {
    863			curp = curp->ifa_next;
    864			continue;
    865		}
    866		if ((curp->ifa_addr->sa_family != AF_INET) &&
    867			(curp->ifa_addr->sa_family != AF_INET6)) {
    868			curp = curp->ifa_next;
    869			continue;
    870		}
    871
    872		if (op == KVP_OP_GET_IP_INFO) {
    873			/*
    874			 * Gather info other than the IP address.
    875			 * IP address info will be gathered later.
    876			 */
    877			if (curp->ifa_addr->sa_family == AF_INET) {
    878				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
    879				/*
    880				 * Get subnet info.
    881				 */
    882				error = kvp_process_ip_address(
    883							     curp->ifa_netmask,
    884							     AF_INET,
    885							     (char *)
    886							     ip_buffer->sub_net,
    887							     length,
    888							     &sn_offset);
    889				if (error)
    890					goto gather_ipaddr;
    891			} else {
    892				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
    893
    894				/*
    895				 * Get subnet info in CIDR format.
    896				 */
    897				weight = 0;
    898				sn_str = (char *)ip_buffer->sub_net;
    899				addr6 = (struct sockaddr_in6 *)
    900					curp->ifa_netmask;
    901				w = addr6->sin6_addr.s6_addr32;
    902
    903				for (i = 0; i < 4; i++)
    904					weight += hweight32(&w[i]);
    905
    906				sprintf(cidr_mask, "/%d", weight);
    907				if (length < sn_offset + strlen(cidr_mask) + 1)
    908					goto gather_ipaddr;
    909
    910				if (sn_offset == 0)
    911					strcpy(sn_str, cidr_mask);
    912				else {
    913					strcat((char *)ip_buffer->sub_net, ";");
    914					strcat(sn_str, cidr_mask);
    915				}
    916				sn_offset += strlen(sn_str) + 1;
    917			}
    918
    919			/*
    920			 * Collect other ip related configuration info.
    921			 */
    922
    923			kvp_get_ipconfig_info(if_name, ip_buffer);
    924		}
    925
    926gather_ipaddr:
    927		error = kvp_process_ip_address(curp->ifa_addr,
    928						curp->ifa_addr->sa_family,
    929						buffer,
    930						length, &offset);
    931		if (error)
    932			goto getaddr_done;
    933
    934		curp = curp->ifa_next;
    935	}
    936
    937getaddr_done:
    938	freeifaddrs(ifap);
    939	return error;
    940}
    941
    942/*
    943 * Retrieve the IP given the MAC address.
    944 */
    945static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
    946{
    947	char *mac = (char *)kvp_ip_val->adapter_id;
    948	DIR *dir;
    949	struct dirent *entry;
    950	FILE    *file;
    951	char    *p, *x;
    952	char    *if_name = NULL;
    953	char    buf[256];
    954	char dev_id[PATH_MAX];
    955	unsigned int i;
    956	int error = HV_E_FAIL;
    957
    958	dir = opendir(KVP_NET_DIR);
    959	if (dir == NULL)
    960		return HV_E_FAIL;
    961
    962	while ((entry = readdir(dir)) != NULL) {
    963		/*
    964		 * Set the state for the next pass.
    965		 */
    966		snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
    967			 entry->d_name);
    968
    969		file = fopen(dev_id, "r");
    970		if (file == NULL)
    971			continue;
    972
    973		p = fgets(buf, sizeof(buf), file);
    974		fclose(file);
    975		if (!p)
    976			continue;
    977
    978		x = strchr(p, '\n');
    979		if (x)
    980			*x = '\0';
    981
    982		for (i = 0; i < strlen(p); i++)
    983			p[i] = toupper(p[i]);
    984
    985		if (strcmp(p, mac))
    986			continue;
    987
    988		/*
    989		 * Found the MAC match.
    990		 * A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
    991		 */
    992		if_name = entry->d_name;
    993		if (!if_name)
    994			continue;
    995
    996		error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
    997					kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
    998
    999		if (!error && strlen((char *)kvp_ip_val->ip_addr))
   1000			break;
   1001	}
   1002
   1003	closedir(dir);
   1004	return error;
   1005}
   1006
   1007static int expand_ipv6(char *addr, int type)
   1008{
   1009	int ret;
   1010	struct in6_addr v6_addr;
   1011
   1012	ret = inet_pton(AF_INET6, addr, &v6_addr);
   1013
   1014	if (ret != 1) {
   1015		if (type == NETMASK)
   1016			return 1;
   1017		return 0;
   1018	}
   1019
   1020	sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
   1021		"%02x%02x:%02x%02x:%02x%02x",
   1022		(int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
   1023		(int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
   1024		(int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
   1025		(int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
   1026		(int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
   1027		(int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
   1028		(int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
   1029		(int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
   1030
   1031	return 1;
   1032
   1033}
   1034
   1035static int is_ipv4(char *addr)
   1036{
   1037	int ret;
   1038	struct in_addr ipv4_addr;
   1039
   1040	ret = inet_pton(AF_INET, addr, &ipv4_addr);
   1041
   1042	if (ret == 1)
   1043		return 1;
   1044	return 0;
   1045}
   1046
   1047static int parse_ip_val_buffer(char *in_buf, int *offset,
   1048				char *out_buf, int out_len)
   1049{
   1050	char *x;
   1051	char *start;
   1052
   1053	/*
   1054	 * in_buf has sequence of characters that are separated by
   1055	 * the character ';'. The last sequence does not have the
   1056	 * terminating ";" character.
   1057	 */
   1058	start = in_buf + *offset;
   1059
   1060	x = strchr(start, ';');
   1061	if (x)
   1062		*x = 0;
   1063	else
   1064		x = start + strlen(start);
   1065
   1066	if (strlen(start) != 0) {
   1067		int i = 0;
   1068		/*
   1069		 * Get rid of leading spaces.
   1070		 */
   1071		while (start[i] == ' ')
   1072			i++;
   1073
   1074		if ((x - start) <= out_len) {
   1075			strcpy(out_buf, (start + i));
   1076			*offset += (x - start) + 1;
   1077			return 1;
   1078		}
   1079	}
   1080	return 0;
   1081}
   1082
   1083static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
   1084{
   1085	int ret;
   1086
   1087	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
   1088
   1089	if (ret < 0)
   1090		return HV_E_FAIL;
   1091
   1092	return 0;
   1093}
   1094
   1095
   1096static int process_ip_string(FILE *f, char *ip_string, int type)
   1097{
   1098	int error = 0;
   1099	char addr[INET6_ADDRSTRLEN];
   1100	int i = 0;
   1101	int j = 0;
   1102	char str[256];
   1103	char sub_str[13];
   1104	int offset = 0;
   1105
   1106	memset(addr, 0, sizeof(addr));
   1107
   1108	while (parse_ip_val_buffer(ip_string, &offset, addr,
   1109					(MAX_IP_ADDR_SIZE * 2))) {
   1110
   1111		sub_str[0] = 0;
   1112		if (is_ipv4(addr)) {
   1113			switch (type) {
   1114			case IPADDR:
   1115				snprintf(str, sizeof(str), "%s", "IPADDR");
   1116				break;
   1117			case NETMASK:
   1118				snprintf(str, sizeof(str), "%s", "NETMASK");
   1119				break;
   1120			case GATEWAY:
   1121				snprintf(str, sizeof(str), "%s", "GATEWAY");
   1122				break;
   1123			case DNS:
   1124				snprintf(str, sizeof(str), "%s", "DNS");
   1125				break;
   1126			}
   1127
   1128			if (type == DNS) {
   1129				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
   1130			} else if (type == GATEWAY && i == 0) {
   1131				++i;
   1132			} else {
   1133				snprintf(sub_str, sizeof(sub_str), "%d", i++);
   1134			}
   1135
   1136
   1137		} else if (expand_ipv6(addr, type)) {
   1138			switch (type) {
   1139			case IPADDR:
   1140				snprintf(str, sizeof(str), "%s", "IPV6ADDR");
   1141				break;
   1142			case NETMASK:
   1143				snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
   1144				break;
   1145			case GATEWAY:
   1146				snprintf(str, sizeof(str), "%s",
   1147					"IPV6_DEFAULTGW");
   1148				break;
   1149			case DNS:
   1150				snprintf(str, sizeof(str), "%s",  "DNS");
   1151				break;
   1152			}
   1153
   1154			if (type == DNS) {
   1155				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
   1156			} else if (j == 0) {
   1157				++j;
   1158			} else {
   1159				snprintf(sub_str, sizeof(sub_str), "_%d", j++);
   1160			}
   1161		} else {
   1162			return  HV_INVALIDARG;
   1163		}
   1164
   1165		error = kvp_write_file(f, str, sub_str, addr);
   1166		if (error)
   1167			return error;
   1168		memset(addr, 0, sizeof(addr));
   1169	}
   1170
   1171	return 0;
   1172}
   1173
   1174static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
   1175{
   1176	int error = 0;
   1177	char if_file[PATH_MAX];
   1178	FILE *file;
   1179	char cmd[PATH_MAX];
   1180	char *mac_addr;
   1181	int str_len;
   1182
   1183	/*
   1184	 * Set the configuration for the specified interface with
   1185	 * the information provided. Since there is no standard
   1186	 * way to configure an interface, we will have an external
   1187	 * script that does the job of configuring the interface and
   1188	 * flushing the configuration.
   1189	 *
   1190	 * The parameters passed to this external script are:
   1191	 * 1. A configuration file that has the specified configuration.
   1192	 *
   1193	 * We will embed the name of the interface in the configuration
   1194	 * file: ifcfg-ethx (where ethx is the interface name).
   1195	 *
   1196	 * The information provided here may be more than what is needed
   1197	 * in a given distro to configure the interface and so are free
   1198	 * ignore information that may not be relevant.
   1199	 *
   1200	 * Here is the format of the ip configuration file:
   1201	 *
   1202	 * HWADDR=macaddr
   1203	 * DEVICE=interface name
   1204	 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
   1205	 *                       or "none" if no boot-time protocol should be used)
   1206	 *
   1207	 * IPADDR0=ipaddr1
   1208	 * IPADDR1=ipaddr2
   1209	 * IPADDRx=ipaddry (where y = x + 1)
   1210	 *
   1211	 * NETMASK0=netmask1
   1212	 * NETMASKx=netmasky (where y = x + 1)
   1213	 *
   1214	 * GATEWAY=ipaddr1
   1215	 * GATEWAYx=ipaddry (where y = x + 1)
   1216	 *
   1217	 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
   1218	 *
   1219	 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
   1220	 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
   1221	 * IPV6NETMASK.
   1222	 *
   1223	 * The host can specify multiple ipv4 and ipv6 addresses to be
   1224	 * configured for the interface. Furthermore, the configuration
   1225	 * needs to be persistent. A subsequent GET call on the interface
   1226	 * is expected to return the configuration that is set via the SET
   1227	 * call.
   1228	 */
   1229
   1230	snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
   1231		"/ifcfg-", if_name);
   1232
   1233	file = fopen(if_file, "w");
   1234
   1235	if (file == NULL) {
   1236		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
   1237				errno, strerror(errno));
   1238		return HV_E_FAIL;
   1239	}
   1240
   1241	/*
   1242	 * First write out the MAC address.
   1243	 */
   1244
   1245	mac_addr = kvp_if_name_to_mac(if_name);
   1246	if (mac_addr == NULL) {
   1247		error = HV_E_FAIL;
   1248		goto setval_error;
   1249	}
   1250
   1251	error = kvp_write_file(file, "HWADDR", "", mac_addr);
   1252	free(mac_addr);
   1253	if (error)
   1254		goto setval_error;
   1255
   1256	error = kvp_write_file(file, "DEVICE", "", if_name);
   1257	if (error)
   1258		goto setval_error;
   1259
   1260	/*
   1261	 * The dhcp_enabled flag is only for IPv4. In the case the host only
   1262	 * injects an IPv6 address, the flag is true, but we still need to
   1263	 * proceed to parse and pass the IPv6 information to the
   1264	 * disto-specific script hv_set_ifconfig.
   1265	 */
   1266	if (new_val->dhcp_enabled) {
   1267		error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
   1268		if (error)
   1269			goto setval_error;
   1270
   1271	} else {
   1272		error = kvp_write_file(file, "BOOTPROTO", "", "none");
   1273		if (error)
   1274			goto setval_error;
   1275	}
   1276
   1277	/*
   1278	 * Write the configuration for ipaddress, netmask, gateway and
   1279	 * name servers.
   1280	 */
   1281
   1282	error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
   1283	if (error)
   1284		goto setval_error;
   1285
   1286	error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
   1287	if (error)
   1288		goto setval_error;
   1289
   1290	error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
   1291	if (error)
   1292		goto setval_error;
   1293
   1294	error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
   1295	if (error)
   1296		goto setval_error;
   1297
   1298	fclose(file);
   1299
   1300	/*
   1301	 * Now that we have populated the configuration file,
   1302	 * invoke the external script to do its magic.
   1303	 */
   1304
   1305	str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
   1306			   "hv_set_ifconfig", if_file);
   1307	/*
   1308	 * This is a little overcautious, but it's necessary to suppress some
   1309	 * false warnings from gcc 8.0.1.
   1310	 */
   1311	if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
   1312		syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
   1313		       cmd, str_len);
   1314		return HV_E_FAIL;
   1315	}
   1316
   1317	if (system(cmd)) {
   1318		syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
   1319				cmd, errno, strerror(errno));
   1320		return HV_E_FAIL;
   1321	}
   1322	return 0;
   1323
   1324setval_error:
   1325	syslog(LOG_ERR, "Failed to write config file");
   1326	fclose(file);
   1327	return error;
   1328}
   1329
   1330
   1331static void
   1332kvp_get_domain_name(char *buffer, int length)
   1333{
   1334	struct addrinfo	hints, *info ;
   1335	int error = 0;
   1336
   1337	gethostname(buffer, length);
   1338	memset(&hints, 0, sizeof(hints));
   1339	hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
   1340	hints.ai_socktype = SOCK_STREAM;
   1341	hints.ai_flags = AI_CANONNAME;
   1342
   1343	error = getaddrinfo(buffer, NULL, &hints, &info);
   1344	if (error != 0) {
   1345		snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
   1346			error, gai_strerror(error));
   1347		return;
   1348	}
   1349	snprintf(buffer, length, "%s", info->ai_canonname);
   1350	freeaddrinfo(info);
   1351}
   1352
   1353void print_usage(char *argv[])
   1354{
   1355	fprintf(stderr, "Usage: %s [options]\n"
   1356		"Options are:\n"
   1357		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
   1358		"  -h, --help             print this help\n", argv[0]);
   1359}
   1360
   1361int main(int argc, char *argv[])
   1362{
   1363	int kvp_fd = -1, len;
   1364	int error;
   1365	struct pollfd pfd;
   1366	char    *p;
   1367	struct hv_kvp_msg hv_msg[1];
   1368	char	*key_value;
   1369	char	*key_name;
   1370	int	op;
   1371	int	pool;
   1372	char	*if_name;
   1373	struct hv_kvp_ipaddr_value *kvp_ip_val;
   1374	int daemonize = 1, long_index = 0, opt;
   1375
   1376	static struct option long_options[] = {
   1377		{"help",	no_argument,	   0,  'h' },
   1378		{"no-daemon",	no_argument,	   0,  'n' },
   1379		{0,		0,		   0,  0   }
   1380	};
   1381
   1382	while ((opt = getopt_long(argc, argv, "hn", long_options,
   1383				  &long_index)) != -1) {
   1384		switch (opt) {
   1385		case 'n':
   1386			daemonize = 0;
   1387			break;
   1388		case 'h':
   1389			print_usage(argv);
   1390			exit(0);
   1391		default:
   1392			print_usage(argv);
   1393			exit(EXIT_FAILURE);
   1394		}
   1395	}
   1396
   1397	if (daemonize && daemon(1, 0))
   1398		return 1;
   1399
   1400	openlog("KVP", 0, LOG_USER);
   1401	syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
   1402
   1403	/*
   1404	 * Retrieve OS release information.
   1405	 */
   1406	kvp_get_os_info();
   1407	/*
   1408	 * Cache Fully Qualified Domain Name because getaddrinfo takes an
   1409	 * unpredictable amount of time to finish.
   1410	 */
   1411	kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
   1412
   1413	if (kvp_file_init()) {
   1414		syslog(LOG_ERR, "Failed to initialize the pools");
   1415		exit(EXIT_FAILURE);
   1416	}
   1417
   1418reopen_kvp_fd:
   1419	if (kvp_fd != -1)
   1420		close(kvp_fd);
   1421	in_hand_shake = 1;
   1422	kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
   1423
   1424	if (kvp_fd < 0) {
   1425		syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
   1426		       errno, strerror(errno));
   1427		exit(EXIT_FAILURE);
   1428	}
   1429
   1430	/*
   1431	 * Register ourselves with the kernel.
   1432	 */
   1433	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
   1434	len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
   1435	if (len != sizeof(struct hv_kvp_msg)) {
   1436		syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
   1437		       errno, strerror(errno));
   1438		close(kvp_fd);
   1439		exit(EXIT_FAILURE);
   1440	}
   1441
   1442	pfd.fd = kvp_fd;
   1443
   1444	while (1) {
   1445		pfd.events = POLLIN;
   1446		pfd.revents = 0;
   1447
   1448		if (poll(&pfd, 1, -1) < 0) {
   1449			syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
   1450			if (errno == EINVAL) {
   1451				close(kvp_fd);
   1452				exit(EXIT_FAILURE);
   1453			}
   1454			else
   1455				continue;
   1456		}
   1457
   1458		len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
   1459
   1460		if (len != sizeof(struct hv_kvp_msg)) {
   1461			syslog(LOG_ERR, "read failed; error:%d %s",
   1462			       errno, strerror(errno));
   1463			goto reopen_kvp_fd;
   1464		}
   1465
   1466		/*
   1467		 * We will use the KVP header information to pass back
   1468		 * the error from this daemon. So, first copy the state
   1469		 * and set the error code to success.
   1470		 */
   1471		op = hv_msg->kvp_hdr.operation;
   1472		pool = hv_msg->kvp_hdr.pool;
   1473		hv_msg->error = HV_S_OK;
   1474
   1475		if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
   1476			/*
   1477			 * Driver is registering with us; stash away the version
   1478			 * information.
   1479			 */
   1480			in_hand_shake = 0;
   1481			p = (char *)hv_msg->body.kvp_register.version;
   1482			lic_version = malloc(strlen(p) + 1);
   1483			if (lic_version) {
   1484				strcpy(lic_version, p);
   1485				syslog(LOG_INFO, "KVP LIC Version: %s",
   1486				       lic_version);
   1487			} else {
   1488				syslog(LOG_ERR, "malloc failed");
   1489			}
   1490			continue;
   1491		}
   1492
   1493		switch (op) {
   1494		case KVP_OP_GET_IP_INFO:
   1495			kvp_ip_val = &hv_msg->body.kvp_ip_val;
   1496
   1497			error = kvp_mac_to_ip(kvp_ip_val);
   1498
   1499			if (error)
   1500				hv_msg->error = error;
   1501
   1502			break;
   1503
   1504		case KVP_OP_SET_IP_INFO:
   1505			kvp_ip_val = &hv_msg->body.kvp_ip_val;
   1506			if_name = kvp_get_if_name(
   1507					(char *)kvp_ip_val->adapter_id);
   1508			if (if_name == NULL) {
   1509				/*
   1510				 * We could not map the guid to an
   1511				 * interface name; return error.
   1512				 */
   1513				hv_msg->error = HV_GUID_NOTFOUND;
   1514				break;
   1515			}
   1516			error = kvp_set_ip_info(if_name, kvp_ip_val);
   1517			if (error)
   1518				hv_msg->error = error;
   1519
   1520			free(if_name);
   1521			break;
   1522
   1523		case KVP_OP_SET:
   1524			if (kvp_key_add_or_modify(pool,
   1525					hv_msg->body.kvp_set.data.key,
   1526					hv_msg->body.kvp_set.data.key_size,
   1527					hv_msg->body.kvp_set.data.value,
   1528					hv_msg->body.kvp_set.data.value_size))
   1529					hv_msg->error = HV_S_CONT;
   1530			break;
   1531
   1532		case KVP_OP_GET:
   1533			if (kvp_get_value(pool,
   1534					hv_msg->body.kvp_set.data.key,
   1535					hv_msg->body.kvp_set.data.key_size,
   1536					hv_msg->body.kvp_set.data.value,
   1537					hv_msg->body.kvp_set.data.value_size))
   1538					hv_msg->error = HV_S_CONT;
   1539			break;
   1540
   1541		case KVP_OP_DELETE:
   1542			if (kvp_key_delete(pool,
   1543					hv_msg->body.kvp_delete.key,
   1544					hv_msg->body.kvp_delete.key_size))
   1545					hv_msg->error = HV_S_CONT;
   1546			break;
   1547
   1548		default:
   1549			break;
   1550		}
   1551
   1552		if (op != KVP_OP_ENUMERATE)
   1553			goto kvp_done;
   1554
   1555		/*
   1556		 * If the pool is KVP_POOL_AUTO, dynamically generate
   1557		 * both the key and the value; if not read from the
   1558		 * appropriate pool.
   1559		 */
   1560		if (pool != KVP_POOL_AUTO) {
   1561			if (kvp_pool_enumerate(pool,
   1562					hv_msg->body.kvp_enum_data.index,
   1563					hv_msg->body.kvp_enum_data.data.key,
   1564					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
   1565					hv_msg->body.kvp_enum_data.data.value,
   1566					HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
   1567					hv_msg->error = HV_S_CONT;
   1568			goto kvp_done;
   1569		}
   1570
   1571		key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
   1572		key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
   1573
   1574		switch (hv_msg->body.kvp_enum_data.index) {
   1575		case FullyQualifiedDomainName:
   1576			strcpy(key_value, full_domain_name);
   1577			strcpy(key_name, "FullyQualifiedDomainName");
   1578			break;
   1579		case IntegrationServicesVersion:
   1580			strcpy(key_name, "IntegrationServicesVersion");
   1581			strcpy(key_value, lic_version);
   1582			break;
   1583		case NetworkAddressIPv4:
   1584			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
   1585				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
   1586			strcpy(key_name, "NetworkAddressIPv4");
   1587			break;
   1588		case NetworkAddressIPv6:
   1589			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
   1590				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
   1591			strcpy(key_name, "NetworkAddressIPv6");
   1592			break;
   1593		case OSBuildNumber:
   1594			strcpy(key_value, os_build);
   1595			strcpy(key_name, "OSBuildNumber");
   1596			break;
   1597		case OSName:
   1598			strcpy(key_value, os_name);
   1599			strcpy(key_name, "OSName");
   1600			break;
   1601		case OSMajorVersion:
   1602			strcpy(key_value, os_major);
   1603			strcpy(key_name, "OSMajorVersion");
   1604			break;
   1605		case OSMinorVersion:
   1606			strcpy(key_value, os_minor);
   1607			strcpy(key_name, "OSMinorVersion");
   1608			break;
   1609		case OSVersion:
   1610			strcpy(key_value, os_version);
   1611			strcpy(key_name, "OSVersion");
   1612			break;
   1613		case ProcessorArchitecture:
   1614			strcpy(key_value, processor_arch);
   1615			strcpy(key_name, "ProcessorArchitecture");
   1616			break;
   1617		default:
   1618			hv_msg->error = HV_S_CONT;
   1619			break;
   1620		}
   1621
   1622		/*
   1623		 * Send the value back to the kernel. Note: the write() may
   1624		 * return an error due to hibernation; we can ignore the error
   1625		 * by resetting the dev file, i.e. closing and re-opening it.
   1626		 */
   1627kvp_done:
   1628		len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
   1629		if (len != sizeof(struct hv_kvp_msg)) {
   1630			syslog(LOG_ERR, "write failed; error: %d %s", errno,
   1631			       strerror(errno));
   1632			goto reopen_kvp_fd;
   1633		}
   1634	}
   1635
   1636	close(kvp_fd);
   1637	exit(0);
   1638}