File Index
Files and directories
Sign in
FILE

hv_kvp_daemon.c

File preview with syntax highlighting.

linux-6.19.14/tools/hv/hv_kvp_daemon.c C
   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/poll.h>
  26#include <sys/utsname.h>
  27#include <stdbool.h>
  28#include <stdio.h>
  29#include <stdlib.h>
  30#include <unistd.h>
  31#include <string.h>
  32#include <ctype.h>
  33#include <errno.h>
  34#include <arpa/inet.h>
  35#include <linux/hyperv.h>
  36#include <ifaddrs.h>
  37#include <netdb.h>
  38#include <syslog.h>
  39#include <sys/stat.h>
  40#include <fcntl.h>
  41#include <dirent.h>
  42#include <net/if.h>
  43#include <limits.h>
  44#include <getopt.h>
  45
  46/*
  47 * KVP protocol: The user mode component first registers with the
  48 * kernel component. Subsequently, the kernel component requests, data
  49 * for the specified keys. In response to this message the user mode component
  50 * fills in the value corresponding to the specified key. We overload the
  51 * sequence field in the cn_msg header to define our KVP message types.
  52 *
  53 * We use this infrastructure for also supporting queries from user mode
  54 * application for state that may be maintained in the KVP kernel component.
  55 *
  56 */
  57
  58
  59enum key_index {
  60	FullyQualifiedDomainName = 0,
  61	IntegrationServicesVersion, /*This key is serviced in the kernel*/
  62	NetworkAddressIPv4,
  63	NetworkAddressIPv6,
  64	OSBuildNumber,
  65	OSName,
  66	OSMajorVersion,
  67	OSMinorVersion,
  68	OSVersion,
  69	ProcessorArchitecture
  70};
  71
  72
  73enum {
  74	IPADDR = 0,
  75	NETMASK,
  76	GATEWAY,
  77	DNS
  78};
  79
  80enum {
  81	IPV4 = 1,
  82	IPV6,
  83	IP_TYPE_MAX
  84};
  85
  86static int in_hand_shake;
  87static int debug;
  88
  89static char *os_name = "";
  90static char *os_major = "";
  91static char *os_minor = "";
  92static char *processor_arch;
  93static char *os_build;
  94static char *os_version;
  95static char *lic_version = "Unknown version";
  96static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
  97static struct utsname uts_buf;
  98
  99/*
 100 * The location of the interface configuration file.
 101 */
 102
 103#define KVP_CONFIG_LOC	"/var/lib/hyperv"
 104
 105#ifndef KVP_SCRIPTS_PATH
 106#define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
 107#endif
 108
 109#define KVP_NET_DIR "/sys/class/net/"
 110
 111#define MAX_FILE_NAME 100
 112#define ENTRIES_PER_BLOCK 50
 113/*
 114 * Change this entry if the number of addresses increases in future
 115 */
 116#define MAX_IP_ENTRIES 64
 117#define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
 118
 119struct kvp_record {
 120	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
 121	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
 122};
 123
 124struct kvp_file_state {
 125	int fd;
 126	int num_blocks;
 127	struct kvp_record *records;
 128	int num_records;
 129	char fname[MAX_FILE_NAME];
 130};
 131
 132static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
 133
 134static void kvp_acquire_lock(int pool)
 135{
 136	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
 137	fl.l_pid = getpid();
 138
 139	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
 140		syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
 141				errno, strerror(errno));
 142		exit(EXIT_FAILURE);
 143	}
 144}
 145
 146static void kvp_release_lock(int pool)
 147{
 148	struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
 149	fl.l_pid = getpid();
 150
 151	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
 152		syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
 153				errno, strerror(errno));
 154		exit(EXIT_FAILURE);
 155	}
 156}
 157
 158static void kvp_update_file(int pool)
 159{
 160	FILE *filep;
 161
 162	/*
 163	 * We are going to write our in-memory registry out to
 164	 * disk; acquire the lock first.
 165	 */
 166	kvp_acquire_lock(pool);
 167
 168	filep = fopen(kvp_file_info[pool].fname, "we");
 169	if (!filep) {
 170		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
 171				errno, strerror(errno));
 172		kvp_release_lock(pool);
 173		exit(EXIT_FAILURE);
 174	}
 175
 176	fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
 177				kvp_file_info[pool].num_records, filep);
 178
 179	if (ferror(filep) || fclose(filep)) {
 180		kvp_release_lock(pool);
 181		syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
 182		exit(EXIT_FAILURE);
 183	}
 184
 185	kvp_release_lock(pool);
 186}
 187
 188static void kvp_dump_initial_pools(int pool)
 189{
 190	int i;
 191
 192	syslog(LOG_DEBUG, "===Start dumping the contents of pool %d ===\n",
 193	       pool);
 194
 195	for (i = 0; i < kvp_file_info[pool].num_records; i++)
 196		syslog(LOG_DEBUG, "pool: %d, %d/%d key=%s val=%s\n",
 197		       pool, i + 1, kvp_file_info[pool].num_records,
 198		       kvp_file_info[pool].records[i].key,
 199		       kvp_file_info[pool].records[i].value);
 200}
 201
 202static void kvp_update_mem_state(int pool)
 203{
 204	FILE *filep;
 205	size_t records_read = 0;
 206	struct kvp_record *record = kvp_file_info[pool].records;
 207	struct kvp_record *readp;
 208	int num_blocks = kvp_file_info[pool].num_blocks;
 209	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 210
 211	kvp_acquire_lock(pool);
 212
 213	filep = fopen(kvp_file_info[pool].fname, "re");
 214	if (!filep) {
 215		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
 216				errno, strerror(errno));
 217		kvp_release_lock(pool);
 218		exit(EXIT_FAILURE);
 219	}
 220	for (;;) {
 221		readp = &record[records_read];
 222		records_read += fread(readp, sizeof(struct kvp_record),
 223				ENTRIES_PER_BLOCK * num_blocks - records_read,
 224				filep);
 225
 226		if (ferror(filep)) {
 227			syslog(LOG_ERR,
 228				"Failed to read file, pool: %d; error: %d %s",
 229				 pool, errno, strerror(errno));
 230			kvp_release_lock(pool);
 231			exit(EXIT_FAILURE);
 232		}
 233
 234		if (!feof(filep)) {
 235			/*
 236			 * We have more data to read.
 237			 */
 238			num_blocks++;
 239			record = realloc(record, alloc_unit * num_blocks);
 240
 241			if (record == NULL) {
 242				syslog(LOG_ERR, "malloc failed");
 243				kvp_release_lock(pool);
 244				exit(EXIT_FAILURE);
 245			}
 246			continue;
 247		}
 248		break;
 249	}
 250
 251	kvp_file_info[pool].num_blocks = num_blocks;
 252	kvp_file_info[pool].records = record;
 253	kvp_file_info[pool].num_records = records_read;
 254
 255	fclose(filep);
 256	kvp_release_lock(pool);
 257}
 258
 259static int kvp_file_init(void)
 260{
 261	int  fd;
 262	char *fname;
 263	int i;
 264	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 265
 266	if (access(KVP_CONFIG_LOC, F_OK)) {
 267		if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
 268			syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
 269					errno, strerror(errno));
 270			exit(EXIT_FAILURE);
 271		}
 272	}
 273
 274	for (i = 0; i < KVP_POOL_COUNT; i++) {
 275		fname = kvp_file_info[i].fname;
 276		sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
 277		fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
 278
 279		if (fd == -1)
 280			return 1;
 281
 282		kvp_file_info[i].fd = fd;
 283		kvp_file_info[i].num_blocks = 1;
 284		kvp_file_info[i].records = malloc(alloc_unit);
 285		if (kvp_file_info[i].records == NULL)
 286			return 1;
 287		kvp_file_info[i].num_records = 0;
 288		kvp_update_mem_state(i);
 289		if (debug)
 290			kvp_dump_initial_pools(i);
 291	}
 292
 293	return 0;
 294}
 295
 296static int kvp_key_delete(int pool, const __u8 *key, int key_size)
 297{
 298	int i;
 299	int j, k;
 300	int num_records;
 301	struct kvp_record *record;
 302
 303	/*
 304	 * First update the in-memory state.
 305	 */
 306	kvp_update_mem_state(pool);
 307
 308	num_records = kvp_file_info[pool].num_records;
 309	record = kvp_file_info[pool].records;
 310
 311	for (i = 0; i < num_records; i++) {
 312		if (memcmp(key, record[i].key, key_size))
 313			continue;
 314		/*
 315		 * Found a match; just move the remaining
 316		 * entries up.
 317		 */
 318		if (debug)
 319			syslog(LOG_DEBUG, "%s: deleting the KVP: pool=%d key=%s val=%s",
 320			       __func__, pool, record[i].key, record[i].value);
 321		if (i == (num_records - 1)) {
 322			kvp_file_info[pool].num_records--;
 323			kvp_update_file(pool);
 324			return 0;
 325		}
 326
 327		j = i;
 328		k = j + 1;
 329		for (; k < num_records; k++) {
 330			strcpy(record[j].key, record[k].key);
 331			strcpy(record[j].value, record[k].value);
 332			j++;
 333		}
 334
 335		kvp_file_info[pool].num_records--;
 336		kvp_update_file(pool);
 337		return 0;
 338	}
 339
 340	if (debug)
 341		syslog(LOG_DEBUG, "%s: could not delete KVP: pool=%d key=%s. Record not found",
 342		       __func__, pool, key);
 343
 344	return 1;
 345}
 346
 347static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
 348				 const __u8 *value, int value_size)
 349{
 350	struct kvp_record *record;
 351	int num_records;
 352	int num_blocks;
 353	int i;
 354
 355	if (debug)
 356		syslog(LOG_DEBUG, "%s: got a KVP: pool=%d key=%s val=%s",
 357		       __func__, pool, key, value);
 358
 359	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 360		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
 361		syslog(LOG_ERR, "%s: Too long key or value: key=%s, val=%s",
 362		       __func__, key, value);
 363
 364		if (debug)
 365			syslog(LOG_DEBUG, "%s: Too long key or value: pool=%d, key=%s, val=%s",
 366			       __func__, pool, key, value);
 367		return 1;
 368	}
 369
 370	/*
 371	 * First update the in-memory state.
 372	 */
 373	kvp_update_mem_state(pool);
 374
 375	num_records = kvp_file_info[pool].num_records;
 376	record = kvp_file_info[pool].records;
 377	num_blocks = kvp_file_info[pool].num_blocks;
 378
 379	for (i = 0; i < num_records; i++) {
 380		if (memcmp(key, record[i].key, key_size))
 381			continue;
 382		/*
 383		 * Found a match; just update the value -
 384		 * this is the modify case.
 385		 */
 386		memcpy(record[i].value, value, value_size);
 387		kvp_update_file(pool);
 388		if (debug)
 389			syslog(LOG_DEBUG, "%s: updated: pool=%d key=%s val=%s",
 390			       __func__, pool, key, value);
 391		return 0;
 392	}
 393
 394	/*
 395	 * Need to add a new entry;
 396	 */
 397	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
 398		/* Need to allocate a larger array for reg entries. */
 399		record = realloc(record, sizeof(struct kvp_record) *
 400			 ENTRIES_PER_BLOCK * (num_blocks + 1));
 401
 402		if (!record) {
 403			syslog(LOG_ERR, "%s: Memory alloc failure", __func__);
 404			return 1;
 405		}
 406		kvp_file_info[pool].num_blocks++;
 407
 408	}
 409	memcpy(record[i].value, value, value_size);
 410	memcpy(record[i].key, key, key_size);
 411	kvp_file_info[pool].records = record;
 412	kvp_file_info[pool].num_records++;
 413
 414	if (debug)
 415		syslog(LOG_DEBUG, "%s: added: pool=%d key=%s val=%s",
 416		       __func__, pool, key, value);
 417
 418	kvp_update_file(pool);
 419	return 0;
 420}
 421
 422static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
 423			int value_size)
 424{
 425	int i;
 426	int num_records;
 427	struct kvp_record *record;
 428
 429	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 430		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
 431		return 1;
 432
 433	/*
 434	 * First update the in-memory state.
 435	 */
 436	kvp_update_mem_state(pool);
 437
 438	num_records = kvp_file_info[pool].num_records;
 439	record = kvp_file_info[pool].records;
 440
 441	for (i = 0; i < num_records; i++) {
 442		if (memcmp(key, record[i].key, key_size))
 443			continue;
 444		/*
 445		 * Found a match; just copy the value out.
 446		 */
 447		memcpy(value, record[i].value, value_size);
 448		return 0;
 449	}
 450
 451	return 1;
 452}
 453
 454static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
 455				__u8 *value, int value_size)
 456{
 457	struct kvp_record *record;
 458
 459	/*
 460	 * First update our in-memory database.
 461	 */
 462	kvp_update_mem_state(pool);
 463	record = kvp_file_info[pool].records;
 464
 465	if (index >= kvp_file_info[pool].num_records) {
 466		return 1;
 467	}
 468
 469	memcpy(key, record[index].key, key_size);
 470	memcpy(value, record[index].value, value_size);
 471	return 0;
 472}
 473
 474
 475void kvp_get_os_info(void)
 476{
 477	FILE	*file;
 478	char	*p, buf[512];
 479
 480	uname(&uts_buf);
 481	os_version = uts_buf.release;
 482	os_build = strdup(uts_buf.release);
 483
 484	os_name = uts_buf.sysname;
 485	processor_arch = uts_buf.machine;
 486
 487	/*
 488	 * The current windows host (win7) expects the build
 489	 * string to be of the form: x.y.z
 490	 * Strip additional information we may have.
 491	 */
 492	p = strchr(os_version, '-');
 493	if (p)
 494		*p = '\0';
 495
 496	/*
 497	 * Parse the /etc/os-release file if present:
 498	 * https://www.freedesktop.org/software/systemd/man/os-release.html
 499	 */
 500	file = fopen("/etc/os-release", "r");
 501	if (file != NULL) {
 502		while (fgets(buf, sizeof(buf), file)) {
 503			char *value, *q;
 504
 505			/* Ignore comments */
 506			if (buf[0] == '#')
 507				continue;
 508
 509			/* Split into name=value */
 510			p = strchr(buf, '=');
 511			if (!p)
 512				continue;
 513			*p++ = 0;
 514
 515			/* Remove quotes and newline; un-escape */
 516			value = p;
 517			q = p;
 518			while (*p) {
 519				if (*p == '\\') {
 520					++p;
 521					if (!*p)
 522						break;
 523					*q++ = *p++;
 524				} else if (*p == '\'' || *p == '"' ||
 525					   *p == '\n') {
 526					++p;
 527				} else {
 528					*q++ = *p++;
 529				}
 530			}
 531			*q = 0;
 532
 533			if (!strcmp(buf, "NAME")) {
 534				p = strdup(value);
 535				if (!p)
 536					break;
 537				os_name = p;
 538			} else if (!strcmp(buf, "VERSION_ID")) {
 539				p = strdup(value);
 540				if (!p)
 541					break;
 542				os_major = p;
 543			}
 544		}
 545		fclose(file);
 546		return;
 547	}
 548
 549	/* Fallback for older RH/SUSE releases */
 550	file = fopen("/etc/SuSE-release", "r");
 551	if (file != NULL)
 552		goto kvp_osinfo_found;
 553	file  = fopen("/etc/redhat-release", "r");
 554	if (file != NULL)
 555		goto kvp_osinfo_found;
 556
 557	/*
 558	 * We don't have information about the os.
 559	 */
 560	return;
 561
 562kvp_osinfo_found:
 563	/* up to three lines */
 564	p = fgets(buf, sizeof(buf), file);
 565	if (p) {
 566		p = strchr(buf, '\n');
 567		if (p)
 568			*p = '\0';
 569		p = strdup(buf);
 570		if (!p)
 571			goto done;
 572		os_name = p;
 573
 574		/* second line */
 575		p = fgets(buf, sizeof(buf), file);
 576		if (p) {
 577			p = strchr(buf, '\n');
 578			if (p)
 579				*p = '\0';
 580			p = strdup(buf);
 581			if (!p)
 582				goto done;
 583			os_major = p;
 584
 585			/* third line */
 586			p = fgets(buf, sizeof(buf), file);
 587			if (p)  {
 588				p = strchr(buf, '\n');
 589				if (p)
 590					*p = '\0';
 591				p = strdup(buf);
 592				if (p)
 593					os_minor = p;
 594			}
 595		}
 596	}
 597
 598done:
 599	fclose(file);
 600	return;
 601}
 602
 603
 604
 605/*
 606 * Retrieve an interface name corresponding to the specified guid.
 607 * If there is a match, the function returns a pointer
 608 * to the interface name and if not, a NULL is returned.
 609 * If a match is found, the caller is responsible for
 610 * freeing the memory.
 611 */
 612
 613static char *kvp_get_if_name(char *guid)
 614{
 615	DIR *dir;
 616	struct dirent *entry;
 617	FILE    *file;
 618	char    *p, *x;
 619	char    *if_name = NULL;
 620	char    buf[256];
 621	char dev_id[PATH_MAX];
 622
 623	dir = opendir(KVP_NET_DIR);
 624	if (dir == NULL)
 625		return NULL;
 626
 627	while ((entry = readdir(dir)) != NULL) {
 628		/*
 629		 * Set the state for the next pass.
 630		 */
 631		snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
 632			 KVP_NET_DIR, entry->d_name);
 633
 634		file = fopen(dev_id, "r");
 635		if (file == NULL)
 636			continue;
 637
 638		p = fgets(buf, sizeof(buf), file);
 639		if (p) {
 640			x = strchr(p, '\n');
 641			if (x)
 642				*x = '\0';
 643
 644			if (!strcmp(p, guid)) {
 645				/*
 646				 * Found the guid match; return the interface
 647				 * name. The caller will free the memory.
 648				 */
 649				if_name = strdup(entry->d_name);
 650				fclose(file);
 651				break;
 652			}
 653		}
 654		fclose(file);
 655	}
 656
 657	closedir(dir);
 658	return if_name;
 659}
 660
 661/*
 662 * Retrieve the MAC address given the interface name.
 663 */
 664
 665static char *kvp_if_name_to_mac(char *if_name)
 666{
 667	FILE    *file;
 668	char    *p, *x;
 669	char    buf[256];
 670	char addr_file[PATH_MAX];
 671	unsigned int i;
 672	char *mac_addr = NULL;
 673
 674	snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
 675		 if_name, "/address");
 676
 677	file = fopen(addr_file, "r");
 678	if (file == NULL)
 679		return NULL;
 680
 681	p = fgets(buf, sizeof(buf), file);
 682	if (p) {
 683		x = strchr(p, '\n');
 684		if (x)
 685			*x = '\0';
 686		for (i = 0; i < strlen(p); i++)
 687			p[i] = toupper(p[i]);
 688		mac_addr = strdup(p);
 689	}
 690
 691	fclose(file);
 692	return mac_addr;
 693}
 694
 695static void kvp_process_ipconfig_file(char *cmd,
 696					char *config_buf, unsigned int len,
 697					int element_size, int offset)
 698{
 699	char buf[256];
 700	char *p;
 701	char *x;
 702	FILE *file;
 703
 704	/*
 705	 * First execute the command.
 706	 */
 707	file = popen(cmd, "r");
 708	if (file == NULL)
 709		return;
 710
 711	if (offset == 0)
 712		memset(config_buf, 0, len);
 713	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
 714		if (len < strlen(config_buf) + element_size + 1)
 715			break;
 716
 717		x = strchr(p, '\n');
 718		if (x)
 719			*x = '\0';
 720
 721		strcat(config_buf, p);
 722		strcat(config_buf, ";");
 723	}
 724	pclose(file);
 725}
 726
 727static bool kvp_verify_ip_address(const void *address_string)
 728{
 729	char verify_buf[sizeof(struct in6_addr)];
 730
 731	if (inet_pton(AF_INET, address_string, verify_buf) == 1)
 732		return true;
 733	if (inet_pton(AF_INET6, address_string, verify_buf) == 1)
 734		return true;
 735	return false;
 736}
 737
 738static void kvp_extract_routes(const char *line, void **output, size_t *remaining)
 739{
 740	static const char needle[] = "via ";
 741	const char *match, *haystack = line;
 742
 743	while ((match = strstr(haystack, needle))) {
 744		const char *address, *next_char;
 745
 746		/* Address starts after needle. */
 747		address = match + strlen(needle);
 748
 749		/* The char following address is a space or end of line. */
 750		next_char = strpbrk(address, " \t\\");
 751		if (!next_char)
 752			next_char = address + strlen(address) + 1;
 753
 754		/* Enough room for address and semicolon. */
 755		if (*remaining >= (next_char - address) + 1) {
 756			memcpy(*output, address, next_char - address);
 757			/* Terminate string for verification. */
 758			memcpy(*output + (next_char - address), "", 1);
 759			if (kvp_verify_ip_address(*output)) {
 760				/* Advance output buffer. */
 761				*output += next_char - address;
 762				*remaining -= next_char - address;
 763
 764				/* Each address needs a trailing semicolon. */
 765				memcpy(*output, ";", 1);
 766				*output += 1;
 767				*remaining -= 1;
 768			}
 769		}
 770		haystack = next_char;
 771	}
 772}
 773
 774static void kvp_get_gateway(void *buffer, size_t buffer_len)
 775{
 776	static const char needle[] = "default ";
 777	FILE *f;
 778	void *output = buffer;
 779	char *line = NULL;
 780	size_t alloc_size = 0, remaining = buffer_len - 1;
 781	ssize_t num_chars;
 782
 783	/* Show route information in a single line, for each address family */
 784	f = popen("ip --oneline -4 route show;ip --oneline -6 route show", "r");
 785	if (!f) {
 786		/* Convert buffer into C-String. */
 787		memcpy(output, "", 1);
 788		return;
 789	}
 790	while ((num_chars = getline(&line, &alloc_size, f)) > 0) {
 791		/* Skip short lines. */
 792		if (num_chars <= strlen(needle))
 793			continue;
 794		/* Skip lines without default route. */
 795		if (memcmp(line, needle, strlen(needle)))
 796			continue;
 797		/* Remove trailing newline to simplify further parsing. */
 798		if (line[num_chars - 1] == '\n')
 799			line[num_chars - 1] = '\0';
 800		/* Search routes after match. */
 801		kvp_extract_routes(line + strlen(needle), &output, &remaining);
 802	}
 803	/* Convert buffer into C-String. */
 804	memcpy(output, "", 1);
 805	free(line);
 806	pclose(f);
 807}
 808
 809static void kvp_get_ipconfig_info(char *if_name,
 810				 struct hv_kvp_ipaddr_value *buffer)
 811{
 812	char cmd[512];
 813	char dhcp_info[128];
 814	char *p;
 815	FILE *file;
 816
 817	kvp_get_gateway(buffer->gate_way, sizeof(buffer->gate_way));
 818
 819	/*
 820	 * Gather the DNS state.
 821	 * Since there is no standard way to get this information
 822	 * across various distributions of interest; we just invoke
 823	 * an external script that needs to be ported across distros
 824	 * of interest.
 825	 *
 826	 * Following is the expected format of the information from the script:
 827	 *
 828	 * ipaddr1 (nameserver1)
 829	 * ipaddr2 (nameserver2)
 830	 * .
 831	 * .
 832	 */
 833
 834	sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dns_info", if_name);
 835
 836	/*
 837	 * Execute the command to gather DNS info.
 838	 */
 839	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
 840				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
 841
 842	/*
 843	 * Gather the DHCP state.
 844	 * We will gather this state by invoking an external script.
 845	 * The parameter to the script is the interface name.
 846	 * Here is the expected output:
 847	 *
 848	 * Enabled: DHCP enabled.
 849	 */
 850
 851	sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dhcp_info", if_name);
 852
 853	file = popen(cmd, "r");
 854	if (file == NULL)
 855		return;
 856
 857	p = fgets(dhcp_info, sizeof(dhcp_info), file);
 858	if (p == NULL) {
 859		pclose(file);
 860		return;
 861	}
 862
 863	if (!strncmp(p, "Enabled", 7))
 864		buffer->dhcp_enabled = 1;
 865	else
 866		buffer->dhcp_enabled = 0;
 867
 868	pclose(file);
 869}
 870
 871
 872static unsigned int hweight32(unsigned int *w)
 873{
 874	unsigned int res = *w - ((*w >> 1) & 0x55555555);
 875	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
 876	res = (res + (res >> 4)) & 0x0F0F0F0F;
 877	res = res + (res >> 8);
 878	return (res + (res >> 16)) & 0x000000FF;
 879}
 880
 881static int kvp_process_ip_address(void *addrp,
 882				int family, char *buffer,
 883				int length,  int *offset)
 884{
 885	struct sockaddr_in *addr;
 886	struct sockaddr_in6 *addr6;
 887	int addr_length;
 888	char tmp[50];
 889	const char *str;
 890
 891	if (family == AF_INET) {
 892		addr = addrp;
 893		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
 894		addr_length = INET_ADDRSTRLEN;
 895	} else {
 896		addr6 = addrp;
 897		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
 898		addr_length = INET6_ADDRSTRLEN;
 899	}
 900
 901	if ((length - *offset) < addr_length + 2)
 902		return HV_E_FAIL;
 903	if (str == NULL) {
 904		strcpy(buffer, "inet_ntop failed\n");
 905		return HV_E_FAIL;
 906	}
 907	if (*offset == 0)
 908		strcpy(buffer, tmp);
 909	else {
 910		strcat(buffer, ";");
 911		strcat(buffer, tmp);
 912	}
 913
 914	*offset += strlen(str) + 1;
 915
 916	return 0;
 917}
 918
 919static int
 920kvp_get_ip_info(int family, char *if_name, int op,
 921		 void  *out_buffer, unsigned int length)
 922{
 923	struct ifaddrs *ifap;
 924	struct ifaddrs *curp;
 925	int offset = 0;
 926	int sn_offset = 0;
 927	int error = 0;
 928	char *buffer;
 929	struct hv_kvp_ipaddr_value *ip_buffer = NULL;
 930	char cidr_mask[5]; /* /xyz */
 931	int weight;
 932	int i;
 933	unsigned int *w;
 934	char *sn_str;
 935	struct sockaddr_in6 *addr6;
 936
 937	if (op == KVP_OP_ENUMERATE) {
 938		buffer = out_buffer;
 939	} else {
 940		ip_buffer = out_buffer;
 941		buffer = (char *)ip_buffer->ip_addr;
 942		ip_buffer->addr_family = 0;
 943	}
 944	/*
 945	 * On entry into this function, the buffer is capable of holding the
 946	 * maximum key value.
 947	 */
 948
 949	if (getifaddrs(&ifap)) {
 950		strcpy(buffer, "getifaddrs failed\n");
 951		return HV_E_FAIL;
 952	}
 953
 954	curp = ifap;
 955	while (curp != NULL) {
 956		if (curp->ifa_addr == NULL) {
 957			curp = curp->ifa_next;
 958			continue;
 959		}
 960
 961		if ((if_name != NULL) &&
 962			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
 963			/*
 964			 * We want info about a specific interface;
 965			 * just continue.
 966			 */
 967			curp = curp->ifa_next;
 968			continue;
 969		}
 970
 971		/*
 972		 * We only support two address families: AF_INET and AF_INET6.
 973		 * If a family value of 0 is specified, we collect both
 974		 * supported address families; if not we gather info on
 975		 * the specified address family.
 976		 */
 977		if ((((family != 0) &&
 978			 (curp->ifa_addr->sa_family != family))) ||
 979			 (curp->ifa_flags & IFF_LOOPBACK)) {
 980			curp = curp->ifa_next;
 981			continue;
 982		}
 983		if ((curp->ifa_addr->sa_family != AF_INET) &&
 984			(curp->ifa_addr->sa_family != AF_INET6)) {
 985			curp = curp->ifa_next;
 986			continue;
 987		}
 988
 989		if (op == KVP_OP_GET_IP_INFO) {
 990			/*
 991			 * Gather info other than the IP address.
 992			 * IP address info will be gathered later.
 993			 */
 994			if (curp->ifa_addr->sa_family == AF_INET) {
 995				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
 996				/*
 997				 * Get subnet info.
 998				 */
 999				error = kvp_process_ip_address(
1000							     curp->ifa_netmask,
1001							     AF_INET,
1002							     (char *)
1003							     ip_buffer->sub_net,
1004							     length,
1005							     &sn_offset);
1006				if (error)
1007					goto gather_ipaddr;
1008			} else {
1009				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
1010
1011				/*
1012				 * Get subnet info in CIDR format.
1013				 */
1014				weight = 0;
1015				sn_str = (char *)ip_buffer->sub_net;
1016				addr6 = (struct sockaddr_in6 *)
1017					curp->ifa_netmask;
1018				w = addr6->sin6_addr.s6_addr32;
1019
1020				for (i = 0; i < 4; i++)
1021					weight += hweight32(&w[i]);
1022
1023				sprintf(cidr_mask, "/%d", weight);
1024				if (length < sn_offset + strlen(cidr_mask) + 1)
1025					goto gather_ipaddr;
1026
1027				if (sn_offset == 0)
1028					strcpy(sn_str, cidr_mask);
1029				else {
1030					strcat((char *)ip_buffer->sub_net, ";");
1031					strcat(sn_str, cidr_mask);
1032				}
1033				sn_offset += strlen(sn_str) + 1;
1034			}
1035
1036			/*
1037			 * Collect other ip related configuration info.
1038			 */
1039
1040			kvp_get_ipconfig_info(if_name, ip_buffer);
1041		}
1042
1043gather_ipaddr:
1044		error = kvp_process_ip_address(curp->ifa_addr,
1045						curp->ifa_addr->sa_family,
1046						buffer,
1047						length, &offset);
1048		if (error)
1049			goto getaddr_done;
1050
1051		curp = curp->ifa_next;
1052	}
1053
1054getaddr_done:
1055	freeifaddrs(ifap);
1056	return error;
1057}
1058
1059/*
1060 * Retrieve the IP given the MAC address.
1061 */
1062static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
1063{
1064	char *mac = (char *)kvp_ip_val->adapter_id;
1065	DIR *dir;
1066	struct dirent *entry;
1067	FILE    *file;
1068	char    *p, *x;
1069	char    *if_name = NULL;
1070	char    buf[256];
1071	char dev_id[PATH_MAX];
1072	unsigned int i;
1073	int error = HV_E_FAIL;
1074
1075	dir = opendir(KVP_NET_DIR);
1076	if (dir == NULL)
1077		return HV_E_FAIL;
1078
1079	while ((entry = readdir(dir)) != NULL) {
1080		/*
1081		 * Set the state for the next pass.
1082		 */
1083		snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
1084			 entry->d_name);
1085
1086		file = fopen(dev_id, "r");
1087		if (file == NULL)
1088			continue;
1089
1090		p = fgets(buf, sizeof(buf), file);
1091		fclose(file);
1092		if (!p)
1093			continue;
1094
1095		x = strchr(p, '\n');
1096		if (x)
1097			*x = '\0';
1098
1099		for (i = 0; i < strlen(p); i++)
1100			p[i] = toupper(p[i]);
1101
1102		if (strcmp(p, mac))
1103			continue;
1104
1105		/*
1106		 * Found the MAC match.
1107		 * A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
1108		 */
1109		if_name = entry->d_name;
1110		if (!if_name)
1111			continue;
1112
1113		error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
1114					kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
1115
1116		if (!error && strlen((char *)kvp_ip_val->ip_addr))
1117			break;
1118	}
1119
1120	closedir(dir);
1121	return error;
1122}
1123
1124static int expand_ipv6(char *addr, int type)
1125{
1126	int ret;
1127	struct in6_addr v6_addr;
1128
1129	ret = inet_pton(AF_INET6, addr, &v6_addr);
1130
1131	if (ret != 1) {
1132		if (type == NETMASK)
1133			return 1;
1134		return 0;
1135	}
1136
1137	sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1138		"%02x%02x:%02x%02x:%02x%02x",
1139		(int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1140		(int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1141		(int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1142		(int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1143		(int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1144		(int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1145		(int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1146		(int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1147
1148	return 1;
1149
1150}
1151
1152static int is_ipv4(char *addr)
1153{
1154	int ret;
1155	struct in_addr ipv4_addr;
1156
1157	ret = inet_pton(AF_INET, addr, &ipv4_addr);
1158
1159	if (ret == 1)
1160		return 1;
1161	return 0;
1162}
1163
1164static int parse_ip_val_buffer(char *in_buf, int *offset,
1165				char *out_buf, int out_len)
1166{
1167	char *x;
1168	char *start;
1169
1170	/*
1171	 * in_buf has sequence of characters that are separated by
1172	 * the character ';'. The last sequence does not have the
1173	 * terminating ";" character.
1174	 */
1175	start = in_buf + *offset;
1176
1177	x = strchr(start, ';');
1178	if (x)
1179		*x = 0;
1180	else
1181		x = start + strlen(start);
1182
1183	if (strlen(start) != 0) {
1184		int i = 0;
1185		/*
1186		 * Get rid of leading spaces.
1187		 */
1188		while (start[i] == ' ')
1189			i++;
1190
1191		if ((x - start) <= out_len) {
1192			strcpy(out_buf, (start + i));
1193			*offset += (x - start) + 1;
1194			return 1;
1195		}
1196	}
1197	return 0;
1198}
1199
1200static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1201{
1202	int ret;
1203
1204	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1205
1206	if (ret < 0)
1207		return HV_E_FAIL;
1208
1209	return 0;
1210}
1211
1212
1213static int process_ip_string(FILE *f, char *ip_string, int type)
1214{
1215	int error = 0;
1216	char addr[INET6_ADDRSTRLEN];
1217	int i = 0;
1218	int j = 0;
1219	char str[256];
1220	char sub_str[13];
1221	int offset = 0;
1222
1223	memset(addr, 0, sizeof(addr));
1224
1225	while (parse_ip_val_buffer(ip_string, &offset, addr,
1226					(MAX_IP_ADDR_SIZE * 2))) {
1227
1228		sub_str[0] = 0;
1229		if (is_ipv4(addr)) {
1230			switch (type) {
1231			case IPADDR:
1232				snprintf(str, sizeof(str), "%s", "IPADDR");
1233				break;
1234			case NETMASK:
1235				snprintf(str, sizeof(str), "%s", "NETMASK");
1236				break;
1237			case GATEWAY:
1238				snprintf(str, sizeof(str), "%s", "GATEWAY");
1239				break;
1240			case DNS:
1241				snprintf(str, sizeof(str), "%s", "DNS");
1242				break;
1243			}
1244
1245			if (type == DNS) {
1246				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1247			} else if (type == GATEWAY && i == 0) {
1248				++i;
1249			} else {
1250				snprintf(sub_str, sizeof(sub_str), "%d", i++);
1251			}
1252
1253
1254		} else if (expand_ipv6(addr, type)) {
1255			switch (type) {
1256			case IPADDR:
1257				snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1258				break;
1259			case NETMASK:
1260				snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1261				break;
1262			case GATEWAY:
1263				snprintf(str, sizeof(str), "%s",
1264					"IPV6_DEFAULTGW");
1265				break;
1266			case DNS:
1267				snprintf(str, sizeof(str), "%s",  "DNS");
1268				break;
1269			}
1270
1271			if (type == DNS) {
1272				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1273			} else if (j == 0) {
1274				++j;
1275			} else {
1276				snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1277			}
1278		} else {
1279			return  HV_INVALIDARG;
1280		}
1281
1282		error = kvp_write_file(f, str, sub_str, addr);
1283		if (error)
1284			return error;
1285		memset(addr, 0, sizeof(addr));
1286	}
1287
1288	return 0;
1289}
1290
1291int ip_version_check(const char *input_addr)
1292{
1293	struct in6_addr addr;
1294
1295	if (inet_pton(AF_INET, input_addr, &addr))
1296		return IPV4;
1297	else if (inet_pton(AF_INET6, input_addr, &addr))
1298		return IPV6;
1299
1300	return -EINVAL;
1301}
1302
1303/*
1304 * Only IPv4 subnet strings needs to be converted to plen
1305 * For IPv6 the subnet is already privided in plen format
1306 */
1307static int kvp_subnet_to_plen(char *subnet_addr_str)
1308{
1309	int plen = 0;
1310	struct in_addr subnet_addr4;
1311
1312	/*
1313	 * Convert subnet address to binary representation
1314	 */
1315	if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) {
1316		uint32_t subnet_mask = ntohl(subnet_addr4.s_addr);
1317
1318		while (subnet_mask & 0x80000000) {
1319			plen++;
1320			subnet_mask <<= 1;
1321		}
1322	} else {
1323		return -1;
1324	}
1325
1326	return plen;
1327}
1328
1329static int process_dns_gateway_nm(FILE *f, char *ip_string, int type,
1330				  int ip_sec)
1331{
1332	char addr[INET6_ADDRSTRLEN], *output_str;
1333	int ip_offset = 0, error = 0, ip_ver;
1334	char *param_name;
1335
1336	if (type == DNS)
1337		param_name = "dns";
1338	else if (type == GATEWAY)
1339		param_name = "gateway";
1340	else
1341		return -EINVAL;
1342
1343	output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char));
1344	if (!output_str)
1345		return -ENOMEM;
1346
1347	while (1) {
1348		memset(addr, 0, sizeof(addr));
1349
1350		if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
1351					 (MAX_IP_ADDR_SIZE * 2)))
1352			break;
1353
1354		ip_ver = ip_version_check(addr);
1355		if (ip_ver < 0)
1356			continue;
1357
1358		if ((ip_ver == IPV4 && ip_sec == IPV4) ||
1359		    (ip_ver == IPV6 && ip_sec == IPV6)) {
1360			/*
1361			 * do a bound check to avoid out-of bound writes
1362			 */
1363			if ((OUTSTR_BUF_SIZE - strlen(output_str)) >
1364			    (strlen(addr) + 1)) {
1365				strncat(output_str, addr,
1366					OUTSTR_BUF_SIZE -
1367					strlen(output_str) - 1);
1368				strncat(output_str, ",",
1369					OUTSTR_BUF_SIZE -
1370					strlen(output_str) - 1);
1371			}
1372		} else {
1373			continue;
1374		}
1375	}
1376
1377	if (strlen(output_str)) {
1378		/*
1379		 * This is to get rid of that extra comma character
1380		 * in the end of the string
1381		 */
1382		output_str[strlen(output_str) - 1] = '\0';
1383		error = fprintf(f, "%s=%s\n", param_name, output_str);
1384	}
1385
1386	free(output_str);
1387	return error;
1388}
1389
1390static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
1391				int ip_sec)
1392{
1393	char addr[INET6_ADDRSTRLEN];
1394	char subnet_addr[INET6_ADDRSTRLEN];
1395	int error = 0, i = 0;
1396	int ip_offset = 0, subnet_offset = 0;
1397	int plen, ip_ver;
1398
1399	memset(addr, 0, sizeof(addr));
1400	memset(subnet_addr, 0, sizeof(subnet_addr));
1401
1402	while (parse_ip_val_buffer(ip_string, &ip_offset, addr,
1403				   (MAX_IP_ADDR_SIZE * 2)) &&
1404				   parse_ip_val_buffer(subnet,
1405						       &subnet_offset,
1406						       subnet_addr,
1407						       (MAX_IP_ADDR_SIZE *
1408							2))) {
1409		ip_ver = ip_version_check(addr);
1410		if (ip_ver < 0)
1411			continue;
1412
1413		if (ip_ver == IPV4 && ip_sec == IPV4)
1414			plen = kvp_subnet_to_plen((char *)subnet_addr);
1415		else if (ip_ver == IPV6 && ip_sec == IPV6)
1416			plen = atoi(subnet_addr);
1417		else
1418			continue;
1419
1420		if (plen < 0)
1421			return plen;
1422
1423		error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr,
1424				plen);
1425		if (error < 0)
1426			return error;
1427
1428		memset(addr, 0, sizeof(addr));
1429		memset(subnet_addr, 0, sizeof(subnet_addr));
1430	}
1431
1432	return error;
1433}
1434
1435static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1436{
1437	int error = 0, ip_ver;
1438	char if_filename[PATH_MAX];
1439	char nm_filename[PATH_MAX];
1440	FILE *ifcfg_file, *nmfile;
1441	char cmd[PATH_MAX];
1442	char *mac_addr;
1443	int str_len;
1444
1445	/*
1446	 * Set the configuration for the specified interface with
1447	 * the information provided. Since there is no standard
1448	 * way to configure an interface, we will have an external
1449	 * script that does the job of configuring the interface and
1450	 * flushing the configuration.
1451	 *
1452	 * The parameters passed to this external script are:
1453	 * 1. A configuration file that has the specified configuration.
1454	 *
1455	 * We will embed the name of the interface in the configuration
1456	 * file: ifcfg-ethx (where ethx is the interface name).
1457	 *
1458	 * The information provided here may be more than what is needed
1459	 * in a given distro to configure the interface and so are free
1460	 * ignore information that may not be relevant.
1461	 *
1462	 * Here is the ifcfg format of the ip configuration file:
1463	 *
1464	 * HWADDR=macaddr
1465	 * DEVICE=interface name
1466	 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
1467	 *                       or "none" if no boot-time protocol should be used)
1468	 *
1469	 * IPADDR0=ipaddr1
1470	 * IPADDR1=ipaddr2
1471	 * IPADDRx=ipaddry (where y = x + 1)
1472	 *
1473	 * NETMASK0=netmask1
1474	 * NETMASKx=netmasky (where y = x + 1)
1475	 *
1476	 * GATEWAY=ipaddr1
1477	 * GATEWAYx=ipaddry (where y = x + 1)
1478	 *
1479	 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1480	 *
1481	 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1482	 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1483	 * IPV6NETMASK.
1484	 *
1485	 * Here is the keyfile format of the ip configuration file:
1486	 *
1487	 * [ethernet]
1488	 * mac-address=macaddr
1489	 * [connection]
1490	 * interface-name=interface name
1491	 *
1492	 * [ipv4]
1493	 * method=<protocol> (where <protocol> is "auto" if DHCP is configured
1494	 *                       or "manual" if no boot-time protocol should be used)
1495	 *
1496	 * address1=ipaddr1/plen
1497	 * address2=ipaddr2/plen
1498	 *
1499	 * gateway=gateway1;gateway2
1500	 *
1501	 * dns=dns1;dns2
1502	 *
1503	 * [ipv6]
1504	 * address1=ipaddr1/plen
1505	 * address2=ipaddr2/plen
1506	 *
1507	 * gateway=gateway1;gateway2
1508	 *
1509	 * dns=dns1;dns2
1510	 *
1511	 * The host can specify multiple ipv4 and ipv6 addresses to be
1512	 * configured for the interface. Furthermore, the configuration
1513	 * needs to be persistent. A subsequent GET call on the interface
1514	 * is expected to return the configuration that is set via the SET
1515	 * call.
1516	 */
1517
1518	/*
1519	 * We are populating both ifcfg and nmconnection files
1520	 */
1521	snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC,
1522		 "/ifcfg-", if_name);
1523
1524	ifcfg_file = fopen(if_filename, "w");
1525
1526	if (!ifcfg_file) {
1527		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1528		       errno, strerror(errno));
1529		return HV_E_FAIL;
1530	}
1531
1532	snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC,
1533		 "/", if_name, ".nmconnection");
1534
1535	nmfile = fopen(nm_filename, "w");
1536
1537	if (!nmfile) {
1538		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1539		       errno, strerror(errno));
1540		fclose(ifcfg_file);
1541		return HV_E_FAIL;
1542	}
1543
1544	/*
1545	 * First write out the MAC address.
1546	 */
1547
1548	mac_addr = kvp_if_name_to_mac(if_name);
1549	if (mac_addr == NULL) {
1550		error = HV_E_FAIL;
1551		goto setval_error;
1552	}
1553
1554	error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr);
1555	if (error < 0)
1556		goto setmac_error;
1557
1558	error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name);
1559	if (error < 0)
1560		goto setmac_error;
1561
1562	error = fprintf(nmfile, "\n[connection]\n");
1563	if (error < 0)
1564		goto setmac_error;
1565
1566	error = kvp_write_file(nmfile, "interface-name", "", if_name);
1567	if (error)
1568		goto setmac_error;
1569
1570	error = fprintf(nmfile, "\n[ethernet]\n");
1571	if (error < 0)
1572		goto setmac_error;
1573
1574	error = kvp_write_file(nmfile, "mac-address", "", mac_addr);
1575	if (error)
1576		goto setmac_error;
1577
1578	free(mac_addr);
1579
1580	/*
1581	 * The dhcp_enabled flag is only for IPv4. In the case the host only
1582	 * injects an IPv6 address, the flag is true, but we still need to
1583	 * proceed to parse and pass the IPv6 information to the
1584	 * disto-specific script hv_set_ifconfig.
1585	 */
1586
1587	/*
1588	 * First populate the ifcfg file format
1589	 */
1590	if (new_val->dhcp_enabled) {
1591		error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp");
1592		if (error)
1593			goto setval_error;
1594	} else {
1595		error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none");
1596		if (error)
1597			goto setval_error;
1598	}
1599
1600	error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr,
1601				  IPADDR);
1602	if (error)
1603		goto setval_error;
1604
1605	error = process_ip_string(ifcfg_file, (char *)new_val->sub_net,
1606				  NETMASK);
1607	if (error)
1608		goto setval_error;
1609
1610	error = process_ip_string(ifcfg_file, (char *)new_val->gate_way,
1611				  GATEWAY);
1612	if (error)
1613		goto setval_error;
1614
1615	error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS);
1616	if (error)
1617		goto setval_error;
1618
1619	/*
1620	 * Now we populate the keyfile format
1621	 *
1622	 * The keyfile format expects the IPv6 and IPv4 configuration in
1623	 * different sections. Therefore we iterate through the list twice,
1624	 * once to populate the IPv4 section and the next time for IPv6
1625	 */
1626	ip_ver = IPV4;
1627	do {
1628		if (ip_ver == IPV4) {
1629			error = fprintf(nmfile, "\n[ipv4]\n");
1630			if (error < 0)
1631				goto setval_error;
1632		} else {
1633			error = fprintf(nmfile, "\n[ipv6]\n");
1634			if (error < 0)
1635				goto setval_error;
1636		}
1637
1638		/*
1639		 * Write the configuration for ipaddress, netmask, gateway and
1640		 * name services
1641		 */
1642		error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
1643					     (char *)new_val->sub_net,
1644					     ip_ver);
1645		if (error < 0)
1646			goto setval_error;
1647
1648		/*
1649		 * As dhcp_enabled is only valid for ipv4, we do not set dhcp
1650		 * methods for ipv6 based on dhcp_enabled flag.
1651		 *
1652		 * For ipv4, set method to manual only when dhcp_enabled is
1653		 * false and specific ipv4 addresses are configured. If neither
1654		 * dhcp_enabled is true and no ipv4 addresses are configured,
1655		 * set method to 'disabled'.
1656		 *
1657		 * For ipv6, set method to manual when we configure ipv6
1658		 * addresses. Otherwise set method to 'auto' so that SLAAC from
1659		 * RA may be used.
1660		 */
1661		if (ip_ver == IPV4) {
1662			if (new_val->dhcp_enabled) {
1663				error = kvp_write_file(nmfile, "method", "",
1664						       "auto");
1665				if (error < 0)
1666					goto setval_error;
1667			} else if (error) {
1668				error = kvp_write_file(nmfile, "method", "",
1669						       "manual");
1670				if (error < 0)
1671					goto setval_error;
1672			} else {
1673				error = kvp_write_file(nmfile, "method", "",
1674						       "disabled");
1675				if (error < 0)
1676					goto setval_error;
1677			}
1678		} else if (ip_ver == IPV6) {
1679			if (error) {
1680				error = kvp_write_file(nmfile, "method", "",
1681						       "manual");
1682				if (error < 0)
1683					goto setval_error;
1684			} else {
1685				error = kvp_write_file(nmfile, "method", "",
1686						       "auto");
1687				if (error < 0)
1688					goto setval_error;
1689			}
1690		}
1691
1692		error = process_dns_gateway_nm(nmfile,
1693					       (char *)new_val->gate_way,
1694					       GATEWAY, ip_ver);
1695		if (error < 0)
1696			goto setval_error;
1697
1698		error = process_dns_gateway_nm(nmfile,
1699					       (char *)new_val->dns_addr, DNS,
1700					       ip_ver);
1701		if (error < 0)
1702			goto setval_error;
1703
1704		ip_ver++;
1705	} while (ip_ver < IP_TYPE_MAX);
1706
1707	fclose(nmfile);
1708	fclose(ifcfg_file);
1709
1710	/*
1711	 * Now that we have populated the configuration file,
1712	 * invoke the external script to do its magic.
1713	 */
1714
1715	str_len = snprintf(cmd, sizeof(cmd), "exec %s %s %s",
1716			   KVP_SCRIPTS_PATH "hv_set_ifconfig",
1717			   if_filename, nm_filename);
1718	/*
1719	 * This is a little overcautious, but it's necessary to suppress some
1720	 * false warnings from gcc 8.0.1.
1721	 */
1722	if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
1723		syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
1724		       cmd, str_len);
1725		return HV_E_FAIL;
1726	}
1727
1728	if (system(cmd)) {
1729		syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1730		       cmd, errno, strerror(errno));
1731		return HV_E_FAIL;
1732	}
1733	return 0;
1734setmac_error:
1735	free(mac_addr);
1736setval_error:
1737	syslog(LOG_ERR, "Failed to write config file");
1738	fclose(ifcfg_file);
1739	fclose(nmfile);
1740	return error;
1741}
1742
1743
1744static void
1745kvp_get_domain_name(char *buffer, int length)
1746{
1747	struct addrinfo	hints, *info ;
1748	int error = 0;
1749
1750	gethostname(buffer, length);
1751	memset(&hints, 0, sizeof(hints));
1752	hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1753	hints.ai_socktype = SOCK_STREAM;
1754	hints.ai_flags = AI_CANONNAME;
1755
1756	error = getaddrinfo(buffer, NULL, &hints, &info);
1757	if (error != 0) {
1758		snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1759			error, gai_strerror(error));
1760		return;
1761	}
1762	snprintf(buffer, length, "%s", info->ai_canonname);
1763	freeaddrinfo(info);
1764}
1765
1766void print_usage(char *argv[])
1767{
1768	fprintf(stderr, "Usage: %s [options]\n"
1769		"Options are:\n"
1770		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
1771		"  -d, --debug            Enable debug logs(syslog debug by default)\n"
1772		"  -h, --help             print this help\n", argv[0]);
1773}
1774
1775int main(int argc, char *argv[])
1776{
1777	int kvp_fd = -1, len;
1778	int error;
1779	struct pollfd pfd;
1780	char    *p;
1781	struct hv_kvp_msg hv_msg[1];
1782	char	*key_value;
1783	char	*key_name;
1784	int	op;
1785	int	pool;
1786	char	*if_name;
1787	struct hv_kvp_ipaddr_value *kvp_ip_val;
1788	int daemonize = 1, long_index = 0, opt;
1789
1790	static struct option long_options[] = {
1791		{"help",	no_argument,	   0,  'h' },
1792		{"no-daemon",	no_argument,	   0,  'n' },
1793		{"debug",	no_argument,	   0,  'd' },
1794		{0,		0,		   0,  0   }
1795	};
1796
1797	while ((opt = getopt_long(argc, argv, "hnd", long_options,
1798				  &long_index)) != -1) {
1799		switch (opt) {
1800		case 'n':
1801			daemonize = 0;
1802			break;
1803		case 'h':
1804			print_usage(argv);
1805			exit(0);
1806		case 'd':
1807			debug = 1;
1808			break;
1809		default:
1810			print_usage(argv);
1811			exit(EXIT_FAILURE);
1812		}
1813	}
1814
1815	if (daemonize && daemon(1, 0))
1816		return 1;
1817
1818	openlog("KVP", 0, LOG_USER);
1819	syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1820
1821	/*
1822	 * Retrieve OS release information.
1823	 */
1824	kvp_get_os_info();
1825	/*
1826	 * Cache Fully Qualified Domain Name because getaddrinfo takes an
1827	 * unpredictable amount of time to finish.
1828	 */
1829	kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1830
1831	if (debug)
1832		syslog(LOG_INFO, "Logging debug info in syslog(debug)");
1833
1834	if (kvp_file_init()) {
1835		syslog(LOG_ERR, "Failed to initialize the pools");
1836		exit(EXIT_FAILURE);
1837	}
1838
1839reopen_kvp_fd:
1840	if (kvp_fd != -1)
1841		close(kvp_fd);
1842	in_hand_shake = 1;
1843	kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1844
1845	if (kvp_fd < 0) {
1846		syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1847		       errno, strerror(errno));
1848		exit(EXIT_FAILURE);
1849	}
1850
1851	/*
1852	 * Register ourselves with the kernel.
1853	 */
1854	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1855	len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1856	if (len != sizeof(struct hv_kvp_msg)) {
1857		syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1858		       errno, strerror(errno));
1859		close(kvp_fd);
1860		exit(EXIT_FAILURE);
1861	}
1862
1863	pfd.fd = kvp_fd;
1864
1865	while (1) {
1866		pfd.events = POLLIN;
1867		pfd.revents = 0;
1868
1869		if (poll(&pfd, 1, -1) < 0) {
1870			syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1871			if (errno == EINVAL) {
1872				close(kvp_fd);
1873				exit(EXIT_FAILURE);
1874			}
1875			else
1876				continue;
1877		}
1878
1879		len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1880
1881		if (len != sizeof(struct hv_kvp_msg)) {
1882			syslog(LOG_ERR, "read failed; error:%d %s",
1883			       errno, strerror(errno));
1884			goto reopen_kvp_fd;
1885		}
1886
1887		/*
1888		 * We will use the KVP header information to pass back
1889		 * the error from this daemon. So, first copy the state
1890		 * and set the error code to success.
1891		 */
1892		op = hv_msg->kvp_hdr.operation;
1893		pool = hv_msg->kvp_hdr.pool;
1894		hv_msg->error = HV_S_OK;
1895
1896		if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1897			/*
1898			 * Driver is registering with us; stash away the version
1899			 * information.
1900			 */
1901			in_hand_shake = 0;
1902			p = (char *)hv_msg->body.kvp_register.version;
1903			lic_version = malloc(strlen(p) + 1);
1904			if (lic_version) {
1905				strcpy(lic_version, p);
1906				syslog(LOG_INFO, "KVP LIC Version: %s",
1907				       lic_version);
1908			} else {
1909				syslog(LOG_ERR, "malloc failed");
1910			}
1911			continue;
1912		}
1913
1914		switch (op) {
1915		case KVP_OP_GET_IP_INFO:
1916			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1917
1918			error = kvp_mac_to_ip(kvp_ip_val);
1919
1920			if (error)
1921				hv_msg->error = error;
1922
1923			break;
1924
1925		case KVP_OP_SET_IP_INFO:
1926			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1927			if_name = kvp_get_if_name(
1928					(char *)kvp_ip_val->adapter_id);
1929			if (if_name == NULL) {
1930				/*
1931				 * We could not map the guid to an
1932				 * interface name; return error.
1933				 */
1934				hv_msg->error = HV_GUID_NOTFOUND;
1935				break;
1936			}
1937			error = kvp_set_ip_info(if_name, kvp_ip_val);
1938			if (error)
1939				hv_msg->error = error;
1940
1941			free(if_name);
1942			break;
1943
1944		case KVP_OP_SET:
1945			if (kvp_key_add_or_modify(pool,
1946					hv_msg->body.kvp_set.data.key,
1947					hv_msg->body.kvp_set.data.key_size,
1948					hv_msg->body.kvp_set.data.value,
1949					hv_msg->body.kvp_set.data.value_size))
1950					hv_msg->error = HV_S_CONT;
1951			break;
1952
1953		case KVP_OP_GET:
1954			if (kvp_get_value(pool,
1955					hv_msg->body.kvp_set.data.key,
1956					hv_msg->body.kvp_set.data.key_size,
1957					hv_msg->body.kvp_set.data.value,
1958					hv_msg->body.kvp_set.data.value_size))
1959					hv_msg->error = HV_S_CONT;
1960			break;
1961
1962		case KVP_OP_DELETE:
1963			if (kvp_key_delete(pool,
1964					hv_msg->body.kvp_delete.key,
1965					hv_msg->body.kvp_delete.key_size))
1966					hv_msg->error = HV_S_CONT;
1967			break;
1968
1969		default:
1970			break;
1971		}
1972
1973		if (op != KVP_OP_ENUMERATE)
1974			goto kvp_done;
1975
1976		/*
1977		 * If the pool is KVP_POOL_AUTO, dynamically generate
1978		 * both the key and the value; if not read from the
1979		 * appropriate pool.
1980		 */
1981		if (pool != KVP_POOL_AUTO) {
1982			if (kvp_pool_enumerate(pool,
1983					hv_msg->body.kvp_enum_data.index,
1984					hv_msg->body.kvp_enum_data.data.key,
1985					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1986					hv_msg->body.kvp_enum_data.data.value,
1987					HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1988					hv_msg->error = HV_S_CONT;
1989			goto kvp_done;
1990		}
1991
1992		key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1993		key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1994
1995		switch (hv_msg->body.kvp_enum_data.index) {
1996		case FullyQualifiedDomainName:
1997			strcpy(key_value, full_domain_name);
1998			strcpy(key_name, "FullyQualifiedDomainName");
1999			break;
2000		case IntegrationServicesVersion:
2001			strcpy(key_name, "IntegrationServicesVersion");
2002			strcpy(key_value, lic_version);
2003			break;
2004		case NetworkAddressIPv4:
2005			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
2006				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
2007			strcpy(key_name, "NetworkAddressIPv4");
2008			break;
2009		case NetworkAddressIPv6:
2010			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
2011				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
2012			strcpy(key_name, "NetworkAddressIPv6");
2013			break;
2014		case OSBuildNumber:
2015			strcpy(key_value, os_build);
2016			strcpy(key_name, "OSBuildNumber");
2017			break;
2018		case OSName:
2019			strcpy(key_value, os_name);
2020			strcpy(key_name, "OSName");
2021			break;
2022		case OSMajorVersion:
2023			strcpy(key_value, os_major);
2024			strcpy(key_name, "OSMajorVersion");
2025			break;
2026		case OSMinorVersion:
2027			strcpy(key_value, os_minor);
2028			strcpy(key_name, "OSMinorVersion");
2029			break;
2030		case OSVersion:
2031			strcpy(key_value, os_version);
2032			strcpy(key_name, "OSVersion");
2033			break;
2034		case ProcessorArchitecture:
2035			strcpy(key_value, processor_arch);
2036			strcpy(key_name, "ProcessorArchitecture");
2037			break;
2038		default:
2039			hv_msg->error = HV_S_CONT;
2040			break;
2041		}
2042
2043		/*
2044		 * Send the value back to the kernel. Note: the write() may
2045		 * return an error due to hibernation; we can ignore the error
2046		 * by resetting the dev file, i.e. closing and re-opening it.
2047		 */
2048kvp_done:
2049		len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
2050		if (len != sizeof(struct hv_kvp_msg)) {
2051			syslog(LOG_ERR, "write failed; error: %d %s", errno,
2052			       strerror(errno));
2053			goto reopen_kvp_fd;
2054		}
2055	}
2056
2057	close(kvp_fd);
2058	exit(0);
2059}
~/ Read-only file preview.