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