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