1 /*- 2 * Copyright (c) 2014 Microsoft Corp. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <sys/poll.h> 30 #include <sys/utsname.h> 31 #include <sys/stat.h> 32 #include <sys/un.h> 33 34 #include <arpa/inet.h> 35 #include <ifaddrs.h> 36 #include <netdb.h> 37 38 #include <netinet/in.h> 39 #include <net/ethernet.h> 40 #include <net/if_dl.h> 41 #include <net/if_types.h> 42 43 #include <assert.h> 44 45 #include <ctype.h> 46 #include <dirent.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <poll.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <syslog.h> 54 #include <unistd.h> 55 56 #include "hv_kvp.h" 57 58 typedef uint8_t __u8; 59 typedef uint16_t __u16; 60 typedef uint32_t __u32; 61 typedef uint64_t __u64; 62 63 /* 64 * ENUM Data 65 */ 66 67 enum key_index { 68 FullyQualifiedDomainName = 0, 69 IntegrationServicesVersion, /*This key is serviced in the kernel*/ 70 NetworkAddressIPv4, 71 NetworkAddressIPv6, 72 OSBuildNumber, 73 OSName, 74 OSMajorVersion, 75 OSMinorVersion, 76 OSVersion, 77 ProcessorArchitecture 78 }; 79 80 81 enum { 82 IPADDR = 0, 83 NETMASK, 84 GATEWAY, 85 DNS 86 }; 87 88 89 /* Global Variables */ 90 91 /* 92 * The structure for operation handlers. 93 */ 94 struct kvp_op_hdlr { 95 int kvp_op_key; 96 void (*kvp_op_init)(void); 97 int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data); 98 }; 99 100 static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT]; 101 102 /* OS information */ 103 104 static const char *os_name = ""; 105 static const char *os_major = ""; 106 static const char *os_minor = ""; 107 static const char *processor_arch; 108 static const char *os_build; 109 static const char *lic_version = "BSD Pre-Release version"; 110 static struct utsname uts_buf; 111 112 /* Global flags */ 113 static int is_daemon = 1; 114 static int is_debugging = 0; 115 116 #define KVP_LOG(priority, format, args...) do { \ 117 if (is_debugging == 1) { \ 118 if (is_daemon == 1) \ 119 syslog(priority, format, ## args); \ 120 else \ 121 printf(format, ## args); \ 122 } else { \ 123 if (priority < LOG_DEBUG) { \ 124 if (is_daemon == 1) \ 125 syslog(priority, format, ## args); \ 126 else \ 127 printf(format, ## args); \ 128 } \ 129 } \ 130 } while(0) 131 132 /* 133 * For KVP pool file 134 */ 135 136 #define MAX_FILE_NAME 100 137 #define ENTRIES_PER_BLOCK 50 138 139 struct kvp_record { 140 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; 141 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 142 }; 143 144 struct kvp_pool { 145 int pool_fd; 146 int num_blocks; 147 struct kvp_record *records; 148 int num_records; 149 char fname[MAX_FILE_NAME]; 150 }; 151 152 static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT]; 153 154 155 static void 156 kvp_acquire_lock(int pool) 157 { 158 struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 }; 159 160 fl.l_pid = getpid(); 161 162 if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) { 163 KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool); 164 exit(EXIT_FAILURE); 165 } 166 } 167 168 169 static void 170 kvp_release_lock(int pool) 171 { 172 struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 }; 173 174 fl.l_pid = getpid(); 175 176 if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) { 177 perror("fcntl"); 178 KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool); 179 exit(EXIT_FAILURE); 180 } 181 } 182 183 184 /* 185 * Write in-memory copy of KVP to pool files 186 */ 187 static void 188 kvp_update_file(int pool) 189 { 190 FILE *filep; 191 size_t bytes_written; 192 193 kvp_acquire_lock(pool); 194 195 filep = fopen(kvp_pools[pool].fname, "w"); 196 if (!filep) { 197 kvp_release_lock(pool); 198 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool); 199 exit(EXIT_FAILURE); 200 } 201 202 bytes_written = fwrite(kvp_pools[pool].records, 203 sizeof(struct kvp_record), 204 kvp_pools[pool].num_records, filep); 205 206 if (ferror(filep) || fclose(filep)) { 207 kvp_release_lock(pool); 208 KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool); 209 exit(EXIT_FAILURE); 210 } 211 212 kvp_release_lock(pool); 213 } 214 215 216 /* 217 * Read KVPs from pool files and store in memory 218 */ 219 static void 220 kvp_update_mem_state(int pool) 221 { 222 FILE *filep; 223 size_t records_read = 0; 224 struct kvp_record *record = kvp_pools[pool].records; 225 struct kvp_record *readp; 226 int num_blocks = kvp_pools[pool].num_blocks; 227 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 228 229 kvp_acquire_lock(pool); 230 231 filep = fopen(kvp_pools[pool].fname, "r"); 232 if (!filep) { 233 kvp_release_lock(pool); 234 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool); 235 exit(EXIT_FAILURE); 236 } 237 for ( ; ; ) 238 { 239 readp = &record[records_read]; 240 records_read += fread(readp, sizeof(struct kvp_record), 241 ENTRIES_PER_BLOCK * num_blocks, 242 filep); 243 244 if (ferror(filep)) { 245 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool); 246 exit(EXIT_FAILURE); 247 } 248 249 if (!feof(filep)) { 250 /* 251 * Have more data to read. Expand the memory. 252 */ 253 num_blocks++; 254 record = realloc(record, alloc_unit * num_blocks); 255 256 if (record == NULL) { 257 KVP_LOG(LOG_ERR, "malloc failed\n"); 258 exit(EXIT_FAILURE); 259 } 260 continue; 261 } 262 break; 263 } 264 265 kvp_pools[pool].num_blocks = num_blocks; 266 kvp_pools[pool].records = record; 267 kvp_pools[pool].num_records = records_read; 268 269 fclose(filep); 270 kvp_release_lock(pool); 271 } 272 273 274 static int 275 kvp_file_init(void) 276 { 277 int fd; 278 FILE *filep; 279 size_t records_read; 280 char *fname; 281 struct kvp_record *record; 282 struct kvp_record *readp; 283 int num_blocks; 284 int i; 285 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 286 287 if (mkdir("/var/db/hyperv/pool", S_IRUSR | S_IWUSR | S_IROTH) < 0 && 288 (errno != EEXIST && errno != EISDIR)) { 289 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n"); 290 exit(EXIT_FAILURE); 291 } 292 293 for (i = 0; i < HV_KVP_POOL_COUNT; i++) 294 { 295 fname = kvp_pools[i].fname; 296 records_read = 0; 297 num_blocks = 1; 298 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i); 299 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); 300 301 if (fd == -1) { 302 return (1); 303 } 304 305 306 filep = fopen(fname, "r"); 307 if (!filep) { 308 close(fd); 309 return (1); 310 } 311 312 record = malloc(alloc_unit * num_blocks); 313 if (record == NULL) { 314 close(fd); 315 fclose(filep); 316 return (1); 317 } 318 for ( ; ; ) 319 { 320 readp = &record[records_read]; 321 records_read += fread(readp, sizeof(struct kvp_record), 322 ENTRIES_PER_BLOCK, 323 filep); 324 325 if (ferror(filep)) { 326 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", 327 i); 328 exit(EXIT_FAILURE); 329 } 330 331 if (!feof(filep)) { 332 /* 333 * More data to read. 334 */ 335 num_blocks++; 336 record = realloc(record, alloc_unit * 337 num_blocks); 338 if (record == NULL) { 339 close(fd); 340 fclose(filep); 341 return (1); 342 } 343 continue; 344 } 345 break; 346 } 347 kvp_pools[i].pool_fd = fd; 348 kvp_pools[i].num_blocks = num_blocks; 349 kvp_pools[i].records = record; 350 kvp_pools[i].num_records = records_read; 351 fclose(filep); 352 } 353 354 return (0); 355 } 356 357 358 static int 359 kvp_key_delete(int pool, __u8 *key, int key_size) 360 { 361 int i; 362 int j, k; 363 int num_records; 364 struct kvp_record *record; 365 366 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, " 367 "key = %s\n", pool, key); 368 369 /* Update in-memory state */ 370 kvp_update_mem_state(pool); 371 372 num_records = kvp_pools[pool].num_records; 373 record = kvp_pools[pool].records; 374 375 for (i = 0; i < num_records; i++) 376 { 377 if (memcmp(key, record[i].key, key_size)) { 378 continue; 379 } 380 381 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n", 382 pool); 383 /* 384 * We found a match at the end; Just update the number of 385 * entries and we are done. 386 */ 387 if (i == num_records) { 388 kvp_pools[pool].num_records--; 389 kvp_update_file(pool); 390 return (0); 391 } 392 393 /* 394 * We found a match in the middle; Move the remaining 395 * entries up. 396 */ 397 j = i; 398 k = j + 1; 399 for ( ; k < num_records; k++) 400 { 401 strcpy(record[j].key, record[k].key); 402 strcpy(record[j].value, record[k].value); 403 j++; 404 } 405 kvp_pools[pool].num_records--; 406 kvp_update_file(pool); 407 return (0); 408 } 409 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n", 410 pool); 411 return (1); 412 } 413 414 415 static int 416 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value, 417 __u32 value_size) 418 { 419 int i; 420 int num_records; 421 struct kvp_record *record; 422 int num_blocks; 423 424 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, " 425 "key = %s, value = %s\n,", pool, key, value); 426 427 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 428 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 429 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n"); 430 return (1); 431 } 432 433 /* Update the in-memory state. */ 434 kvp_update_mem_state(pool); 435 436 num_records = kvp_pools[pool].num_records; 437 record = kvp_pools[pool].records; 438 num_blocks = kvp_pools[pool].num_blocks; 439 440 for (i = 0; i < num_records; i++) 441 { 442 if (memcmp(key, record[i].key, key_size)) { 443 continue; 444 } 445 446 /* 447 * Key exists. Just update the value and we are done. 448 */ 449 memcpy(record[i].value, value, value_size); 450 kvp_update_file(pool); 451 return (0); 452 } 453 454 /* 455 * Key doesn't exist; Add a new KVP. 456 */ 457 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { 458 /* Increase the size of the recodrd array. */ 459 record = realloc(record, sizeof(struct kvp_record) * 460 ENTRIES_PER_BLOCK * (num_blocks + 1)); 461 462 if (record == NULL) { 463 return (1); 464 } 465 kvp_pools[pool].num_blocks++; 466 } 467 memcpy(record[i].value, value, value_size); 468 memcpy(record[i].key, key, key_size); 469 kvp_pools[pool].records = record; 470 kvp_pools[pool].num_records++; 471 kvp_update_file(pool); 472 return (0); 473 } 474 475 476 static int 477 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, 478 int value_size) 479 { 480 int i; 481 int num_records; 482 struct kvp_record *record; 483 484 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,", 485 pool, key); 486 487 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 488 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 489 return (1); 490 } 491 492 /* Update the in-memory state first. */ 493 kvp_update_mem_state(pool); 494 495 num_records = kvp_pools[pool].num_records; 496 record = kvp_pools[pool].records; 497 498 for (i = 0; i < num_records; i++) 499 { 500 if (memcmp(key, record[i].key, key_size)) { 501 continue; 502 } 503 504 /* Found the key */ 505 memcpy(value, record[i].value, value_size); 506 return (0); 507 } 508 509 return (1); 510 } 511 512 513 static int 514 kvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size, 515 __u8 *value, int value_size) 516 { 517 struct kvp_record *record; 518 519 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,", 520 pool, idx); 521 522 /* First update our in-memory state first. */ 523 kvp_update_mem_state(pool); 524 record = kvp_pools[pool].records; 525 526 /* Index starts with 0 */ 527 if (idx >= kvp_pools[pool].num_records) { 528 return (1); 529 } 530 531 memcpy(key, record[idx].key, key_size); 532 memcpy(value, record[idx].value, value_size); 533 return (0); 534 } 535 536 537 static void 538 kvp_get_os_info(void) 539 { 540 char *p; 541 542 uname(&uts_buf); 543 os_build = uts_buf.release; 544 os_name = uts_buf.sysname; 545 processor_arch = uts_buf.machine; 546 547 /* 548 * Win7 host expects the build string to be of the form: x.y.z 549 * Strip additional information we may have. 550 */ 551 p = strchr(os_build, '-'); 552 if (p) { 553 *p = '\0'; 554 } 555 556 /* 557 * We don't have any other information about the FreeBSD os. 558 */ 559 return; 560 } 561 562 /* 563 * Given the interface name, return the MAC address. 564 */ 565 static char * 566 kvp_if_name_to_mac(char *if_name) 567 { 568 char *mac_addr = NULL; 569 struct ifaddrs *ifaddrs_ptr; 570 struct ifaddrs *head_ifaddrs_ptr; 571 struct sockaddr_dl *sdl; 572 int status; 573 574 status = getifaddrs(&ifaddrs_ptr); 575 576 if (status >= 0) { 577 head_ifaddrs_ptr = ifaddrs_ptr; 578 do { 579 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr; 580 if ((sdl->sdl_type == IFT_ETHER) && 581 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) { 582 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl)))); 583 break; 584 } 585 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL); 586 freeifaddrs(head_ifaddrs_ptr); 587 } 588 589 return (mac_addr); 590 } 591 592 593 /* 594 * Given the MAC address, return the interface name. 595 */ 596 static char * 597 kvp_mac_to_if_name(char *mac) 598 { 599 char *if_name = NULL; 600 struct ifaddrs *ifaddrs_ptr; 601 struct ifaddrs *head_ifaddrs_ptr; 602 struct sockaddr_dl *sdl; 603 int status; 604 char *buf_ptr, *p; 605 606 status = getifaddrs(&ifaddrs_ptr); 607 608 if (status >= 0) { 609 head_ifaddrs_ptr = ifaddrs_ptr; 610 do { 611 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr; 612 if (sdl->sdl_type == IFT_ETHER) { 613 buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl)))); 614 if (buf_ptr != NULL) { 615 for (p = buf_ptr; *p != '\0'; p++) 616 *p = toupper(*p); 617 618 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) { 619 /* Caller will free the memory */ 620 if_name = strdup(ifaddrs_ptr->ifa_name); 621 free(buf_ptr); 622 break; 623 } else 624 free(buf_ptr); 625 } 626 } 627 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL); 628 freeifaddrs(head_ifaddrs_ptr); 629 } 630 return (if_name); 631 } 632 633 634 static void 635 kvp_process_ipconfig_file(char *cmd, 636 char *config_buf, size_t len, 637 size_t element_size, int offset) 638 { 639 char buf[256]; 640 char *p; 641 char *x; 642 FILE *file; 643 644 /* 645 * First execute the command. 646 */ 647 file = popen(cmd, "r"); 648 if (file == NULL) { 649 return; 650 } 651 652 if (offset == 0) { 653 memset(config_buf, 0, len); 654 } 655 while ((p = fgets(buf, sizeof(buf), file)) != NULL) { 656 if ((len - strlen(config_buf)) < (element_size + 1)) { 657 break; 658 } 659 660 x = strchr(p, '\n'); 661 *x = '\0'; 662 strlcat(config_buf, p, len); 663 strlcat(config_buf, ";", len); 664 } 665 pclose(file); 666 } 667 668 669 static void 670 kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer) 671 { 672 char cmd[512]; 673 char dhcp_info[128]; 674 char *p; 675 FILE *file; 676 677 /* 678 * Retrieve the IPV4 address of default gateway. 679 */ 680 snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name); 681 682 /* 683 * Execute the command to gather gateway IPV4 info. 684 */ 685 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 686 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); 687 688 /* 689 * Retrieve the IPV6 address of default gateway. 690 */ 691 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }", if_name); 692 693 /* 694 * Execute the command to gather gateway IPV6 info. 695 */ 696 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 697 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); 698 699 /* 700 * we just invoke an external script to get the DNS info. 701 * 702 * Following is the expected format of the information from the script: 703 * 704 * ipaddr1 (nameserver1) 705 * ipaddr2 (nameserver2) 706 * . 707 * . 708 */ 709 /* Scripts are stored in /usr/libexec/hyperv/ directory */ 710 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info"); 711 712 /* 713 * Execute the command to get DNS info. 714 */ 715 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, 716 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); 717 718 /* 719 * Invoke an external script to get the DHCP state info. 720 * The parameter to the script is the interface name. 721 * Here is the expected output: 722 * 723 * Enabled: DHCP enabled. 724 */ 725 726 727 snprintf(cmd, sizeof(cmd), "%s %s", 728 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name); 729 730 file = popen(cmd, "r"); 731 if (file == NULL) { 732 return; 733 } 734 735 p = fgets(dhcp_info, sizeof(dhcp_info), file); 736 if (p == NULL) { 737 pclose(file); 738 return; 739 } 740 741 if (!strncmp(p, "Enabled", 7)) { 742 buffer->dhcp_enabled = 1; 743 } else{ 744 buffer->dhcp_enabled = 0; 745 } 746 747 pclose(file); 748 } 749 750 751 static unsigned int 752 hweight32(unsigned int *w) 753 { 754 unsigned int res = *w - ((*w >> 1) & 0x55555555); 755 756 res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 757 res = (res + (res >> 4)) & 0x0F0F0F0F; 758 res = res + (res >> 8); 759 return ((res + (res >> 16)) & 0x000000FF); 760 } 761 762 763 static int 764 kvp_process_ip_address(void *addrp, 765 int family, char *buffer, 766 int length, int *offset) 767 { 768 struct sockaddr_in *addr; 769 struct sockaddr_in6 *addr6; 770 int addr_length; 771 char tmp[50]; 772 const char *str; 773 774 if (family == AF_INET) { 775 addr = (struct sockaddr_in *)addrp; 776 str = inet_ntop(family, &addr->sin_addr, tmp, 50); 777 addr_length = INET_ADDRSTRLEN; 778 } else { 779 addr6 = (struct sockaddr_in6 *)addrp; 780 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); 781 addr_length = INET6_ADDRSTRLEN; 782 } 783 784 if ((length - *offset) < addr_length + 1) { 785 return (HV_KVP_E_FAIL); 786 } 787 if (str == NULL) { 788 strlcpy(buffer, "inet_ntop failed\n", length); 789 return (HV_KVP_E_FAIL); 790 } 791 if (*offset == 0) { 792 strlcpy(buffer, tmp, length); 793 } else{ 794 strlcat(buffer, tmp, length); 795 } 796 strlcat(buffer, ";", length); 797 798 *offset += strlen(str) + 1; 799 return (0); 800 } 801 802 803 static int 804 kvp_get_ip_info(int family, char *if_name, int op, 805 void *out_buffer, size_t length) 806 { 807 struct ifaddrs *ifap; 808 struct ifaddrs *curp; 809 int offset = 0; 810 int sn_offset = 0; 811 int error = 0; 812 char *buffer; 813 size_t buffer_length; 814 struct hv_kvp_ipaddr_value *ip_buffer = NULL; 815 char cidr_mask[5]; 816 int weight; 817 int i; 818 unsigned int *w = NULL; 819 char *sn_str; 820 size_t sn_str_length; 821 struct sockaddr_in6 *addr6; 822 823 if (op == HV_KVP_OP_ENUMERATE) { 824 buffer = out_buffer; 825 buffer_length = length; 826 } else { 827 ip_buffer = out_buffer; 828 buffer = (char *)ip_buffer->ip_addr; 829 buffer_length = sizeof(ip_buffer->ip_addr); 830 ip_buffer->addr_family = 0; 831 } 832 833 if (getifaddrs(&ifap)) { 834 strlcpy(buffer, "getifaddrs failed\n", buffer_length); 835 return (HV_KVP_E_FAIL); 836 } 837 838 curp = ifap; 839 while (curp != NULL) { 840 if (curp->ifa_addr == NULL) { 841 curp = curp->ifa_next; 842 continue; 843 } 844 845 if ((if_name != NULL) && 846 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { 847 /* 848 * We want info about a specific interface; 849 * just continue. 850 */ 851 curp = curp->ifa_next; 852 continue; 853 } 854 855 /* 856 * We support two address families: AF_INET and AF_INET6. 857 * If family value is 0, we gather both supported 858 * address families; if not we gather info on 859 * the specified address family. 860 */ 861 if ((family != 0) && (curp->ifa_addr->sa_family != family)) { 862 curp = curp->ifa_next; 863 continue; 864 } 865 if ((curp->ifa_addr->sa_family != AF_INET) && 866 (curp->ifa_addr->sa_family != AF_INET6)) { 867 curp = curp->ifa_next; 868 continue; 869 } 870 871 if (op == HV_KVP_OP_GET_IP_INFO) { 872 /* 873 * Get the info other than the IP address. 874 */ 875 if (curp->ifa_addr->sa_family == AF_INET) { 876 ip_buffer->addr_family |= ADDR_FAMILY_IPV4; 877 878 /* 879 * Get subnet info. 880 */ 881 error = kvp_process_ip_address( 882 curp->ifa_netmask, 883 AF_INET, 884 (char *) 885 ip_buffer->sub_net, 886 length, 887 &sn_offset); 888 if (error) { 889 goto kvp_get_ip_info_ipaddr; 890 } 891 } else { 892 ip_buffer->addr_family |= ADDR_FAMILY_IPV6; 893 894 /* 895 * Get subnet info in CIDR format. 896 */ 897 weight = 0; 898 sn_str = (char *)ip_buffer->sub_net; 899 sn_str_length = sizeof(ip_buffer->sub_net); 900 addr6 = (struct sockaddr_in6 *)(uintptr_t) 901 curp->ifa_netmask; 902 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr; 903 904 for (i = 0; i < 4; i++) 905 { 906 weight += hweight32(&w[i]); 907 } 908 909 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight); 910 if ((length - sn_offset) < 911 (strlen(cidr_mask) + 1)) { 912 goto kvp_get_ip_info_ipaddr; 913 } 914 915 if (sn_offset == 0) { 916 strlcpy(sn_str, cidr_mask, sn_str_length); 917 } else{ 918 strlcat(sn_str, cidr_mask, sn_str_length); 919 } 920 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length); 921 sn_offset += strlen(sn_str) + 1; 922 } 923 924 /* 925 * Collect other ip configuration info. 926 */ 927 928 kvp_get_ipconfig_info(if_name, ip_buffer); 929 } 930 931 kvp_get_ip_info_ipaddr: 932 error = kvp_process_ip_address(curp->ifa_addr, 933 curp->ifa_addr->sa_family, 934 buffer, 935 length, &offset); 936 if (error) { 937 goto kvp_get_ip_info_done; 938 } 939 940 curp = curp->ifa_next; 941 } 942 943 kvp_get_ip_info_done: 944 freeifaddrs(ifap); 945 return (error); 946 } 947 948 949 static int 950 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3) 951 { 952 int ret; 953 954 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); 955 956 if (ret < 0) { 957 return (HV_KVP_E_FAIL); 958 } 959 960 return (0); 961 } 962 963 964 static int 965 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 966 { 967 int error = 0; 968 char if_file[128]; 969 FILE *file; 970 char cmd[512]; 971 char *mac_addr; 972 973 /* 974 * FreeBSD - Configuration File 975 */ 976 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv", 977 "hv_set_ip_data"); 978 file = fopen(if_file, "w"); 979 980 if (file == NULL) { 981 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n"); 982 return (HV_KVP_E_FAIL); 983 } 984 985 /* 986 * Write out the MAC address. 987 */ 988 989 mac_addr = kvp_if_name_to_mac(if_name); 990 if (mac_addr == NULL) { 991 error = HV_KVP_E_FAIL; 992 goto kvp_set_ip_info_error; 993 } 994 /* MAC Address */ 995 error = kvp_write_file(file, "HWADDR", "", mac_addr); 996 if (error) { 997 goto kvp_set_ip_info_error; 998 } 999 1000 /* Interface Name */ 1001 error = kvp_write_file(file, "IF_NAME", "", if_name); 1002 if (error) { 1003 goto kvp_set_ip_info_error; 1004 } 1005 1006 /* IP Address */ 1007 error = kvp_write_file(file, "IP_ADDR", "", 1008 (char *)new_val->ip_addr); 1009 if (error) { 1010 goto kvp_set_ip_info_error; 1011 } 1012 1013 /* Subnet Mask */ 1014 error = kvp_write_file(file, "SUBNET", "", 1015 (char *)new_val->sub_net); 1016 if (error) { 1017 goto kvp_set_ip_info_error; 1018 } 1019 1020 1021 /* Gateway */ 1022 error = kvp_write_file(file, "GATEWAY", "", 1023 (char *)new_val->gate_way); 1024 if (error) { 1025 goto kvp_set_ip_info_error; 1026 } 1027 1028 /* DNS */ 1029 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr); 1030 if (error) { 1031 goto kvp_set_ip_info_error; 1032 } 1033 1034 /* DHCP */ 1035 if (new_val->dhcp_enabled) { 1036 error = kvp_write_file(file, "DHCP", "", "1"); 1037 } else{ 1038 error = kvp_write_file(file, "DHCP", "", "0"); 1039 } 1040 1041 if (error) { 1042 goto kvp_set_ip_info_error; 1043 } 1044 1045 free(mac_addr); 1046 fclose(file); 1047 1048 /* 1049 * Invoke the external script with the populated 1050 * configuration file. 1051 */ 1052 1053 snprintf(cmd, sizeof(cmd), "%s %s", 1054 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file); 1055 system(cmd); 1056 return (0); 1057 1058 kvp_set_ip_info_error: 1059 KVP_LOG(LOG_ERR, "Failed to write config file\n"); 1060 free(mac_addr); 1061 fclose(file); 1062 return (error); 1063 } 1064 1065 1066 static int 1067 kvp_get_domain_name(char *buffer, int length) 1068 { 1069 struct addrinfo hints, *info; 1070 int error = 0; 1071 1072 gethostname(buffer, length); 1073 memset(&hints, 0, sizeof(hints)); 1074 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */ 1075 hints.ai_socktype = SOCK_STREAM; 1076 hints.ai_flags = AI_CANONNAME; 1077 1078 error = getaddrinfo(buffer, NULL, &hints, &info); 1079 if (error != 0) { 1080 strlcpy(buffer, "getaddrinfo failed\n", length); 1081 return (error); 1082 } 1083 strlcpy(buffer, info->ai_canonname, length); 1084 freeaddrinfo(info); 1085 return (error); 1086 } 1087 1088 1089 static int 1090 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1091 { 1092 struct hv_kvp_ipaddr_value *ip_val; 1093 char *if_name; 1094 1095 assert(op_msg != NULL); 1096 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n"); 1097 1098 ip_val = &op_msg->body.kvp_ip_val; 1099 op_msg->hdr.error = HV_KVP_S_OK; 1100 1101 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id); 1102 1103 if (if_name == NULL) { 1104 /* No interface found with the mac address. */ 1105 op_msg->hdr.error = HV_KVP_E_FAIL; 1106 goto kvp_op_getipinfo_done; 1107 } 1108 1109 op_msg->hdr.error = kvp_get_ip_info(0, if_name, 1110 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2)); 1111 1112 free(if_name); 1113 1114 kvp_op_getipinfo_done: 1115 return(op_msg->hdr.error); 1116 } 1117 1118 1119 static int 1120 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1121 { 1122 struct hv_kvp_ipaddr_value *ip_val; 1123 char *if_name; 1124 1125 assert(op_msg != NULL); 1126 KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n"); 1127 1128 ip_val = &op_msg->body.kvp_ip_val; 1129 op_msg->hdr.error = HV_KVP_S_OK; 1130 1131 if_name = (char *)ip_val->adapter_id; 1132 1133 if (if_name == NULL) { 1134 /* No adapter provided. */ 1135 op_msg->hdr.error = HV_KVP_GUID_NOTFOUND; 1136 goto kvp_op_setipinfo_done; 1137 } 1138 1139 op_msg->hdr.error = kvp_set_ip_info(if_name, ip_val); 1140 1141 kvp_op_setipinfo_done: 1142 return(op_msg->hdr.error); 1143 } 1144 1145 1146 static int 1147 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data) 1148 { 1149 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data; 1150 int error = 0; 1151 int op_pool; 1152 1153 assert(op_msg != NULL); 1154 assert(op_hdlr != NULL); 1155 1156 op_pool = op_msg->hdr.kvp_hdr.pool; 1157 op_msg->hdr.error = HV_KVP_S_OK; 1158 1159 switch(op_hdlr->kvp_op_key) { 1160 case HV_KVP_OP_SET: 1161 if (op_pool == HV_KVP_POOL_AUTO) { 1162 /* Auto Pool is not writeable from host side. */ 1163 error = 1; 1164 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n", 1165 op_pool); 1166 } else { 1167 error = kvp_key_add_or_modify(op_pool, 1168 op_msg->body.kvp_set.data.key, 1169 op_msg->body.kvp_set.data.key_size, 1170 op_msg->body.kvp_set.data.msg_value.value, 1171 op_msg->body.kvp_set.data.value_size); 1172 } 1173 break; 1174 1175 case HV_KVP_OP_GET: 1176 error = kvp_get_value(op_pool, 1177 op_msg->body.kvp_get.data.key, 1178 op_msg->body.kvp_get.data.key_size, 1179 op_msg->body.kvp_get.data.msg_value.value, 1180 op_msg->body.kvp_get.data.value_size); 1181 break; 1182 1183 case HV_KVP_OP_DELETE: 1184 if (op_pool == HV_KVP_POOL_AUTO) { 1185 /* Auto Pool is not writeable from host side. */ 1186 error = 1; 1187 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n", 1188 op_pool); 1189 } else { 1190 error = kvp_key_delete(op_pool, 1191 op_msg->body.kvp_delete.key, 1192 op_msg->body.kvp_delete.key_size); 1193 } 1194 break; 1195 1196 default: 1197 break; 1198 } 1199 1200 if (error != 0) 1201 op_msg->hdr.error = HV_KVP_S_CONT; 1202 1203 return(error); 1204 } 1205 1206 1207 static int 1208 kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused) 1209 { 1210 char *key_name, *key_value; 1211 int error = 0; 1212 int op_pool; 1213 int op; 1214 1215 assert(op_msg != NULL); 1216 1217 op = op_msg->hdr.kvp_hdr.operation; 1218 op_pool = op_msg->hdr.kvp_hdr.pool; 1219 op_msg->hdr.error = HV_KVP_S_OK; 1220 1221 /* 1222 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate 1223 * pool and return the KVP according to the index requested. 1224 */ 1225 if (op_pool != HV_KVP_POOL_AUTO) { 1226 if (kvp_pool_enumerate(op_pool, 1227 op_msg->body.kvp_enum_data.index, 1228 op_msg->body.kvp_enum_data.data.key, 1229 HV_KVP_EXCHANGE_MAX_KEY_SIZE, 1230 op_msg->body.kvp_enum_data.data.msg_value.value, 1231 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 1232 op_msg->hdr.error = HV_KVP_S_CONT; 1233 error = -1; 1234 } 1235 goto kvp_op_enumerate_done; 1236 } 1237 1238 key_name = (char *)op_msg->body.kvp_enum_data.data.key; 1239 key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value; 1240 1241 switch (op_msg->body.kvp_enum_data.index) 1242 { 1243 case FullyQualifiedDomainName: 1244 kvp_get_domain_name(key_value, 1245 HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1246 strcpy(key_name, "FullyQualifiedDomainName"); 1247 break; 1248 1249 case IntegrationServicesVersion: 1250 strcpy(key_name, "IntegrationServicesVersion"); 1251 strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1252 break; 1253 1254 case NetworkAddressIPv4: 1255 kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE, 1256 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1257 strcpy(key_name, "NetworkAddressIPv4"); 1258 break; 1259 1260 case NetworkAddressIPv6: 1261 kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE, 1262 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1263 strcpy(key_name, "NetworkAddressIPv6"); 1264 break; 1265 1266 case OSBuildNumber: 1267 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1268 strcpy(key_name, "OSBuildNumber"); 1269 break; 1270 1271 case OSName: 1272 strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1273 strcpy(key_name, "OSName"); 1274 break; 1275 1276 case OSMajorVersion: 1277 strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1278 strcpy(key_name, "OSMajorVersion"); 1279 break; 1280 1281 case OSMinorVersion: 1282 strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1283 strcpy(key_name, "OSMinorVersion"); 1284 break; 1285 1286 case OSVersion: 1287 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1288 strcpy(key_name, "OSVersion"); 1289 break; 1290 1291 case ProcessorArchitecture: 1292 strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1293 strcpy(key_name, "ProcessorArchitecture"); 1294 break; 1295 1296 default: 1297 #ifdef DEBUG 1298 KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n", 1299 op_msg->body.kvp_enum_data.index); 1300 #endif 1301 op_msg->hdr.error = HV_KVP_S_CONT; 1302 error = -1; 1303 break; 1304 } 1305 1306 kvp_op_enumerate_done: 1307 return(error); 1308 } 1309 1310 1311 /* 1312 * Load handler, and call init routine if provided. 1313 */ 1314 static int 1315 kvp_op_load(int key, void (*init)(void), 1316 int (*exec)(struct hv_kvp_msg *, void *)) 1317 { 1318 int error = 0; 1319 1320 if (key < 0 || key >= HV_KVP_OP_COUNT) { 1321 KVP_LOG(LOG_ERR, "Operation key out of supported range\n"); 1322 error = -1; 1323 goto kvp_op_load_done; 1324 } 1325 1326 kvp_op_hdlrs[key].kvp_op_key = key; 1327 kvp_op_hdlrs[key].kvp_op_init = init; 1328 kvp_op_hdlrs[key].kvp_op_exec = exec; 1329 1330 if (kvp_op_hdlrs[key].kvp_op_init != NULL) 1331 kvp_op_hdlrs[key].kvp_op_init(); 1332 1333 kvp_op_load_done: 1334 return(error); 1335 } 1336 1337 1338 /* 1339 * Initialize the operation hanlders. 1340 */ 1341 static int 1342 kvp_ops_init(void) 1343 { 1344 int i; 1345 1346 /* Set the initial values. */ 1347 for (i = 0; i < HV_KVP_OP_COUNT; i++) { 1348 kvp_op_hdlrs[i].kvp_op_key = -1; 1349 kvp_op_hdlrs[i].kvp_op_init = NULL; 1350 kvp_op_hdlrs[i].kvp_op_exec = NULL; 1351 } 1352 1353 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) | 1354 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) | 1355 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) | 1356 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info, 1357 kvp_op_enumerate) | 1358 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) | 1359 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo)); 1360 } 1361 1362 1363 int 1364 main(int argc, char *argv[]) 1365 { 1366 struct hv_kvp_msg *hv_kvp_dev_buf; 1367 struct hv_kvp_msg *hv_msg; 1368 struct pollfd hv_kvp_poll_fd[1]; 1369 int op, pool; 1370 int hv_kvp_dev_fd, error, len, r; 1371 int ch; 1372 1373 while ((ch = getopt(argc, argv, "dn")) != -1) { 1374 switch (ch) { 1375 case 'n': 1376 /* Run as regular process for debugging purpose. */ 1377 is_daemon = 0; 1378 break; 1379 case 'd': 1380 /* Generate debugging output */ 1381 is_debugging = 1; 1382 break; 1383 default: 1384 break; 1385 } 1386 } 1387 1388 openlog("HV_KVP", 0, LOG_USER); 1389 1390 /* Become daemon first. */ 1391 if (is_daemon == 1) 1392 daemon(1, 0); 1393 else 1394 KVP_LOG(LOG_DEBUG, "Run as regular process.\n"); 1395 1396 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid()); 1397 1398 /* Communication buffer hv_kvp_dev_buf */ 1399 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf)); 1400 /* Buffer for daemon internal use */ 1401 hv_msg = malloc(sizeof(*hv_msg)); 1402 1403 /* Memory allocation failed */ 1404 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) { 1405 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n"); 1406 exit(EXIT_FAILURE); 1407 } 1408 1409 /* Initialize op handlers */ 1410 if (kvp_ops_init() != 0) { 1411 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n"); 1412 exit(EXIT_FAILURE); 1413 } 1414 1415 if (kvp_file_init()) { 1416 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n"); 1417 exit(EXIT_FAILURE); 1418 } 1419 1420 /* Open the Character Device */ 1421 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR); 1422 1423 if (hv_kvp_dev_fd < 0) { 1424 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n", 1425 errno, strerror(errno)); 1426 exit(EXIT_FAILURE); 1427 } 1428 1429 /* Initialize the struct for polling the char device */ 1430 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd; 1431 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM); 1432 1433 /* Register the daemon to the KVP driver */ 1434 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf)); 1435 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER; 1436 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf)); 1437 1438 1439 for (;;) { 1440 r = poll (hv_kvp_poll_fd, 1, INFTIM); 1441 1442 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n", 1443 r, hv_kvp_poll_fd[0].revents); 1444 1445 if (r == 0 || (r < 0 && errno == EAGAIN) || 1446 (r < 0 && errno == EINTR)) { 1447 /* Nothing to read */ 1448 continue; 1449 } 1450 1451 if (r < 0) { 1452 /* 1453 * For pread return failure other than EAGAIN, 1454 * we want to exit. 1455 */ 1456 KVP_LOG(LOG_ERR, "Poll failed.\n"); 1457 perror("poll"); 1458 exit(EIO); 1459 } 1460 1461 /* Read from character device */ 1462 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf, 1463 sizeof(*hv_kvp_dev_buf), 0); 1464 1465 if (len < 0) { 1466 KVP_LOG(LOG_ERR, "Read failed.\n"); 1467 perror("pread"); 1468 exit(EIO); 1469 } 1470 1471 if (len != sizeof(struct hv_kvp_msg)) { 1472 KVP_LOG(LOG_ERR, "read len is: %d\n", len); 1473 continue; 1474 } 1475 1476 /* Copy hv_kvp_dev_buf to hv_msg */ 1477 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg)); 1478 1479 /* 1480 * We will use the KVP header information to pass back 1481 * the error from this daemon. So, first save the op 1482 * and pool info to local variables. 1483 */ 1484 1485 op = hv_msg->hdr.kvp_hdr.operation; 1486 pool = hv_msg->hdr.kvp_hdr.pool; 1487 1488 if (op < 0 || op >= HV_KVP_OP_COUNT || 1489 kvp_op_hdlrs[op].kvp_op_exec == NULL) { 1490 KVP_LOG(LOG_WARNING, 1491 "Unsupported operation OP = %d\n", op); 1492 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED; 1493 } else { 1494 /* 1495 * Call the operateion handler's execution routine. 1496 */ 1497 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg, 1498 (void *)&kvp_op_hdlrs[op]); 1499 if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT) 1500 KVP_LOG(LOG_WARNING, 1501 "Operation failed OP = %d, error = 0x%x\n", 1502 op, error); 1503 } 1504 1505 /* 1506 * Send the value back to the kernel. The response is 1507 * already in the receive buffer. 1508 */ 1509 hv_kvp_done: 1510 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0); 1511 1512 if (len != sizeof(struct hv_kvp_msg)) { 1513 KVP_LOG(LOG_ERR, "write len is: %d\n", len); 1514 goto hv_kvp_done; 1515 } 1516 } 1517 } 1518