hv_kvp_daemon.c revision 272322
1/*-
2 * Copyright (c) 2014 Microsoft Corp.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <sys/poll.h>
30#include <sys/utsname.h>
31#include <sys/stat.h>
32#include <sys/un.h>
33
34#include <arpa/inet.h>
35#include <ifaddrs.h>
36#include <netdb.h>
37
38#include <netinet/in.h>
39#include <net/ethernet.h>
40#include <net/if_dl.h>
41#include <net/if_types.h>
42
43#include <assert.h>
44
45#include <ctype.h>
46#include <dirent.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <poll.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <syslog.h>
54#include <unistd.h>
55
56#include "hv_kvp.h"
57
58typedef uint8_t		__u8;
59typedef uint16_t	__u16;
60typedef uint32_t	__u32;
61typedef uint64_t	__u64;
62
63/*
64 * ENUM Data
65 */
66
67enum key_index {
68	FullyQualifiedDomainName = 0,
69	IntegrationServicesVersion, /*This key is serviced in the kernel*/
70	NetworkAddressIPv4,
71	NetworkAddressIPv6,
72	OSBuildNumber,
73	OSName,
74	OSMajorVersion,
75	OSMinorVersion,
76	OSVersion,
77	ProcessorArchitecture
78};
79
80
81enum {
82	IPADDR = 0,
83	NETMASK,
84	GATEWAY,
85	DNS
86};
87
88
89/* Global Variables */
90
91/*
92 * The structure for operation handlers.
93 */
94struct kvp_op_hdlr {
95	int	kvp_op_key;
96	void	(*kvp_op_init)(void);
97 	int	(*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
98};
99
100static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
101
102/* OS information */
103
104static const char *os_name = "";
105static const char *os_major = "";
106static const char *os_minor = "";
107static const char *processor_arch;
108static const char *os_build;
109static const char *lic_version = "BSD Pre-Release version";
110static struct utsname uts_buf;
111
112/* Global flags */
113static int is_daemon = 1;
114static int is_debugging = 0;
115
116#define	KVP_LOG(priority, format, args...) do	{			\
117		if (is_debugging == 1) {				\
118			if (is_daemon == 1)				\
119				syslog(priority, format, ## args);	\
120			else						\
121				printf(format, ## args);		\
122		} else {						\
123			if (priority < LOG_DEBUG) {			\
124				if (is_daemon == 1)			\
125					syslog(priority, format, ## args);	\
126				else					\
127					printf(format, ## args);	\
128			}						\
129		}							\
130	} while(0)
131
132/*
133 * For KVP pool file
134 */
135
136#define MAX_FILE_NAME		100
137#define ENTRIES_PER_BLOCK	50
138
139struct kvp_record {
140	char	key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
141	char	value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
142};
143
144struct kvp_pool {
145	int			pool_fd;
146	int			num_blocks;
147	struct kvp_record	*records;
148	int			num_records;
149	char			fname[MAX_FILE_NAME];
150};
151
152static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
153
154
155static void
156kvp_acquire_lock(int pool)
157{
158	struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
159
160	fl.l_pid = getpid();
161
162	if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) {
163		KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
164		exit(EXIT_FAILURE);
165	}
166}
167
168
169static void
170kvp_release_lock(int pool)
171{
172	struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
173
174	fl.l_pid = getpid();
175
176	if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
177		perror("fcntl");
178		KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
179		exit(EXIT_FAILURE);
180	}
181}
182
183
184/*
185 * Write in-memory copy of KVP to pool files
186 */
187static void
188kvp_update_file(int pool)
189{
190	FILE *filep;
191	size_t bytes_written;
192
193	kvp_acquire_lock(pool);
194
195	filep = fopen(kvp_pools[pool].fname, "w");
196	if (!filep) {
197		kvp_release_lock(pool);
198		KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
199		exit(EXIT_FAILURE);
200	}
201
202	bytes_written = fwrite(kvp_pools[pool].records,
203		sizeof(struct kvp_record),
204		kvp_pools[pool].num_records, filep);
205
206	if (ferror(filep) || fclose(filep)) {
207		kvp_release_lock(pool);
208		KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
209		exit(EXIT_FAILURE);
210	}
211
212	kvp_release_lock(pool);
213}
214
215
216/*
217 * Read KVPs from pool files and store in memory
218 */
219static void
220kvp_update_mem_state(int pool)
221{
222	FILE *filep;
223	size_t records_read = 0;
224	struct kvp_record *record = kvp_pools[pool].records;
225	struct kvp_record *readp;
226	int num_blocks = kvp_pools[pool].num_blocks;
227	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
228
229	kvp_acquire_lock(pool);
230
231	filep = fopen(kvp_pools[pool].fname, "r");
232	if (!filep) {
233		kvp_release_lock(pool);
234		KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
235		exit(EXIT_FAILURE);
236	}
237	for ( ; ; )
238	{
239		readp = &record[records_read];
240		records_read += fread(readp, sizeof(struct kvp_record),
241			ENTRIES_PER_BLOCK * num_blocks,
242			filep);
243
244		if (ferror(filep)) {
245			KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
246			exit(EXIT_FAILURE);
247		}
248
249		if (!feof(filep)) {
250			/*
251			 * Have more data to read. Expand the memory.
252			 */
253			num_blocks++;
254			record = realloc(record, alloc_unit * num_blocks);
255
256			if (record == NULL) {
257				KVP_LOG(LOG_ERR, "malloc failed\n");
258				exit(EXIT_FAILURE);
259			}
260			continue;
261		}
262		break;
263	}
264
265	kvp_pools[pool].num_blocks = num_blocks;
266	kvp_pools[pool].records = record;
267	kvp_pools[pool].num_records = records_read;
268
269	fclose(filep);
270	kvp_release_lock(pool);
271}
272
273
274static int
275kvp_file_init(void)
276{
277	int fd;
278	FILE *filep;
279	size_t records_read;
280	char *fname;
281	struct kvp_record *record;
282	struct kvp_record *readp;
283	int num_blocks;
284	int i;
285	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
286
287	if (mkdir("/var/db/hyperv/pool", S_IRUSR | S_IWUSR | S_IROTH) < 0 &&
288	    errno != EISDIR) {
289		KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
290		exit(EXIT_FAILURE);
291	}
292
293	for (i = 0; i < HV_KVP_POOL_COUNT; i++)
294	{
295		fname = kvp_pools[i].fname;
296		records_read = 0;
297		num_blocks = 1;
298		snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
299		fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
300
301		if (fd == -1) {
302			return (1);
303		}
304
305
306		filep = fopen(fname, "r");
307		if (!filep) {
308			close(fd);
309			return (1);
310		}
311
312		record = malloc(alloc_unit * num_blocks);
313		if (record == NULL) {
314			close(fd);
315			fclose(filep);
316			return (1);
317		}
318		for ( ; ; )
319		{
320			readp = &record[records_read];
321			records_read += fread(readp, sizeof(struct kvp_record),
322				ENTRIES_PER_BLOCK,
323				filep);
324
325			if (ferror(filep)) {
326				KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
327				    i);
328				exit(EXIT_FAILURE);
329			}
330
331			if (!feof(filep)) {
332				/*
333				 * More data to read.
334				 */
335				num_blocks++;
336				record = realloc(record, alloc_unit *
337					num_blocks);
338				if (record == NULL) {
339					close(fd);
340					fclose(filep);
341					return (1);
342				}
343				continue;
344			}
345			break;
346		}
347		kvp_pools[i].pool_fd = fd;
348		kvp_pools[i].num_blocks = num_blocks;
349		kvp_pools[i].records = record;
350		kvp_pools[i].num_records = records_read;
351		fclose(filep);
352	}
353
354	return (0);
355}
356
357
358static int
359kvp_key_delete(int pool, __u8 *key, int key_size)
360{
361	int i;
362	int j, k;
363	int num_records;
364	struct kvp_record *record;
365
366	KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool =  %d, "
367	    "key = %s\n", pool, key);
368
369	/* Update in-memory state */
370	kvp_update_mem_state(pool);
371
372	num_records = kvp_pools[pool].num_records;
373	record = kvp_pools[pool].records;
374
375	for (i = 0; i < num_records; i++)
376	{
377		if (memcmp(key, record[i].key, key_size)) {
378			continue;
379		}
380
381		KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
382		    pool);
383		/*
384		 * We found a match at the end; Just update the number of
385		 * entries and we are done.
386		 */
387		if (i == num_records) {
388			kvp_pools[pool].num_records--;
389			kvp_update_file(pool);
390			return (0);
391		}
392
393		/*
394		 * We found a match in the middle; Move the remaining
395		 * entries up.
396		 */
397		j = i;
398		k = j + 1;
399		for ( ; k < num_records; k++)
400		{
401			strcpy(record[j].key, record[k].key);
402			strcpy(record[j].value, record[k].value);
403			j++;
404		}
405		kvp_pools[pool].num_records--;
406		kvp_update_file(pool);
407		return (0);
408	}
409	KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
410	    pool);
411	return (1);
412}
413
414
415static int
416kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
417    __u32 value_size)
418{
419	int i;
420	int num_records;
421	struct kvp_record *record;
422	int num_blocks;
423
424	KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool =  %d, "
425	    "key = %s, value = %s\n,", pool, key, value);
426
427	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
428	    (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
429		KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
430		return (1);
431	}
432
433	/* Update the in-memory state. */
434	kvp_update_mem_state(pool);
435
436	num_records = kvp_pools[pool].num_records;
437	record = kvp_pools[pool].records;
438	num_blocks = kvp_pools[pool].num_blocks;
439
440	for (i = 0; i < num_records; i++)
441	{
442		if (memcmp(key, record[i].key, key_size)) {
443			continue;
444		}
445
446		/*
447		 * Key exists. Just update the value and we are done.
448		 */
449		memcpy(record[i].value, value, value_size);
450		kvp_update_file(pool);
451		return (0);
452	}
453
454	/*
455	 * Key doesn't exist; Add a new KVP.
456	 */
457	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
458		/* Increase the size of the recodrd array. */
459		record = realloc(record, sizeof(struct kvp_record) *
460			ENTRIES_PER_BLOCK * (num_blocks + 1));
461
462		if (record == NULL) {
463			return (1);
464		}
465		kvp_pools[pool].num_blocks++;
466	}
467	memcpy(record[i].value, value, value_size);
468	memcpy(record[i].key, key, key_size);
469	kvp_pools[pool].records = record;
470	kvp_pools[pool].num_records++;
471	kvp_update_file(pool);
472	return (0);
473}
474
475
476static int
477kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
478    int value_size)
479{
480	int i;
481	int num_records;
482	struct kvp_record *record;
483
484	KVP_LOG(LOG_DEBUG, "kvp_get_value: pool =  %d, key = %s\n,",
485	    pool, key);
486
487	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
488	    (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
489		return (1);
490	}
491
492	/* Update the in-memory state first. */
493	kvp_update_mem_state(pool);
494
495	num_records = kvp_pools[pool].num_records;
496	record = kvp_pools[pool].records;
497
498	for (i = 0; i < num_records; i++)
499	{
500		if (memcmp(key, record[i].key, key_size)) {
501			continue;
502		}
503
504		/* Found the key */
505		memcpy(value, record[i].value, value_size);
506		return (0);
507	}
508
509	return (1);
510}
511
512
513static int
514kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
515    __u8 *value, int value_size)
516{
517	struct kvp_record *record;
518
519	KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
520	    pool, index);
521
522	/* First update our in-memory state first. */
523	kvp_update_mem_state(pool);
524	record = kvp_pools[pool].records;
525
526	/* Index starts with 0 */
527	if (index >= kvp_pools[pool].num_records) {
528		return (1);
529	}
530
531	memcpy(key, record[index].key, key_size);
532	memcpy(value, record[index].value, value_size);
533	return (0);
534}
535
536
537static void
538kvp_get_os_info(void)
539{
540	char *p;
541
542	uname(&uts_buf);
543	os_build = uts_buf.release;
544	os_name = uts_buf.sysname;
545	processor_arch = uts_buf.machine;
546
547	/*
548	 * Win7 host expects the build string to be of the form: x.y.z
549	 * Strip additional information we may have.
550	 */
551	p = strchr(os_build, '-');
552	if (p) {
553		*p = '\0';
554	}
555
556	/*
557	 * We don't have any other information about the FreeBSD os.
558	 */
559	return;
560}
561
562/*
563 * Given the interface name, return the MAC address.
564 */
565static char *
566kvp_if_name_to_mac(char *if_name)
567{
568	char *mac_addr = NULL;
569	struct ifaddrs *ifaddrs_ptr;
570	struct ifaddrs *head_ifaddrs_ptr;
571	struct sockaddr_dl *sdl;
572	int status;
573
574	status = getifaddrs(&ifaddrs_ptr);
575
576	if (status >= 0) {
577		head_ifaddrs_ptr = ifaddrs_ptr;
578		do {
579			sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
580			if ((sdl->sdl_type == IFT_ETHER) &&
581			    (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
582				mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
583				break;
584			}
585		} while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
586		freeifaddrs(head_ifaddrs_ptr);
587	}
588
589	return (mac_addr);
590}
591
592
593/*
594 * Given the MAC address, return the interface name.
595 */
596static char *
597kvp_mac_to_if_name(char *mac)
598{
599	char *if_name = NULL;
600	struct ifaddrs *ifaddrs_ptr;
601	struct ifaddrs *head_ifaddrs_ptr;
602	struct sockaddr_dl *sdl;
603	int status;
604	char *buf_ptr, *p;
605
606	status = getifaddrs(&ifaddrs_ptr);
607
608	if (status >= 0) {
609		head_ifaddrs_ptr = ifaddrs_ptr;
610		do {
611			sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
612			if (sdl->sdl_type == IFT_ETHER) {
613				buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
614				if (buf_ptr != NULL) {
615					for (p = buf_ptr; *p != '\0'; p++)
616						*p = toupper(*p);
617
618					if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
619						/* Caller will free the memory */
620						if_name = strdup(ifaddrs_ptr->ifa_name);
621						free(buf_ptr);
622						break;
623					} else
624						free(buf_ptr);
625				}
626			}
627		} while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
628		freeifaddrs(head_ifaddrs_ptr);
629	}
630	return (if_name);
631}
632
633
634static void
635kvp_process_ipconfig_file(char *cmd,
636    char *config_buf, size_t len,
637    size_t element_size, int offset)
638{
639	char buf[256];
640	char *p;
641	char *x;
642	FILE *file;
643
644	/*
645	 * First execute the command.
646	 */
647	file = popen(cmd, "r");
648	if (file == NULL) {
649		return;
650	}
651
652	if (offset == 0) {
653		memset(config_buf, 0, len);
654	}
655	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
656		if ((len - strlen(config_buf)) < (element_size + 1)) {
657			break;
658		}
659
660		x = strchr(p, '\n');
661		*x = '\0';
662		strlcat(config_buf, p, len);
663		strlcat(config_buf, ";", len);
664	}
665	pclose(file);
666}
667
668
669static void
670kvp_get_ipconfig_info(char *if_name, 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	 * Retrieve the IPV4 address of default gateway.
679	 */
680	snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
681
682	/*
683	 * Execute the command to gather gateway IPV4 info.
684	 */
685	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
686	    (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
687
688	/*
689	 * Retrieve the IPV6 address of default gateway.
690	 */
691	snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }", if_name);
692
693	/*
694	 * Execute the command to gather gateway IPV6 info.
695	 */
696	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
697	    (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
698
699	/*
700	 * we just invoke an external script to get the DNS info.
701	 *
702	 * Following is the expected format of the information from the script:
703	 *
704	 * ipaddr1 (nameserver1)
705	 * ipaddr2 (nameserver2)
706	 * .
707	 * .
708	 */
709	/* Scripts are stored in /usr/libexec/hyperv/ directory */
710	snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
711
712	/*
713	 * Execute the command to get DNS info.
714	 */
715	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
716	    (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
717
718	/*
719	 * Invoke an external script to get the DHCP state info.
720	 * The parameter to the script is the interface name.
721	 * Here is the expected output:
722	 *
723	 * Enabled: DHCP enabled.
724	 */
725
726
727	snprintf(cmd, sizeof(cmd), "%s %s",
728	    "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
729
730	file = popen(cmd, "r");
731	if (file == NULL) {
732		return;
733	}
734
735	p = fgets(dhcp_info, sizeof(dhcp_info), file);
736	if (p == NULL) {
737		pclose(file);
738		return;
739	}
740
741	if (!strncmp(p, "Enabled", 7)) {
742		buffer->dhcp_enabled = 1;
743	} else{
744		buffer->dhcp_enabled = 0;
745	}
746
747	pclose(file);
748}
749
750
751static unsigned int
752hweight32(unsigned int *w)
753{
754	unsigned int res = *w - ((*w >> 1) & 0x55555555);
755
756	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
757	res = (res + (res >> 4)) & 0x0F0F0F0F;
758	res = res + (res >> 8);
759	return ((res + (res >> 16)) & 0x000000FF);
760}
761
762
763static int
764kvp_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 + 1) {
785		return (HV_KVP_E_FAIL);
786	}
787	if (str == NULL) {
788		strlcpy(buffer, "inet_ntop failed\n", length);
789		return (HV_KVP_E_FAIL);
790	}
791	if (*offset == 0) {
792		strlcpy(buffer, tmp, length);
793	} else{
794		strlcat(buffer, tmp, length);
795	}
796	strlcat(buffer, ";", length);
797
798	*offset += strlen(str) + 1;
799	return (0);
800}
801
802
803static int
804kvp_get_ip_info(int family, char *if_name, int op,
805    void *out_buffer, size_t length)
806{
807	struct ifaddrs *ifap;
808	struct ifaddrs *curp;
809	int offset = 0;
810	int sn_offset = 0;
811	int error = 0;
812	char *buffer;
813	size_t buffer_length;
814	struct hv_kvp_ipaddr_value *ip_buffer;
815	char cidr_mask[5];
816	int weight;
817	int i;
818	unsigned int *w = NULL;
819	char *sn_str;
820	size_t sn_str_length;
821	struct sockaddr_in6 *addr6;
822
823	if (op == HV_KVP_OP_ENUMERATE) {
824		buffer = out_buffer;
825		buffer_length = length;
826	} else {
827		ip_buffer = out_buffer;
828		buffer = (char *)ip_buffer->ip_addr;
829		buffer_length = sizeof(ip_buffer->ip_addr);
830		ip_buffer->addr_family = 0;
831	}
832
833	if (getifaddrs(&ifap)) {
834		strlcpy(buffer, "getifaddrs failed\n", buffer_length);
835		return (HV_KVP_E_FAIL);
836	}
837
838	curp = ifap;
839	while (curp != NULL) {
840		if (curp->ifa_addr == NULL) {
841			curp = curp->ifa_next;
842			continue;
843		}
844
845		if ((if_name != NULL) &&
846		    (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
847			/*
848			 * We want info about a specific interface;
849			 * just continue.
850			 */
851			curp = curp->ifa_next;
852			continue;
853		}
854
855		/*
856		 * We support two address families: AF_INET and AF_INET6.
857		 * If family value is 0, we gather both supported
858		 * address families; if not we gather info on
859		 * the specified address family.
860		 */
861		if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
862			curp = curp->ifa_next;
863			continue;
864		}
865		if ((curp->ifa_addr->sa_family != AF_INET) &&
866		    (curp->ifa_addr->sa_family != AF_INET6)) {
867			curp = curp->ifa_next;
868			continue;
869		}
870
871		if (op == HV_KVP_OP_GET_IP_INFO) {
872			/*
873			 * Get the info other than the IP address.
874			 */
875			if (curp->ifa_addr->sa_family == AF_INET) {
876				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
877
878				/*
879				 * Get subnet info.
880				 */
881				error = kvp_process_ip_address(
882					curp->ifa_netmask,
883					AF_INET,
884					(char *)
885					ip_buffer->sub_net,
886					length,
887					&sn_offset);
888				if (error) {
889					goto kvp_get_ip_info_ipaddr;
890				}
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				sn_str_length = sizeof(ip_buffer->sub_net);
900				addr6 = (struct sockaddr_in6 *)(uintptr_t)
901				    curp->ifa_netmask;
902				w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
903
904				for (i = 0; i < 4; i++)
905				{
906					weight += hweight32(&w[i]);
907				}
908
909				snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
910				if ((length - sn_offset) <
911				    (strlen(cidr_mask) + 1)) {
912					goto kvp_get_ip_info_ipaddr;
913				}
914
915				if (sn_offset == 0) {
916					strlcpy(sn_str, cidr_mask, sn_str_length);
917				} else{
918					strlcat(sn_str, cidr_mask, sn_str_length);
919				}
920				strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
921				sn_offset += strlen(sn_str) + 1;
922			}
923
924			/*
925			 * Collect other ip configuration info.
926			 */
927
928			kvp_get_ipconfig_info(if_name, ip_buffer);
929		}
930
931kvp_get_ip_info_ipaddr:
932		error = kvp_process_ip_address(curp->ifa_addr,
933			curp->ifa_addr->sa_family,
934			buffer,
935			length, &offset);
936		if (error) {
937			goto kvp_get_ip_info_done;
938		}
939
940		curp = curp->ifa_next;
941	}
942
943kvp_get_ip_info_done:
944	freeifaddrs(ifap);
945	return (error);
946}
947
948
949static int
950kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
951{
952	int ret;
953
954	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
955
956	if (ret < 0) {
957		return (HV_KVP_E_FAIL);
958	}
959
960	return (0);
961}
962
963
964static int
965kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
966{
967	int error = 0;
968	char if_file[128];
969	FILE *file;
970	char cmd[512];
971	char *mac_addr;
972
973	/*
974	 * FreeBSD - Configuration File
975	 */
976	snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
977	    "hv_set_ip_data");
978	file = fopen(if_file, "w");
979
980	if (file == NULL) {
981		KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
982		return (HV_KVP_E_FAIL);
983	}
984
985	/*
986	 * Write out the MAC address.
987	 */
988
989	mac_addr = kvp_if_name_to_mac(if_name);
990	if (mac_addr == NULL) {
991		error = HV_KVP_E_FAIL;
992		goto kvp_set_ip_info_error;
993	}
994	/* MAC Address */
995	error = kvp_write_file(file, "HWADDR", "", mac_addr);
996	if (error) {
997		goto kvp_set_ip_info_error;
998	}
999
1000	/* Interface Name  */
1001	error = kvp_write_file(file, "IF_NAME", "", if_name);
1002	if (error) {
1003		goto kvp_set_ip_info_error;
1004	}
1005
1006	/* IP Address  */
1007	error = kvp_write_file(file, "IP_ADDR", "",
1008	    (char *)new_val->ip_addr);
1009	if (error) {
1010		goto kvp_set_ip_info_error;
1011	}
1012
1013	/* Subnet Mask */
1014	error = kvp_write_file(file, "SUBNET", "",
1015	    (char *)new_val->sub_net);
1016	if (error) {
1017		goto kvp_set_ip_info_error;
1018	}
1019
1020
1021	/* Gateway */
1022	error = kvp_write_file(file, "GATEWAY", "",
1023	    (char *)new_val->gate_way);
1024	if (error) {
1025		goto kvp_set_ip_info_error;
1026	}
1027
1028	/* DNS */
1029	error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1030	if (error) {
1031		goto kvp_set_ip_info_error;
1032	}
1033
1034	/* DHCP */
1035	if (new_val->dhcp_enabled) {
1036		error = kvp_write_file(file, "DHCP", "", "1");
1037	} else{
1038		error = kvp_write_file(file, "DHCP", "", "0");
1039	}
1040
1041	if (error) {
1042		goto kvp_set_ip_info_error;
1043	}
1044
1045	free(mac_addr);
1046	fclose(file);
1047
1048	/*
1049	 * Invoke the external script with the populated
1050	 * configuration file.
1051	 */
1052
1053	snprintf(cmd, sizeof(cmd), "%s %s",
1054	    "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1055	system(cmd);
1056	return (0);
1057
1058kvp_set_ip_info_error:
1059	KVP_LOG(LOG_ERR, "Failed to write config file\n");
1060	free(mac_addr);
1061	fclose(file);
1062	return (error);
1063}
1064
1065
1066static int
1067kvp_get_domain_name(char *buffer, int length)
1068{
1069	struct addrinfo hints, *info;
1070	int error = 0;
1071
1072	gethostname(buffer, length);
1073	memset(&hints, 0, sizeof(hints));
1074	hints.ai_family = AF_INET;    /* Get only ipv4 addrinfo. */
1075	hints.ai_socktype = SOCK_STREAM;
1076	hints.ai_flags = AI_CANONNAME;
1077
1078	error = getaddrinfo(buffer, NULL, &hints, &info);
1079	if (error != 0) {
1080		strlcpy(buffer, "getaddrinfo failed\n", length);
1081		return (error);
1082	}
1083	strlcpy(buffer, info->ai_canonname, length);
1084	freeaddrinfo(info);
1085	return (error);
1086}
1087
1088
1089static int
1090kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1091{
1092	struct hv_kvp_ipaddr_value *ip_val;
1093	char *if_name;
1094
1095	assert(op_msg != NULL);
1096	KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1097
1098	ip_val = &op_msg->body.kvp_ip_val;
1099	op_msg->hdr.error = HV_KVP_S_OK;
1100
1101	if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1102
1103	if (if_name == NULL) {
1104		/* No interface found with the mac address. */
1105		op_msg->hdr.error = HV_KVP_E_FAIL;
1106		goto kvp_op_getipinfo_done;
1107	}
1108
1109	op_msg->hdr.error = kvp_get_ip_info(0, if_name,
1110	    HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1111
1112	free(if_name);
1113
1114kvp_op_getipinfo_done:
1115	return(op_msg->hdr.error);
1116}
1117
1118
1119static int
1120kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1121{
1122	struct hv_kvp_ipaddr_value *ip_val;
1123	char *if_name;
1124
1125	assert(op_msg != NULL);
1126	KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1127
1128	ip_val = &op_msg->body.kvp_ip_val;
1129	op_msg->hdr.error = HV_KVP_S_OK;
1130
1131	if_name = (char *)ip_val->adapter_id;
1132
1133	if (if_name == NULL) {
1134		/* No adapter provided. */
1135		op_msg->hdr.error = HV_KVP_GUID_NOTFOUND;
1136		goto kvp_op_setipinfo_done;
1137	}
1138
1139	op_msg->hdr.error = kvp_set_ip_info(if_name, ip_val);
1140
1141kvp_op_setipinfo_done:
1142	return(op_msg->hdr.error);
1143}
1144
1145
1146static int
1147kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1148{
1149	struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1150	int error = 0;
1151	int op_pool;
1152
1153	assert(op_msg != NULL);
1154	assert(op_hdlr != NULL);
1155
1156	op_pool = op_msg->hdr.kvp_hdr.pool;
1157	op_msg->hdr.error = HV_KVP_S_OK;
1158
1159	switch(op_hdlr->kvp_op_key) {
1160	case HV_KVP_OP_SET:
1161		if (op_pool == HV_KVP_POOL_AUTO) {
1162			/* Auto Pool is not writeable from host side. */
1163			error = 1;
1164			KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1165			    op_pool);
1166		} else {
1167			error = kvp_key_add_or_modify(op_pool,
1168			    op_msg->body.kvp_set.data.key,
1169			    op_msg->body.kvp_set.data.key_size,
1170			    op_msg->body.kvp_set.data.msg_value.value,
1171			    op_msg->body.kvp_set.data.value_size);
1172		}
1173		break;
1174
1175	case HV_KVP_OP_GET:
1176		error = kvp_get_value(op_pool,
1177		    op_msg->body.kvp_get.data.key,
1178		    op_msg->body.kvp_get.data.key_size,
1179		    op_msg->body.kvp_get.data.msg_value.value,
1180		    op_msg->body.kvp_get.data.value_size);
1181		break;
1182
1183	case HV_KVP_OP_DELETE:
1184		if (op_pool == HV_KVP_POOL_AUTO) {
1185			/* Auto Pool is not writeable from host side. */
1186			error = 1;
1187			KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1188			    op_pool);
1189		} else {
1190			error = kvp_key_delete(op_pool,
1191			    op_msg->body.kvp_delete.key,
1192			    op_msg->body.kvp_delete.key_size);
1193		}
1194		break;
1195
1196	default:
1197		break;
1198	}
1199
1200	if (error != 0)
1201		op_msg->hdr.error = HV_KVP_S_CONT;
1202
1203	return(error);
1204}
1205
1206
1207static int
1208kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1209{
1210	char *key_name, *key_value;
1211	int error = 0;
1212	int op_pool;
1213	int op;
1214
1215	assert(op_msg != NULL);
1216
1217	op = op_msg->hdr.kvp_hdr.operation;
1218	op_pool = op_msg->hdr.kvp_hdr.pool;
1219	op_msg->hdr.error = HV_KVP_S_OK;
1220
1221	/*
1222	 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1223	 * pool and return the KVP according to the index requested.
1224	 */
1225	if (op_pool != HV_KVP_POOL_AUTO) {
1226		if (kvp_pool_enumerate(op_pool,
1227		    op_msg->body.kvp_enum_data.index,
1228		    op_msg->body.kvp_enum_data.data.key,
1229		    HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1230		    op_msg->body.kvp_enum_data.data.msg_value.value,
1231		    HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1232			op_msg->hdr.error = HV_KVP_S_CONT;
1233			error = -1;
1234		}
1235		goto kvp_op_enumerate_done;
1236	}
1237
1238	key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1239	key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1240
1241	switch (op_msg->body.kvp_enum_data.index)
1242	{
1243	case FullyQualifiedDomainName:
1244		kvp_get_domain_name(key_value,
1245		    HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1246		strcpy(key_name, "FullyQualifiedDomainName");
1247		break;
1248
1249	case IntegrationServicesVersion:
1250		strcpy(key_name, "IntegrationServicesVersion");
1251		strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1252		break;
1253
1254	case NetworkAddressIPv4:
1255		kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1256		    key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1257		strcpy(key_name, "NetworkAddressIPv4");
1258		break;
1259
1260	case NetworkAddressIPv6:
1261		kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1262		    key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1263		strcpy(key_name, "NetworkAddressIPv6");
1264		break;
1265
1266	case OSBuildNumber:
1267		strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1268		strcpy(key_name, "OSBuildNumber");
1269		break;
1270
1271	case OSName:
1272		strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1273		strcpy(key_name, "OSName");
1274		break;
1275
1276	case OSMajorVersion:
1277		strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1278		strcpy(key_name, "OSMajorVersion");
1279		break;
1280
1281	case OSMinorVersion:
1282		strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1283		strcpy(key_name, "OSMinorVersion");
1284		break;
1285
1286	case OSVersion:
1287		strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1288		strcpy(key_name, "OSVersion");
1289		break;
1290
1291	case ProcessorArchitecture:
1292		strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1293		strcpy(key_name, "ProcessorArchitecture");
1294		break;
1295
1296	default:
1297#ifdef DEBUG
1298		KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1299		    op_msg->body.kvp_enum_data.index);
1300#endif
1301		op_msg->hdr.error = HV_KVP_S_CONT;
1302		error = -1;
1303		break;
1304	}
1305
1306kvp_op_enumerate_done:
1307	return(error);
1308}
1309
1310
1311/*
1312 * Load handler, and call init routine if provided.
1313 */
1314static int
1315kvp_op_load(int key, void (*init)(void),
1316	    int (*exec)(struct hv_kvp_msg *, void *))
1317{
1318	int error = 0;
1319
1320	if (key < 0 || key >= HV_KVP_OP_COUNT) {
1321		KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1322		error = -1;
1323		goto kvp_op_load_done;
1324	}
1325
1326	kvp_op_hdlrs[key].kvp_op_key = key;
1327	kvp_op_hdlrs[key].kvp_op_init = init;
1328	kvp_op_hdlrs[key].kvp_op_exec = exec;
1329
1330	if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1331		kvp_op_hdlrs[key].kvp_op_init();
1332
1333kvp_op_load_done:
1334	return(error);
1335}
1336
1337
1338/*
1339 * Initialize the operation hanlders.
1340 */
1341static int
1342kvp_ops_init(void)
1343{
1344	int i;
1345
1346	/* Set the initial values. */
1347	for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1348		kvp_op_hdlrs[i].kvp_op_key = -1;
1349		kvp_op_hdlrs[i].kvp_op_init = NULL;
1350		kvp_op_hdlrs[i].kvp_op_exec = NULL;
1351	}
1352
1353	return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1354	    kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1355	    kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1356	    kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1357	        kvp_op_enumerate) |
1358	    kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1359	    kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1360}
1361
1362
1363int
1364main(int argc, char *argv[])
1365{
1366	struct hv_kvp_msg *hv_kvp_dev_buf;
1367	struct hv_kvp_msg *hv_msg;
1368	struct pollfd hv_kvp_poll_fd[1];
1369	int op, pool;
1370	int hv_kvp_dev_fd, error, len, r;
1371	int ch;
1372
1373	while ((ch = getopt(argc, argv, "dn")) != -1) {
1374		switch (ch) {
1375		case 'n':
1376			/* Run as regular process for debugging purpose. */
1377			is_daemon = 0;
1378			break;
1379		case 'd':
1380			/* Generate debugging output */
1381			is_debugging = 1;
1382			break;
1383		default:
1384			break;
1385		}
1386	}
1387
1388	openlog("HV_KVP", 0, LOG_USER);
1389
1390	/* Become daemon first. */
1391	if (is_daemon == 1)
1392		daemon(1, 0);
1393	else
1394		KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1395
1396	KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1397
1398	/* Communication buffer hv_kvp_dev_buf */
1399	hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1400	/* Buffer for daemon internal use */
1401	hv_msg = malloc(sizeof(*hv_msg));
1402
1403	/* Memory allocation failed */
1404	if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1405		KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1406		exit(EXIT_FAILURE);
1407	}
1408
1409	/* Initialize op handlers */
1410	if (kvp_ops_init() != 0) {
1411		KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1412		exit(EXIT_FAILURE);
1413	}
1414
1415	if (kvp_file_init()) {
1416		KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1417		exit(EXIT_FAILURE);
1418	}
1419
1420	/* Open the Character Device */
1421	hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1422
1423	if (hv_kvp_dev_fd < 0) {
1424		KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1425		    errno, strerror(errno));
1426		exit(EXIT_FAILURE);
1427	}
1428
1429	/* Initialize the struct for polling the char device */
1430	hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1431	hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1432
1433	/* Register the daemon to the KVP driver */
1434	memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1435	hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1436	len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1437
1438
1439	for (;;) {
1440		r = poll (hv_kvp_poll_fd, 1, 100);
1441
1442		KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1443		    r, hv_kvp_poll_fd[0].revents);
1444
1445		if (r == 0 || (r < 0 && errno == EAGAIN) ||
1446		    (r < 0 && errno == EINTR)) {
1447			/* Nothing to read */
1448			continue;
1449		}
1450
1451		if (r < 0) {
1452			/*
1453			 * For pread return failure other than EAGAIN,
1454			 * we want to exit.
1455			 */
1456			KVP_LOG(LOG_ERR, "Poll failed.\n");
1457			perror("poll");
1458			exit(EIO);
1459		}
1460
1461		/* Read from character device */
1462		len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1463		    sizeof(*hv_kvp_dev_buf), 0);
1464
1465		if (len < 0) {
1466			KVP_LOG(LOG_ERR, "Read failed.\n");
1467			perror("pread");
1468			exit(EIO);
1469		}
1470
1471		if (len != sizeof(struct hv_kvp_msg)) {
1472			KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1473			continue;
1474		}
1475
1476		/* Copy hv_kvp_dev_buf to hv_msg */
1477		memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1478
1479		/*
1480		 * We will use the KVP header information to pass back
1481		 * the error from this daemon. So, first save the op
1482		 * and pool info to local variables.
1483		 */
1484
1485		op = hv_msg->hdr.kvp_hdr.operation;
1486		pool = hv_msg->hdr.kvp_hdr.pool;
1487
1488		if (op < 0 || op >= HV_KVP_OP_COUNT ||
1489		    kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1490			KVP_LOG(LOG_WARNING,
1491			    "Unsupported operation OP = %d\n", op);
1492			hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1493		} else {
1494			/*
1495			 * Call the operateion handler's execution routine.
1496			 */
1497			error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1498			    (void *)&kvp_op_hdlrs[op]);
1499			if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT)
1500				KVP_LOG(LOG_WARNING,
1501				    "Operation failed OP = %d, error = 0x%x\n",
1502				    op, error);
1503		}
1504
1505		/*
1506		 * Send the value back to the kernel. The response is
1507		 * already in the receive buffer.
1508		 */
1509hv_kvp_done:
1510		len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1511
1512		if (len != sizeof(struct hv_kvp_msg)) {
1513			KVP_LOG(LOG_ERR, "write len is: %d\n", len);
1514			goto hv_kvp_done;
1515		}
1516	}
1517}
1518