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