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