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 (access("/var/db/hyperv/pool", F_OK)) { 288 if (mkdir("/var/db/hyperv/pool", 289 S_IRUSR | S_IWUSR | S_IROTH)) { 290 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n"); 291 exit(EXIT_FAILURE); 292 } 293 } 294 295 for (i = 0; i < HV_KVP_POOL_COUNT; i++) 296 { 297 fname = kvp_pools[i].fname; 298 records_read = 0; 299 num_blocks = 1; 300 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i); 301 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); 302 303 if (fd == -1) { 304 return (1); 305 } 306 307 308 filep = fopen(fname, "r"); 309 if (!filep) { 310 return (1); 311 } 312 313 record = malloc(alloc_unit * num_blocks); 314 if (record == NULL) { 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 fclose(filep); 340 return (1); 341 } 342 continue; 343 } 344 break; 345 } 346 kvp_pools[i].pool_fd = fd; 347 kvp_pools[i].num_blocks = num_blocks; 348 kvp_pools[i].records = record; 349 kvp_pools[i].num_records = records_read; 350 fclose(filep); 351 } 352 353 return (0); 354 } 355 356 357 static int 358 kvp_key_delete(int pool, __u8 *key, int key_size) 359 { 360 int i; 361 int j, k; 362 int num_records; 363 struct kvp_record *record; 364 365 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, " 366 "key = %s\n", pool, key); 367 368 /* Update in-memory state */ 369 kvp_update_mem_state(pool); 370 371 num_records = kvp_pools[pool].num_records; 372 record = kvp_pools[pool].records; 373 374 for (i = 0; i < num_records; i++) 375 { 376 if (memcmp(key, record[i].key, key_size)) { 377 continue; 378 } 379 380 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n", 381 pool); 382 /* 383 * We found a match at the end; Just update the number of 384 * entries and we are done. 385 */ 386 if (i == num_records) { 387 kvp_pools[pool].num_records--; 388 kvp_update_file(pool); 389 return (0); 390 } 391 392 /* 393 * We found a match in the middle; Move the remaining 394 * entries up. 395 */ 396 j = i; 397 k = j + 1; 398 for ( ; k < num_records; k++) 399 { 400 strcpy(record[j].key, record[k].key); 401 strcpy(record[j].value, record[k].value); 402 j++; 403 } 404 kvp_pools[pool].num_records--; 405 kvp_update_file(pool); 406 return (0); 407 } 408 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n", 409 pool); 410 return (1); 411 } 412 413 414 static int 415 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value, 416 __u32 value_size) 417 { 418 int i; 419 int num_records; 420 struct kvp_record *record; 421 int num_blocks; 422 423 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, " 424 "key = %s, value = %s\n,", pool, key, value); 425 426 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 427 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 428 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n"); 429 return (1); 430 } 431 432 /* Update the in-memory state. */ 433 kvp_update_mem_state(pool); 434 435 num_records = kvp_pools[pool].num_records; 436 record = kvp_pools[pool].records; 437 num_blocks = kvp_pools[pool].num_blocks; 438 439 for (i = 0; i < num_records; i++) 440 { 441 if (memcmp(key, record[i].key, key_size)) { 442 continue; 443 } 444 445 /* 446 * Key exists. Just update the value and we are done. 447 */ 448 memcpy(record[i].value, value, value_size); 449 kvp_update_file(pool); 450 return (0); 451 } 452 453 /* 454 * Key doesn't exist; Add a new KVP. 455 */ 456 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { 457 /* Increase the size of the recodrd array. */ 458 record = realloc(record, sizeof(struct kvp_record) * 459 ENTRIES_PER_BLOCK * (num_blocks + 1)); 460 461 if (record == NULL) { 462 return (1); 463 } 464 kvp_pools[pool].num_blocks++; 465 } 466 memcpy(record[i].value, value, value_size); 467 memcpy(record[i].key, key, key_size); 468 kvp_pools[pool].records = record; 469 kvp_pools[pool].num_records++; 470 kvp_update_file(pool); 471 return (0); 472 } 473 474 475 static int 476 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, 477 int value_size) 478 { 479 int i; 480 int num_records; 481 struct kvp_record *record; 482 483 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,", 484 pool, key); 485 486 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 487 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 488 return (1); 489 } 490 491 /* Update the in-memory state first. */ 492 kvp_update_mem_state(pool); 493 494 num_records = kvp_pools[pool].num_records; 495 record = kvp_pools[pool].records; 496 497 for (i = 0; i < num_records; i++) 498 { 499 if (memcmp(key, record[i].key, key_size)) { 500 continue; 501 } 502 503 /* Found the key */ 504 memcpy(value, record[i].value, value_size); 505 return (0); 506 } 507 508 return (1); 509 } 510 511 512 static int 513 kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 514 __u8 *value, int value_size) 515 { 516 struct kvp_record *record; 517 518 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,", 519 pool, index); 520 521 /* First update our in-memory state first. */ 522 kvp_update_mem_state(pool); 523 record = kvp_pools[pool].records; 524 525 /* Index starts with 0 */ 526 if (index >= kvp_pools[pool].num_records) { 527 return (1); 528 } 529 530 memcpy(key, record[index].key, key_size); 531 memcpy(value, record[index].value, value_size); 532 return (0); 533 } 534 535 536 static void 537 kvp_get_os_info(void) 538 { 539 char *p; 540 541 uname(&uts_buf); 542 os_build = uts_buf.release; 543 os_name = uts_buf.sysname; 544 processor_arch = uts_buf.machine; 545 546 /* 547 * Win7 host expects the build string to be of the form: x.y.z 548 * Strip additional information we may have. 549 */ 550 p = strchr(os_build, '-'); 551 if (p) { 552 *p = '\0'; 553 } 554 555 /* 556 * We don't have any other information about the FreeBSD os. 557 */ 558 return; 559 } 560 561 /* 562 * Given the interface name, return the MAC address. 563 */ 564 static char * 565 kvp_if_name_to_mac(char *if_name) 566 { 567 char *mac_addr = NULL; 568 struct ifaddrs *ifaddrs_ptr; 569 struct ifaddrs *head_ifaddrs_ptr; 570 struct sockaddr_dl *sdl; 571 int status; 572 573 status = getifaddrs(&ifaddrs_ptr); 574 575 if (status >= 0) { 576 head_ifaddrs_ptr = ifaddrs_ptr; 577 do { 578 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr; 579 if ((sdl->sdl_type == IFT_ETHER) && 580 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) { 581 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl)))); 582 break; 583 } 584 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL); 585 freeifaddrs(head_ifaddrs_ptr); 586 } 587 588 return (mac_addr); 589 } 590 591 592 /* 593 * Given the MAC address, return the interface name. 594 */ 595 static char * 596 kvp_mac_to_if_name(char *mac) 597 { 598 char *if_name = NULL; 599 struct ifaddrs *ifaddrs_ptr; 600 struct ifaddrs *head_ifaddrs_ptr; 601 struct sockaddr_dl *sdl; 602 int status; 603 size_t i; 604 char *buf_ptr; 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 for (i = 0; i < strlen(buf_ptr); i++) 615 { 616 buf_ptr[i] = toupper(buf_ptr[i]); 617 } 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 if (buf_ptr != NULL) { 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 /* 690 * Retrieve the IPV6 address of default gateway. 691 */ 692 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }", if_name); 693 694 /* 695 * Execute the command to gather gateway IPV6 info. 696 */ 697 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 698 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); 699 700 /* 701 * we just invoke an external script to get the DNS info. 702 * 703 * Following is the expected format of the information from the script: 704 * 705 * ipaddr1 (nameserver1) 706 * ipaddr2 (nameserver2) 707 * . 708 * . 709 */ 710 /* Scripts are stored in /usr/libexec/hyperv/ directory */ 711 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info"); 712 713 /* 714 * Execute the command to get DNS info. 715 */ 716 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, 717 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); 718 719 /* 720 * Invoke an external script to get the DHCP state info. 721 * The parameter to the script is the interface name. 722 * Here is the expected output: 723 * 724 * Enabled: DHCP enabled. 725 */ 726 727 728 snprintf(cmd, sizeof(cmd), "%s %s", 729 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name); 730 731 file = popen(cmd, "r"); 732 if (file == NULL) { 733 return; 734 } 735 736 p = fgets(dhcp_info, sizeof(dhcp_info), file); 737 if (p == NULL) { 738 pclose(file); 739 return; 740 } 741 742 if (!strncmp(p, "Enabled", 7)) { 743 buffer->dhcp_enabled = 1; 744 } else{ 745 buffer->dhcp_enabled = 0; 746 } 747 748 pclose(file); 749 } 750 751 752 static unsigned int 753 hweight32(unsigned int *w) 754 { 755 unsigned int res = *w - ((*w >> 1) & 0x55555555); 756 757 res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 758 res = (res + (res >> 4)) & 0x0F0F0F0F; 759 res = res + (res >> 8); 760 return ((res + (res >> 16)) & 0x000000FF); 761 } 762 763 764 static int 765 kvp_process_ip_address(void *addrp, 766 int family, char *buffer, 767 int length, int *offset) 768 { 769 struct sockaddr_in *addr; 770 struct sockaddr_in6 *addr6; 771 int addr_length; 772 char tmp[50]; 773 const char *str; 774 775 if (family == AF_INET) { 776 addr = (struct sockaddr_in *)addrp; 777 str = inet_ntop(family, &addr->sin_addr, tmp, 50); 778 addr_length = INET_ADDRSTRLEN; 779 } else { 780 addr6 = (struct sockaddr_in6 *)addrp; 781 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); 782 addr_length = INET6_ADDRSTRLEN; 783 } 784 785 if ((length - *offset) < addr_length + 1) { 786 return (HV_KVP_E_FAIL); 787 } 788 if (str == NULL) { 789 strlcpy(buffer, "inet_ntop failed\n", length); 790 return (HV_KVP_E_FAIL); 791 } 792 if (*offset == 0) { 793 strlcpy(buffer, tmp, length); 794 } else{ 795 strlcat(buffer, tmp, length); 796 } 797 strlcat(buffer, ";", length); 798 799 *offset += strlen(str) + 1; 800 return (0); 801 } 802 803 804 static int 805 kvp_get_ip_info(int family, char *if_name, int op, 806 void *out_buffer, size_t length) 807 { 808 struct ifaddrs *ifap; 809 struct ifaddrs *curp; 810 int offset = 0; 811 int sn_offset = 0; 812 int error = 0; 813 char *buffer; 814 size_t buffer_length; 815 struct hv_kvp_ipaddr_value *ip_buffer; 816 char cidr_mask[5]; 817 int weight; 818 int i; 819 unsigned int *w = NULL; 820 char *sn_str; 821 size_t sn_str_length; 822 struct sockaddr_in6 *addr6; 823 824 if (op == HV_KVP_OP_ENUMERATE) { 825 buffer = out_buffer; 826 buffer_length = length; 827 } else { 828 ip_buffer = out_buffer; 829 buffer = (char *)ip_buffer->ip_addr; 830 buffer_length = sizeof(ip_buffer->ip_addr); 831 ip_buffer->addr_family = 0; 832 } 833 834 if (getifaddrs(&ifap)) { 835 strlcpy(buffer, "getifaddrs failed\n", buffer_length); 836 return (HV_KVP_E_FAIL); 837 } 838 839 curp = ifap; 840 while (curp != NULL) { 841 if (curp->ifa_addr == NULL) { 842 curp = curp->ifa_next; 843 continue; 844 } 845 846 if ((if_name != NULL) && 847 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { 848 /* 849 * We want info about a specific interface; 850 * just continue. 851 */ 852 curp = curp->ifa_next; 853 continue; 854 } 855 856 /* 857 * We support two address families: AF_INET and AF_INET6. 858 * If family value is 0, we gather both supported 859 * address families; if not we gather info on 860 * the specified address family. 861 */ 862 if ((family != 0) && (curp->ifa_addr->sa_family != family)) { 863 curp = curp->ifa_next; 864 continue; 865 } 866 if ((curp->ifa_addr->sa_family != AF_INET) && 867 (curp->ifa_addr->sa_family != AF_INET6)) { 868 curp = curp->ifa_next; 869 continue; 870 } 871 872 if (op == HV_KVP_OP_GET_IP_INFO) { 873 /* 874 * Get the info other than the IP address. 875 */ 876 if (curp->ifa_addr->sa_family == AF_INET) { 877 ip_buffer->addr_family |= ADDR_FAMILY_IPV4; 878 879 /* 880 * Get subnet info. 881 */ 882 error = kvp_process_ip_address( 883 curp->ifa_netmask, 884 AF_INET, 885 (char *) 886 ip_buffer->sub_net, 887 length, 888 &sn_offset); 889 if (error) { 890 goto kvp_get_ip_info_ipaddr; 891 } 892 } else { 893 ip_buffer->addr_family |= ADDR_FAMILY_IPV6; 894 895 /* 896 * Get subnet info in CIDR format. 897 */ 898 weight = 0; 899 sn_str = (char *)ip_buffer->sub_net; 900 sn_str_length = sizeof(ip_buffer->sub_net); 901 addr6 = (struct sockaddr_in6 *)(uintptr_t) 902 curp->ifa_netmask; 903 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr; 904 905 for (i = 0; i < 4; i++) 906 { 907 weight += hweight32(&w[i]); 908 } 909 910 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight); 911 if ((length - sn_offset) < 912 (strlen(cidr_mask) + 1)) { 913 goto kvp_get_ip_info_ipaddr; 914 } 915 916 if (sn_offset == 0) { 917 strlcpy(sn_str, cidr_mask, sn_str_length); 918 } else{ 919 strlcat(sn_str, cidr_mask, sn_str_length); 920 } 921 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length); 922 sn_offset += strlen(sn_str) + 1; 923 } 924 925 /* 926 * Collect other ip configuration info. 927 */ 928 929 kvp_get_ipconfig_info(if_name, ip_buffer); 930 } 931 932 kvp_get_ip_info_ipaddr: 933 error = kvp_process_ip_address(curp->ifa_addr, 934 curp->ifa_addr->sa_family, 935 buffer, 936 length, &offset); 937 if (error) { 938 goto kvp_get_ip_info_done; 939 } 940 941 curp = curp->ifa_next; 942 } 943 944 kvp_get_ip_info_done: 945 freeifaddrs(ifap); 946 return (error); 947 } 948 949 950 static int 951 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3) 952 { 953 int ret; 954 955 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); 956 957 if (ret < 0) { 958 return (HV_KVP_E_FAIL); 959 } 960 961 return (0); 962 } 963 964 965 static int 966 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 967 { 968 int error = 0; 969 char if_file[128]; 970 FILE *file; 971 char cmd[512]; 972 char *mac_addr; 973 974 /* 975 * FreeBSD - Configuration File 976 */ 977 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv", 978 "hv_set_ip_data"); 979 file = fopen(if_file, "w"); 980 981 if (file == NULL) { 982 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n"); 983 return (HV_KVP_E_FAIL); 984 } 985 986 /* 987 * Write out the MAC address. 988 */ 989 990 mac_addr = kvp_if_name_to_mac(if_name); 991 if (mac_addr == NULL) { 992 error = HV_KVP_E_FAIL; 993 goto kvp_set_ip_info_error; 994 } 995 /* MAC Address */ 996 error = kvp_write_file(file, "HWADDR", "", mac_addr); 997 if (error) { 998 goto kvp_set_ip_info_error; 999 } 1000 1001 /* Interface Name */ 1002 error = kvp_write_file(file, "IF_NAME", "", if_name); 1003 if (error) { 1004 goto kvp_set_ip_info_error; 1005 } 1006 1007 /* IP Address */ 1008 error = kvp_write_file(file, "IP_ADDR", "", 1009 (char *)new_val->ip_addr); 1010 if (error) { 1011 goto kvp_set_ip_info_error; 1012 } 1013 1014 /* Subnet Mask */ 1015 error = kvp_write_file(file, "SUBNET", "", 1016 (char *)new_val->sub_net); 1017 if (error) { 1018 goto kvp_set_ip_info_error; 1019 } 1020 1021 1022 /* Gateway */ 1023 error = kvp_write_file(file, "GATEWAY", "", 1024 (char *)new_val->gate_way); 1025 if (error) { 1026 goto kvp_set_ip_info_error; 1027 } 1028 1029 /* DNS */ 1030 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr); 1031 if (error) { 1032 goto kvp_set_ip_info_error; 1033 } 1034 1035 /* DHCP */ 1036 if (new_val->dhcp_enabled) { 1037 error = kvp_write_file(file, "DHCP", "", "1"); 1038 } else{ 1039 error = kvp_write_file(file, "DHCP", "", "0"); 1040 } 1041 1042 if (error) { 1043 goto kvp_set_ip_info_error; 1044 } 1045 1046 free(mac_addr); 1047 fclose(file); 1048 1049 /* 1050 * Invoke the external script with the populated 1051 * configuration file. 1052 */ 1053 1054 snprintf(cmd, sizeof(cmd), "%s %s", 1055 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file); 1056 system(cmd); 1057 return (0); 1058 1059 kvp_set_ip_info_error: 1060 KVP_LOG(LOG_ERR, "Failed to write config file\n"); 1061 free(mac_addr); 1062 fclose(file); 1063 return (error); 1064 } 1065 1066 1067 static int 1068 kvp_get_domain_name(char *buffer, int length) 1069 { 1070 struct addrinfo hints, *info; 1071 int error = 0; 1072 1073 gethostname(buffer, length); 1074 memset(&hints, 0, sizeof(hints)); 1075 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */ 1076 hints.ai_socktype = SOCK_STREAM; 1077 hints.ai_flags = AI_CANONNAME; 1078 1079 error = getaddrinfo(buffer, NULL, &hints, &info); 1080 if (error != 0) { 1081 strlcpy(buffer, "getaddrinfo failed\n", length); 1082 return (error); 1083 } 1084 strlcpy(buffer, info->ai_canonname, length); 1085 freeaddrinfo(info); 1086 return (error); 1087 } 1088 1089 1090 static int 1091 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1092 { 1093 struct hv_kvp_ipaddr_value *ip_val; 1094 char *if_name; 1095 1096 assert(op_msg != NULL); 1097 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n"); 1098 1099 ip_val = &op_msg->body.kvp_ip_val; 1100 op_msg->hdr.error = HV_KVP_S_OK; 1101 1102 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id); 1103 1104 if (if_name == NULL) { 1105 /* No interface found with the mac address. */ 1106 op_msg->hdr.error = HV_KVP_E_FAIL; 1107 goto kvp_op_getipinfo_done; 1108 } 1109 1110 op_msg->hdr.error = kvp_get_ip_info(0, if_name, 1111 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2)); 1112 1113 free(if_name); 1114 1115 kvp_op_getipinfo_done: 1116 return(op_msg->hdr.error); 1117 } 1118 1119 1120 static int 1121 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1122 { 1123 struct hv_kvp_ipaddr_value *ip_val; 1124 char *if_name; 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_KVP_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_KVP_GUID_NOTFOUND; 1137 goto kvp_op_setipinfo_done; 1138 } 1139 1140 op_msg->hdr.error = kvp_set_ip_info(if_name, ip_val); 1141 1142 kvp_op_setipinfo_done: 1143 return(op_msg->hdr.error); 1144 } 1145 1146 1147 static int 1148 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data) 1149 { 1150 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data; 1151 int error = 0; 1152 int op_pool; 1153 1154 assert(op_msg != NULL); 1155 assert(op_hdlr != NULL); 1156 1157 op_pool = op_msg->hdr.kvp_hdr.pool; 1158 op_msg->hdr.error = HV_KVP_S_OK; 1159 1160 switch(op_hdlr->kvp_op_key) { 1161 case HV_KVP_OP_SET: 1162 if (op_pool == HV_KVP_POOL_AUTO) { 1163 /* Auto Pool is not writeable from host side. */ 1164 error = 1; 1165 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n", 1166 op_pool); 1167 } else { 1168 error = kvp_key_add_or_modify(op_pool, 1169 op_msg->body.kvp_set.data.key, 1170 op_msg->body.kvp_set.data.key_size, 1171 op_msg->body.kvp_set.data.msg_value.value, 1172 op_msg->body.kvp_set.data.value_size); 1173 } 1174 break; 1175 1176 case HV_KVP_OP_GET: 1177 error = kvp_get_value(op_pool, 1178 op_msg->body.kvp_get.data.key, 1179 op_msg->body.kvp_get.data.key_size, 1180 op_msg->body.kvp_get.data.msg_value.value, 1181 op_msg->body.kvp_get.data.value_size); 1182 break; 1183 1184 case HV_KVP_OP_DELETE: 1185 if (op_pool == HV_KVP_POOL_AUTO) { 1186 /* Auto Pool is not writeable from host side. */ 1187 error = 1; 1188 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n", 1189 op_pool); 1190 } else { 1191 error = kvp_key_delete(op_pool, 1192 op_msg->body.kvp_delete.key, 1193 op_msg->body.kvp_delete.key_size); 1194 } 1195 break; 1196 1197 default: 1198 break; 1199 } 1200 1201 if (error != 0) 1202 op_msg->hdr.error = HV_KVP_S_CONT; 1203 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_KVP_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_KVP_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 strcpy(key_value, lic_version); 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 strcpy(key_value, os_build); 1269 strcpy(key_name, "OSBuildNumber"); 1270 break; 1271 1272 case OSName: 1273 strcpy(key_value, os_name); 1274 strcpy(key_name, "OSName"); 1275 break; 1276 1277 case OSMajorVersion: 1278 strcpy(key_value, os_major); 1279 strcpy(key_name, "OSMajorVersion"); 1280 break; 1281 1282 case OSMinorVersion: 1283 strcpy(key_value, os_minor); 1284 strcpy(key_name, "OSMinorVersion"); 1285 break; 1286 1287 case OSVersion: 1288 strcpy(key_value, os_build); 1289 strcpy(key_name, "OSVersion"); 1290 break; 1291 1292 case ProcessorArchitecture: 1293 strcpy(key_value, processor_arch); 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_KVP_S_CONT; 1303 error = -1; 1304 break; 1305 } 1306 1307 kvp_op_enumerate_done: 1308 return(error); 1309 } 1310 1311 1312 /* 1313 * Load handler, and call init routine if provided. 1314 */ 1315 static int 1316 kvp_op_load(int key, void (*init)(void), 1317 int (*exec)(struct hv_kvp_msg *, void *)) 1318 { 1319 int error = 0; 1320 1321 if (key < 0 || key >= HV_KVP_OP_COUNT) { 1322 KVP_LOG(LOG_ERR, "Operation key out of supported range\n"); 1323 error = -1; 1324 goto kvp_op_load_done; 1325 } 1326 1327 kvp_op_hdlrs[key].kvp_op_key = key; 1328 kvp_op_hdlrs[key].kvp_op_init = init; 1329 kvp_op_hdlrs[key].kvp_op_exec = exec; 1330 1331 if (kvp_op_hdlrs[key].kvp_op_init != NULL) 1332 kvp_op_hdlrs[key].kvp_op_init(); 1333 1334 kvp_op_load_done: 1335 return(error); 1336 } 1337 1338 1339 /* 1340 * Initialize the operation hanlders. 1341 */ 1342 static int 1343 kvp_ops_init(void) 1344 { 1345 int i; 1346 1347 /* Set the initial values. */ 1348 for (i = 0; i < HV_KVP_OP_COUNT; i++) { 1349 kvp_op_hdlrs[i].kvp_op_key = -1; 1350 kvp_op_hdlrs[i].kvp_op_init = NULL; 1351 kvp_op_hdlrs[i].kvp_op_exec = NULL; 1352 } 1353 1354 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) | 1355 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) | 1356 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) | 1357 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info, 1358 kvp_op_enumerate) | 1359 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) | 1360 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo)); 1361 } 1362 1363 1364 int 1365 main(int argc, char *argv[]) 1366 { 1367 struct hv_kvp_msg *hv_kvp_dev_buf; 1368 struct hv_kvp_msg *hv_msg; 1369 struct pollfd hv_kvp_poll_fd[1]; 1370 int op, pool; 1371 int hv_kvp_dev_fd, error, len, r; 1372 int ch; 1373 1374 while ((ch = getopt(argc, argv, "dn")) != -1) { 1375 switch (ch) { 1376 case 'n': 1377 /* Run as regular process for debugging purpose. */ 1378 is_daemon = 0; 1379 break; 1380 case 'd': 1381 /* Generate debugging output */ 1382 is_debugging = 1; 1383 break; 1384 default: 1385 break; 1386 } 1387 } 1388 1389 openlog("HV_KVP", 0, LOG_USER); 1390 1391 /* Become daemon first. */ 1392 if (is_daemon == 1) 1393 daemon(1, 0); 1394 else 1395 KVP_LOG(LOG_DEBUG, "Run as regular process.\n"); 1396 1397 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid()); 1398 1399 /* Communication buffer hv_kvp_dev_buf */ 1400 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf)); 1401 /* Buffer for daemon internal use */ 1402 hv_msg = malloc(sizeof(*hv_msg)); 1403 1404 /* Memory allocation failed */ 1405 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) { 1406 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n"); 1407 exit(EXIT_FAILURE); 1408 } 1409 1410 /* Initialize op handlers */ 1411 if (kvp_ops_init() != 0) { 1412 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n"); 1413 exit(EXIT_FAILURE); 1414 } 1415 1416 if (kvp_file_init()) { 1417 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n"); 1418 exit(EXIT_FAILURE); 1419 } 1420 1421 /* Open the Character Device */ 1422 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR); 1423 1424 if (hv_kvp_dev_fd < 0) { 1425 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n", 1426 errno, strerror(errno)); 1427 exit(EXIT_FAILURE); 1428 } 1429 1430 /* Initialize the struct for polling the char device */ 1431 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd; 1432 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM); 1433 1434 /* Register the daemon to the KVP driver */ 1435 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf)); 1436 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER; 1437 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf)); 1438 1439 1440 for (;;) { 1441 r = poll (hv_kvp_poll_fd, 1, 100); 1442 1443 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n", 1444 r, hv_kvp_poll_fd[0].revents); 1445 1446 if (r == 0 || (r < 0 && errno == EAGAIN) || 1447 (r < 0 && errno == EINTR)) { 1448 /* Nothing to read */ 1449 continue; 1450 } 1451 1452 if (r < 0) { 1453 /* 1454 * For pread return failure other than EAGAIN, 1455 * we want to exit. 1456 */ 1457 KVP_LOG(LOG_ERR, "Poll failed.\n"); 1458 perror("poll"); 1459 exit(EIO); 1460 } 1461 1462 /* Read from character device */ 1463 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf, 1464 sizeof(*hv_kvp_dev_buf), 0); 1465 1466 if (len < 0) { 1467 KVP_LOG(LOG_ERR, "Read failed.\n"); 1468 perror("pread"); 1469 exit(EIO); 1470 } 1471 1472 if (len != sizeof(struct hv_kvp_msg)) { 1473 KVP_LOG(LOG_ERR, "read len is: %d\n", len); 1474 continue; 1475 } 1476 1477 /* Copy hv_kvp_dev_buf to hv_msg */ 1478 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg)); 1479 1480 /* 1481 * We will use the KVP header information to pass back 1482 * the error from this daemon. So, first save the op 1483 * and pool info to local variables. 1484 */ 1485 1486 op = hv_msg->hdr.kvp_hdr.operation; 1487 pool = hv_msg->hdr.kvp_hdr.pool; 1488 1489 if (op < 0 || op >= HV_KVP_OP_COUNT || 1490 kvp_op_hdlrs[op].kvp_op_exec == NULL) { 1491 KVP_LOG(LOG_WARNING, 1492 "Unsupported operation OP = %d\n", op); 1493 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED; 1494 } else { 1495 /* 1496 * Call the operateion handler's execution routine. 1497 */ 1498 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg, 1499 (void *)&kvp_op_hdlrs[op]); 1500 if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT) 1501 KVP_LOG(LOG_WARNING, 1502 "Operation failed OP = %d, error = 0x%x\n", 1503 op, error); 1504 } 1505 1506 /* 1507 * Send the value back to the kernel. The response is 1508 * already in the receive buffer. 1509 */ 1510 hv_kvp_done: 1511 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0); 1512 1513 if (len != sizeof(struct hv_kvp_msg)) { 1514 KVP_LOG(LOG_ERR, "write len is: %d\n", len); 1515 goto hv_kvp_done; 1516 } 1517 } 1518 } 1519