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