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