• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * An implementation of key value pair (KVP) functionality for Linux.
3  *
4  *
5  * Copyright (C) 2010, Novell, Inc.
6  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published
10  * by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15  * NON INFRINGEMENT.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23 
24 
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/poll.h>
28 #include <sys/utsname.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
39 #include <ifaddrs.h>
40 #include <netdb.h>
41 #include <syslog.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <dirent.h>
45 #include <net/if.h>
46 
47 /*
48  * KVP protocol: The user mode component first registers with the
49  * the kernel component. Subsequently, the kernel component requests, data
50  * for the specified keys. In response to this message the user mode component
51  * fills in the value corresponding to the specified key. We overload the
52  * sequence field in the cn_msg header to define our KVP message types.
53  *
54  * We use this infrastructure for also supporting queries from user mode
55  * application for state that may be maintained in the KVP kernel component.
56  *
57  */
58 
59 
60 enum key_index {
61 	FullyQualifiedDomainName = 0,
62 	IntegrationServicesVersion, /*This key is serviced in the kernel*/
63 	NetworkAddressIPv4,
64 	NetworkAddressIPv6,
65 	OSBuildNumber,
66 	OSName,
67 	OSMajorVersion,
68 	OSMinorVersion,
69 	OSVersion,
70 	ProcessorArchitecture
71 };
72 
73 
74 enum {
75 	IPADDR = 0,
76 	NETMASK,
77 	GATEWAY,
78 	DNS
79 };
80 
81 static struct sockaddr_nl addr;
82 static int in_hand_shake = 1;
83 
84 static char *os_name = "";
85 static char *os_major = "";
86 static char *os_minor = "";
87 static char *processor_arch;
88 static char *os_build;
89 static char *os_version;
90 static char *lic_version = "Unknown version";
91 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
92 static struct utsname uts_buf;
93 
94 /*
95  * The location of the interface configuration file.
96  */
97 
98 #define KVP_CONFIG_LOC	"/var/lib/hyperv"
99 
100 #define MAX_FILE_NAME 100
101 #define ENTRIES_PER_BLOCK 50
102 
103 #ifndef SOL_NETLINK
104 #define SOL_NETLINK 270
105 #endif
106 
107 struct kvp_record {
108 	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
109 	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
110 };
111 
112 struct kvp_file_state {
113 	int fd;
114 	int num_blocks;
115 	struct kvp_record *records;
116 	int num_records;
117 	char fname[MAX_FILE_NAME];
118 };
119 
120 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
121 
kvp_acquire_lock(int pool)122 static void kvp_acquire_lock(int pool)
123 {
124 	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
125 	fl.l_pid = getpid();
126 
127 	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
128 		syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
129 				errno, strerror(errno));
130 		exit(EXIT_FAILURE);
131 	}
132 }
133 
kvp_release_lock(int pool)134 static void kvp_release_lock(int pool)
135 {
136 	struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
137 	fl.l_pid = getpid();
138 
139 	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
140 		syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
141 				errno, strerror(errno));
142 		exit(EXIT_FAILURE);
143 	}
144 }
145 
kvp_update_file(int pool)146 static void kvp_update_file(int pool)
147 {
148 	FILE *filep;
149 	size_t bytes_written;
150 
151 	/*
152 	 * We are going to write our in-memory registry out to
153 	 * disk; acquire the lock first.
154 	 */
155 	kvp_acquire_lock(pool);
156 
157 	filep = fopen(kvp_file_info[pool].fname, "we");
158 	if (!filep) {
159 		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
160 				errno, strerror(errno));
161 		kvp_release_lock(pool);
162 		exit(EXIT_FAILURE);
163 	}
164 
165 	bytes_written = fwrite(kvp_file_info[pool].records,
166 				sizeof(struct kvp_record),
167 				kvp_file_info[pool].num_records, filep);
168 
169 	if (ferror(filep) || fclose(filep)) {
170 		kvp_release_lock(pool);
171 		syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
172 		exit(EXIT_FAILURE);
173 	}
174 
175 	kvp_release_lock(pool);
176 }
177 
kvp_update_mem_state(int pool)178 static void kvp_update_mem_state(int pool)
179 {
180 	FILE *filep;
181 	size_t records_read = 0;
182 	struct kvp_record *record = kvp_file_info[pool].records;
183 	struct kvp_record *readp;
184 	int num_blocks = kvp_file_info[pool].num_blocks;
185 	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
186 
187 	kvp_acquire_lock(pool);
188 
189 	filep = fopen(kvp_file_info[pool].fname, "re");
190 	if (!filep) {
191 		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
192 				errno, strerror(errno));
193 		kvp_release_lock(pool);
194 		exit(EXIT_FAILURE);
195 	}
196 	for (;;) {
197 		readp = &record[records_read];
198 		records_read += fread(readp, sizeof(struct kvp_record),
199 				ENTRIES_PER_BLOCK * num_blocks - records_read,
200 				filep);
201 
202 		if (ferror(filep)) {
203 			syslog(LOG_ERR,
204 				"Failed to read file, pool: %d; error: %d %s",
205 				 pool, errno, strerror(errno));
206 			kvp_release_lock(pool);
207 			exit(EXIT_FAILURE);
208 		}
209 
210 		if (!feof(filep)) {
211 			/*
212 			 * We have more data to read.
213 			 */
214 			num_blocks++;
215 			record = realloc(record, alloc_unit * num_blocks);
216 
217 			if (record == NULL) {
218 				syslog(LOG_ERR, "malloc failed");
219 				kvp_release_lock(pool);
220 				exit(EXIT_FAILURE);
221 			}
222 			continue;
223 		}
224 		break;
225 	}
226 
227 	kvp_file_info[pool].num_blocks = num_blocks;
228 	kvp_file_info[pool].records = record;
229 	kvp_file_info[pool].num_records = records_read;
230 
231 	fclose(filep);
232 	kvp_release_lock(pool);
233 }
234 
kvp_file_init(void)235 static int kvp_file_init(void)
236 {
237 	int  fd;
238 	char *fname;
239 	int i;
240 	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
241 
242 	if (access(KVP_CONFIG_LOC, F_OK)) {
243 		if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
244 			syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
245 					errno, strerror(errno));
246 			exit(EXIT_FAILURE);
247 		}
248 	}
249 
250 	for (i = 0; i < KVP_POOL_COUNT; i++) {
251 		fname = kvp_file_info[i].fname;
252 		sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
253 		fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
254 
255 		if (fd == -1)
256 			return 1;
257 
258 		kvp_file_info[i].fd = fd;
259 		kvp_file_info[i].num_blocks = 1;
260 		kvp_file_info[i].records = malloc(alloc_unit);
261 		if (kvp_file_info[i].records == NULL)
262 			return 1;
263 		kvp_file_info[i].num_records = 0;
264 		kvp_update_mem_state(i);
265 	}
266 
267 	return 0;
268 }
269 
kvp_key_delete(int pool,const char * key,int key_size)270 static int kvp_key_delete(int pool, const char *key, int key_size)
271 {
272 	int i;
273 	int j, k;
274 	int num_records;
275 	struct kvp_record *record;
276 
277 	/*
278 	 * First update the in-memory state.
279 	 */
280 	kvp_update_mem_state(pool);
281 
282 	num_records = kvp_file_info[pool].num_records;
283 	record = kvp_file_info[pool].records;
284 
285 	for (i = 0; i < num_records; i++) {
286 		if (memcmp(key, record[i].key, key_size))
287 			continue;
288 		/*
289 		 * Found a match; just move the remaining
290 		 * entries up.
291 		 */
292 		if (i == num_records) {
293 			kvp_file_info[pool].num_records--;
294 			kvp_update_file(pool);
295 			return 0;
296 		}
297 
298 		j = i;
299 		k = j + 1;
300 		for (; k < num_records; k++) {
301 			strcpy(record[j].key, record[k].key);
302 			strcpy(record[j].value, record[k].value);
303 			j++;
304 		}
305 
306 		kvp_file_info[pool].num_records--;
307 		kvp_update_file(pool);
308 		return 0;
309 	}
310 	return 1;
311 }
312 
kvp_key_add_or_modify(int pool,const char * key,int key_size,const char * value,int value_size)313 static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
314 			int value_size)
315 {
316 	int i;
317 	int num_records;
318 	struct kvp_record *record;
319 	int num_blocks;
320 
321 	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
322 		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
323 		return 1;
324 
325 	/*
326 	 * First update the in-memory state.
327 	 */
328 	kvp_update_mem_state(pool);
329 
330 	num_records = kvp_file_info[pool].num_records;
331 	record = kvp_file_info[pool].records;
332 	num_blocks = kvp_file_info[pool].num_blocks;
333 
334 	for (i = 0; i < num_records; i++) {
335 		if (memcmp(key, record[i].key, key_size))
336 			continue;
337 		/*
338 		 * Found a match; just update the value -
339 		 * this is the modify case.
340 		 */
341 		memcpy(record[i].value, value, value_size);
342 		kvp_update_file(pool);
343 		return 0;
344 	}
345 
346 	/*
347 	 * Need to add a new entry;
348 	 */
349 	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
350 		/* Need to allocate a larger array for reg entries. */
351 		record = realloc(record, sizeof(struct kvp_record) *
352 			 ENTRIES_PER_BLOCK * (num_blocks + 1));
353 
354 		if (record == NULL)
355 			return 1;
356 		kvp_file_info[pool].num_blocks++;
357 
358 	}
359 	memcpy(record[i].value, value, value_size);
360 	memcpy(record[i].key, key, key_size);
361 	kvp_file_info[pool].records = record;
362 	kvp_file_info[pool].num_records++;
363 	kvp_update_file(pool);
364 	return 0;
365 }
366 
kvp_get_value(int pool,const char * key,int key_size,char * value,int value_size)367 static int kvp_get_value(int pool, const char *key, int key_size, char *value,
368 			int value_size)
369 {
370 	int i;
371 	int num_records;
372 	struct kvp_record *record;
373 
374 	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
375 		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
376 		return 1;
377 
378 	/*
379 	 * First update the in-memory state.
380 	 */
381 	kvp_update_mem_state(pool);
382 
383 	num_records = kvp_file_info[pool].num_records;
384 	record = kvp_file_info[pool].records;
385 
386 	for (i = 0; i < num_records; i++) {
387 		if (memcmp(key, record[i].key, key_size))
388 			continue;
389 		/*
390 		 * Found a match; just copy the value out.
391 		 */
392 		memcpy(value, record[i].value, value_size);
393 		return 0;
394 	}
395 
396 	return 1;
397 }
398 
kvp_pool_enumerate(int pool,int index,char * key,int key_size,char * value,int value_size)399 static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
400 				char *value, int value_size)
401 {
402 	struct kvp_record *record;
403 
404 	/*
405 	 * First update our in-memory database.
406 	 */
407 	kvp_update_mem_state(pool);
408 	record = kvp_file_info[pool].records;
409 
410 	if (index >= kvp_file_info[pool].num_records) {
411 		return 1;
412 	}
413 
414 	memcpy(key, record[index].key, key_size);
415 	memcpy(value, record[index].value, value_size);
416 	return 0;
417 }
418 
419 
kvp_get_os_info(void)420 void kvp_get_os_info(void)
421 {
422 	FILE	*file;
423 	char	*p, buf[512];
424 
425 	uname(&uts_buf);
426 	os_version = uts_buf.release;
427 	os_build = strdup(uts_buf.release);
428 
429 	os_name = uts_buf.sysname;
430 	processor_arch = uts_buf.machine;
431 
432 	/*
433 	 * The current windows host (win7) expects the build
434 	 * string to be of the form: x.y.z
435 	 * Strip additional information we may have.
436 	 */
437 	p = strchr(os_version, '-');
438 	if (p)
439 		*p = '\0';
440 
441 	/*
442 	 * Parse the /etc/os-release file if present:
443 	 * http://www.freedesktop.org/software/systemd/man/os-release.html
444 	 */
445 	file = fopen("/etc/os-release", "r");
446 	if (file != NULL) {
447 		while (fgets(buf, sizeof(buf), file)) {
448 			char *value, *q;
449 
450 			/* Ignore comments */
451 			if (buf[0] == '#')
452 				continue;
453 
454 			/* Split into name=value */
455 			p = strchr(buf, '=');
456 			if (!p)
457 				continue;
458 			*p++ = 0;
459 
460 			/* Remove quotes and newline; un-escape */
461 			value = p;
462 			q = p;
463 			while (*p) {
464 				if (*p == '\\') {
465 					++p;
466 					if (!*p)
467 						break;
468 					*q++ = *p++;
469 				} else if (*p == '\'' || *p == '"' ||
470 					   *p == '\n') {
471 					++p;
472 				} else {
473 					*q++ = *p++;
474 				}
475 			}
476 			*q = 0;
477 
478 			if (!strcmp(buf, "NAME")) {
479 				p = strdup(value);
480 				if (!p)
481 					break;
482 				os_name = p;
483 			} else if (!strcmp(buf, "VERSION_ID")) {
484 				p = strdup(value);
485 				if (!p)
486 					break;
487 				os_major = p;
488 			}
489 		}
490 		fclose(file);
491 		return;
492 	}
493 
494 	/* Fallback for older RH/SUSE releases */
495 	file = fopen("/etc/SuSE-release", "r");
496 	if (file != NULL)
497 		goto kvp_osinfo_found;
498 	file  = fopen("/etc/redhat-release", "r");
499 	if (file != NULL)
500 		goto kvp_osinfo_found;
501 
502 	/*
503 	 * We don't have information about the os.
504 	 */
505 	return;
506 
507 kvp_osinfo_found:
508 	/* up to three lines */
509 	p = fgets(buf, sizeof(buf), file);
510 	if (p) {
511 		p = strchr(buf, '\n');
512 		if (p)
513 			*p = '\0';
514 		p = strdup(buf);
515 		if (!p)
516 			goto done;
517 		os_name = p;
518 
519 		/* second line */
520 		p = fgets(buf, sizeof(buf), file);
521 		if (p) {
522 			p = strchr(buf, '\n');
523 			if (p)
524 				*p = '\0';
525 			p = strdup(buf);
526 			if (!p)
527 				goto done;
528 			os_major = p;
529 
530 			/* third line */
531 			p = fgets(buf, sizeof(buf), file);
532 			if (p)  {
533 				p = strchr(buf, '\n');
534 				if (p)
535 					*p = '\0';
536 				p = strdup(buf);
537 				if (p)
538 					os_minor = p;
539 			}
540 		}
541 	}
542 
543 done:
544 	fclose(file);
545 	return;
546 }
547 
548 
549 
550 /*
551  * Retrieve an interface name corresponding to the specified guid.
552  * If there is a match, the function returns a pointer
553  * to the interface name and if not, a NULL is returned.
554  * If a match is found, the caller is responsible for
555  * freeing the memory.
556  */
557 
kvp_get_if_name(char * guid)558 static char *kvp_get_if_name(char *guid)
559 {
560 	DIR *dir;
561 	struct dirent *entry;
562 	FILE    *file;
563 	char    *p, *q, *x;
564 	char    *if_name = NULL;
565 	char    buf[256];
566 	char *kvp_net_dir = "/sys/class/net/";
567 	char dev_id[256];
568 
569 	dir = opendir(kvp_net_dir);
570 	if (dir == NULL)
571 		return NULL;
572 
573 	snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
574 	q = dev_id + strlen(kvp_net_dir);
575 
576 	while ((entry = readdir(dir)) != NULL) {
577 		/*
578 		 * Set the state for the next pass.
579 		 */
580 		*q = '\0';
581 		strcat(dev_id, entry->d_name);
582 		strcat(dev_id, "/device/device_id");
583 
584 		file = fopen(dev_id, "r");
585 		if (file == NULL)
586 			continue;
587 
588 		p = fgets(buf, sizeof(buf), file);
589 		if (p) {
590 			x = strchr(p, '\n');
591 			if (x)
592 				*x = '\0';
593 
594 			if (!strcmp(p, guid)) {
595 				/*
596 				 * Found the guid match; return the interface
597 				 * name. The caller will free the memory.
598 				 */
599 				if_name = strdup(entry->d_name);
600 				fclose(file);
601 				break;
602 			}
603 		}
604 		fclose(file);
605 	}
606 
607 	closedir(dir);
608 	return if_name;
609 }
610 
611 /*
612  * Retrieve the MAC address given the interface name.
613  */
614 
kvp_if_name_to_mac(char * if_name)615 static char *kvp_if_name_to_mac(char *if_name)
616 {
617 	FILE    *file;
618 	char    *p, *x;
619 	char    buf[256];
620 	char addr_file[256];
621 	int i;
622 	char *mac_addr = NULL;
623 
624 	snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
625 		if_name, "/address");
626 
627 	file = fopen(addr_file, "r");
628 	if (file == NULL)
629 		return NULL;
630 
631 	p = fgets(buf, sizeof(buf), file);
632 	if (p) {
633 		x = strchr(p, '\n');
634 		if (x)
635 			*x = '\0';
636 		for (i = 0; i < strlen(p); i++)
637 			p[i] = toupper(p[i]);
638 		mac_addr = strdup(p);
639 	}
640 
641 	fclose(file);
642 	return mac_addr;
643 }
644 
645 
646 /*
647  * Retrieve the interface name given tha MAC address.
648  */
649 
kvp_mac_to_if_name(char * mac)650 static char *kvp_mac_to_if_name(char *mac)
651 {
652 	DIR *dir;
653 	struct dirent *entry;
654 	FILE    *file;
655 	char    *p, *q, *x;
656 	char    *if_name = NULL;
657 	char    buf[256];
658 	char *kvp_net_dir = "/sys/class/net/";
659 	char dev_id[256];
660 	int i;
661 
662 	dir = opendir(kvp_net_dir);
663 	if (dir == NULL)
664 		return NULL;
665 
666 	snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
667 	q = dev_id + strlen(kvp_net_dir);
668 
669 	while ((entry = readdir(dir)) != NULL) {
670 		/*
671 		 * Set the state for the next pass.
672 		 */
673 		*q = '\0';
674 
675 		strcat(dev_id, entry->d_name);
676 		strcat(dev_id, "/address");
677 
678 		file = fopen(dev_id, "r");
679 		if (file == NULL)
680 			continue;
681 
682 		p = fgets(buf, sizeof(buf), file);
683 		if (p) {
684 			x = strchr(p, '\n');
685 			if (x)
686 				*x = '\0';
687 
688 			for (i = 0; i < strlen(p); i++)
689 				p[i] = toupper(p[i]);
690 
691 			if (!strcmp(p, mac)) {
692 				/*
693 				 * Found the MAC match; return the interface
694 				 * name. The caller will free the memory.
695 				 */
696 				if_name = strdup(entry->d_name);
697 				fclose(file);
698 				break;
699 			}
700 		}
701 		fclose(file);
702 	}
703 
704 	closedir(dir);
705 	return if_name;
706 }
707 
708 
kvp_process_ipconfig_file(char * cmd,char * config_buf,int len,int element_size,int offset)709 static void kvp_process_ipconfig_file(char *cmd,
710 					char *config_buf, int len,
711 					int element_size, int offset)
712 {
713 	char buf[256];
714 	char *p;
715 	char *x;
716 	FILE *file;
717 
718 	/*
719 	 * First execute the command.
720 	 */
721 	file = popen(cmd, "r");
722 	if (file == NULL)
723 		return;
724 
725 	if (offset == 0)
726 		memset(config_buf, 0, len);
727 	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
728 		if ((len - strlen(config_buf)) < (element_size + 1))
729 			break;
730 
731 		x = strchr(p, '\n');
732 		if (x)
733 			*x = '\0';
734 
735 		strcat(config_buf, p);
736 		strcat(config_buf, ";");
737 	}
738 	pclose(file);
739 }
740 
kvp_get_ipconfig_info(char * if_name,struct hv_kvp_ipaddr_value * buffer)741 static void kvp_get_ipconfig_info(char *if_name,
742 				 struct hv_kvp_ipaddr_value *buffer)
743 {
744 	char cmd[512];
745 	char dhcp_info[128];
746 	char *p;
747 	FILE *file;
748 
749 	/*
750 	 * Get the address of default gateway (ipv4).
751 	 */
752 	sprintf(cmd, "%s %s", "ip route show dev", if_name);
753 	strcat(cmd, " | awk '/default/ {print $3 }'");
754 
755 	/*
756 	 * Execute the command to gather gateway info.
757 	 */
758 	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
759 				(MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
760 
761 	/*
762 	 * Get the address of default gateway (ipv6).
763 	 */
764 	sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
765 	strcat(cmd, " | awk '/default/ {print $3 }'");
766 
767 	/*
768 	 * Execute the command to gather gateway info (ipv6).
769 	 */
770 	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
771 				(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
772 
773 
774 	/*
775 	 * Gather the DNS  state.
776 	 * Since there is no standard way to get this information
777 	 * across various distributions of interest; we just invoke
778 	 * an external script that needs to be ported across distros
779 	 * of interest.
780 	 *
781 	 * Following is the expected format of the information from the script:
782 	 *
783 	 * ipaddr1 (nameserver1)
784 	 * ipaddr2 (nameserver2)
785 	 * .
786 	 * .
787 	 */
788 
789 	sprintf(cmd, "%s",  "hv_get_dns_info");
790 
791 	/*
792 	 * Execute the command to gather DNS info.
793 	 */
794 	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
795 				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
796 
797 	/*
798 	 * Gather the DHCP state.
799 	 * We will gather this state by invoking an external script.
800 	 * The parameter to the script is the interface name.
801 	 * Here is the expected output:
802 	 *
803 	 * Enabled: DHCP enabled.
804 	 */
805 
806 	sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
807 
808 	file = popen(cmd, "r");
809 	if (file == NULL)
810 		return;
811 
812 	p = fgets(dhcp_info, sizeof(dhcp_info), file);
813 	if (p == NULL) {
814 		pclose(file);
815 		return;
816 	}
817 
818 	if (!strncmp(p, "Enabled", 7))
819 		buffer->dhcp_enabled = 1;
820 	else
821 		buffer->dhcp_enabled = 0;
822 
823 	pclose(file);
824 }
825 
826 
hweight32(unsigned int * w)827 static unsigned int hweight32(unsigned int *w)
828 {
829 	unsigned int res = *w - ((*w >> 1) & 0x55555555);
830 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
831 	res = (res + (res >> 4)) & 0x0F0F0F0F;
832 	res = res + (res >> 8);
833 	return (res + (res >> 16)) & 0x000000FF;
834 }
835 
kvp_process_ip_address(void * addrp,int family,char * buffer,int length,int * offset)836 static int kvp_process_ip_address(void *addrp,
837 				int family, char *buffer,
838 				int length,  int *offset)
839 {
840 	struct sockaddr_in *addr;
841 	struct sockaddr_in6 *addr6;
842 	int addr_length;
843 	char tmp[50];
844 	const char *str;
845 
846 	if (family == AF_INET) {
847 		addr = (struct sockaddr_in *)addrp;
848 		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
849 		addr_length = INET_ADDRSTRLEN;
850 	} else {
851 		addr6 = (struct sockaddr_in6 *)addrp;
852 		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
853 		addr_length = INET6_ADDRSTRLEN;
854 	}
855 
856 	if ((length - *offset) < addr_length + 2)
857 		return HV_E_FAIL;
858 	if (str == NULL) {
859 		strcpy(buffer, "inet_ntop failed\n");
860 		return HV_E_FAIL;
861 	}
862 	if (*offset == 0)
863 		strcpy(buffer, tmp);
864 	else {
865 		strcat(buffer, ";");
866 		strcat(buffer, tmp);
867 	}
868 
869 	*offset += strlen(str) + 1;
870 
871 	return 0;
872 }
873 
874 static int
kvp_get_ip_info(int family,char * if_name,int op,void * out_buffer,int length)875 kvp_get_ip_info(int family, char *if_name, int op,
876 		 void  *out_buffer, int length)
877 {
878 	struct ifaddrs *ifap;
879 	struct ifaddrs *curp;
880 	int offset = 0;
881 	int sn_offset = 0;
882 	int error = 0;
883 	char *buffer;
884 	struct hv_kvp_ipaddr_value *ip_buffer;
885 	char cidr_mask[5]; /* /xyz */
886 	int weight;
887 	int i;
888 	unsigned int *w;
889 	char *sn_str;
890 	struct sockaddr_in6 *addr6;
891 
892 	if (op == KVP_OP_ENUMERATE) {
893 		buffer = out_buffer;
894 	} else {
895 		ip_buffer = out_buffer;
896 		buffer = (char *)ip_buffer->ip_addr;
897 		ip_buffer->addr_family = 0;
898 	}
899 	/*
900 	 * On entry into this function, the buffer is capable of holding the
901 	 * maximum key value.
902 	 */
903 
904 	if (getifaddrs(&ifap)) {
905 		strcpy(buffer, "getifaddrs failed\n");
906 		return HV_E_FAIL;
907 	}
908 
909 	curp = ifap;
910 	while (curp != NULL) {
911 		if (curp->ifa_addr == NULL) {
912 			curp = curp->ifa_next;
913 			continue;
914 		}
915 
916 		if ((if_name != NULL) &&
917 			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
918 			/*
919 			 * We want info about a specific interface;
920 			 * just continue.
921 			 */
922 			curp = curp->ifa_next;
923 			continue;
924 		}
925 
926 		/*
927 		 * We only support two address families: AF_INET and AF_INET6.
928 		 * If a family value of 0 is specified, we collect both
929 		 * supported address families; if not we gather info on
930 		 * the specified address family.
931 		 */
932 		if ((((family != 0) &&
933 			 (curp->ifa_addr->sa_family != family))) ||
934 			 (curp->ifa_flags & IFF_LOOPBACK)) {
935 			curp = curp->ifa_next;
936 			continue;
937 		}
938 		if ((curp->ifa_addr->sa_family != AF_INET) &&
939 			(curp->ifa_addr->sa_family != AF_INET6)) {
940 			curp = curp->ifa_next;
941 			continue;
942 		}
943 
944 		if (op == KVP_OP_GET_IP_INFO) {
945 			/*
946 			 * Gather info other than the IP address.
947 			 * IP address info will be gathered later.
948 			 */
949 			if (curp->ifa_addr->sa_family == AF_INET) {
950 				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
951 				/*
952 				 * Get subnet info.
953 				 */
954 				error = kvp_process_ip_address(
955 							     curp->ifa_netmask,
956 							     AF_INET,
957 							     (char *)
958 							     ip_buffer->sub_net,
959 							     length,
960 							     &sn_offset);
961 				if (error)
962 					goto gather_ipaddr;
963 			} else {
964 				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
965 
966 				/*
967 				 * Get subnet info in CIDR format.
968 				 */
969 				weight = 0;
970 				sn_str = (char *)ip_buffer->sub_net;
971 				addr6 = (struct sockaddr_in6 *)
972 					curp->ifa_netmask;
973 				w = addr6->sin6_addr.s6_addr32;
974 
975 				for (i = 0; i < 4; i++)
976 					weight += hweight32(&w[i]);
977 
978 				sprintf(cidr_mask, "/%d", weight);
979 				if ((length - sn_offset) <
980 					(strlen(cidr_mask) + 1))
981 					goto gather_ipaddr;
982 
983 				if (sn_offset == 0)
984 					strcpy(sn_str, cidr_mask);
985 				else {
986 					strcat((char *)ip_buffer->sub_net, ";");
987 					strcat(sn_str, cidr_mask);
988 				}
989 				sn_offset += strlen(sn_str) + 1;
990 			}
991 
992 			/*
993 			 * Collect other ip related configuration info.
994 			 */
995 
996 			kvp_get_ipconfig_info(if_name, ip_buffer);
997 		}
998 
999 gather_ipaddr:
1000 		error = kvp_process_ip_address(curp->ifa_addr,
1001 						curp->ifa_addr->sa_family,
1002 						buffer,
1003 						length, &offset);
1004 		if (error)
1005 			goto getaddr_done;
1006 
1007 		curp = curp->ifa_next;
1008 	}
1009 
1010 getaddr_done:
1011 	freeifaddrs(ifap);
1012 	return error;
1013 }
1014 
1015 
expand_ipv6(char * addr,int type)1016 static int expand_ipv6(char *addr, int type)
1017 {
1018 	int ret;
1019 	struct in6_addr v6_addr;
1020 
1021 	ret = inet_pton(AF_INET6, addr, &v6_addr);
1022 
1023 	if (ret != 1) {
1024 		if (type == NETMASK)
1025 			return 1;
1026 		return 0;
1027 	}
1028 
1029 	sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1030 		"%02x%02x:%02x%02x:%02x%02x",
1031 		(int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1032 		(int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1033 		(int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1034 		(int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1035 		(int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1036 		(int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1037 		(int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1038 		(int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1039 
1040 	return 1;
1041 
1042 }
1043 
is_ipv4(char * addr)1044 static int is_ipv4(char *addr)
1045 {
1046 	int ret;
1047 	struct in_addr ipv4_addr;
1048 
1049 	ret = inet_pton(AF_INET, addr, &ipv4_addr);
1050 
1051 	if (ret == 1)
1052 		return 1;
1053 	return 0;
1054 }
1055 
parse_ip_val_buffer(char * in_buf,int * offset,char * out_buf,int out_len)1056 static int parse_ip_val_buffer(char *in_buf, int *offset,
1057 				char *out_buf, int out_len)
1058 {
1059 	char *x;
1060 	char *start;
1061 
1062 	/*
1063 	 * in_buf has sequence of characters that are seperated by
1064 	 * the character ';'. The last sequence does not have the
1065 	 * terminating ";" character.
1066 	 */
1067 	start = in_buf + *offset;
1068 
1069 	x = strchr(start, ';');
1070 	if (x)
1071 		*x = 0;
1072 	else
1073 		x = start + strlen(start);
1074 
1075 	if (strlen(start) != 0) {
1076 		int i = 0;
1077 		/*
1078 		 * Get rid of leading spaces.
1079 		 */
1080 		while (start[i] == ' ')
1081 			i++;
1082 
1083 		if ((x - start) <= out_len) {
1084 			strcpy(out_buf, (start + i));
1085 			*offset += (x - start) + 1;
1086 			return 1;
1087 		}
1088 	}
1089 	return 0;
1090 }
1091 
kvp_write_file(FILE * f,char * s1,char * s2,char * s3)1092 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1093 {
1094 	int ret;
1095 
1096 	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1097 
1098 	if (ret < 0)
1099 		return HV_E_FAIL;
1100 
1101 	return 0;
1102 }
1103 
1104 
process_ip_string(FILE * f,char * ip_string,int type)1105 static int process_ip_string(FILE *f, char *ip_string, int type)
1106 {
1107 	int error = 0;
1108 	char addr[INET6_ADDRSTRLEN];
1109 	int i = 0;
1110 	int j = 0;
1111 	char str[256];
1112 	char sub_str[10];
1113 	int offset = 0;
1114 
1115 	memset(addr, 0, sizeof(addr));
1116 
1117 	while (parse_ip_val_buffer(ip_string, &offset, addr,
1118 					(MAX_IP_ADDR_SIZE * 2))) {
1119 
1120 		sub_str[0] = 0;
1121 		if (is_ipv4(addr)) {
1122 			switch (type) {
1123 			case IPADDR:
1124 				snprintf(str, sizeof(str), "%s", "IPADDR");
1125 				break;
1126 			case NETMASK:
1127 				snprintf(str, sizeof(str), "%s", "NETMASK");
1128 				break;
1129 			case GATEWAY:
1130 				snprintf(str, sizeof(str), "%s", "GATEWAY");
1131 				break;
1132 			case DNS:
1133 				snprintf(str, sizeof(str), "%s", "DNS");
1134 				break;
1135 			}
1136 
1137 			if (type == DNS) {
1138 				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1139 			} else if (type == GATEWAY && i == 0) {
1140 				++i;
1141 			} else {
1142 				snprintf(sub_str, sizeof(sub_str), "%d", i++);
1143 			}
1144 
1145 
1146 		} else if (expand_ipv6(addr, type)) {
1147 			switch (type) {
1148 			case IPADDR:
1149 				snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1150 				break;
1151 			case NETMASK:
1152 				snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1153 				break;
1154 			case GATEWAY:
1155 				snprintf(str, sizeof(str), "%s",
1156 					"IPV6_DEFAULTGW");
1157 				break;
1158 			case DNS:
1159 				snprintf(str, sizeof(str), "%s",  "DNS");
1160 				break;
1161 			}
1162 
1163 			if (type == DNS) {
1164 				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1165 			} else if (j == 0) {
1166 				++j;
1167 			} else {
1168 				snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1169 			}
1170 		} else {
1171 			return  HV_INVALIDARG;
1172 		}
1173 
1174 		error = kvp_write_file(f, str, sub_str, addr);
1175 		if (error)
1176 			return error;
1177 		memset(addr, 0, sizeof(addr));
1178 	}
1179 
1180 	return 0;
1181 }
1182 
kvp_set_ip_info(char * if_name,struct hv_kvp_ipaddr_value * new_val)1183 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1184 {
1185 	int error = 0;
1186 	char if_file[128];
1187 	FILE *file;
1188 	char cmd[512];
1189 	char *mac_addr;
1190 
1191 	/*
1192 	 * Set the configuration for the specified interface with
1193 	 * the information provided. Since there is no standard
1194 	 * way to configure an interface, we will have an external
1195 	 * script that does the job of configuring the interface and
1196 	 * flushing the configuration.
1197 	 *
1198 	 * The parameters passed to this external script are:
1199 	 * 1. A configuration file that has the specified configuration.
1200 	 *
1201 	 * We will embed the name of the interface in the configuration
1202 	 * file: ifcfg-ethx (where ethx is the interface name).
1203 	 *
1204 	 * The information provided here may be more than what is needed
1205 	 * in a given distro to configure the interface and so are free
1206 	 * ignore information that may not be relevant.
1207 	 *
1208 	 * Here is the format of the ip configuration file:
1209 	 *
1210 	 * HWADDR=macaddr
1211 	 * DEVICE=interface name
1212 	 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
1213 	 *                       or "none" if no boot-time protocol should be used)
1214 	 *
1215 	 * IPADDR0=ipaddr1
1216 	 * IPADDR1=ipaddr2
1217 	 * IPADDRx=ipaddry (where y = x + 1)
1218 	 *
1219 	 * NETMASK0=netmask1
1220 	 * NETMASKx=netmasky (where y = x + 1)
1221 	 *
1222 	 * GATEWAY=ipaddr1
1223 	 * GATEWAYx=ipaddry (where y = x + 1)
1224 	 *
1225 	 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1226 	 *
1227 	 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1228 	 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1229 	 * IPV6NETMASK.
1230 	 *
1231 	 * The host can specify multiple ipv4 and ipv6 addresses to be
1232 	 * configured for the interface. Furthermore, the configuration
1233 	 * needs to be persistent. A subsequent GET call on the interface
1234 	 * is expected to return the configuration that is set via the SET
1235 	 * call.
1236 	 */
1237 
1238 	snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1239 		"/ifcfg-", if_name);
1240 
1241 	file = fopen(if_file, "w");
1242 
1243 	if (file == NULL) {
1244 		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1245 				errno, strerror(errno));
1246 		return HV_E_FAIL;
1247 	}
1248 
1249 	/*
1250 	 * First write out the MAC address.
1251 	 */
1252 
1253 	mac_addr = kvp_if_name_to_mac(if_name);
1254 	if (mac_addr == NULL) {
1255 		error = HV_E_FAIL;
1256 		goto setval_error;
1257 	}
1258 
1259 	error = kvp_write_file(file, "HWADDR", "", mac_addr);
1260 	free(mac_addr);
1261 	if (error)
1262 		goto setval_error;
1263 
1264 	error = kvp_write_file(file, "DEVICE", "", if_name);
1265 	if (error)
1266 		goto setval_error;
1267 
1268 	if (new_val->dhcp_enabled) {
1269 		error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1270 		if (error)
1271 			goto setval_error;
1272 
1273 		/*
1274 		 * We are done!.
1275 		 */
1276 		goto setval_done;
1277 
1278 	} else {
1279 		error = kvp_write_file(file, "BOOTPROTO", "", "none");
1280 		if (error)
1281 			goto setval_error;
1282 	}
1283 
1284 	/*
1285 	 * Write the configuration for ipaddress, netmask, gateway and
1286 	 * name servers.
1287 	 */
1288 
1289 	error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1290 	if (error)
1291 		goto setval_error;
1292 
1293 	error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1294 	if (error)
1295 		goto setval_error;
1296 
1297 	error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1298 	if (error)
1299 		goto setval_error;
1300 
1301 	error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1302 	if (error)
1303 		goto setval_error;
1304 
1305 setval_done:
1306 	fclose(file);
1307 
1308 	/*
1309 	 * Now that we have populated the configuration file,
1310 	 * invoke the external script to do its magic.
1311 	 */
1312 
1313 	snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1314 	if (system(cmd)) {
1315 		syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1316 				cmd, errno, strerror(errno));
1317 		return HV_E_FAIL;
1318 	}
1319 	return 0;
1320 
1321 setval_error:
1322 	syslog(LOG_ERR, "Failed to write config file");
1323 	fclose(file);
1324 	return error;
1325 }
1326 
1327 
1328 static void
kvp_get_domain_name(char * buffer,int length)1329 kvp_get_domain_name(char *buffer, int length)
1330 {
1331 	struct addrinfo	hints, *info ;
1332 	int error = 0;
1333 
1334 	gethostname(buffer, length);
1335 	memset(&hints, 0, sizeof(hints));
1336 	hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1337 	hints.ai_socktype = SOCK_STREAM;
1338 	hints.ai_flags = AI_CANONNAME;
1339 
1340 	error = getaddrinfo(buffer, NULL, &hints, &info);
1341 	if (error != 0) {
1342 		snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1343 			error, gai_strerror(error));
1344 		return;
1345 	}
1346 	snprintf(buffer, length, "%s", info->ai_canonname);
1347 	freeaddrinfo(info);
1348 }
1349 
1350 static int
netlink_send(int fd,struct cn_msg * msg)1351 netlink_send(int fd, struct cn_msg *msg)
1352 {
1353 	struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
1354 	unsigned int size;
1355 	struct msghdr message;
1356 	struct iovec iov[2];
1357 
1358 	size = sizeof(struct cn_msg) + msg->len;
1359 
1360 	nlh.nlmsg_pid = getpid();
1361 	nlh.nlmsg_len = NLMSG_LENGTH(size);
1362 
1363 	iov[0].iov_base = &nlh;
1364 	iov[0].iov_len = sizeof(nlh);
1365 
1366 	iov[1].iov_base = msg;
1367 	iov[1].iov_len = size;
1368 
1369 	memset(&message, 0, sizeof(message));
1370 	message.msg_name = &addr;
1371 	message.msg_namelen = sizeof(addr);
1372 	message.msg_iov = iov;
1373 	message.msg_iovlen = 2;
1374 
1375 	return sendmsg(fd, &message, 0);
1376 }
1377 
main(void)1378 int main(void)
1379 {
1380 	int fd, len, nl_group;
1381 	int error;
1382 	struct cn_msg *message;
1383 	struct pollfd pfd;
1384 	struct nlmsghdr *incoming_msg;
1385 	struct cn_msg	*incoming_cn_msg;
1386 	struct hv_kvp_msg *hv_msg;
1387 	char	*p;
1388 	char	*key_value;
1389 	char	*key_name;
1390 	int	op;
1391 	int	pool;
1392 	char	*if_name;
1393 	struct hv_kvp_ipaddr_value *kvp_ip_val;
1394 	char *kvp_recv_buffer;
1395 	size_t kvp_recv_buffer_len;
1396 
1397 	if (daemon(1, 0))
1398 		return 1;
1399 	openlog("KVP", 0, LOG_USER);
1400 	syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1401 
1402 	kvp_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg);
1403 	kvp_recv_buffer = calloc(1, kvp_recv_buffer_len);
1404 	if (!kvp_recv_buffer) {
1405 		syslog(LOG_ERR, "Failed to allocate netlink buffer");
1406 		exit(EXIT_FAILURE);
1407 	}
1408 	/*
1409 	 * Retrieve OS release information.
1410 	 */
1411 	kvp_get_os_info();
1412 	/*
1413 	 * Cache Fully Qualified Domain Name because getaddrinfo takes an
1414 	 * unpredictable amount of time to finish.
1415 	 */
1416 	kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1417 
1418 	if (kvp_file_init()) {
1419 		syslog(LOG_ERR, "Failed to initialize the pools");
1420 		exit(EXIT_FAILURE);
1421 	}
1422 
1423 	fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1424 	if (fd < 0) {
1425 		syslog(LOG_ERR, "netlink socket creation failed; error: %d %s", errno,
1426 				strerror(errno));
1427 		exit(EXIT_FAILURE);
1428 	}
1429 	addr.nl_family = AF_NETLINK;
1430 	addr.nl_pad = 0;
1431 	addr.nl_pid = 0;
1432 	addr.nl_groups = 0;
1433 
1434 
1435 	error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1436 	if (error < 0) {
1437 		syslog(LOG_ERR, "bind failed; error: %d %s", errno, strerror(errno));
1438 		close(fd);
1439 		exit(EXIT_FAILURE);
1440 	}
1441 	nl_group = CN_KVP_IDX;
1442 
1443 	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
1444 		syslog(LOG_ERR, "setsockopt failed; error: %d %s", errno, strerror(errno));
1445 		close(fd);
1446 		exit(EXIT_FAILURE);
1447 	}
1448 
1449 	/*
1450 	 * Register ourselves with the kernel.
1451 	 */
1452 	message = (struct cn_msg *)kvp_recv_buffer;
1453 	message->id.idx = CN_KVP_IDX;
1454 	message->id.val = CN_KVP_VAL;
1455 
1456 	hv_msg = (struct hv_kvp_msg *)message->data;
1457 	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1458 	message->ack = 0;
1459 	message->len = sizeof(struct hv_kvp_msg);
1460 
1461 	len = netlink_send(fd, message);
1462 	if (len < 0) {
1463 		syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, strerror(errno));
1464 		close(fd);
1465 		exit(EXIT_FAILURE);
1466 	}
1467 
1468 	pfd.fd = fd;
1469 
1470 	while (1) {
1471 		struct sockaddr *addr_p = (struct sockaddr *) &addr;
1472 		socklen_t addr_l = sizeof(addr);
1473 		pfd.events = POLLIN;
1474 		pfd.revents = 0;
1475 
1476 		if (poll(&pfd, 1, -1) < 0) {
1477 			syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1478 			if (errno == EINVAL) {
1479 				close(fd);
1480 				exit(EXIT_FAILURE);
1481 			}
1482 			else
1483 				continue;
1484 		}
1485 
1486 		len = recvfrom(fd, kvp_recv_buffer, kvp_recv_buffer_len, 0,
1487 				addr_p, &addr_l);
1488 
1489 		if (len < 0) {
1490 			syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1491 					addr.nl_pid, errno, strerror(errno));
1492 			close(fd);
1493 			return -1;
1494 		}
1495 
1496 		if (addr.nl_pid) {
1497 			syslog(LOG_WARNING, "Received packet from untrusted pid:%u",
1498 					addr.nl_pid);
1499 			continue;
1500 		}
1501 
1502 		incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1503 
1504 		if (incoming_msg->nlmsg_type != NLMSG_DONE)
1505 			continue;
1506 
1507 		incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1508 		hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1509 
1510 		/*
1511 		 * We will use the KVP header information to pass back
1512 		 * the error from this daemon. So, first copy the state
1513 		 * and set the error code to success.
1514 		 */
1515 		op = hv_msg->kvp_hdr.operation;
1516 		pool = hv_msg->kvp_hdr.pool;
1517 		hv_msg->error = HV_S_OK;
1518 
1519 		if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1520 			/*
1521 			 * Driver is registering with us; stash away the version
1522 			 * information.
1523 			 */
1524 			in_hand_shake = 0;
1525 			p = (char *)hv_msg->body.kvp_register.version;
1526 			lic_version = malloc(strlen(p) + 1);
1527 			if (lic_version) {
1528 				strcpy(lic_version, p);
1529 				syslog(LOG_INFO, "KVP LIC Version: %s",
1530 					lic_version);
1531 			} else {
1532 				syslog(LOG_ERR, "malloc failed");
1533 			}
1534 			continue;
1535 		}
1536 
1537 		switch (op) {
1538 		case KVP_OP_GET_IP_INFO:
1539 			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1540 			if_name =
1541 			kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1542 
1543 			if (if_name == NULL) {
1544 				/*
1545 				 * We could not map the mac address to an
1546 				 * interface name; return error.
1547 				 */
1548 				hv_msg->error = HV_E_FAIL;
1549 				break;
1550 			}
1551 			error = kvp_get_ip_info(
1552 						0, if_name, KVP_OP_GET_IP_INFO,
1553 						kvp_ip_val,
1554 						(MAX_IP_ADDR_SIZE * 2));
1555 
1556 			if (error)
1557 				hv_msg->error = error;
1558 
1559 			free(if_name);
1560 			break;
1561 
1562 		case KVP_OP_SET_IP_INFO:
1563 			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1564 			if_name = kvp_get_if_name(
1565 					(char *)kvp_ip_val->adapter_id);
1566 			if (if_name == NULL) {
1567 				/*
1568 				 * We could not map the guid to an
1569 				 * interface name; return error.
1570 				 */
1571 				hv_msg->error = HV_GUID_NOTFOUND;
1572 				break;
1573 			}
1574 			error = kvp_set_ip_info(if_name, kvp_ip_val);
1575 			if (error)
1576 				hv_msg->error = error;
1577 
1578 			free(if_name);
1579 			break;
1580 
1581 		case KVP_OP_SET:
1582 			if (kvp_key_add_or_modify(pool,
1583 					hv_msg->body.kvp_set.data.key,
1584 					hv_msg->body.kvp_set.data.key_size,
1585 					hv_msg->body.kvp_set.data.value,
1586 					hv_msg->body.kvp_set.data.value_size))
1587 					hv_msg->error = HV_S_CONT;
1588 			break;
1589 
1590 		case KVP_OP_GET:
1591 			if (kvp_get_value(pool,
1592 					hv_msg->body.kvp_set.data.key,
1593 					hv_msg->body.kvp_set.data.key_size,
1594 					hv_msg->body.kvp_set.data.value,
1595 					hv_msg->body.kvp_set.data.value_size))
1596 					hv_msg->error = HV_S_CONT;
1597 			break;
1598 
1599 		case KVP_OP_DELETE:
1600 			if (kvp_key_delete(pool,
1601 					hv_msg->body.kvp_delete.key,
1602 					hv_msg->body.kvp_delete.key_size))
1603 					hv_msg->error = HV_S_CONT;
1604 			break;
1605 
1606 		default:
1607 			break;
1608 		}
1609 
1610 		if (op != KVP_OP_ENUMERATE)
1611 			goto kvp_done;
1612 
1613 		/*
1614 		 * If the pool is KVP_POOL_AUTO, dynamically generate
1615 		 * both the key and the value; if not read from the
1616 		 * appropriate pool.
1617 		 */
1618 		if (pool != KVP_POOL_AUTO) {
1619 			if (kvp_pool_enumerate(pool,
1620 					hv_msg->body.kvp_enum_data.index,
1621 					hv_msg->body.kvp_enum_data.data.key,
1622 					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1623 					hv_msg->body.kvp_enum_data.data.value,
1624 					HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1625 					hv_msg->error = HV_S_CONT;
1626 			goto kvp_done;
1627 		}
1628 
1629 		hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1630 		key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1631 		key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1632 
1633 		switch (hv_msg->body.kvp_enum_data.index) {
1634 		case FullyQualifiedDomainName:
1635 			strcpy(key_value, full_domain_name);
1636 			strcpy(key_name, "FullyQualifiedDomainName");
1637 			break;
1638 		case IntegrationServicesVersion:
1639 			strcpy(key_name, "IntegrationServicesVersion");
1640 			strcpy(key_value, lic_version);
1641 			break;
1642 		case NetworkAddressIPv4:
1643 			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1644 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1645 			strcpy(key_name, "NetworkAddressIPv4");
1646 			break;
1647 		case NetworkAddressIPv6:
1648 			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1649 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1650 			strcpy(key_name, "NetworkAddressIPv6");
1651 			break;
1652 		case OSBuildNumber:
1653 			strcpy(key_value, os_build);
1654 			strcpy(key_name, "OSBuildNumber");
1655 			break;
1656 		case OSName:
1657 			strcpy(key_value, os_name);
1658 			strcpy(key_name, "OSName");
1659 			break;
1660 		case OSMajorVersion:
1661 			strcpy(key_value, os_major);
1662 			strcpy(key_name, "OSMajorVersion");
1663 			break;
1664 		case OSMinorVersion:
1665 			strcpy(key_value, os_minor);
1666 			strcpy(key_name, "OSMinorVersion");
1667 			break;
1668 		case OSVersion:
1669 			strcpy(key_value, os_version);
1670 			strcpy(key_name, "OSVersion");
1671 			break;
1672 		case ProcessorArchitecture:
1673 			strcpy(key_value, processor_arch);
1674 			strcpy(key_name, "ProcessorArchitecture");
1675 			break;
1676 		default:
1677 			hv_msg->error = HV_S_CONT;
1678 			break;
1679 		}
1680 		/*
1681 		 * Send the value back to the kernel. The response is
1682 		 * already in the receive buffer. Update the cn_msg header to
1683 		 * reflect the key value that has been added to the message
1684 		 */
1685 kvp_done:
1686 
1687 		incoming_cn_msg->id.idx = CN_KVP_IDX;
1688 		incoming_cn_msg->id.val = CN_KVP_VAL;
1689 		incoming_cn_msg->ack = 0;
1690 		incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1691 
1692 		len = netlink_send(fd, incoming_cn_msg);
1693 		if (len < 0) {
1694 			syslog(LOG_ERR, "net_link send failed; error: %d %s", errno,
1695 					strerror(errno));
1696 			exit(EXIT_FAILURE);
1697 		}
1698 	}
1699 
1700 }
1701