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