1271493Sdelphij/*- 2271493Sdelphij * Copyright (c) 2014 Microsoft Corp. 3271493Sdelphij * All rights reserved. 4271493Sdelphij * 5271493Sdelphij * Redistribution and use in source and binary forms, with or without 6271493Sdelphij * modification, are permitted provided that the following conditions 7271493Sdelphij * are met: 8271493Sdelphij * 1. Redistributions of source code must retain the above copyright 9271493Sdelphij * notice unmodified, this list of conditions, and the following 10271493Sdelphij * disclaimer. 11271493Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 12271493Sdelphij * notice, this list of conditions and the following disclaimer in the 13271493Sdelphij * documentation and/or other materials provided with the distribution. 14271493Sdelphij * 15271493Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16271493Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17271493Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18271493Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19271493Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20271493Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21271493Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22271493Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23271493Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24271493Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25271493Sdelphij */ 26271493Sdelphij 27271493Sdelphij#include <sys/types.h> 28271493Sdelphij#include <sys/socket.h> 29271493Sdelphij#include <sys/poll.h> 30271493Sdelphij#include <sys/utsname.h> 31271493Sdelphij#include <sys/stat.h> 32271493Sdelphij#include <sys/un.h> 33271493Sdelphij 34271493Sdelphij#include <arpa/inet.h> 35271493Sdelphij#include <ifaddrs.h> 36271493Sdelphij#include <netdb.h> 37271493Sdelphij 38271493Sdelphij#include <netinet/in.h> 39271493Sdelphij#include <net/ethernet.h> 40271493Sdelphij#include <net/if_dl.h> 41271493Sdelphij#include <net/if_types.h> 42271493Sdelphij 43271493Sdelphij#include <assert.h> 44271493Sdelphij 45271493Sdelphij#include <ctype.h> 46271493Sdelphij#include <dirent.h> 47271493Sdelphij#include <errno.h> 48271493Sdelphij#include <fcntl.h> 49271493Sdelphij#include <poll.h> 50271493Sdelphij#include <stdio.h> 51271493Sdelphij#include <stdlib.h> 52271493Sdelphij#include <string.h> 53271493Sdelphij#include <syslog.h> 54271493Sdelphij#include <unistd.h> 55308635Ssephe#include <assert.h> 56271493Sdelphij 57271493Sdelphij#include "hv_kvp.h" 58308635Ssephe#include "hv_utilreg.h" 59271493Sdelphijtypedef uint8_t __u8; 60271493Sdelphijtypedef uint16_t __u16; 61271493Sdelphijtypedef uint32_t __u32; 62271493Sdelphijtypedef uint64_t __u64; 63271493Sdelphij 64318433Ssephe#define POOL_FILE_MODE (S_IRUSR | S_IWUSR) 65318433Ssephe#define POOL_DIR_MODE (POOL_FILE_MODE | S_IXUSR) 66318433Ssephe#define POOL_DIR "/var/db/hyperv/pool" 67318433Ssephe 68271493Sdelphij/* 69271493Sdelphij * ENUM Data 70271493Sdelphij */ 71271493Sdelphij 72271493Sdelphijenum key_index { 73271493Sdelphij FullyQualifiedDomainName = 0, 74271493Sdelphij IntegrationServicesVersion, /*This key is serviced in the kernel*/ 75271493Sdelphij NetworkAddressIPv4, 76271493Sdelphij NetworkAddressIPv6, 77271493Sdelphij OSBuildNumber, 78271493Sdelphij OSName, 79271493Sdelphij OSMajorVersion, 80271493Sdelphij OSMinorVersion, 81271493Sdelphij OSVersion, 82271493Sdelphij ProcessorArchitecture 83271493Sdelphij}; 84271493Sdelphij 85271493Sdelphij 86271493Sdelphijenum { 87271493Sdelphij IPADDR = 0, 88271493Sdelphij NETMASK, 89271493Sdelphij GATEWAY, 90271493Sdelphij DNS 91271493Sdelphij}; 92271493Sdelphij 93271493Sdelphij 94271493Sdelphij/* Global Variables */ 95271493Sdelphij 96271493Sdelphij/* 97271493Sdelphij * The structure for operation handlers. 98271493Sdelphij */ 99271493Sdelphijstruct kvp_op_hdlr { 100271493Sdelphij int kvp_op_key; 101271493Sdelphij void (*kvp_op_init)(void); 102271493Sdelphij int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data); 103271493Sdelphij}; 104271493Sdelphij 105271493Sdelphijstatic struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT]; 106271493Sdelphij 107271493Sdelphij/* OS information */ 108271493Sdelphij 109271493Sdelphijstatic const char *os_name = ""; 110271493Sdelphijstatic const char *os_major = ""; 111271493Sdelphijstatic const char *os_minor = ""; 112271493Sdelphijstatic const char *processor_arch; 113271493Sdelphijstatic const char *os_build; 114271493Sdelphijstatic const char *lic_version = "BSD Pre-Release version"; 115271493Sdelphijstatic struct utsname uts_buf; 116271493Sdelphij 117271493Sdelphij/* Global flags */ 118271493Sdelphijstatic int is_daemon = 1; 119271493Sdelphijstatic int is_debugging = 0; 120271493Sdelphij 121271493Sdelphij#define KVP_LOG(priority, format, args...) do { \ 122271493Sdelphij if (is_debugging == 1) { \ 123271493Sdelphij if (is_daemon == 1) \ 124271493Sdelphij syslog(priority, format, ## args); \ 125271493Sdelphij else \ 126271493Sdelphij printf(format, ## args); \ 127271493Sdelphij } else { \ 128271493Sdelphij if (priority < LOG_DEBUG) { \ 129271493Sdelphij if (is_daemon == 1) \ 130271493Sdelphij syslog(priority, format, ## args); \ 131271493Sdelphij else \ 132271493Sdelphij printf(format, ## args); \ 133271493Sdelphij } \ 134271493Sdelphij } \ 135271493Sdelphij } while(0) 136271493Sdelphij 137271493Sdelphij/* 138271493Sdelphij * For KVP pool file 139271493Sdelphij */ 140271493Sdelphij 141271493Sdelphij#define MAX_FILE_NAME 100 142271493Sdelphij#define ENTRIES_PER_BLOCK 50 143271493Sdelphij 144271493Sdelphijstruct kvp_record { 145271493Sdelphij char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; 146271493Sdelphij char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 147271493Sdelphij}; 148271493Sdelphij 149271493Sdelphijstruct kvp_pool { 150271493Sdelphij int pool_fd; 151271493Sdelphij int num_blocks; 152271493Sdelphij struct kvp_record *records; 153271493Sdelphij int num_records; 154271493Sdelphij char fname[MAX_FILE_NAME]; 155271493Sdelphij}; 156271493Sdelphij 157271493Sdelphijstatic struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT]; 158271493Sdelphij 159271493Sdelphij 160271493Sdelphijstatic void 161271493Sdelphijkvp_acquire_lock(int pool) 162271493Sdelphij{ 163271493Sdelphij struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 }; 164271493Sdelphij 165271493Sdelphij fl.l_pid = getpid(); 166271493Sdelphij 167271493Sdelphij if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) { 168271493Sdelphij KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool); 169271493Sdelphij exit(EXIT_FAILURE); 170271493Sdelphij } 171271493Sdelphij} 172271493Sdelphij 173271493Sdelphij 174271493Sdelphijstatic void 175271493Sdelphijkvp_release_lock(int pool) 176271493Sdelphij{ 177271493Sdelphij struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 }; 178271493Sdelphij 179271493Sdelphij fl.l_pid = getpid(); 180271493Sdelphij 181271493Sdelphij if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) { 182271493Sdelphij perror("fcntl"); 183271493Sdelphij KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool); 184271493Sdelphij exit(EXIT_FAILURE); 185271493Sdelphij } 186271493Sdelphij} 187271493Sdelphij 188271493Sdelphij 189271493Sdelphij/* 190271493Sdelphij * Write in-memory copy of KVP to pool files 191271493Sdelphij */ 192271493Sdelphijstatic void 193271493Sdelphijkvp_update_file(int pool) 194271493Sdelphij{ 195271493Sdelphij FILE *filep; 196271493Sdelphij size_t bytes_written; 197271493Sdelphij 198271493Sdelphij kvp_acquire_lock(pool); 199271493Sdelphij 200271493Sdelphij filep = fopen(kvp_pools[pool].fname, "w"); 201271493Sdelphij if (!filep) { 202271493Sdelphij kvp_release_lock(pool); 203271493Sdelphij KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool); 204271493Sdelphij exit(EXIT_FAILURE); 205271493Sdelphij } 206271493Sdelphij 207271493Sdelphij bytes_written = fwrite(kvp_pools[pool].records, 208271493Sdelphij sizeof(struct kvp_record), 209271493Sdelphij kvp_pools[pool].num_records, filep); 210271493Sdelphij 211271493Sdelphij if (ferror(filep) || fclose(filep)) { 212271493Sdelphij kvp_release_lock(pool); 213271493Sdelphij KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool); 214271493Sdelphij exit(EXIT_FAILURE); 215271493Sdelphij } 216271493Sdelphij 217271493Sdelphij kvp_release_lock(pool); 218271493Sdelphij} 219271493Sdelphij 220271493Sdelphij 221271493Sdelphij/* 222271493Sdelphij * Read KVPs from pool files and store in memory 223271493Sdelphij */ 224271493Sdelphijstatic void 225271493Sdelphijkvp_update_mem_state(int pool) 226271493Sdelphij{ 227271493Sdelphij FILE *filep; 228271493Sdelphij size_t records_read = 0; 229271493Sdelphij struct kvp_record *record = kvp_pools[pool].records; 230271493Sdelphij struct kvp_record *readp; 231271493Sdelphij int num_blocks = kvp_pools[pool].num_blocks; 232271493Sdelphij int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 233271493Sdelphij 234271493Sdelphij kvp_acquire_lock(pool); 235271493Sdelphij 236271493Sdelphij filep = fopen(kvp_pools[pool].fname, "r"); 237271493Sdelphij if (!filep) { 238271493Sdelphij kvp_release_lock(pool); 239271493Sdelphij KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool); 240271493Sdelphij exit(EXIT_FAILURE); 241271493Sdelphij } 242271493Sdelphij for ( ; ; ) 243271493Sdelphij { 244271493Sdelphij readp = &record[records_read]; 245271493Sdelphij records_read += fread(readp, sizeof(struct kvp_record), 246271493Sdelphij ENTRIES_PER_BLOCK * num_blocks, 247271493Sdelphij filep); 248271493Sdelphij 249271493Sdelphij if (ferror(filep)) { 250271493Sdelphij KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool); 251271493Sdelphij exit(EXIT_FAILURE); 252271493Sdelphij } 253271493Sdelphij 254271493Sdelphij if (!feof(filep)) { 255271493Sdelphij /* 256271493Sdelphij * Have more data to read. Expand the memory. 257271493Sdelphij */ 258271493Sdelphij num_blocks++; 259271493Sdelphij record = realloc(record, alloc_unit * num_blocks); 260271493Sdelphij 261271493Sdelphij if (record == NULL) { 262271493Sdelphij KVP_LOG(LOG_ERR, "malloc failed\n"); 263271493Sdelphij exit(EXIT_FAILURE); 264271493Sdelphij } 265271493Sdelphij continue; 266271493Sdelphij } 267271493Sdelphij break; 268271493Sdelphij } 269271493Sdelphij 270271493Sdelphij kvp_pools[pool].num_blocks = num_blocks; 271271493Sdelphij kvp_pools[pool].records = record; 272271493Sdelphij kvp_pools[pool].num_records = records_read; 273271493Sdelphij 274271493Sdelphij fclose(filep); 275271493Sdelphij kvp_release_lock(pool); 276271493Sdelphij} 277271493Sdelphij 278271493Sdelphij 279271493Sdelphijstatic int 280271493Sdelphijkvp_file_init(void) 281271493Sdelphij{ 282271493Sdelphij int fd; 283271493Sdelphij FILE *filep; 284271493Sdelphij size_t records_read; 285271493Sdelphij char *fname; 286271493Sdelphij struct kvp_record *record; 287271493Sdelphij struct kvp_record *readp; 288271493Sdelphij int num_blocks; 289271493Sdelphij int i; 290271493Sdelphij int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 291271493Sdelphij 292318433Ssephe if (mkdir(POOL_DIR, POOL_DIR_MODE) < 0 && 293274383Sdelphij (errno != EEXIST && errno != EISDIR)) { 294272139Sdelphij KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n"); 295272139Sdelphij exit(EXIT_FAILURE); 296271493Sdelphij } 297318433Ssephe chmod(POOL_DIR, POOL_DIR_MODE); /* fix old mistake */ 298271493Sdelphij 299271493Sdelphij for (i = 0; i < HV_KVP_POOL_COUNT; i++) 300271493Sdelphij { 301271493Sdelphij fname = kvp_pools[i].fname; 302271493Sdelphij records_read = 0; 303271493Sdelphij num_blocks = 1; 304271493Sdelphij snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i); 305318433Ssephe fd = open(fname, O_RDWR | O_CREAT, POOL_FILE_MODE); 306271493Sdelphij 307271493Sdelphij if (fd == -1) { 308271493Sdelphij return (1); 309271493Sdelphij } 310318433Ssephe fchmod(fd, POOL_FILE_MODE); /* fix old mistake */ 311271493Sdelphij 312271493Sdelphij 313271493Sdelphij filep = fopen(fname, "r"); 314271493Sdelphij if (!filep) { 315272140Sdelphij close(fd); 316271493Sdelphij return (1); 317271493Sdelphij } 318271493Sdelphij 319271493Sdelphij record = malloc(alloc_unit * num_blocks); 320271493Sdelphij if (record == NULL) { 321272140Sdelphij close(fd); 322271493Sdelphij fclose(filep); 323271493Sdelphij return (1); 324271493Sdelphij } 325271493Sdelphij for ( ; ; ) 326271493Sdelphij { 327271493Sdelphij readp = &record[records_read]; 328271493Sdelphij records_read += fread(readp, sizeof(struct kvp_record), 329271493Sdelphij ENTRIES_PER_BLOCK, 330271493Sdelphij filep); 331271493Sdelphij 332271493Sdelphij if (ferror(filep)) { 333271493Sdelphij KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", 334271493Sdelphij i); 335271493Sdelphij exit(EXIT_FAILURE); 336271493Sdelphij } 337271493Sdelphij 338271493Sdelphij if (!feof(filep)) { 339271493Sdelphij /* 340271493Sdelphij * More data to read. 341271493Sdelphij */ 342271493Sdelphij num_blocks++; 343271493Sdelphij record = realloc(record, alloc_unit * 344271493Sdelphij num_blocks); 345271493Sdelphij if (record == NULL) { 346272140Sdelphij close(fd); 347271493Sdelphij fclose(filep); 348271493Sdelphij return (1); 349271493Sdelphij } 350271493Sdelphij continue; 351271493Sdelphij } 352271493Sdelphij break; 353271493Sdelphij } 354271493Sdelphij kvp_pools[i].pool_fd = fd; 355271493Sdelphij kvp_pools[i].num_blocks = num_blocks; 356271493Sdelphij kvp_pools[i].records = record; 357271493Sdelphij kvp_pools[i].num_records = records_read; 358271493Sdelphij fclose(filep); 359271493Sdelphij } 360271493Sdelphij 361271493Sdelphij return (0); 362271493Sdelphij} 363271493Sdelphij 364271493Sdelphij 365271493Sdelphijstatic int 366271493Sdelphijkvp_key_delete(int pool, __u8 *key, int key_size) 367271493Sdelphij{ 368271493Sdelphij int i; 369271493Sdelphij int j, k; 370271493Sdelphij int num_records; 371271493Sdelphij struct kvp_record *record; 372271493Sdelphij 373271493Sdelphij KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, " 374271493Sdelphij "key = %s\n", pool, key); 375271493Sdelphij 376271493Sdelphij /* Update in-memory state */ 377271493Sdelphij kvp_update_mem_state(pool); 378271493Sdelphij 379271493Sdelphij num_records = kvp_pools[pool].num_records; 380271493Sdelphij record = kvp_pools[pool].records; 381271493Sdelphij 382271493Sdelphij for (i = 0; i < num_records; i++) 383271493Sdelphij { 384271493Sdelphij if (memcmp(key, record[i].key, key_size)) { 385271493Sdelphij continue; 386271493Sdelphij } 387271493Sdelphij 388271493Sdelphij KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n", 389271493Sdelphij pool); 390271493Sdelphij /* 391271493Sdelphij * We found a match at the end; Just update the number of 392271493Sdelphij * entries and we are done. 393271493Sdelphij */ 394271493Sdelphij if (i == num_records) { 395271493Sdelphij kvp_pools[pool].num_records--; 396271493Sdelphij kvp_update_file(pool); 397271493Sdelphij return (0); 398271493Sdelphij } 399271493Sdelphij 400271493Sdelphij /* 401271493Sdelphij * We found a match in the middle; Move the remaining 402271493Sdelphij * entries up. 403271493Sdelphij */ 404271493Sdelphij j = i; 405271493Sdelphij k = j + 1; 406271493Sdelphij for ( ; k < num_records; k++) 407271493Sdelphij { 408271493Sdelphij strcpy(record[j].key, record[k].key); 409271493Sdelphij strcpy(record[j].value, record[k].value); 410271493Sdelphij j++; 411271493Sdelphij } 412271493Sdelphij kvp_pools[pool].num_records--; 413271493Sdelphij kvp_update_file(pool); 414271493Sdelphij return (0); 415271493Sdelphij } 416271493Sdelphij KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n", 417271493Sdelphij pool); 418271493Sdelphij return (1); 419271493Sdelphij} 420271493Sdelphij 421271493Sdelphij 422271493Sdelphijstatic int 423271493Sdelphijkvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value, 424271493Sdelphij __u32 value_size) 425271493Sdelphij{ 426271493Sdelphij int i; 427271493Sdelphij int num_records; 428271493Sdelphij struct kvp_record *record; 429271493Sdelphij int num_blocks; 430271493Sdelphij 431271493Sdelphij KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, " 432271493Sdelphij "key = %s, value = %s\n,", pool, key, value); 433271493Sdelphij 434271493Sdelphij if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 435271493Sdelphij (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 436271493Sdelphij KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n"); 437271493Sdelphij return (1); 438271493Sdelphij } 439271493Sdelphij 440271493Sdelphij /* Update the in-memory state. */ 441271493Sdelphij kvp_update_mem_state(pool); 442271493Sdelphij 443271493Sdelphij num_records = kvp_pools[pool].num_records; 444271493Sdelphij record = kvp_pools[pool].records; 445271493Sdelphij num_blocks = kvp_pools[pool].num_blocks; 446271493Sdelphij 447271493Sdelphij for (i = 0; i < num_records; i++) 448271493Sdelphij { 449271493Sdelphij if (memcmp(key, record[i].key, key_size)) { 450271493Sdelphij continue; 451271493Sdelphij } 452271493Sdelphij 453271493Sdelphij /* 454271493Sdelphij * Key exists. Just update the value and we are done. 455271493Sdelphij */ 456271493Sdelphij memcpy(record[i].value, value, value_size); 457271493Sdelphij kvp_update_file(pool); 458271493Sdelphij return (0); 459271493Sdelphij } 460271493Sdelphij 461271493Sdelphij /* 462271493Sdelphij * Key doesn't exist; Add a new KVP. 463271493Sdelphij */ 464271493Sdelphij if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { 465271493Sdelphij /* Increase the size of the recodrd array. */ 466271493Sdelphij record = realloc(record, sizeof(struct kvp_record) * 467271493Sdelphij ENTRIES_PER_BLOCK * (num_blocks + 1)); 468271493Sdelphij 469271493Sdelphij if (record == NULL) { 470271493Sdelphij return (1); 471271493Sdelphij } 472271493Sdelphij kvp_pools[pool].num_blocks++; 473271493Sdelphij } 474271493Sdelphij memcpy(record[i].value, value, value_size); 475271493Sdelphij memcpy(record[i].key, key, key_size); 476271493Sdelphij kvp_pools[pool].records = record; 477271493Sdelphij kvp_pools[pool].num_records++; 478271493Sdelphij kvp_update_file(pool); 479271493Sdelphij return (0); 480271493Sdelphij} 481271493Sdelphij 482271493Sdelphij 483271493Sdelphijstatic int 484271493Sdelphijkvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, 485271493Sdelphij int value_size) 486271493Sdelphij{ 487271493Sdelphij int i; 488271493Sdelphij int num_records; 489271493Sdelphij struct kvp_record *record; 490271493Sdelphij 491271493Sdelphij KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,", 492271493Sdelphij pool, key); 493271493Sdelphij 494271493Sdelphij if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 495271493Sdelphij (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 496271493Sdelphij return (1); 497271493Sdelphij } 498271493Sdelphij 499271493Sdelphij /* Update the in-memory state first. */ 500271493Sdelphij kvp_update_mem_state(pool); 501271493Sdelphij 502271493Sdelphij num_records = kvp_pools[pool].num_records; 503271493Sdelphij record = kvp_pools[pool].records; 504271493Sdelphij 505271493Sdelphij for (i = 0; i < num_records; i++) 506271493Sdelphij { 507271493Sdelphij if (memcmp(key, record[i].key, key_size)) { 508271493Sdelphij continue; 509271493Sdelphij } 510271493Sdelphij 511271493Sdelphij /* Found the key */ 512271493Sdelphij memcpy(value, record[i].value, value_size); 513271493Sdelphij return (0); 514271493Sdelphij } 515271493Sdelphij 516271493Sdelphij return (1); 517271493Sdelphij} 518271493Sdelphij 519271493Sdelphij 520271493Sdelphijstatic int 521274370Sdelphijkvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size, 522271493Sdelphij __u8 *value, int value_size) 523271493Sdelphij{ 524271493Sdelphij struct kvp_record *record; 525271493Sdelphij 526271493Sdelphij KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,", 527274370Sdelphij pool, idx); 528271493Sdelphij 529271493Sdelphij /* First update our in-memory state first. */ 530271493Sdelphij kvp_update_mem_state(pool); 531271493Sdelphij record = kvp_pools[pool].records; 532271493Sdelphij 533271493Sdelphij /* Index starts with 0 */ 534274370Sdelphij if (idx >= kvp_pools[pool].num_records) { 535271493Sdelphij return (1); 536271493Sdelphij } 537271493Sdelphij 538274370Sdelphij memcpy(key, record[idx].key, key_size); 539274370Sdelphij memcpy(value, record[idx].value, value_size); 540271493Sdelphij return (0); 541271493Sdelphij} 542271493Sdelphij 543271493Sdelphij 544271493Sdelphijstatic void 545271493Sdelphijkvp_get_os_info(void) 546271493Sdelphij{ 547271493Sdelphij char *p; 548271493Sdelphij 549271493Sdelphij uname(&uts_buf); 550271493Sdelphij os_build = uts_buf.release; 551271493Sdelphij os_name = uts_buf.sysname; 552271493Sdelphij processor_arch = uts_buf.machine; 553271493Sdelphij 554271493Sdelphij /* 555271493Sdelphij * Win7 host expects the build string to be of the form: x.y.z 556271493Sdelphij * Strip additional information we may have. 557271493Sdelphij */ 558271493Sdelphij p = strchr(os_build, '-'); 559271493Sdelphij if (p) { 560271493Sdelphij *p = '\0'; 561271493Sdelphij } 562271493Sdelphij 563271493Sdelphij /* 564271493Sdelphij * We don't have any other information about the FreeBSD os. 565271493Sdelphij */ 566271493Sdelphij return; 567271493Sdelphij} 568271493Sdelphij 569271493Sdelphij/* 570271493Sdelphij * Given the interface name, return the MAC address. 571271493Sdelphij */ 572271493Sdelphijstatic char * 573271493Sdelphijkvp_if_name_to_mac(char *if_name) 574271493Sdelphij{ 575271493Sdelphij char *mac_addr = NULL; 576271493Sdelphij struct ifaddrs *ifaddrs_ptr; 577271493Sdelphij struct ifaddrs *head_ifaddrs_ptr; 578271493Sdelphij struct sockaddr_dl *sdl; 579271493Sdelphij int status; 580271493Sdelphij 581271493Sdelphij status = getifaddrs(&ifaddrs_ptr); 582271493Sdelphij 583271493Sdelphij if (status >= 0) { 584271493Sdelphij head_ifaddrs_ptr = ifaddrs_ptr; 585271493Sdelphij do { 586271493Sdelphij sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr; 587271493Sdelphij if ((sdl->sdl_type == IFT_ETHER) && 588271493Sdelphij (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) { 589271493Sdelphij mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl)))); 590271493Sdelphij break; 591271493Sdelphij } 592271493Sdelphij } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL); 593271493Sdelphij freeifaddrs(head_ifaddrs_ptr); 594271493Sdelphij } 595271493Sdelphij 596271493Sdelphij return (mac_addr); 597271493Sdelphij} 598271493Sdelphij 599271493Sdelphij 600271493Sdelphij/* 601271493Sdelphij * Given the MAC address, return the interface name. 602271493Sdelphij */ 603271493Sdelphijstatic char * 604271493Sdelphijkvp_mac_to_if_name(char *mac) 605271493Sdelphij{ 606271493Sdelphij char *if_name = NULL; 607271493Sdelphij struct ifaddrs *ifaddrs_ptr; 608271493Sdelphij struct ifaddrs *head_ifaddrs_ptr; 609271493Sdelphij struct sockaddr_dl *sdl; 610271493Sdelphij int status; 611272143Sdelphij char *buf_ptr, *p; 612271493Sdelphij 613271493Sdelphij status = getifaddrs(&ifaddrs_ptr); 614271493Sdelphij 615271493Sdelphij if (status >= 0) { 616271493Sdelphij head_ifaddrs_ptr = ifaddrs_ptr; 617271493Sdelphij do { 618271493Sdelphij sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr; 619271493Sdelphij if (sdl->sdl_type == IFT_ETHER) { 620271493Sdelphij buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl)))); 621272141Sdelphij if (buf_ptr != NULL) { 622272143Sdelphij for (p = buf_ptr; *p != '\0'; p++) 623272143Sdelphij *p = toupper(*p); 624271493Sdelphij 625272141Sdelphij if (strncmp(buf_ptr, mac, strlen(mac)) == 0) { 626272141Sdelphij /* Caller will free the memory */ 627272141Sdelphij if_name = strdup(ifaddrs_ptr->ifa_name); 628272141Sdelphij free(buf_ptr); 629272141Sdelphij break; 630272141Sdelphij } else 631272141Sdelphij free(buf_ptr); 632271493Sdelphij } 633271493Sdelphij } 634271493Sdelphij } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL); 635271493Sdelphij freeifaddrs(head_ifaddrs_ptr); 636271493Sdelphij } 637271493Sdelphij return (if_name); 638271493Sdelphij} 639271493Sdelphij 640271493Sdelphij 641271493Sdelphijstatic void 642271493Sdelphijkvp_process_ipconfig_file(char *cmd, 643271493Sdelphij char *config_buf, size_t len, 644271493Sdelphij size_t element_size, int offset) 645271493Sdelphij{ 646271493Sdelphij char buf[256]; 647271493Sdelphij char *p; 648271493Sdelphij char *x; 649271493Sdelphij FILE *file; 650271493Sdelphij 651271493Sdelphij /* 652271493Sdelphij * First execute the command. 653271493Sdelphij */ 654271493Sdelphij file = popen(cmd, "r"); 655271493Sdelphij if (file == NULL) { 656271493Sdelphij return; 657271493Sdelphij } 658271493Sdelphij 659271493Sdelphij if (offset == 0) { 660271493Sdelphij memset(config_buf, 0, len); 661271493Sdelphij } 662271493Sdelphij while ((p = fgets(buf, sizeof(buf), file)) != NULL) { 663271493Sdelphij if ((len - strlen(config_buf)) < (element_size + 1)) { 664271493Sdelphij break; 665271493Sdelphij } 666271493Sdelphij 667271493Sdelphij x = strchr(p, '\n'); 668271493Sdelphij *x = '\0'; 669271493Sdelphij strlcat(config_buf, p, len); 670271493Sdelphij strlcat(config_buf, ";", len); 671271493Sdelphij } 672271493Sdelphij pclose(file); 673271493Sdelphij} 674271493Sdelphij 675271493Sdelphij 676271493Sdelphijstatic void 677271493Sdelphijkvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer) 678271493Sdelphij{ 679271493Sdelphij char cmd[512]; 680271493Sdelphij char dhcp_info[128]; 681271493Sdelphij char *p; 682271493Sdelphij FILE *file; 683271493Sdelphij 684271493Sdelphij /* 685271493Sdelphij * Retrieve the IPV4 address of default gateway. 686271493Sdelphij */ 687271493Sdelphij snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name); 688271493Sdelphij 689271493Sdelphij /* 690271493Sdelphij * Execute the command to gather gateway IPV4 info. 691271493Sdelphij */ 692271493Sdelphij kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 693271493Sdelphij (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); 694271493Sdelphij /* 695271493Sdelphij * Retrieve the IPV6 address of default gateway. 696271493Sdelphij */ 697308635Ssephe snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }'", if_name); 698271493Sdelphij 699271493Sdelphij /* 700271493Sdelphij * Execute the command to gather gateway IPV6 info. 701271493Sdelphij */ 702271493Sdelphij kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 703271493Sdelphij (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); 704271493Sdelphij /* 705271493Sdelphij * we just invoke an external script to get the DNS info. 706271493Sdelphij * 707271493Sdelphij * Following is the expected format of the information from the script: 708271493Sdelphij * 709271493Sdelphij * ipaddr1 (nameserver1) 710271493Sdelphij * ipaddr2 (nameserver2) 711271493Sdelphij * . 712271493Sdelphij * . 713271493Sdelphij */ 714271493Sdelphij /* Scripts are stored in /usr/libexec/hyperv/ directory */ 715271493Sdelphij snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info"); 716271493Sdelphij 717271493Sdelphij /* 718271493Sdelphij * Execute the command to get DNS info. 719271493Sdelphij */ 720271493Sdelphij kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, 721271493Sdelphij (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); 722271493Sdelphij 723271493Sdelphij /* 724271493Sdelphij * Invoke an external script to get the DHCP state info. 725271493Sdelphij * The parameter to the script is the interface name. 726271493Sdelphij * Here is the expected output: 727271493Sdelphij * 728271493Sdelphij * Enabled: DHCP enabled. 729271493Sdelphij */ 730271493Sdelphij 731271493Sdelphij 732271493Sdelphij snprintf(cmd, sizeof(cmd), "%s %s", 733271493Sdelphij "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name); 734271493Sdelphij 735271493Sdelphij file = popen(cmd, "r"); 736271493Sdelphij if (file == NULL) { 737271493Sdelphij return; 738271493Sdelphij } 739271493Sdelphij 740271493Sdelphij p = fgets(dhcp_info, sizeof(dhcp_info), file); 741271493Sdelphij if (p == NULL) { 742271493Sdelphij pclose(file); 743271493Sdelphij return; 744271493Sdelphij } 745271493Sdelphij 746271493Sdelphij if (!strncmp(p, "Enabled", 7)) { 747271493Sdelphij buffer->dhcp_enabled = 1; 748271493Sdelphij } else{ 749271493Sdelphij buffer->dhcp_enabled = 0; 750271493Sdelphij } 751271493Sdelphij 752271493Sdelphij pclose(file); 753271493Sdelphij} 754271493Sdelphij 755271493Sdelphij 756271493Sdelphijstatic unsigned int 757271493Sdelphijhweight32(unsigned int *w) 758271493Sdelphij{ 759271493Sdelphij unsigned int res = *w - ((*w >> 1) & 0x55555555); 760271493Sdelphij 761271493Sdelphij res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 762271493Sdelphij res = (res + (res >> 4)) & 0x0F0F0F0F; 763271493Sdelphij res = res + (res >> 8); 764271493Sdelphij return ((res + (res >> 16)) & 0x000000FF); 765271493Sdelphij} 766271493Sdelphij 767271493Sdelphij 768271493Sdelphijstatic int 769271493Sdelphijkvp_process_ip_address(void *addrp, 770271493Sdelphij int family, char *buffer, 771271493Sdelphij int length, int *offset) 772271493Sdelphij{ 773271493Sdelphij struct sockaddr_in *addr; 774271493Sdelphij struct sockaddr_in6 *addr6; 775271493Sdelphij int addr_length; 776271493Sdelphij char tmp[50]; 777271493Sdelphij const char *str; 778271493Sdelphij 779271493Sdelphij if (family == AF_INET) { 780271493Sdelphij addr = (struct sockaddr_in *)addrp; 781271493Sdelphij str = inet_ntop(family, &addr->sin_addr, tmp, 50); 782271493Sdelphij addr_length = INET_ADDRSTRLEN; 783271493Sdelphij } else { 784271493Sdelphij addr6 = (struct sockaddr_in6 *)addrp; 785271493Sdelphij str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); 786271493Sdelphij addr_length = INET6_ADDRSTRLEN; 787271493Sdelphij } 788271493Sdelphij 789271493Sdelphij if ((length - *offset) < addr_length + 1) { 790308635Ssephe return (EINVAL); 791271493Sdelphij } 792271493Sdelphij if (str == NULL) { 793271493Sdelphij strlcpy(buffer, "inet_ntop failed\n", length); 794308635Ssephe return (errno); 795271493Sdelphij } 796271493Sdelphij if (*offset == 0) { 797271493Sdelphij strlcpy(buffer, tmp, length); 798271493Sdelphij } else{ 799271493Sdelphij strlcat(buffer, tmp, length); 800271493Sdelphij } 801271493Sdelphij strlcat(buffer, ";", length); 802271493Sdelphij 803271493Sdelphij *offset += strlen(str) + 1; 804271493Sdelphij return (0); 805271493Sdelphij} 806271493Sdelphij 807271493Sdelphij 808271493Sdelphijstatic int 809271493Sdelphijkvp_get_ip_info(int family, char *if_name, int op, 810271493Sdelphij void *out_buffer, size_t length) 811271493Sdelphij{ 812271493Sdelphij struct ifaddrs *ifap; 813271493Sdelphij struct ifaddrs *curp; 814271493Sdelphij int offset = 0; 815271493Sdelphij int sn_offset = 0; 816271493Sdelphij int error = 0; 817271493Sdelphij char *buffer; 818271493Sdelphij size_t buffer_length; 819286972Spfg struct hv_kvp_ipaddr_value *ip_buffer = NULL; 820271493Sdelphij char cidr_mask[5]; 821271493Sdelphij int weight; 822271493Sdelphij int i; 823271493Sdelphij unsigned int *w = NULL; 824271493Sdelphij char *sn_str; 825271493Sdelphij size_t sn_str_length; 826271493Sdelphij struct sockaddr_in6 *addr6; 827271493Sdelphij 828271493Sdelphij if (op == HV_KVP_OP_ENUMERATE) { 829271493Sdelphij buffer = out_buffer; 830271493Sdelphij buffer_length = length; 831271493Sdelphij } else { 832271493Sdelphij ip_buffer = out_buffer; 833271493Sdelphij buffer = (char *)ip_buffer->ip_addr; 834271493Sdelphij buffer_length = sizeof(ip_buffer->ip_addr); 835271493Sdelphij ip_buffer->addr_family = 0; 836271493Sdelphij } 837271493Sdelphij 838271493Sdelphij if (getifaddrs(&ifap)) { 839271493Sdelphij strlcpy(buffer, "getifaddrs failed\n", buffer_length); 840308635Ssephe return (errno); 841271493Sdelphij } 842271493Sdelphij 843271493Sdelphij curp = ifap; 844271493Sdelphij while (curp != NULL) { 845271493Sdelphij if (curp->ifa_addr == NULL) { 846271493Sdelphij curp = curp->ifa_next; 847271493Sdelphij continue; 848271493Sdelphij } 849271493Sdelphij 850271493Sdelphij if ((if_name != NULL) && 851271493Sdelphij (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { 852271493Sdelphij /* 853271493Sdelphij * We want info about a specific interface; 854271493Sdelphij * just continue. 855271493Sdelphij */ 856271493Sdelphij curp = curp->ifa_next; 857271493Sdelphij continue; 858271493Sdelphij } 859271493Sdelphij 860271493Sdelphij /* 861271493Sdelphij * We support two address families: AF_INET and AF_INET6. 862271493Sdelphij * If family value is 0, we gather both supported 863271493Sdelphij * address families; if not we gather info on 864271493Sdelphij * the specified address family. 865271493Sdelphij */ 866271493Sdelphij if ((family != 0) && (curp->ifa_addr->sa_family != family)) { 867271493Sdelphij curp = curp->ifa_next; 868271493Sdelphij continue; 869271493Sdelphij } 870271493Sdelphij if ((curp->ifa_addr->sa_family != AF_INET) && 871271493Sdelphij (curp->ifa_addr->sa_family != AF_INET6)) { 872271493Sdelphij curp = curp->ifa_next; 873271493Sdelphij continue; 874271493Sdelphij } 875271493Sdelphij 876271493Sdelphij if (op == HV_KVP_OP_GET_IP_INFO) { 877271493Sdelphij /* 878271493Sdelphij * Get the info other than the IP address. 879271493Sdelphij */ 880271493Sdelphij if (curp->ifa_addr->sa_family == AF_INET) { 881271493Sdelphij ip_buffer->addr_family |= ADDR_FAMILY_IPV4; 882271493Sdelphij 883271493Sdelphij /* 884271493Sdelphij * Get subnet info. 885271493Sdelphij */ 886271493Sdelphij error = kvp_process_ip_address( 887271493Sdelphij curp->ifa_netmask, 888271493Sdelphij AF_INET, 889271493Sdelphij (char *) 890271493Sdelphij ip_buffer->sub_net, 891271493Sdelphij length, 892271493Sdelphij &sn_offset); 893271493Sdelphij if (error) { 894271493Sdelphij goto kvp_get_ip_info_ipaddr; 895271493Sdelphij } 896271493Sdelphij } else { 897271493Sdelphij ip_buffer->addr_family |= ADDR_FAMILY_IPV6; 898271493Sdelphij 899271493Sdelphij /* 900271493Sdelphij * Get subnet info in CIDR format. 901271493Sdelphij */ 902271493Sdelphij weight = 0; 903271493Sdelphij sn_str = (char *)ip_buffer->sub_net; 904271493Sdelphij sn_str_length = sizeof(ip_buffer->sub_net); 905271493Sdelphij addr6 = (struct sockaddr_in6 *)(uintptr_t) 906271493Sdelphij curp->ifa_netmask; 907271493Sdelphij w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr; 908271493Sdelphij 909271493Sdelphij for (i = 0; i < 4; i++) 910271493Sdelphij { 911271493Sdelphij weight += hweight32(&w[i]); 912271493Sdelphij } 913271493Sdelphij 914271493Sdelphij snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight); 915271493Sdelphij if ((length - sn_offset) < 916271493Sdelphij (strlen(cidr_mask) + 1)) { 917271493Sdelphij goto kvp_get_ip_info_ipaddr; 918271493Sdelphij } 919271493Sdelphij 920271493Sdelphij if (sn_offset == 0) { 921271493Sdelphij strlcpy(sn_str, cidr_mask, sn_str_length); 922271493Sdelphij } else{ 923271493Sdelphij strlcat(sn_str, cidr_mask, sn_str_length); 924271493Sdelphij } 925271493Sdelphij strlcat((char *)ip_buffer->sub_net, ";", sn_str_length); 926271493Sdelphij sn_offset += strlen(sn_str) + 1; 927271493Sdelphij } 928271493Sdelphij 929271493Sdelphij /* 930271493Sdelphij * Collect other ip configuration info. 931271493Sdelphij */ 932271493Sdelphij kvp_get_ipconfig_info(if_name, ip_buffer); 933271493Sdelphij } 934271493Sdelphij 935271493Sdelphijkvp_get_ip_info_ipaddr: 936271493Sdelphij error = kvp_process_ip_address(curp->ifa_addr, 937271493Sdelphij curp->ifa_addr->sa_family, 938271493Sdelphij buffer, 939271493Sdelphij length, &offset); 940271493Sdelphij if (error) { 941271493Sdelphij goto kvp_get_ip_info_done; 942271493Sdelphij } 943271493Sdelphij 944271493Sdelphij curp = curp->ifa_next; 945271493Sdelphij } 946271493Sdelphij 947271493Sdelphijkvp_get_ip_info_done: 948271493Sdelphij freeifaddrs(ifap); 949271493Sdelphij return (error); 950271493Sdelphij} 951271493Sdelphij 952271493Sdelphij 953271493Sdelphijstatic int 954271493Sdelphijkvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3) 955271493Sdelphij{ 956271493Sdelphij int ret; 957271493Sdelphij 958271493Sdelphij ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); 959271493Sdelphij 960271493Sdelphij if (ret < 0) { 961308635Ssephe return (EIO); 962271493Sdelphij } 963271493Sdelphij 964271493Sdelphij return (0); 965271493Sdelphij} 966271493Sdelphij 967271493Sdelphij 968271493Sdelphijstatic int 969271493Sdelphijkvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 970271493Sdelphij{ 971271493Sdelphij int error = 0; 972271493Sdelphij char if_file[128]; 973271493Sdelphij FILE *file; 974271493Sdelphij char cmd[512]; 975271493Sdelphij char *mac_addr; 976271493Sdelphij 977271493Sdelphij /* 978271493Sdelphij * FreeBSD - Configuration File 979271493Sdelphij */ 980271493Sdelphij snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv", 981271493Sdelphij "hv_set_ip_data"); 982271493Sdelphij file = fopen(if_file, "w"); 983271493Sdelphij 984271493Sdelphij if (file == NULL) { 985271493Sdelphij KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n"); 986308635Ssephe return (errno); 987271493Sdelphij } 988271493Sdelphij 989271493Sdelphij /* 990271493Sdelphij * Write out the MAC address. 991271493Sdelphij */ 992271493Sdelphij 993271493Sdelphij mac_addr = kvp_if_name_to_mac(if_name); 994271493Sdelphij if (mac_addr == NULL) { 995308635Ssephe error = EINVAL; 996271493Sdelphij goto kvp_set_ip_info_error; 997271493Sdelphij } 998271493Sdelphij /* MAC Address */ 999271493Sdelphij error = kvp_write_file(file, "HWADDR", "", mac_addr); 1000271493Sdelphij if (error) { 1001271493Sdelphij goto kvp_set_ip_info_error; 1002271493Sdelphij } 1003271493Sdelphij 1004271493Sdelphij /* Interface Name */ 1005271493Sdelphij error = kvp_write_file(file, "IF_NAME", "", if_name); 1006271493Sdelphij if (error) { 1007271493Sdelphij goto kvp_set_ip_info_error; 1008271493Sdelphij } 1009271493Sdelphij 1010271493Sdelphij /* IP Address */ 1011271493Sdelphij error = kvp_write_file(file, "IP_ADDR", "", 1012271493Sdelphij (char *)new_val->ip_addr); 1013271493Sdelphij if (error) { 1014271493Sdelphij goto kvp_set_ip_info_error; 1015271493Sdelphij } 1016271493Sdelphij 1017271493Sdelphij /* Subnet Mask */ 1018271493Sdelphij error = kvp_write_file(file, "SUBNET", "", 1019271493Sdelphij (char *)new_val->sub_net); 1020271493Sdelphij if (error) { 1021271493Sdelphij goto kvp_set_ip_info_error; 1022271493Sdelphij } 1023271493Sdelphij 1024271493Sdelphij 1025271493Sdelphij /* Gateway */ 1026271493Sdelphij error = kvp_write_file(file, "GATEWAY", "", 1027271493Sdelphij (char *)new_val->gate_way); 1028271493Sdelphij if (error) { 1029271493Sdelphij goto kvp_set_ip_info_error; 1030271493Sdelphij } 1031271493Sdelphij 1032271493Sdelphij /* DNS */ 1033271493Sdelphij error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr); 1034271493Sdelphij if (error) { 1035271493Sdelphij goto kvp_set_ip_info_error; 1036271493Sdelphij } 1037271493Sdelphij 1038271493Sdelphij /* DHCP */ 1039271493Sdelphij if (new_val->dhcp_enabled) { 1040271493Sdelphij error = kvp_write_file(file, "DHCP", "", "1"); 1041271493Sdelphij } else{ 1042271493Sdelphij error = kvp_write_file(file, "DHCP", "", "0"); 1043271493Sdelphij } 1044271493Sdelphij 1045271493Sdelphij if (error) { 1046271493Sdelphij goto kvp_set_ip_info_error; 1047271493Sdelphij } 1048271493Sdelphij 1049271493Sdelphij free(mac_addr); 1050271493Sdelphij fclose(file); 1051271493Sdelphij 1052271493Sdelphij /* 1053271493Sdelphij * Invoke the external script with the populated 1054271493Sdelphij * configuration file. 1055271493Sdelphij */ 1056271493Sdelphij 1057271493Sdelphij snprintf(cmd, sizeof(cmd), "%s %s", 1058271493Sdelphij "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file); 1059271493Sdelphij system(cmd); 1060271493Sdelphij return (0); 1061271493Sdelphij 1062271493Sdelphijkvp_set_ip_info_error: 1063271493Sdelphij KVP_LOG(LOG_ERR, "Failed to write config file\n"); 1064271493Sdelphij free(mac_addr); 1065271493Sdelphij fclose(file); 1066271493Sdelphij return (error); 1067271493Sdelphij} 1068271493Sdelphij 1069271493Sdelphij 1070271493Sdelphijstatic int 1071271493Sdelphijkvp_get_domain_name(char *buffer, int length) 1072271493Sdelphij{ 1073271493Sdelphij struct addrinfo hints, *info; 1074271493Sdelphij int error = 0; 1075271493Sdelphij 1076271493Sdelphij gethostname(buffer, length); 1077271493Sdelphij memset(&hints, 0, sizeof(hints)); 1078271493Sdelphij hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */ 1079271493Sdelphij hints.ai_socktype = SOCK_STREAM; 1080271493Sdelphij hints.ai_flags = AI_CANONNAME; 1081271493Sdelphij 1082271493Sdelphij error = getaddrinfo(buffer, NULL, &hints, &info); 1083271493Sdelphij if (error != 0) { 1084271493Sdelphij strlcpy(buffer, "getaddrinfo failed\n", length); 1085271493Sdelphij return (error); 1086271493Sdelphij } 1087271493Sdelphij strlcpy(buffer, info->ai_canonname, length); 1088271493Sdelphij freeaddrinfo(info); 1089271493Sdelphij return (error); 1090271493Sdelphij} 1091271493Sdelphij 1092271493Sdelphij 1093271493Sdelphijstatic int 1094271493Sdelphijkvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1095271493Sdelphij{ 1096271493Sdelphij struct hv_kvp_ipaddr_value *ip_val; 1097271493Sdelphij char *if_name; 1098308635Ssephe int error = 0; 1099271493Sdelphij 1100271493Sdelphij assert(op_msg != NULL); 1101271493Sdelphij KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n"); 1102271493Sdelphij 1103271493Sdelphij ip_val = &op_msg->body.kvp_ip_val; 1104308635Ssephe op_msg->hdr.error = HV_S_OK; 1105271493Sdelphij 1106271493Sdelphij if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id); 1107271493Sdelphij 1108271493Sdelphij if (if_name == NULL) { 1109271493Sdelphij /* No interface found with the mac address. */ 1110308635Ssephe op_msg->hdr.error = HV_E_FAIL; 1111271493Sdelphij goto kvp_op_getipinfo_done; 1112271493Sdelphij } 1113271493Sdelphij 1114308635Ssephe error = kvp_get_ip_info(0, if_name, 1115271493Sdelphij HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2)); 1116308635Ssephe if (error) 1117308635Ssephe op_msg->hdr.error = HV_E_FAIL; 1118271493Sdelphij free(if_name); 1119271493Sdelphij 1120271493Sdelphijkvp_op_getipinfo_done: 1121308635Ssephe return (error); 1122271493Sdelphij} 1123271493Sdelphij 1124271493Sdelphij 1125271493Sdelphijstatic int 1126271493Sdelphijkvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused) 1127271493Sdelphij{ 1128271493Sdelphij struct hv_kvp_ipaddr_value *ip_val; 1129271493Sdelphij char *if_name; 1130308635Ssephe int error = 0; 1131271493Sdelphij 1132271493Sdelphij assert(op_msg != NULL); 1133271493Sdelphij KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n"); 1134271493Sdelphij 1135271493Sdelphij ip_val = &op_msg->body.kvp_ip_val; 1136308635Ssephe op_msg->hdr.error = HV_S_OK; 1137271493Sdelphij 1138271493Sdelphij if_name = (char *)ip_val->adapter_id; 1139271493Sdelphij 1140271493Sdelphij if (if_name == NULL) { 1141271493Sdelphij /* No adapter provided. */ 1142308635Ssephe op_msg->hdr.error = HV_GUID_NOTFOUND; 1143271493Sdelphij goto kvp_op_setipinfo_done; 1144271493Sdelphij } 1145271493Sdelphij 1146308635Ssephe error = kvp_set_ip_info(if_name, ip_val); 1147308635Ssephe if (error) 1148308635Ssephe op_msg->hdr.error = HV_E_FAIL; 1149271493Sdelphijkvp_op_setipinfo_done: 1150308635Ssephe return (error); 1151271493Sdelphij} 1152271493Sdelphij 1153271493Sdelphij 1154271493Sdelphijstatic int 1155271493Sdelphijkvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data) 1156271493Sdelphij{ 1157271493Sdelphij struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data; 1158271493Sdelphij int error = 0; 1159271493Sdelphij int op_pool; 1160271493Sdelphij 1161271493Sdelphij assert(op_msg != NULL); 1162271493Sdelphij assert(op_hdlr != NULL); 1163271493Sdelphij 1164271493Sdelphij op_pool = op_msg->hdr.kvp_hdr.pool; 1165308635Ssephe op_msg->hdr.error = HV_S_OK; 1166271493Sdelphij 1167271493Sdelphij switch(op_hdlr->kvp_op_key) { 1168271493Sdelphij case HV_KVP_OP_SET: 1169271493Sdelphij if (op_pool == HV_KVP_POOL_AUTO) { 1170271493Sdelphij /* Auto Pool is not writeable from host side. */ 1171271493Sdelphij error = 1; 1172271493Sdelphij KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n", 1173271493Sdelphij op_pool); 1174271493Sdelphij } else { 1175271493Sdelphij error = kvp_key_add_or_modify(op_pool, 1176271493Sdelphij op_msg->body.kvp_set.data.key, 1177271493Sdelphij op_msg->body.kvp_set.data.key_size, 1178271493Sdelphij op_msg->body.kvp_set.data.msg_value.value, 1179271493Sdelphij op_msg->body.kvp_set.data.value_size); 1180271493Sdelphij } 1181271493Sdelphij break; 1182271493Sdelphij 1183271493Sdelphij case HV_KVP_OP_GET: 1184271493Sdelphij error = kvp_get_value(op_pool, 1185271493Sdelphij op_msg->body.kvp_get.data.key, 1186271493Sdelphij op_msg->body.kvp_get.data.key_size, 1187271493Sdelphij op_msg->body.kvp_get.data.msg_value.value, 1188271493Sdelphij op_msg->body.kvp_get.data.value_size); 1189271493Sdelphij break; 1190271493Sdelphij 1191271493Sdelphij case HV_KVP_OP_DELETE: 1192271493Sdelphij if (op_pool == HV_KVP_POOL_AUTO) { 1193271493Sdelphij /* Auto Pool is not writeable from host side. */ 1194271493Sdelphij error = 1; 1195271493Sdelphij KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n", 1196271493Sdelphij op_pool); 1197271493Sdelphij } else { 1198271493Sdelphij error = kvp_key_delete(op_pool, 1199271493Sdelphij op_msg->body.kvp_delete.key, 1200271493Sdelphij op_msg->body.kvp_delete.key_size); 1201271493Sdelphij } 1202271493Sdelphij break; 1203271493Sdelphij 1204271493Sdelphij default: 1205271493Sdelphij break; 1206271493Sdelphij } 1207271493Sdelphij 1208271493Sdelphij if (error != 0) 1209308635Ssephe op_msg->hdr.error = HV_S_CONT; 1210271493Sdelphij return(error); 1211271493Sdelphij} 1212271493Sdelphij 1213271493Sdelphij 1214271493Sdelphijstatic int 1215271493Sdelphijkvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused) 1216271493Sdelphij{ 1217271493Sdelphij char *key_name, *key_value; 1218271493Sdelphij int error = 0; 1219271493Sdelphij int op_pool; 1220271493Sdelphij int op; 1221271493Sdelphij 1222271493Sdelphij assert(op_msg != NULL); 1223271493Sdelphij 1224271493Sdelphij op = op_msg->hdr.kvp_hdr.operation; 1225271493Sdelphij op_pool = op_msg->hdr.kvp_hdr.pool; 1226308635Ssephe op_msg->hdr.error = HV_S_OK; 1227271493Sdelphij 1228271493Sdelphij /* 1229271493Sdelphij * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate 1230271493Sdelphij * pool and return the KVP according to the index requested. 1231271493Sdelphij */ 1232271493Sdelphij if (op_pool != HV_KVP_POOL_AUTO) { 1233271493Sdelphij if (kvp_pool_enumerate(op_pool, 1234271493Sdelphij op_msg->body.kvp_enum_data.index, 1235271493Sdelphij op_msg->body.kvp_enum_data.data.key, 1236271493Sdelphij HV_KVP_EXCHANGE_MAX_KEY_SIZE, 1237271493Sdelphij op_msg->body.kvp_enum_data.data.msg_value.value, 1238271493Sdelphij HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 1239308635Ssephe op_msg->hdr.error = HV_S_CONT; 1240271493Sdelphij error = -1; 1241271493Sdelphij } 1242271493Sdelphij goto kvp_op_enumerate_done; 1243271493Sdelphij } 1244271493Sdelphij 1245271493Sdelphij key_name = (char *)op_msg->body.kvp_enum_data.data.key; 1246271493Sdelphij key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value; 1247271493Sdelphij 1248271493Sdelphij switch (op_msg->body.kvp_enum_data.index) 1249271493Sdelphij { 1250271493Sdelphij case FullyQualifiedDomainName: 1251271493Sdelphij kvp_get_domain_name(key_value, 1252271493Sdelphij HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1253271493Sdelphij strcpy(key_name, "FullyQualifiedDomainName"); 1254271493Sdelphij break; 1255271493Sdelphij 1256271493Sdelphij case IntegrationServicesVersion: 1257271493Sdelphij strcpy(key_name, "IntegrationServicesVersion"); 1258272142Sdelphij strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1259271493Sdelphij break; 1260271493Sdelphij 1261271493Sdelphij case NetworkAddressIPv4: 1262271493Sdelphij kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE, 1263271493Sdelphij key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1264271493Sdelphij strcpy(key_name, "NetworkAddressIPv4"); 1265271493Sdelphij break; 1266271493Sdelphij 1267271493Sdelphij case NetworkAddressIPv6: 1268271493Sdelphij kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE, 1269271493Sdelphij key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1270271493Sdelphij strcpy(key_name, "NetworkAddressIPv6"); 1271271493Sdelphij break; 1272271493Sdelphij 1273271493Sdelphij case OSBuildNumber: 1274272142Sdelphij strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1275271493Sdelphij strcpy(key_name, "OSBuildNumber"); 1276271493Sdelphij break; 1277271493Sdelphij 1278271493Sdelphij case OSName: 1279272142Sdelphij strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1280271493Sdelphij strcpy(key_name, "OSName"); 1281271493Sdelphij break; 1282271493Sdelphij 1283271493Sdelphij case OSMajorVersion: 1284272142Sdelphij strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1285271493Sdelphij strcpy(key_name, "OSMajorVersion"); 1286271493Sdelphij break; 1287271493Sdelphij 1288271493Sdelphij case OSMinorVersion: 1289272142Sdelphij strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1290271493Sdelphij strcpy(key_name, "OSMinorVersion"); 1291271493Sdelphij break; 1292271493Sdelphij 1293271493Sdelphij case OSVersion: 1294272142Sdelphij strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1295271493Sdelphij strcpy(key_name, "OSVersion"); 1296271493Sdelphij break; 1297271493Sdelphij 1298271493Sdelphij case ProcessorArchitecture: 1299272142Sdelphij strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1300271493Sdelphij strcpy(key_name, "ProcessorArchitecture"); 1301271493Sdelphij break; 1302271493Sdelphij 1303271493Sdelphij default: 1304271493Sdelphij#ifdef DEBUG 1305271493Sdelphij KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n", 1306271493Sdelphij op_msg->body.kvp_enum_data.index); 1307271493Sdelphij#endif 1308308635Ssephe op_msg->hdr.error = HV_S_CONT; 1309271493Sdelphij error = -1; 1310271493Sdelphij break; 1311271493Sdelphij } 1312271493Sdelphij 1313271493Sdelphijkvp_op_enumerate_done: 1314308635Ssephe if (error != 0) 1315308635Ssephe op_msg->hdr.error = HV_S_CONT; 1316271493Sdelphij return(error); 1317271493Sdelphij} 1318271493Sdelphij 1319271493Sdelphij 1320271493Sdelphij/* 1321271493Sdelphij * Load handler, and call init routine if provided. 1322271493Sdelphij */ 1323271493Sdelphijstatic int 1324271493Sdelphijkvp_op_load(int key, void (*init)(void), 1325271493Sdelphij int (*exec)(struct hv_kvp_msg *, void *)) 1326271493Sdelphij{ 1327271493Sdelphij int error = 0; 1328271493Sdelphij 1329271493Sdelphij if (key < 0 || key >= HV_KVP_OP_COUNT) { 1330271493Sdelphij KVP_LOG(LOG_ERR, "Operation key out of supported range\n"); 1331271493Sdelphij error = -1; 1332271493Sdelphij goto kvp_op_load_done; 1333271493Sdelphij } 1334271493Sdelphij 1335271493Sdelphij kvp_op_hdlrs[key].kvp_op_key = key; 1336271493Sdelphij kvp_op_hdlrs[key].kvp_op_init = init; 1337271493Sdelphij kvp_op_hdlrs[key].kvp_op_exec = exec; 1338271493Sdelphij 1339271493Sdelphij if (kvp_op_hdlrs[key].kvp_op_init != NULL) 1340271493Sdelphij kvp_op_hdlrs[key].kvp_op_init(); 1341271493Sdelphij 1342271493Sdelphijkvp_op_load_done: 1343271493Sdelphij return(error); 1344271493Sdelphij} 1345271493Sdelphij 1346271493Sdelphij 1347271493Sdelphij/* 1348271493Sdelphij * Initialize the operation hanlders. 1349271493Sdelphij */ 1350271493Sdelphijstatic int 1351271493Sdelphijkvp_ops_init(void) 1352271493Sdelphij{ 1353271493Sdelphij int i; 1354271493Sdelphij 1355271493Sdelphij /* Set the initial values. */ 1356271493Sdelphij for (i = 0; i < HV_KVP_OP_COUNT; i++) { 1357271493Sdelphij kvp_op_hdlrs[i].kvp_op_key = -1; 1358271493Sdelphij kvp_op_hdlrs[i].kvp_op_init = NULL; 1359271493Sdelphij kvp_op_hdlrs[i].kvp_op_exec = NULL; 1360271493Sdelphij } 1361271493Sdelphij 1362271493Sdelphij return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) | 1363271493Sdelphij kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) | 1364271493Sdelphij kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) | 1365271493Sdelphij kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info, 1366271493Sdelphij kvp_op_enumerate) | 1367271493Sdelphij kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) | 1368271493Sdelphij kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo)); 1369271493Sdelphij} 1370271493Sdelphij 1371271493Sdelphij 1372271493Sdelphijint 1373271493Sdelphijmain(int argc, char *argv[]) 1374271493Sdelphij{ 1375271493Sdelphij struct hv_kvp_msg *hv_kvp_dev_buf; 1376271493Sdelphij struct hv_kvp_msg *hv_msg; 1377271493Sdelphij struct pollfd hv_kvp_poll_fd[1]; 1378271493Sdelphij int op, pool; 1379271493Sdelphij int hv_kvp_dev_fd, error, len, r; 1380271493Sdelphij int ch; 1381271493Sdelphij 1382271493Sdelphij while ((ch = getopt(argc, argv, "dn")) != -1) { 1383271493Sdelphij switch (ch) { 1384271493Sdelphij case 'n': 1385271493Sdelphij /* Run as regular process for debugging purpose. */ 1386271493Sdelphij is_daemon = 0; 1387271493Sdelphij break; 1388271493Sdelphij case 'd': 1389271493Sdelphij /* Generate debugging output */ 1390271493Sdelphij is_debugging = 1; 1391271493Sdelphij break; 1392271493Sdelphij default: 1393271493Sdelphij break; 1394271493Sdelphij } 1395271493Sdelphij } 1396271493Sdelphij 1397271493Sdelphij openlog("HV_KVP", 0, LOG_USER); 1398271493Sdelphij 1399271493Sdelphij /* Become daemon first. */ 1400271493Sdelphij if (is_daemon == 1) 1401271493Sdelphij daemon(1, 0); 1402271493Sdelphij else 1403271493Sdelphij KVP_LOG(LOG_DEBUG, "Run as regular process.\n"); 1404271493Sdelphij 1405271493Sdelphij KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid()); 1406271493Sdelphij 1407271493Sdelphij /* Communication buffer hv_kvp_dev_buf */ 1408271493Sdelphij hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf)); 1409271493Sdelphij /* Buffer for daemon internal use */ 1410271493Sdelphij hv_msg = malloc(sizeof(*hv_msg)); 1411271493Sdelphij 1412271493Sdelphij /* Memory allocation failed */ 1413271493Sdelphij if (hv_kvp_dev_buf == NULL || hv_msg == NULL) { 1414271493Sdelphij KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n"); 1415271493Sdelphij exit(EXIT_FAILURE); 1416271493Sdelphij } 1417271493Sdelphij 1418271493Sdelphij /* Initialize op handlers */ 1419271493Sdelphij if (kvp_ops_init() != 0) { 1420271493Sdelphij KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n"); 1421271493Sdelphij exit(EXIT_FAILURE); 1422271493Sdelphij } 1423271493Sdelphij 1424271493Sdelphij if (kvp_file_init()) { 1425271493Sdelphij KVP_LOG(LOG_ERR, "Failed to initialize the pools\n"); 1426271493Sdelphij exit(EXIT_FAILURE); 1427271493Sdelphij } 1428271493Sdelphij 1429271493Sdelphij /* Open the Character Device */ 1430271493Sdelphij hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR); 1431271493Sdelphij 1432271493Sdelphij if (hv_kvp_dev_fd < 0) { 1433271493Sdelphij KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n", 1434271493Sdelphij errno, strerror(errno)); 1435271493Sdelphij exit(EXIT_FAILURE); 1436271493Sdelphij } 1437271493Sdelphij 1438271493Sdelphij /* Initialize the struct for polling the char device */ 1439271493Sdelphij hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd; 1440271493Sdelphij hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM); 1441271493Sdelphij 1442271493Sdelphij /* Register the daemon to the KVP driver */ 1443271493Sdelphij memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf)); 1444271493Sdelphij hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER; 1445271493Sdelphij len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf)); 1446271493Sdelphij 1447271493Sdelphij 1448271493Sdelphij for (;;) { 1449293653Ssephe r = poll (hv_kvp_poll_fd, 1, INFTIM); 1450271493Sdelphij 1451271493Sdelphij KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n", 1452271493Sdelphij r, hv_kvp_poll_fd[0].revents); 1453271493Sdelphij 1454271493Sdelphij if (r == 0 || (r < 0 && errno == EAGAIN) || 1455271493Sdelphij (r < 0 && errno == EINTR)) { 1456271493Sdelphij /* Nothing to read */ 1457271493Sdelphij continue; 1458271493Sdelphij } 1459271493Sdelphij 1460271493Sdelphij if (r < 0) { 1461271493Sdelphij /* 1462271493Sdelphij * For pread return failure other than EAGAIN, 1463271493Sdelphij * we want to exit. 1464271493Sdelphij */ 1465271493Sdelphij KVP_LOG(LOG_ERR, "Poll failed.\n"); 1466271493Sdelphij perror("poll"); 1467271493Sdelphij exit(EIO); 1468271493Sdelphij } 1469271493Sdelphij 1470271493Sdelphij /* Read from character device */ 1471271493Sdelphij len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf, 1472271493Sdelphij sizeof(*hv_kvp_dev_buf), 0); 1473271493Sdelphij 1474271493Sdelphij if (len < 0) { 1475271493Sdelphij KVP_LOG(LOG_ERR, "Read failed.\n"); 1476271493Sdelphij perror("pread"); 1477271493Sdelphij exit(EIO); 1478271493Sdelphij } 1479271493Sdelphij 1480271493Sdelphij if (len != sizeof(struct hv_kvp_msg)) { 1481271493Sdelphij KVP_LOG(LOG_ERR, "read len is: %d\n", len); 1482271493Sdelphij continue; 1483271493Sdelphij } 1484271493Sdelphij 1485271493Sdelphij /* Copy hv_kvp_dev_buf to hv_msg */ 1486271493Sdelphij memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg)); 1487271493Sdelphij 1488271493Sdelphij /* 1489271493Sdelphij * We will use the KVP header information to pass back 1490271493Sdelphij * the error from this daemon. So, first save the op 1491271493Sdelphij * and pool info to local variables. 1492271493Sdelphij */ 1493271493Sdelphij 1494271493Sdelphij op = hv_msg->hdr.kvp_hdr.operation; 1495271493Sdelphij pool = hv_msg->hdr.kvp_hdr.pool; 1496271493Sdelphij 1497271493Sdelphij if (op < 0 || op >= HV_KVP_OP_COUNT || 1498271493Sdelphij kvp_op_hdlrs[op].kvp_op_exec == NULL) { 1499271493Sdelphij KVP_LOG(LOG_WARNING, 1500271493Sdelphij "Unsupported operation OP = %d\n", op); 1501271493Sdelphij hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED; 1502271493Sdelphij } else { 1503271493Sdelphij /* 1504271493Sdelphij * Call the operateion handler's execution routine. 1505271493Sdelphij */ 1506271493Sdelphij error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg, 1507271493Sdelphij (void *)&kvp_op_hdlrs[op]); 1508308635Ssephe if (error != 0) { 1509308635Ssephe assert(hv_msg->hdr.error != HV_S_OK); 1510308635Ssephe if (hv_msg->hdr.error != HV_S_CONT) 1511308635Ssephe KVP_LOG(LOG_WARNING, 1512308635Ssephe "Operation failed OP = %d, error = 0x%x\n", 1513308635Ssephe op, error); 1514308635Ssephe } 1515271493Sdelphij } 1516271493Sdelphij 1517271493Sdelphij /* 1518271493Sdelphij * Send the value back to the kernel. The response is 1519271493Sdelphij * already in the receive buffer. 1520271493Sdelphij */ 1521271493Sdelphijhv_kvp_done: 1522271493Sdelphij len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0); 1523271493Sdelphij 1524271493Sdelphij if (len != sizeof(struct hv_kvp_msg)) { 1525271493Sdelphij KVP_LOG(LOG_ERR, "write len is: %d\n", len); 1526271493Sdelphij goto hv_kvp_done; 1527271493Sdelphij } 1528271493Sdelphij } 1529271493Sdelphij} 1530