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