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