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