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