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