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