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