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