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