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