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