1271493Sdelphij/*-
2271493Sdelphij * Copyright (c) 2014 Microsoft Corp.
3271493Sdelphij * All rights reserved.
4271493Sdelphij *
5271493Sdelphij * Redistribution and use in source and binary forms, with or without
6271493Sdelphij * modification, are permitted provided that the following conditions
7271493Sdelphij * are met:
8271493Sdelphij * 1. Redistributions of source code must retain the above copyright
9271493Sdelphij *    notice unmodified, this list of conditions, and the following
10271493Sdelphij *    disclaimer.
11271493Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12271493Sdelphij *    notice, this list of conditions and the following disclaimer in the
13271493Sdelphij *    documentation and/or other materials provided with the distribution.
14271493Sdelphij *
15271493Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16271493Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17271493Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18271493Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19271493Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20271493Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21271493Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22271493Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23271493Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24271493Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25271493Sdelphij */
26271493Sdelphij
27271493Sdelphij#include <sys/types.h>
28271493Sdelphij#include <sys/socket.h>
29271493Sdelphij#include <sys/poll.h>
30271493Sdelphij#include <sys/utsname.h>
31271493Sdelphij#include <sys/stat.h>
32271493Sdelphij#include <sys/un.h>
33271493Sdelphij
34271493Sdelphij#include <arpa/inet.h>
35271493Sdelphij#include <ifaddrs.h>
36271493Sdelphij#include <netdb.h>
37271493Sdelphij
38271493Sdelphij#include <netinet/in.h>
39271493Sdelphij#include <net/ethernet.h>
40271493Sdelphij#include <net/if_dl.h>
41271493Sdelphij#include <net/if_types.h>
42271493Sdelphij
43271493Sdelphij#include <assert.h>
44271493Sdelphij
45271493Sdelphij#include <ctype.h>
46271493Sdelphij#include <dirent.h>
47271493Sdelphij#include <errno.h>
48271493Sdelphij#include <fcntl.h>
49271493Sdelphij#include <poll.h>
50271493Sdelphij#include <stdio.h>
51271493Sdelphij#include <stdlib.h>
52271493Sdelphij#include <string.h>
53271493Sdelphij#include <syslog.h>
54271493Sdelphij#include <unistd.h>
55308635Ssephe#include <assert.h>
56271493Sdelphij
57271493Sdelphij#include "hv_kvp.h"
58308635Ssephe#include "hv_utilreg.h"
59271493Sdelphijtypedef uint8_t		__u8;
60271493Sdelphijtypedef uint16_t	__u16;
61271493Sdelphijtypedef uint32_t	__u32;
62271493Sdelphijtypedef uint64_t	__u64;
63271493Sdelphij
64318433Ssephe#define POOL_FILE_MODE	(S_IRUSR | S_IWUSR)
65318433Ssephe#define POOL_DIR_MODE	(POOL_FILE_MODE | S_IXUSR)
66318433Ssephe#define POOL_DIR	"/var/db/hyperv/pool"
67318433Ssephe
68271493Sdelphij/*
69271493Sdelphij * ENUM Data
70271493Sdelphij */
71271493Sdelphij
72271493Sdelphijenum key_index {
73271493Sdelphij	FullyQualifiedDomainName = 0,
74271493Sdelphij	IntegrationServicesVersion, /*This key is serviced in the kernel*/
75271493Sdelphij	NetworkAddressIPv4,
76271493Sdelphij	NetworkAddressIPv6,
77271493Sdelphij	OSBuildNumber,
78271493Sdelphij	OSName,
79271493Sdelphij	OSMajorVersion,
80271493Sdelphij	OSMinorVersion,
81271493Sdelphij	OSVersion,
82271493Sdelphij	ProcessorArchitecture
83271493Sdelphij};
84271493Sdelphij
85271493Sdelphij
86271493Sdelphijenum {
87271493Sdelphij	IPADDR = 0,
88271493Sdelphij	NETMASK,
89271493Sdelphij	GATEWAY,
90271493Sdelphij	DNS
91271493Sdelphij};
92271493Sdelphij
93271493Sdelphij
94271493Sdelphij/* Global Variables */
95271493Sdelphij
96271493Sdelphij/*
97271493Sdelphij * The structure for operation handlers.
98271493Sdelphij */
99271493Sdelphijstruct kvp_op_hdlr {
100271493Sdelphij	int	kvp_op_key;
101271493Sdelphij	void	(*kvp_op_init)(void);
102271493Sdelphij 	int	(*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
103271493Sdelphij};
104271493Sdelphij
105271493Sdelphijstatic struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
106271493Sdelphij
107271493Sdelphij/* OS information */
108271493Sdelphij
109271493Sdelphijstatic const char *os_name = "";
110271493Sdelphijstatic const char *os_major = "";
111271493Sdelphijstatic const char *os_minor = "";
112271493Sdelphijstatic const char *processor_arch;
113271493Sdelphijstatic const char *os_build;
114271493Sdelphijstatic const char *lic_version = "BSD Pre-Release version";
115271493Sdelphijstatic struct utsname uts_buf;
116271493Sdelphij
117271493Sdelphij/* Global flags */
118271493Sdelphijstatic int is_daemon = 1;
119271493Sdelphijstatic int is_debugging = 0;
120271493Sdelphij
121271493Sdelphij#define	KVP_LOG(priority, format, args...) do	{			\
122271493Sdelphij		if (is_debugging == 1) {				\
123271493Sdelphij			if (is_daemon == 1)				\
124271493Sdelphij				syslog(priority, format, ## args);	\
125271493Sdelphij			else						\
126271493Sdelphij				printf(format, ## args);		\
127271493Sdelphij		} else {						\
128271493Sdelphij			if (priority < LOG_DEBUG) {			\
129271493Sdelphij				if (is_daemon == 1)			\
130271493Sdelphij					syslog(priority, format, ## args);	\
131271493Sdelphij				else					\
132271493Sdelphij					printf(format, ## args);	\
133271493Sdelphij			}						\
134271493Sdelphij		}							\
135271493Sdelphij	} while(0)
136271493Sdelphij
137271493Sdelphij/*
138271493Sdelphij * For KVP pool file
139271493Sdelphij */
140271493Sdelphij
141271493Sdelphij#define MAX_FILE_NAME		100
142271493Sdelphij#define ENTRIES_PER_BLOCK	50
143271493Sdelphij
144271493Sdelphijstruct kvp_record {
145271493Sdelphij	char	key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
146271493Sdelphij	char	value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
147271493Sdelphij};
148271493Sdelphij
149271493Sdelphijstruct kvp_pool {
150271493Sdelphij	int			pool_fd;
151271493Sdelphij	int			num_blocks;
152271493Sdelphij	struct kvp_record	*records;
153271493Sdelphij	int			num_records;
154271493Sdelphij	char			fname[MAX_FILE_NAME];
155271493Sdelphij};
156271493Sdelphij
157271493Sdelphijstatic struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
158271493Sdelphij
159271493Sdelphij
160271493Sdelphijstatic void
161271493Sdelphijkvp_acquire_lock(int pool)
162271493Sdelphij{
163271493Sdelphij	struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
164271493Sdelphij
165271493Sdelphij	fl.l_pid = getpid();
166271493Sdelphij
167271493Sdelphij	if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) {
168271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
169271493Sdelphij		exit(EXIT_FAILURE);
170271493Sdelphij	}
171271493Sdelphij}
172271493Sdelphij
173271493Sdelphij
174271493Sdelphijstatic void
175271493Sdelphijkvp_release_lock(int pool)
176271493Sdelphij{
177271493Sdelphij	struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
178271493Sdelphij
179271493Sdelphij	fl.l_pid = getpid();
180271493Sdelphij
181271493Sdelphij	if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
182271493Sdelphij		perror("fcntl");
183271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
184271493Sdelphij		exit(EXIT_FAILURE);
185271493Sdelphij	}
186271493Sdelphij}
187271493Sdelphij
188271493Sdelphij
189271493Sdelphij/*
190271493Sdelphij * Write in-memory copy of KVP to pool files
191271493Sdelphij */
192271493Sdelphijstatic void
193271493Sdelphijkvp_update_file(int pool)
194271493Sdelphij{
195271493Sdelphij	FILE *filep;
196271493Sdelphij	size_t bytes_written;
197271493Sdelphij
198271493Sdelphij	kvp_acquire_lock(pool);
199271493Sdelphij
200271493Sdelphij	filep = fopen(kvp_pools[pool].fname, "w");
201271493Sdelphij	if (!filep) {
202271493Sdelphij		kvp_release_lock(pool);
203271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
204271493Sdelphij		exit(EXIT_FAILURE);
205271493Sdelphij	}
206271493Sdelphij
207271493Sdelphij	bytes_written = fwrite(kvp_pools[pool].records,
208271493Sdelphij		sizeof(struct kvp_record),
209271493Sdelphij		kvp_pools[pool].num_records, filep);
210271493Sdelphij
211271493Sdelphij	if (ferror(filep) || fclose(filep)) {
212271493Sdelphij		kvp_release_lock(pool);
213271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
214271493Sdelphij		exit(EXIT_FAILURE);
215271493Sdelphij	}
216271493Sdelphij
217271493Sdelphij	kvp_release_lock(pool);
218271493Sdelphij}
219271493Sdelphij
220271493Sdelphij
221271493Sdelphij/*
222271493Sdelphij * Read KVPs from pool files and store in memory
223271493Sdelphij */
224271493Sdelphijstatic void
225271493Sdelphijkvp_update_mem_state(int pool)
226271493Sdelphij{
227271493Sdelphij	FILE *filep;
228271493Sdelphij	size_t records_read = 0;
229271493Sdelphij	struct kvp_record *record = kvp_pools[pool].records;
230271493Sdelphij	struct kvp_record *readp;
231271493Sdelphij	int num_blocks = kvp_pools[pool].num_blocks;
232271493Sdelphij	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
233271493Sdelphij
234271493Sdelphij	kvp_acquire_lock(pool);
235271493Sdelphij
236271493Sdelphij	filep = fopen(kvp_pools[pool].fname, "r");
237271493Sdelphij	if (!filep) {
238271493Sdelphij		kvp_release_lock(pool);
239271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
240271493Sdelphij		exit(EXIT_FAILURE);
241271493Sdelphij	}
242271493Sdelphij	for ( ; ; )
243271493Sdelphij	{
244271493Sdelphij		readp = &record[records_read];
245271493Sdelphij		records_read += fread(readp, sizeof(struct kvp_record),
246271493Sdelphij			ENTRIES_PER_BLOCK * num_blocks,
247271493Sdelphij			filep);
248271493Sdelphij
249271493Sdelphij		if (ferror(filep)) {
250271493Sdelphij			KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
251271493Sdelphij			exit(EXIT_FAILURE);
252271493Sdelphij		}
253271493Sdelphij
254271493Sdelphij		if (!feof(filep)) {
255271493Sdelphij			/*
256271493Sdelphij			 * Have more data to read. Expand the memory.
257271493Sdelphij			 */
258271493Sdelphij			num_blocks++;
259271493Sdelphij			record = realloc(record, alloc_unit * num_blocks);
260271493Sdelphij
261271493Sdelphij			if (record == NULL) {
262271493Sdelphij				KVP_LOG(LOG_ERR, "malloc failed\n");
263271493Sdelphij				exit(EXIT_FAILURE);
264271493Sdelphij			}
265271493Sdelphij			continue;
266271493Sdelphij		}
267271493Sdelphij		break;
268271493Sdelphij	}
269271493Sdelphij
270271493Sdelphij	kvp_pools[pool].num_blocks = num_blocks;
271271493Sdelphij	kvp_pools[pool].records = record;
272271493Sdelphij	kvp_pools[pool].num_records = records_read;
273271493Sdelphij
274271493Sdelphij	fclose(filep);
275271493Sdelphij	kvp_release_lock(pool);
276271493Sdelphij}
277271493Sdelphij
278271493Sdelphij
279271493Sdelphijstatic int
280271493Sdelphijkvp_file_init(void)
281271493Sdelphij{
282271493Sdelphij	int fd;
283271493Sdelphij	FILE *filep;
284271493Sdelphij	size_t records_read;
285271493Sdelphij	char *fname;
286271493Sdelphij	struct kvp_record *record;
287271493Sdelphij	struct kvp_record *readp;
288271493Sdelphij	int num_blocks;
289271493Sdelphij	int i;
290271493Sdelphij	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
291271493Sdelphij
292318433Ssephe	if (mkdir(POOL_DIR, POOL_DIR_MODE) < 0 &&
293274383Sdelphij	    (errno != EEXIST && errno != EISDIR)) {
294272139Sdelphij		KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
295272139Sdelphij		exit(EXIT_FAILURE);
296271493Sdelphij	}
297318433Ssephe	chmod(POOL_DIR, POOL_DIR_MODE); /* fix old mistake */
298271493Sdelphij
299271493Sdelphij	for (i = 0; i < HV_KVP_POOL_COUNT; i++)
300271493Sdelphij	{
301271493Sdelphij		fname = kvp_pools[i].fname;
302271493Sdelphij		records_read = 0;
303271493Sdelphij		num_blocks = 1;
304271493Sdelphij		snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
305318433Ssephe		fd = open(fname, O_RDWR | O_CREAT, POOL_FILE_MODE);
306271493Sdelphij
307271493Sdelphij		if (fd == -1) {
308271493Sdelphij			return (1);
309271493Sdelphij		}
310318433Ssephe		fchmod(fd, POOL_FILE_MODE); /* fix old mistake */
311271493Sdelphij
312271493Sdelphij
313271493Sdelphij		filep = fopen(fname, "r");
314271493Sdelphij		if (!filep) {
315272140Sdelphij			close(fd);
316271493Sdelphij			return (1);
317271493Sdelphij		}
318271493Sdelphij
319271493Sdelphij		record = malloc(alloc_unit * num_blocks);
320271493Sdelphij		if (record == NULL) {
321272140Sdelphij			close(fd);
322271493Sdelphij			fclose(filep);
323271493Sdelphij			return (1);
324271493Sdelphij		}
325271493Sdelphij		for ( ; ; )
326271493Sdelphij		{
327271493Sdelphij			readp = &record[records_read];
328271493Sdelphij			records_read += fread(readp, sizeof(struct kvp_record),
329271493Sdelphij				ENTRIES_PER_BLOCK,
330271493Sdelphij				filep);
331271493Sdelphij
332271493Sdelphij			if (ferror(filep)) {
333271493Sdelphij				KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
334271493Sdelphij				    i);
335271493Sdelphij				exit(EXIT_FAILURE);
336271493Sdelphij			}
337271493Sdelphij
338271493Sdelphij			if (!feof(filep)) {
339271493Sdelphij				/*
340271493Sdelphij				 * More data to read.
341271493Sdelphij				 */
342271493Sdelphij				num_blocks++;
343271493Sdelphij				record = realloc(record, alloc_unit *
344271493Sdelphij					num_blocks);
345271493Sdelphij				if (record == NULL) {
346272140Sdelphij					close(fd);
347271493Sdelphij					fclose(filep);
348271493Sdelphij					return (1);
349271493Sdelphij				}
350271493Sdelphij				continue;
351271493Sdelphij			}
352271493Sdelphij			break;
353271493Sdelphij		}
354271493Sdelphij		kvp_pools[i].pool_fd = fd;
355271493Sdelphij		kvp_pools[i].num_blocks = num_blocks;
356271493Sdelphij		kvp_pools[i].records = record;
357271493Sdelphij		kvp_pools[i].num_records = records_read;
358271493Sdelphij		fclose(filep);
359271493Sdelphij	}
360271493Sdelphij
361271493Sdelphij	return (0);
362271493Sdelphij}
363271493Sdelphij
364271493Sdelphij
365271493Sdelphijstatic int
366271493Sdelphijkvp_key_delete(int pool, __u8 *key, int key_size)
367271493Sdelphij{
368271493Sdelphij	int i;
369271493Sdelphij	int j, k;
370271493Sdelphij	int num_records;
371271493Sdelphij	struct kvp_record *record;
372271493Sdelphij
373271493Sdelphij	KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool =  %d, "
374271493Sdelphij	    "key = %s\n", pool, key);
375271493Sdelphij
376271493Sdelphij	/* Update in-memory state */
377271493Sdelphij	kvp_update_mem_state(pool);
378271493Sdelphij
379271493Sdelphij	num_records = kvp_pools[pool].num_records;
380271493Sdelphij	record = kvp_pools[pool].records;
381271493Sdelphij
382271493Sdelphij	for (i = 0; i < num_records; i++)
383271493Sdelphij	{
384271493Sdelphij		if (memcmp(key, record[i].key, key_size)) {
385271493Sdelphij			continue;
386271493Sdelphij		}
387271493Sdelphij
388271493Sdelphij		KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
389271493Sdelphij		    pool);
390271493Sdelphij		/*
391271493Sdelphij		 * We found a match at the end; Just update the number of
392271493Sdelphij		 * entries and we are done.
393271493Sdelphij		 */
394271493Sdelphij		if (i == num_records) {
395271493Sdelphij			kvp_pools[pool].num_records--;
396271493Sdelphij			kvp_update_file(pool);
397271493Sdelphij			return (0);
398271493Sdelphij		}
399271493Sdelphij
400271493Sdelphij		/*
401271493Sdelphij		 * We found a match in the middle; Move the remaining
402271493Sdelphij		 * entries up.
403271493Sdelphij		 */
404271493Sdelphij		j = i;
405271493Sdelphij		k = j + 1;
406271493Sdelphij		for ( ; k < num_records; k++)
407271493Sdelphij		{
408271493Sdelphij			strcpy(record[j].key, record[k].key);
409271493Sdelphij			strcpy(record[j].value, record[k].value);
410271493Sdelphij			j++;
411271493Sdelphij		}
412271493Sdelphij		kvp_pools[pool].num_records--;
413271493Sdelphij		kvp_update_file(pool);
414271493Sdelphij		return (0);
415271493Sdelphij	}
416271493Sdelphij	KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
417271493Sdelphij	    pool);
418271493Sdelphij	return (1);
419271493Sdelphij}
420271493Sdelphij
421271493Sdelphij
422271493Sdelphijstatic int
423271493Sdelphijkvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
424271493Sdelphij    __u32 value_size)
425271493Sdelphij{
426271493Sdelphij	int i;
427271493Sdelphij	int num_records;
428271493Sdelphij	struct kvp_record *record;
429271493Sdelphij	int num_blocks;
430271493Sdelphij
431271493Sdelphij	KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool =  %d, "
432271493Sdelphij	    "key = %s, value = %s\n,", pool, key, value);
433271493Sdelphij
434271493Sdelphij	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
435271493Sdelphij	    (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
436271493Sdelphij		KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
437271493Sdelphij		return (1);
438271493Sdelphij	}
439271493Sdelphij
440271493Sdelphij	/* Update the in-memory state. */
441271493Sdelphij	kvp_update_mem_state(pool);
442271493Sdelphij
443271493Sdelphij	num_records = kvp_pools[pool].num_records;
444271493Sdelphij	record = kvp_pools[pool].records;
445271493Sdelphij	num_blocks = kvp_pools[pool].num_blocks;
446271493Sdelphij
447271493Sdelphij	for (i = 0; i < num_records; i++)
448271493Sdelphij	{
449271493Sdelphij		if (memcmp(key, record[i].key, key_size)) {
450271493Sdelphij			continue;
451271493Sdelphij		}
452271493Sdelphij
453271493Sdelphij		/*
454271493Sdelphij		 * Key exists. Just update the value and we are done.
455271493Sdelphij		 */
456271493Sdelphij		memcpy(record[i].value, value, value_size);
457271493Sdelphij		kvp_update_file(pool);
458271493Sdelphij		return (0);
459271493Sdelphij	}
460271493Sdelphij
461271493Sdelphij	/*
462271493Sdelphij	 * Key doesn't exist; Add a new KVP.
463271493Sdelphij	 */
464271493Sdelphij	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
465271493Sdelphij		/* Increase the size of the recodrd array. */
466271493Sdelphij		record = realloc(record, sizeof(struct kvp_record) *
467271493Sdelphij			ENTRIES_PER_BLOCK * (num_blocks + 1));
468271493Sdelphij
469271493Sdelphij		if (record == NULL) {
470271493Sdelphij			return (1);
471271493Sdelphij		}
472271493Sdelphij		kvp_pools[pool].num_blocks++;
473271493Sdelphij	}
474271493Sdelphij	memcpy(record[i].value, value, value_size);
475271493Sdelphij	memcpy(record[i].key, key, key_size);
476271493Sdelphij	kvp_pools[pool].records = record;
477271493Sdelphij	kvp_pools[pool].num_records++;
478271493Sdelphij	kvp_update_file(pool);
479271493Sdelphij	return (0);
480271493Sdelphij}
481271493Sdelphij
482271493Sdelphij
483271493Sdelphijstatic int
484271493Sdelphijkvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
485271493Sdelphij    int value_size)
486271493Sdelphij{
487271493Sdelphij	int i;
488271493Sdelphij	int num_records;
489271493Sdelphij	struct kvp_record *record;
490271493Sdelphij
491271493Sdelphij	KVP_LOG(LOG_DEBUG, "kvp_get_value: pool =  %d, key = %s\n,",
492271493Sdelphij	    pool, key);
493271493Sdelphij
494271493Sdelphij	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
495271493Sdelphij	    (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
496271493Sdelphij		return (1);
497271493Sdelphij	}
498271493Sdelphij
499271493Sdelphij	/* Update the in-memory state first. */
500271493Sdelphij	kvp_update_mem_state(pool);
501271493Sdelphij
502271493Sdelphij	num_records = kvp_pools[pool].num_records;
503271493Sdelphij	record = kvp_pools[pool].records;
504271493Sdelphij
505271493Sdelphij	for (i = 0; i < num_records; i++)
506271493Sdelphij	{
507271493Sdelphij		if (memcmp(key, record[i].key, key_size)) {
508271493Sdelphij			continue;
509271493Sdelphij		}
510271493Sdelphij
511271493Sdelphij		/* Found the key */
512271493Sdelphij		memcpy(value, record[i].value, value_size);
513271493Sdelphij		return (0);
514271493Sdelphij	}
515271493Sdelphij
516271493Sdelphij	return (1);
517271493Sdelphij}
518271493Sdelphij
519271493Sdelphij
520271493Sdelphijstatic int
521274370Sdelphijkvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size,
522271493Sdelphij    __u8 *value, int value_size)
523271493Sdelphij{
524271493Sdelphij	struct kvp_record *record;
525271493Sdelphij
526271493Sdelphij	KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
527274370Sdelphij	    pool, idx);
528271493Sdelphij
529271493Sdelphij	/* First update our in-memory state first. */
530271493Sdelphij	kvp_update_mem_state(pool);
531271493Sdelphij	record = kvp_pools[pool].records;
532271493Sdelphij
533271493Sdelphij	/* Index starts with 0 */
534274370Sdelphij	if (idx >= kvp_pools[pool].num_records) {
535271493Sdelphij		return (1);
536271493Sdelphij	}
537271493Sdelphij
538274370Sdelphij	memcpy(key, record[idx].key, key_size);
539274370Sdelphij	memcpy(value, record[idx].value, value_size);
540271493Sdelphij	return (0);
541271493Sdelphij}
542271493Sdelphij
543271493Sdelphij
544271493Sdelphijstatic void
545271493Sdelphijkvp_get_os_info(void)
546271493Sdelphij{
547271493Sdelphij	char *p;
548271493Sdelphij
549271493Sdelphij	uname(&uts_buf);
550271493Sdelphij	os_build = uts_buf.release;
551271493Sdelphij	os_name = uts_buf.sysname;
552271493Sdelphij	processor_arch = uts_buf.machine;
553271493Sdelphij
554271493Sdelphij	/*
555271493Sdelphij	 * Win7 host expects the build string to be of the form: x.y.z
556271493Sdelphij	 * Strip additional information we may have.
557271493Sdelphij	 */
558271493Sdelphij	p = strchr(os_build, '-');
559271493Sdelphij	if (p) {
560271493Sdelphij		*p = '\0';
561271493Sdelphij	}
562271493Sdelphij
563271493Sdelphij	/*
564271493Sdelphij	 * We don't have any other information about the FreeBSD os.
565271493Sdelphij	 */
566271493Sdelphij	return;
567271493Sdelphij}
568271493Sdelphij
569271493Sdelphij/*
570271493Sdelphij * Given the interface name, return the MAC address.
571271493Sdelphij */
572271493Sdelphijstatic char *
573271493Sdelphijkvp_if_name_to_mac(char *if_name)
574271493Sdelphij{
575271493Sdelphij	char *mac_addr = NULL;
576271493Sdelphij	struct ifaddrs *ifaddrs_ptr;
577271493Sdelphij	struct ifaddrs *head_ifaddrs_ptr;
578271493Sdelphij	struct sockaddr_dl *sdl;
579271493Sdelphij	int status;
580271493Sdelphij
581271493Sdelphij	status = getifaddrs(&ifaddrs_ptr);
582271493Sdelphij
583271493Sdelphij	if (status >= 0) {
584271493Sdelphij		head_ifaddrs_ptr = ifaddrs_ptr;
585271493Sdelphij		do {
586271493Sdelphij			sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
587271493Sdelphij			if ((sdl->sdl_type == IFT_ETHER) &&
588271493Sdelphij			    (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
589271493Sdelphij				mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
590271493Sdelphij				break;
591271493Sdelphij			}
592271493Sdelphij		} while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
593271493Sdelphij		freeifaddrs(head_ifaddrs_ptr);
594271493Sdelphij	}
595271493Sdelphij
596271493Sdelphij	return (mac_addr);
597271493Sdelphij}
598271493Sdelphij
599271493Sdelphij
600271493Sdelphij/*
601271493Sdelphij * Given the MAC address, return the interface name.
602271493Sdelphij */
603271493Sdelphijstatic char *
604271493Sdelphijkvp_mac_to_if_name(char *mac)
605271493Sdelphij{
606271493Sdelphij	char *if_name = NULL;
607271493Sdelphij	struct ifaddrs *ifaddrs_ptr;
608271493Sdelphij	struct ifaddrs *head_ifaddrs_ptr;
609271493Sdelphij	struct sockaddr_dl *sdl;
610271493Sdelphij	int status;
611272143Sdelphij	char *buf_ptr, *p;
612271493Sdelphij
613271493Sdelphij	status = getifaddrs(&ifaddrs_ptr);
614271493Sdelphij
615271493Sdelphij	if (status >= 0) {
616271493Sdelphij		head_ifaddrs_ptr = ifaddrs_ptr;
617271493Sdelphij		do {
618271493Sdelphij			sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
619271493Sdelphij			if (sdl->sdl_type == IFT_ETHER) {
620271493Sdelphij				buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
621272141Sdelphij				if (buf_ptr != NULL) {
622272143Sdelphij					for (p = buf_ptr; *p != '\0'; p++)
623272143Sdelphij						*p = toupper(*p);
624271493Sdelphij
625272141Sdelphij					if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
626272141Sdelphij						/* Caller will free the memory */
627272141Sdelphij						if_name = strdup(ifaddrs_ptr->ifa_name);
628272141Sdelphij						free(buf_ptr);
629272141Sdelphij						break;
630272141Sdelphij					} else
631272141Sdelphij						free(buf_ptr);
632271493Sdelphij				}
633271493Sdelphij			}
634271493Sdelphij		} while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
635271493Sdelphij		freeifaddrs(head_ifaddrs_ptr);
636271493Sdelphij	}
637271493Sdelphij	return (if_name);
638271493Sdelphij}
639271493Sdelphij
640271493Sdelphij
641271493Sdelphijstatic void
642271493Sdelphijkvp_process_ipconfig_file(char *cmd,
643271493Sdelphij    char *config_buf, size_t len,
644271493Sdelphij    size_t element_size, int offset)
645271493Sdelphij{
646271493Sdelphij	char buf[256];
647271493Sdelphij	char *p;
648271493Sdelphij	char *x;
649271493Sdelphij	FILE *file;
650271493Sdelphij
651271493Sdelphij	/*
652271493Sdelphij	 * First execute the command.
653271493Sdelphij	 */
654271493Sdelphij	file = popen(cmd, "r");
655271493Sdelphij	if (file == NULL) {
656271493Sdelphij		return;
657271493Sdelphij	}
658271493Sdelphij
659271493Sdelphij	if (offset == 0) {
660271493Sdelphij		memset(config_buf, 0, len);
661271493Sdelphij	}
662271493Sdelphij	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
663271493Sdelphij		if ((len - strlen(config_buf)) < (element_size + 1)) {
664271493Sdelphij			break;
665271493Sdelphij		}
666271493Sdelphij
667271493Sdelphij		x = strchr(p, '\n');
668271493Sdelphij		*x = '\0';
669271493Sdelphij		strlcat(config_buf, p, len);
670271493Sdelphij		strlcat(config_buf, ";", len);
671271493Sdelphij	}
672271493Sdelphij	pclose(file);
673271493Sdelphij}
674271493Sdelphij
675271493Sdelphij
676271493Sdelphijstatic void
677271493Sdelphijkvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer)
678271493Sdelphij{
679271493Sdelphij	char cmd[512];
680271493Sdelphij	char dhcp_info[128];
681271493Sdelphij	char *p;
682271493Sdelphij	FILE *file;
683271493Sdelphij
684271493Sdelphij	/*
685271493Sdelphij	 * Retrieve the IPV4 address of default gateway.
686271493Sdelphij	 */
687271493Sdelphij	snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
688271493Sdelphij
689271493Sdelphij	/*
690271493Sdelphij	 * Execute the command to gather gateway IPV4 info.
691271493Sdelphij	 */
692271493Sdelphij	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
693271493Sdelphij	    (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
694271493Sdelphij	/*
695271493Sdelphij	 * Retrieve the IPV6 address of default gateway.
696271493Sdelphij	 */
697308635Ssephe	snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }'", if_name);
698271493Sdelphij
699271493Sdelphij	/*
700271493Sdelphij	 * Execute the command to gather gateway IPV6 info.
701271493Sdelphij	 */
702271493Sdelphij	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
703271493Sdelphij	    (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
704271493Sdelphij	/*
705271493Sdelphij	 * we just invoke an external script to get the DNS info.
706271493Sdelphij	 *
707271493Sdelphij	 * Following is the expected format of the information from the script:
708271493Sdelphij	 *
709271493Sdelphij	 * ipaddr1 (nameserver1)
710271493Sdelphij	 * ipaddr2 (nameserver2)
711271493Sdelphij	 * .
712271493Sdelphij	 * .
713271493Sdelphij	 */
714271493Sdelphij	/* Scripts are stored in /usr/libexec/hyperv/ directory */
715271493Sdelphij	snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
716271493Sdelphij
717271493Sdelphij	/*
718271493Sdelphij	 * Execute the command to get DNS info.
719271493Sdelphij	 */
720271493Sdelphij	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
721271493Sdelphij	    (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
722271493Sdelphij
723271493Sdelphij	/*
724271493Sdelphij	 * Invoke an external script to get the DHCP state info.
725271493Sdelphij	 * The parameter to the script is the interface name.
726271493Sdelphij	 * Here is the expected output:
727271493Sdelphij	 *
728271493Sdelphij	 * Enabled: DHCP enabled.
729271493Sdelphij	 */
730271493Sdelphij
731271493Sdelphij
732271493Sdelphij	snprintf(cmd, sizeof(cmd), "%s %s",
733271493Sdelphij	    "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
734271493Sdelphij
735271493Sdelphij	file = popen(cmd, "r");
736271493Sdelphij	if (file == NULL) {
737271493Sdelphij		return;
738271493Sdelphij	}
739271493Sdelphij
740271493Sdelphij	p = fgets(dhcp_info, sizeof(dhcp_info), file);
741271493Sdelphij	if (p == NULL) {
742271493Sdelphij		pclose(file);
743271493Sdelphij		return;
744271493Sdelphij	}
745271493Sdelphij
746271493Sdelphij	if (!strncmp(p, "Enabled", 7)) {
747271493Sdelphij		buffer->dhcp_enabled = 1;
748271493Sdelphij	} else{
749271493Sdelphij		buffer->dhcp_enabled = 0;
750271493Sdelphij	}
751271493Sdelphij
752271493Sdelphij	pclose(file);
753271493Sdelphij}
754271493Sdelphij
755271493Sdelphij
756271493Sdelphijstatic unsigned int
757271493Sdelphijhweight32(unsigned int *w)
758271493Sdelphij{
759271493Sdelphij	unsigned int res = *w - ((*w >> 1) & 0x55555555);
760271493Sdelphij
761271493Sdelphij	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
762271493Sdelphij	res = (res + (res >> 4)) & 0x0F0F0F0F;
763271493Sdelphij	res = res + (res >> 8);
764271493Sdelphij	return ((res + (res >> 16)) & 0x000000FF);
765271493Sdelphij}
766271493Sdelphij
767271493Sdelphij
768271493Sdelphijstatic int
769271493Sdelphijkvp_process_ip_address(void *addrp,
770271493Sdelphij    int family, char *buffer,
771271493Sdelphij    int length, int *offset)
772271493Sdelphij{
773271493Sdelphij	struct sockaddr_in *addr;
774271493Sdelphij	struct sockaddr_in6 *addr6;
775271493Sdelphij	int addr_length;
776271493Sdelphij	char tmp[50];
777271493Sdelphij	const char *str;
778271493Sdelphij
779271493Sdelphij	if (family == AF_INET) {
780271493Sdelphij		addr = (struct sockaddr_in *)addrp;
781271493Sdelphij		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
782271493Sdelphij		addr_length = INET_ADDRSTRLEN;
783271493Sdelphij	} else {
784271493Sdelphij		addr6 = (struct sockaddr_in6 *)addrp;
785271493Sdelphij		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
786271493Sdelphij		addr_length = INET6_ADDRSTRLEN;
787271493Sdelphij	}
788271493Sdelphij
789271493Sdelphij	if ((length - *offset) < addr_length + 1) {
790308635Ssephe		return (EINVAL);
791271493Sdelphij	}
792271493Sdelphij	if (str == NULL) {
793271493Sdelphij		strlcpy(buffer, "inet_ntop failed\n", length);
794308635Ssephe		return (errno);
795271493Sdelphij	}
796271493Sdelphij	if (*offset == 0) {
797271493Sdelphij		strlcpy(buffer, tmp, length);
798271493Sdelphij	} else{
799271493Sdelphij		strlcat(buffer, tmp, length);
800271493Sdelphij	}
801271493Sdelphij	strlcat(buffer, ";", length);
802271493Sdelphij
803271493Sdelphij	*offset += strlen(str) + 1;
804271493Sdelphij	return (0);
805271493Sdelphij}
806271493Sdelphij
807271493Sdelphij
808271493Sdelphijstatic int
809271493Sdelphijkvp_get_ip_info(int family, char *if_name, int op,
810271493Sdelphij    void *out_buffer, size_t length)
811271493Sdelphij{
812271493Sdelphij	struct ifaddrs *ifap;
813271493Sdelphij	struct ifaddrs *curp;
814271493Sdelphij	int offset = 0;
815271493Sdelphij	int sn_offset = 0;
816271493Sdelphij	int error = 0;
817271493Sdelphij	char *buffer;
818271493Sdelphij	size_t buffer_length;
819286972Spfg	struct hv_kvp_ipaddr_value *ip_buffer = NULL;
820271493Sdelphij	char cidr_mask[5];
821271493Sdelphij	int weight;
822271493Sdelphij	int i;
823271493Sdelphij	unsigned int *w = NULL;
824271493Sdelphij	char *sn_str;
825271493Sdelphij	size_t sn_str_length;
826271493Sdelphij	struct sockaddr_in6 *addr6;
827271493Sdelphij
828271493Sdelphij	if (op == HV_KVP_OP_ENUMERATE) {
829271493Sdelphij		buffer = out_buffer;
830271493Sdelphij		buffer_length = length;
831271493Sdelphij	} else {
832271493Sdelphij		ip_buffer = out_buffer;
833271493Sdelphij		buffer = (char *)ip_buffer->ip_addr;
834271493Sdelphij		buffer_length = sizeof(ip_buffer->ip_addr);
835271493Sdelphij		ip_buffer->addr_family = 0;
836271493Sdelphij	}
837271493Sdelphij
838271493Sdelphij	if (getifaddrs(&ifap)) {
839271493Sdelphij		strlcpy(buffer, "getifaddrs failed\n", buffer_length);
840308635Ssephe		return (errno);
841271493Sdelphij	}
842271493Sdelphij
843271493Sdelphij	curp = ifap;
844271493Sdelphij	while (curp != NULL) {
845271493Sdelphij		if (curp->ifa_addr == NULL) {
846271493Sdelphij			curp = curp->ifa_next;
847271493Sdelphij			continue;
848271493Sdelphij		}
849271493Sdelphij
850271493Sdelphij		if ((if_name != NULL) &&
851271493Sdelphij		    (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
852271493Sdelphij			/*
853271493Sdelphij			 * We want info about a specific interface;
854271493Sdelphij			 * just continue.
855271493Sdelphij			 */
856271493Sdelphij			curp = curp->ifa_next;
857271493Sdelphij			continue;
858271493Sdelphij		}
859271493Sdelphij
860271493Sdelphij		/*
861271493Sdelphij		 * We support two address families: AF_INET and AF_INET6.
862271493Sdelphij		 * If family value is 0, we gather both supported
863271493Sdelphij		 * address families; if not we gather info on
864271493Sdelphij		 * the specified address family.
865271493Sdelphij		 */
866271493Sdelphij		if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
867271493Sdelphij			curp = curp->ifa_next;
868271493Sdelphij			continue;
869271493Sdelphij		}
870271493Sdelphij		if ((curp->ifa_addr->sa_family != AF_INET) &&
871271493Sdelphij		    (curp->ifa_addr->sa_family != AF_INET6)) {
872271493Sdelphij			curp = curp->ifa_next;
873271493Sdelphij			continue;
874271493Sdelphij		}
875271493Sdelphij
876271493Sdelphij		if (op == HV_KVP_OP_GET_IP_INFO) {
877271493Sdelphij			/*
878271493Sdelphij			 * Get the info other than the IP address.
879271493Sdelphij			 */
880271493Sdelphij			if (curp->ifa_addr->sa_family == AF_INET) {
881271493Sdelphij				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
882271493Sdelphij
883271493Sdelphij				/*
884271493Sdelphij				 * Get subnet info.
885271493Sdelphij				 */
886271493Sdelphij				error = kvp_process_ip_address(
887271493Sdelphij					curp->ifa_netmask,
888271493Sdelphij					AF_INET,
889271493Sdelphij					(char *)
890271493Sdelphij					ip_buffer->sub_net,
891271493Sdelphij					length,
892271493Sdelphij					&sn_offset);
893271493Sdelphij				if (error) {
894271493Sdelphij					goto kvp_get_ip_info_ipaddr;
895271493Sdelphij				}
896271493Sdelphij			} else {
897271493Sdelphij				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
898271493Sdelphij
899271493Sdelphij				/*
900271493Sdelphij				 * Get subnet info in CIDR format.
901271493Sdelphij				 */
902271493Sdelphij				weight = 0;
903271493Sdelphij				sn_str = (char *)ip_buffer->sub_net;
904271493Sdelphij				sn_str_length = sizeof(ip_buffer->sub_net);
905271493Sdelphij				addr6 = (struct sockaddr_in6 *)(uintptr_t)
906271493Sdelphij				    curp->ifa_netmask;
907271493Sdelphij				w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
908271493Sdelphij
909271493Sdelphij				for (i = 0; i < 4; i++)
910271493Sdelphij				{
911271493Sdelphij					weight += hweight32(&w[i]);
912271493Sdelphij				}
913271493Sdelphij
914271493Sdelphij				snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
915271493Sdelphij				if ((length - sn_offset) <
916271493Sdelphij				    (strlen(cidr_mask) + 1)) {
917271493Sdelphij					goto kvp_get_ip_info_ipaddr;
918271493Sdelphij				}
919271493Sdelphij
920271493Sdelphij				if (sn_offset == 0) {
921271493Sdelphij					strlcpy(sn_str, cidr_mask, sn_str_length);
922271493Sdelphij				} else{
923271493Sdelphij					strlcat(sn_str, cidr_mask, sn_str_length);
924271493Sdelphij				}
925271493Sdelphij				strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
926271493Sdelphij				sn_offset += strlen(sn_str) + 1;
927271493Sdelphij			}
928271493Sdelphij
929271493Sdelphij			/*
930271493Sdelphij			 * Collect other ip configuration info.
931271493Sdelphij			 */
932271493Sdelphij			kvp_get_ipconfig_info(if_name, ip_buffer);
933271493Sdelphij		}
934271493Sdelphij
935271493Sdelphijkvp_get_ip_info_ipaddr:
936271493Sdelphij		error = kvp_process_ip_address(curp->ifa_addr,
937271493Sdelphij			curp->ifa_addr->sa_family,
938271493Sdelphij			buffer,
939271493Sdelphij			length, &offset);
940271493Sdelphij		if (error) {
941271493Sdelphij			goto kvp_get_ip_info_done;
942271493Sdelphij		}
943271493Sdelphij
944271493Sdelphij		curp = curp->ifa_next;
945271493Sdelphij	}
946271493Sdelphij
947271493Sdelphijkvp_get_ip_info_done:
948271493Sdelphij	freeifaddrs(ifap);
949271493Sdelphij	return (error);
950271493Sdelphij}
951271493Sdelphij
952271493Sdelphij
953271493Sdelphijstatic int
954271493Sdelphijkvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
955271493Sdelphij{
956271493Sdelphij	int ret;
957271493Sdelphij
958271493Sdelphij	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
959271493Sdelphij
960271493Sdelphij	if (ret < 0) {
961308635Ssephe		return (EIO);
962271493Sdelphij	}
963271493Sdelphij
964271493Sdelphij	return (0);
965271493Sdelphij}
966271493Sdelphij
967271493Sdelphij
968271493Sdelphijstatic int
969271493Sdelphijkvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
970271493Sdelphij{
971271493Sdelphij	int error = 0;
972271493Sdelphij	char if_file[128];
973271493Sdelphij	FILE *file;
974271493Sdelphij	char cmd[512];
975271493Sdelphij	char *mac_addr;
976271493Sdelphij
977271493Sdelphij	/*
978271493Sdelphij	 * FreeBSD - Configuration File
979271493Sdelphij	 */
980271493Sdelphij	snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
981271493Sdelphij	    "hv_set_ip_data");
982271493Sdelphij	file = fopen(if_file, "w");
983271493Sdelphij
984271493Sdelphij	if (file == NULL) {
985271493Sdelphij		KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
986308635Ssephe		return (errno);
987271493Sdelphij	}
988271493Sdelphij
989271493Sdelphij	/*
990271493Sdelphij	 * Write out the MAC address.
991271493Sdelphij	 */
992271493Sdelphij
993271493Sdelphij	mac_addr = kvp_if_name_to_mac(if_name);
994271493Sdelphij	if (mac_addr == NULL) {
995308635Ssephe		error = EINVAL;
996271493Sdelphij		goto kvp_set_ip_info_error;
997271493Sdelphij	}
998271493Sdelphij	/* MAC Address */
999271493Sdelphij	error = kvp_write_file(file, "HWADDR", "", mac_addr);
1000271493Sdelphij	if (error) {
1001271493Sdelphij		goto kvp_set_ip_info_error;
1002271493Sdelphij	}
1003271493Sdelphij
1004271493Sdelphij	/* Interface Name  */
1005271493Sdelphij	error = kvp_write_file(file, "IF_NAME", "", if_name);
1006271493Sdelphij	if (error) {
1007271493Sdelphij		goto kvp_set_ip_info_error;
1008271493Sdelphij	}
1009271493Sdelphij
1010271493Sdelphij	/* IP Address  */
1011271493Sdelphij	error = kvp_write_file(file, "IP_ADDR", "",
1012271493Sdelphij	    (char *)new_val->ip_addr);
1013271493Sdelphij	if (error) {
1014271493Sdelphij		goto kvp_set_ip_info_error;
1015271493Sdelphij	}
1016271493Sdelphij
1017271493Sdelphij	/* Subnet Mask */
1018271493Sdelphij	error = kvp_write_file(file, "SUBNET", "",
1019271493Sdelphij	    (char *)new_val->sub_net);
1020271493Sdelphij	if (error) {
1021271493Sdelphij		goto kvp_set_ip_info_error;
1022271493Sdelphij	}
1023271493Sdelphij
1024271493Sdelphij
1025271493Sdelphij	/* Gateway */
1026271493Sdelphij	error = kvp_write_file(file, "GATEWAY", "",
1027271493Sdelphij	    (char *)new_val->gate_way);
1028271493Sdelphij	if (error) {
1029271493Sdelphij		goto kvp_set_ip_info_error;
1030271493Sdelphij	}
1031271493Sdelphij
1032271493Sdelphij	/* DNS */
1033271493Sdelphij	error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1034271493Sdelphij	if (error) {
1035271493Sdelphij		goto kvp_set_ip_info_error;
1036271493Sdelphij	}
1037271493Sdelphij
1038271493Sdelphij	/* DHCP */
1039271493Sdelphij	if (new_val->dhcp_enabled) {
1040271493Sdelphij		error = kvp_write_file(file, "DHCP", "", "1");
1041271493Sdelphij	} else{
1042271493Sdelphij		error = kvp_write_file(file, "DHCP", "", "0");
1043271493Sdelphij	}
1044271493Sdelphij
1045271493Sdelphij	if (error) {
1046271493Sdelphij		goto kvp_set_ip_info_error;
1047271493Sdelphij	}
1048271493Sdelphij
1049271493Sdelphij	free(mac_addr);
1050271493Sdelphij	fclose(file);
1051271493Sdelphij
1052271493Sdelphij	/*
1053271493Sdelphij	 * Invoke the external script with the populated
1054271493Sdelphij	 * configuration file.
1055271493Sdelphij	 */
1056271493Sdelphij
1057271493Sdelphij	snprintf(cmd, sizeof(cmd), "%s %s",
1058271493Sdelphij	    "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1059271493Sdelphij	system(cmd);
1060271493Sdelphij	return (0);
1061271493Sdelphij
1062271493Sdelphijkvp_set_ip_info_error:
1063271493Sdelphij	KVP_LOG(LOG_ERR, "Failed to write config file\n");
1064271493Sdelphij	free(mac_addr);
1065271493Sdelphij	fclose(file);
1066271493Sdelphij	return (error);
1067271493Sdelphij}
1068271493Sdelphij
1069271493Sdelphij
1070271493Sdelphijstatic int
1071271493Sdelphijkvp_get_domain_name(char *buffer, int length)
1072271493Sdelphij{
1073271493Sdelphij	struct addrinfo hints, *info;
1074271493Sdelphij	int error = 0;
1075271493Sdelphij
1076271493Sdelphij	gethostname(buffer, length);
1077271493Sdelphij	memset(&hints, 0, sizeof(hints));
1078271493Sdelphij	hints.ai_family = AF_INET;    /* Get only ipv4 addrinfo. */
1079271493Sdelphij	hints.ai_socktype = SOCK_STREAM;
1080271493Sdelphij	hints.ai_flags = AI_CANONNAME;
1081271493Sdelphij
1082271493Sdelphij	error = getaddrinfo(buffer, NULL, &hints, &info);
1083271493Sdelphij	if (error != 0) {
1084271493Sdelphij		strlcpy(buffer, "getaddrinfo failed\n", length);
1085271493Sdelphij		return (error);
1086271493Sdelphij	}
1087271493Sdelphij	strlcpy(buffer, info->ai_canonname, length);
1088271493Sdelphij	freeaddrinfo(info);
1089271493Sdelphij	return (error);
1090271493Sdelphij}
1091271493Sdelphij
1092271493Sdelphij
1093271493Sdelphijstatic int
1094271493Sdelphijkvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1095271493Sdelphij{
1096271493Sdelphij	struct hv_kvp_ipaddr_value *ip_val;
1097271493Sdelphij	char *if_name;
1098308635Ssephe	int error = 0;
1099271493Sdelphij
1100271493Sdelphij	assert(op_msg != NULL);
1101271493Sdelphij	KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1102271493Sdelphij
1103271493Sdelphij	ip_val = &op_msg->body.kvp_ip_val;
1104308635Ssephe	op_msg->hdr.error = HV_S_OK;
1105271493Sdelphij
1106271493Sdelphij	if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1107271493Sdelphij
1108271493Sdelphij	if (if_name == NULL) {
1109271493Sdelphij		/* No interface found with the mac address. */
1110308635Ssephe		op_msg->hdr.error = HV_E_FAIL;
1111271493Sdelphij		goto kvp_op_getipinfo_done;
1112271493Sdelphij	}
1113271493Sdelphij
1114308635Ssephe	error = kvp_get_ip_info(0, if_name,
1115271493Sdelphij	    HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1116308635Ssephe	if (error)
1117308635Ssephe		op_msg->hdr.error = HV_E_FAIL;
1118271493Sdelphij	free(if_name);
1119271493Sdelphij
1120271493Sdelphijkvp_op_getipinfo_done:
1121308635Ssephe	return (error);
1122271493Sdelphij}
1123271493Sdelphij
1124271493Sdelphij
1125271493Sdelphijstatic int
1126271493Sdelphijkvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1127271493Sdelphij{
1128271493Sdelphij	struct hv_kvp_ipaddr_value *ip_val;
1129271493Sdelphij	char *if_name;
1130308635Ssephe	int error = 0;
1131271493Sdelphij
1132271493Sdelphij	assert(op_msg != NULL);
1133271493Sdelphij	KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1134271493Sdelphij
1135271493Sdelphij	ip_val = &op_msg->body.kvp_ip_val;
1136308635Ssephe	op_msg->hdr.error = HV_S_OK;
1137271493Sdelphij
1138271493Sdelphij	if_name = (char *)ip_val->adapter_id;
1139271493Sdelphij
1140271493Sdelphij	if (if_name == NULL) {
1141271493Sdelphij		/* No adapter provided. */
1142308635Ssephe		op_msg->hdr.error = HV_GUID_NOTFOUND;
1143271493Sdelphij		goto kvp_op_setipinfo_done;
1144271493Sdelphij	}
1145271493Sdelphij
1146308635Ssephe	error = kvp_set_ip_info(if_name, ip_val);
1147308635Ssephe	if (error)
1148308635Ssephe		op_msg->hdr.error = HV_E_FAIL;
1149271493Sdelphijkvp_op_setipinfo_done:
1150308635Ssephe	return (error);
1151271493Sdelphij}
1152271493Sdelphij
1153271493Sdelphij
1154271493Sdelphijstatic int
1155271493Sdelphijkvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1156271493Sdelphij{
1157271493Sdelphij	struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1158271493Sdelphij	int error = 0;
1159271493Sdelphij	int op_pool;
1160271493Sdelphij
1161271493Sdelphij	assert(op_msg != NULL);
1162271493Sdelphij	assert(op_hdlr != NULL);
1163271493Sdelphij
1164271493Sdelphij	op_pool = op_msg->hdr.kvp_hdr.pool;
1165308635Ssephe	op_msg->hdr.error = HV_S_OK;
1166271493Sdelphij
1167271493Sdelphij	switch(op_hdlr->kvp_op_key) {
1168271493Sdelphij	case HV_KVP_OP_SET:
1169271493Sdelphij		if (op_pool == HV_KVP_POOL_AUTO) {
1170271493Sdelphij			/* Auto Pool is not writeable from host side. */
1171271493Sdelphij			error = 1;
1172271493Sdelphij			KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1173271493Sdelphij			    op_pool);
1174271493Sdelphij		} else {
1175271493Sdelphij			error = kvp_key_add_or_modify(op_pool,
1176271493Sdelphij			    op_msg->body.kvp_set.data.key,
1177271493Sdelphij			    op_msg->body.kvp_set.data.key_size,
1178271493Sdelphij			    op_msg->body.kvp_set.data.msg_value.value,
1179271493Sdelphij			    op_msg->body.kvp_set.data.value_size);
1180271493Sdelphij		}
1181271493Sdelphij		break;
1182271493Sdelphij
1183271493Sdelphij	case HV_KVP_OP_GET:
1184271493Sdelphij		error = kvp_get_value(op_pool,
1185271493Sdelphij		    op_msg->body.kvp_get.data.key,
1186271493Sdelphij		    op_msg->body.kvp_get.data.key_size,
1187271493Sdelphij		    op_msg->body.kvp_get.data.msg_value.value,
1188271493Sdelphij		    op_msg->body.kvp_get.data.value_size);
1189271493Sdelphij		break;
1190271493Sdelphij
1191271493Sdelphij	case HV_KVP_OP_DELETE:
1192271493Sdelphij		if (op_pool == HV_KVP_POOL_AUTO) {
1193271493Sdelphij			/* Auto Pool is not writeable from host side. */
1194271493Sdelphij			error = 1;
1195271493Sdelphij			KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1196271493Sdelphij			    op_pool);
1197271493Sdelphij		} else {
1198271493Sdelphij			error = kvp_key_delete(op_pool,
1199271493Sdelphij			    op_msg->body.kvp_delete.key,
1200271493Sdelphij			    op_msg->body.kvp_delete.key_size);
1201271493Sdelphij		}
1202271493Sdelphij		break;
1203271493Sdelphij
1204271493Sdelphij	default:
1205271493Sdelphij		break;
1206271493Sdelphij	}
1207271493Sdelphij
1208271493Sdelphij	if (error != 0)
1209308635Ssephe		op_msg->hdr.error = HV_S_CONT;
1210271493Sdelphij	return(error);
1211271493Sdelphij}
1212271493Sdelphij
1213271493Sdelphij
1214271493Sdelphijstatic int
1215271493Sdelphijkvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1216271493Sdelphij{
1217271493Sdelphij	char *key_name, *key_value;
1218271493Sdelphij	int error = 0;
1219271493Sdelphij	int op_pool;
1220271493Sdelphij	int op;
1221271493Sdelphij
1222271493Sdelphij	assert(op_msg != NULL);
1223271493Sdelphij
1224271493Sdelphij	op = op_msg->hdr.kvp_hdr.operation;
1225271493Sdelphij	op_pool = op_msg->hdr.kvp_hdr.pool;
1226308635Ssephe	op_msg->hdr.error = HV_S_OK;
1227271493Sdelphij
1228271493Sdelphij	/*
1229271493Sdelphij	 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1230271493Sdelphij	 * pool and return the KVP according to the index requested.
1231271493Sdelphij	 */
1232271493Sdelphij	if (op_pool != HV_KVP_POOL_AUTO) {
1233271493Sdelphij		if (kvp_pool_enumerate(op_pool,
1234271493Sdelphij		    op_msg->body.kvp_enum_data.index,
1235271493Sdelphij		    op_msg->body.kvp_enum_data.data.key,
1236271493Sdelphij		    HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1237271493Sdelphij		    op_msg->body.kvp_enum_data.data.msg_value.value,
1238271493Sdelphij		    HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1239308635Ssephe			op_msg->hdr.error = HV_S_CONT;
1240271493Sdelphij			error = -1;
1241271493Sdelphij		}
1242271493Sdelphij		goto kvp_op_enumerate_done;
1243271493Sdelphij	}
1244271493Sdelphij
1245271493Sdelphij	key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1246271493Sdelphij	key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1247271493Sdelphij
1248271493Sdelphij	switch (op_msg->body.kvp_enum_data.index)
1249271493Sdelphij	{
1250271493Sdelphij	case FullyQualifiedDomainName:
1251271493Sdelphij		kvp_get_domain_name(key_value,
1252271493Sdelphij		    HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1253271493Sdelphij		strcpy(key_name, "FullyQualifiedDomainName");
1254271493Sdelphij		break;
1255271493Sdelphij
1256271493Sdelphij	case IntegrationServicesVersion:
1257271493Sdelphij		strcpy(key_name, "IntegrationServicesVersion");
1258272142Sdelphij		strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1259271493Sdelphij		break;
1260271493Sdelphij
1261271493Sdelphij	case NetworkAddressIPv4:
1262271493Sdelphij		kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1263271493Sdelphij		    key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1264271493Sdelphij		strcpy(key_name, "NetworkAddressIPv4");
1265271493Sdelphij		break;
1266271493Sdelphij
1267271493Sdelphij	case NetworkAddressIPv6:
1268271493Sdelphij		kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1269271493Sdelphij		    key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1270271493Sdelphij		strcpy(key_name, "NetworkAddressIPv6");
1271271493Sdelphij		break;
1272271493Sdelphij
1273271493Sdelphij	case OSBuildNumber:
1274272142Sdelphij		strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1275271493Sdelphij		strcpy(key_name, "OSBuildNumber");
1276271493Sdelphij		break;
1277271493Sdelphij
1278271493Sdelphij	case OSName:
1279272142Sdelphij		strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1280271493Sdelphij		strcpy(key_name, "OSName");
1281271493Sdelphij		break;
1282271493Sdelphij
1283271493Sdelphij	case OSMajorVersion:
1284272142Sdelphij		strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1285271493Sdelphij		strcpy(key_name, "OSMajorVersion");
1286271493Sdelphij		break;
1287271493Sdelphij
1288271493Sdelphij	case OSMinorVersion:
1289272142Sdelphij		strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1290271493Sdelphij		strcpy(key_name, "OSMinorVersion");
1291271493Sdelphij		break;
1292271493Sdelphij
1293271493Sdelphij	case OSVersion:
1294272142Sdelphij		strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1295271493Sdelphij		strcpy(key_name, "OSVersion");
1296271493Sdelphij		break;
1297271493Sdelphij
1298271493Sdelphij	case ProcessorArchitecture:
1299272142Sdelphij		strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1300271493Sdelphij		strcpy(key_name, "ProcessorArchitecture");
1301271493Sdelphij		break;
1302271493Sdelphij
1303271493Sdelphij	default:
1304271493Sdelphij#ifdef DEBUG
1305271493Sdelphij		KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1306271493Sdelphij		    op_msg->body.kvp_enum_data.index);
1307271493Sdelphij#endif
1308308635Ssephe		op_msg->hdr.error = HV_S_CONT;
1309271493Sdelphij		error = -1;
1310271493Sdelphij		break;
1311271493Sdelphij	}
1312271493Sdelphij
1313271493Sdelphijkvp_op_enumerate_done:
1314308635Ssephe	if (error != 0)
1315308635Ssephe		op_msg->hdr.error = HV_S_CONT;
1316271493Sdelphij	return(error);
1317271493Sdelphij}
1318271493Sdelphij
1319271493Sdelphij
1320271493Sdelphij/*
1321271493Sdelphij * Load handler, and call init routine if provided.
1322271493Sdelphij */
1323271493Sdelphijstatic int
1324271493Sdelphijkvp_op_load(int key, void (*init)(void),
1325271493Sdelphij	    int (*exec)(struct hv_kvp_msg *, void *))
1326271493Sdelphij{
1327271493Sdelphij	int error = 0;
1328271493Sdelphij
1329271493Sdelphij	if (key < 0 || key >= HV_KVP_OP_COUNT) {
1330271493Sdelphij		KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1331271493Sdelphij		error = -1;
1332271493Sdelphij		goto kvp_op_load_done;
1333271493Sdelphij	}
1334271493Sdelphij
1335271493Sdelphij	kvp_op_hdlrs[key].kvp_op_key = key;
1336271493Sdelphij	kvp_op_hdlrs[key].kvp_op_init = init;
1337271493Sdelphij	kvp_op_hdlrs[key].kvp_op_exec = exec;
1338271493Sdelphij
1339271493Sdelphij	if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1340271493Sdelphij		kvp_op_hdlrs[key].kvp_op_init();
1341271493Sdelphij
1342271493Sdelphijkvp_op_load_done:
1343271493Sdelphij	return(error);
1344271493Sdelphij}
1345271493Sdelphij
1346271493Sdelphij
1347271493Sdelphij/*
1348271493Sdelphij * Initialize the operation hanlders.
1349271493Sdelphij */
1350271493Sdelphijstatic int
1351271493Sdelphijkvp_ops_init(void)
1352271493Sdelphij{
1353271493Sdelphij	int i;
1354271493Sdelphij
1355271493Sdelphij	/* Set the initial values. */
1356271493Sdelphij	for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1357271493Sdelphij		kvp_op_hdlrs[i].kvp_op_key = -1;
1358271493Sdelphij		kvp_op_hdlrs[i].kvp_op_init = NULL;
1359271493Sdelphij		kvp_op_hdlrs[i].kvp_op_exec = NULL;
1360271493Sdelphij	}
1361271493Sdelphij
1362271493Sdelphij	return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1363271493Sdelphij	    kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1364271493Sdelphij	    kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1365271493Sdelphij	    kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1366271493Sdelphij	        kvp_op_enumerate) |
1367271493Sdelphij	    kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1368271493Sdelphij	    kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1369271493Sdelphij}
1370271493Sdelphij
1371271493Sdelphij
1372271493Sdelphijint
1373271493Sdelphijmain(int argc, char *argv[])
1374271493Sdelphij{
1375271493Sdelphij	struct hv_kvp_msg *hv_kvp_dev_buf;
1376271493Sdelphij	struct hv_kvp_msg *hv_msg;
1377271493Sdelphij	struct pollfd hv_kvp_poll_fd[1];
1378271493Sdelphij	int op, pool;
1379271493Sdelphij	int hv_kvp_dev_fd, error, len, r;
1380271493Sdelphij	int ch;
1381271493Sdelphij
1382271493Sdelphij	while ((ch = getopt(argc, argv, "dn")) != -1) {
1383271493Sdelphij		switch (ch) {
1384271493Sdelphij		case 'n':
1385271493Sdelphij			/* Run as regular process for debugging purpose. */
1386271493Sdelphij			is_daemon = 0;
1387271493Sdelphij			break;
1388271493Sdelphij		case 'd':
1389271493Sdelphij			/* Generate debugging output */
1390271493Sdelphij			is_debugging = 1;
1391271493Sdelphij			break;
1392271493Sdelphij		default:
1393271493Sdelphij			break;
1394271493Sdelphij		}
1395271493Sdelphij	}
1396271493Sdelphij
1397271493Sdelphij	openlog("HV_KVP", 0, LOG_USER);
1398271493Sdelphij
1399271493Sdelphij	/* Become daemon first. */
1400271493Sdelphij	if (is_daemon == 1)
1401271493Sdelphij		daemon(1, 0);
1402271493Sdelphij	else
1403271493Sdelphij		KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1404271493Sdelphij
1405271493Sdelphij	KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1406271493Sdelphij
1407271493Sdelphij	/* Communication buffer hv_kvp_dev_buf */
1408271493Sdelphij	hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1409271493Sdelphij	/* Buffer for daemon internal use */
1410271493Sdelphij	hv_msg = malloc(sizeof(*hv_msg));
1411271493Sdelphij
1412271493Sdelphij	/* Memory allocation failed */
1413271493Sdelphij	if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1414271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1415271493Sdelphij		exit(EXIT_FAILURE);
1416271493Sdelphij	}
1417271493Sdelphij
1418271493Sdelphij	/* Initialize op handlers */
1419271493Sdelphij	if (kvp_ops_init() != 0) {
1420271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1421271493Sdelphij		exit(EXIT_FAILURE);
1422271493Sdelphij	}
1423271493Sdelphij
1424271493Sdelphij	if (kvp_file_init()) {
1425271493Sdelphij		KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1426271493Sdelphij		exit(EXIT_FAILURE);
1427271493Sdelphij	}
1428271493Sdelphij
1429271493Sdelphij	/* Open the Character Device */
1430271493Sdelphij	hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1431271493Sdelphij
1432271493Sdelphij	if (hv_kvp_dev_fd < 0) {
1433271493Sdelphij		KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1434271493Sdelphij		    errno, strerror(errno));
1435271493Sdelphij		exit(EXIT_FAILURE);
1436271493Sdelphij	}
1437271493Sdelphij
1438271493Sdelphij	/* Initialize the struct for polling the char device */
1439271493Sdelphij	hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1440271493Sdelphij	hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1441271493Sdelphij
1442271493Sdelphij	/* Register the daemon to the KVP driver */
1443271493Sdelphij	memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1444271493Sdelphij	hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1445271493Sdelphij	len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1446271493Sdelphij
1447271493Sdelphij
1448271493Sdelphij	for (;;) {
1449293653Ssephe		r = poll (hv_kvp_poll_fd, 1, INFTIM);
1450271493Sdelphij
1451271493Sdelphij		KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1452271493Sdelphij		    r, hv_kvp_poll_fd[0].revents);
1453271493Sdelphij
1454271493Sdelphij		if (r == 0 || (r < 0 && errno == EAGAIN) ||
1455271493Sdelphij		    (r < 0 && errno == EINTR)) {
1456271493Sdelphij			/* Nothing to read */
1457271493Sdelphij			continue;
1458271493Sdelphij		}
1459271493Sdelphij
1460271493Sdelphij		if (r < 0) {
1461271493Sdelphij			/*
1462271493Sdelphij			 * For pread return failure other than EAGAIN,
1463271493Sdelphij			 * we want to exit.
1464271493Sdelphij			 */
1465271493Sdelphij			KVP_LOG(LOG_ERR, "Poll failed.\n");
1466271493Sdelphij			perror("poll");
1467271493Sdelphij			exit(EIO);
1468271493Sdelphij		}
1469271493Sdelphij
1470271493Sdelphij		/* Read from character device */
1471271493Sdelphij		len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1472271493Sdelphij		    sizeof(*hv_kvp_dev_buf), 0);
1473271493Sdelphij
1474271493Sdelphij		if (len < 0) {
1475271493Sdelphij			KVP_LOG(LOG_ERR, "Read failed.\n");
1476271493Sdelphij			perror("pread");
1477271493Sdelphij			exit(EIO);
1478271493Sdelphij		}
1479271493Sdelphij
1480271493Sdelphij		if (len != sizeof(struct hv_kvp_msg)) {
1481271493Sdelphij			KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1482271493Sdelphij			continue;
1483271493Sdelphij		}
1484271493Sdelphij
1485271493Sdelphij		/* Copy hv_kvp_dev_buf to hv_msg */
1486271493Sdelphij		memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1487271493Sdelphij
1488271493Sdelphij		/*
1489271493Sdelphij		 * We will use the KVP header information to pass back
1490271493Sdelphij		 * the error from this daemon. So, first save the op
1491271493Sdelphij		 * and pool info to local variables.
1492271493Sdelphij		 */
1493271493Sdelphij
1494271493Sdelphij		op = hv_msg->hdr.kvp_hdr.operation;
1495271493Sdelphij		pool = hv_msg->hdr.kvp_hdr.pool;
1496271493Sdelphij
1497271493Sdelphij		if (op < 0 || op >= HV_KVP_OP_COUNT ||
1498271493Sdelphij		    kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1499271493Sdelphij			KVP_LOG(LOG_WARNING,
1500271493Sdelphij			    "Unsupported operation OP = %d\n", op);
1501271493Sdelphij			hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1502271493Sdelphij		} else {
1503271493Sdelphij			/*
1504271493Sdelphij			 * Call the operateion handler's execution routine.
1505271493Sdelphij			 */
1506271493Sdelphij			error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1507271493Sdelphij			    (void *)&kvp_op_hdlrs[op]);
1508308635Ssephe			if (error != 0) {
1509308635Ssephe				assert(hv_msg->hdr.error != HV_S_OK);
1510308635Ssephe				if (hv_msg->hdr.error != HV_S_CONT)
1511308635Ssephe					KVP_LOG(LOG_WARNING,
1512308635Ssephe					    "Operation failed OP = %d, error = 0x%x\n",
1513308635Ssephe					    op, error);
1514308635Ssephe			}
1515271493Sdelphij		}
1516271493Sdelphij
1517271493Sdelphij		/*
1518271493Sdelphij		 * Send the value back to the kernel. The response is
1519271493Sdelphij		 * already in the receive buffer.
1520271493Sdelphij		 */
1521271493Sdelphijhv_kvp_done:
1522271493Sdelphij		len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1523271493Sdelphij
1524271493Sdelphij		if (len != sizeof(struct hv_kvp_msg)) {
1525271493Sdelphij			KVP_LOG(LOG_ERR, "write len is: %d\n", len);
1526271493Sdelphij			goto hv_kvp_done;
1527271493Sdelphij		}
1528271493Sdelphij	}
1529271493Sdelphij}
1530