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