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