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