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