18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * An implementation of key value pair (KVP) functionality for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010, Novell, Inc. 68c2ecf20Sopenharmony_ci * Author : K. Y. Srinivasan <ksrinivasan@novell.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 98c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2 as published 108c2ecf20Sopenharmony_ci * by the Free Software Foundation. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 138c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 148c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 158c2ecf20Sopenharmony_ci * NON INFRINGEMENT. See the GNU General Public License for more 168c2ecf20Sopenharmony_ci * details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 198c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 208c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <sys/poll.h> 268c2ecf20Sopenharmony_ci#include <sys/utsname.h> 278c2ecf20Sopenharmony_ci#include <stdio.h> 288c2ecf20Sopenharmony_ci#include <stdlib.h> 298c2ecf20Sopenharmony_ci#include <unistd.h> 308c2ecf20Sopenharmony_ci#include <string.h> 318c2ecf20Sopenharmony_ci#include <ctype.h> 328c2ecf20Sopenharmony_ci#include <errno.h> 338c2ecf20Sopenharmony_ci#include <arpa/inet.h> 348c2ecf20Sopenharmony_ci#include <linux/hyperv.h> 358c2ecf20Sopenharmony_ci#include <ifaddrs.h> 368c2ecf20Sopenharmony_ci#include <netdb.h> 378c2ecf20Sopenharmony_ci#include <syslog.h> 388c2ecf20Sopenharmony_ci#include <sys/stat.h> 398c2ecf20Sopenharmony_ci#include <fcntl.h> 408c2ecf20Sopenharmony_ci#include <dirent.h> 418c2ecf20Sopenharmony_ci#include <net/if.h> 428c2ecf20Sopenharmony_ci#include <limits.h> 438c2ecf20Sopenharmony_ci#include <getopt.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * KVP protocol: The user mode component first registers with the 478c2ecf20Sopenharmony_ci * the kernel component. Subsequently, the kernel component requests, data 488c2ecf20Sopenharmony_ci * for the specified keys. In response to this message the user mode component 498c2ecf20Sopenharmony_ci * fills in the value corresponding to the specified key. We overload the 508c2ecf20Sopenharmony_ci * sequence field in the cn_msg header to define our KVP message types. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * We use this infrastructure for also supporting queries from user mode 538c2ecf20Sopenharmony_ci * application for state that may be maintained in the KVP kernel component. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cienum key_index { 598c2ecf20Sopenharmony_ci FullyQualifiedDomainName = 0, 608c2ecf20Sopenharmony_ci IntegrationServicesVersion, /*This key is serviced in the kernel*/ 618c2ecf20Sopenharmony_ci NetworkAddressIPv4, 628c2ecf20Sopenharmony_ci NetworkAddressIPv6, 638c2ecf20Sopenharmony_ci OSBuildNumber, 648c2ecf20Sopenharmony_ci OSName, 658c2ecf20Sopenharmony_ci OSMajorVersion, 668c2ecf20Sopenharmony_ci OSMinorVersion, 678c2ecf20Sopenharmony_ci OSVersion, 688c2ecf20Sopenharmony_ci ProcessorArchitecture 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cienum { 738c2ecf20Sopenharmony_ci IPADDR = 0, 748c2ecf20Sopenharmony_ci NETMASK, 758c2ecf20Sopenharmony_ci GATEWAY, 768c2ecf20Sopenharmony_ci DNS 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int in_hand_shake; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic char *os_name = ""; 828c2ecf20Sopenharmony_cistatic char *os_major = ""; 838c2ecf20Sopenharmony_cistatic char *os_minor = ""; 848c2ecf20Sopenharmony_cistatic char *processor_arch; 858c2ecf20Sopenharmony_cistatic char *os_build; 868c2ecf20Sopenharmony_cistatic char *os_version; 878c2ecf20Sopenharmony_cistatic char *lic_version = "Unknown version"; 888c2ecf20Sopenharmony_cistatic char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 898c2ecf20Sopenharmony_cistatic struct utsname uts_buf; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * The location of the interface configuration file. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define KVP_CONFIG_LOC "/var/lib/hyperv" 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#ifndef KVP_SCRIPTS_PATH 988c2ecf20Sopenharmony_ci#define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/" 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define KVP_NET_DIR "/sys/class/net/" 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define MAX_FILE_NAME 100 1048c2ecf20Sopenharmony_ci#define ENTRIES_PER_BLOCK 50 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct kvp_record { 1078c2ecf20Sopenharmony_ci char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; 1088c2ecf20Sopenharmony_ci char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct kvp_file_state { 1128c2ecf20Sopenharmony_ci int fd; 1138c2ecf20Sopenharmony_ci int num_blocks; 1148c2ecf20Sopenharmony_ci struct kvp_record *records; 1158c2ecf20Sopenharmony_ci int num_records; 1168c2ecf20Sopenharmony_ci char fname[MAX_FILE_NAME]; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void kvp_acquire_lock(int pool) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0}; 1248c2ecf20Sopenharmony_ci fl.l_pid = getpid(); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { 1278c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool, 1288c2ecf20Sopenharmony_ci errno, strerror(errno)); 1298c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void kvp_release_lock(int pool) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0}; 1368c2ecf20Sopenharmony_ci fl.l_pid = getpid(); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { 1398c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool, 1408c2ecf20Sopenharmony_ci errno, strerror(errno)); 1418c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void kvp_update_file(int pool) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci FILE *filep; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * We are going to write our in-memory registry out to 1518c2ecf20Sopenharmony_ci * disk; acquire the lock first. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci kvp_acquire_lock(pool); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci filep = fopen(kvp_file_info[pool].fname, "we"); 1568c2ecf20Sopenharmony_ci if (!filep) { 1578c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, 1588c2ecf20Sopenharmony_ci errno, strerror(errno)); 1598c2ecf20Sopenharmony_ci kvp_release_lock(pool); 1608c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record), 1648c2ecf20Sopenharmony_ci kvp_file_info[pool].num_records, filep); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (ferror(filep) || fclose(filep)) { 1678c2ecf20Sopenharmony_ci kvp_release_lock(pool); 1688c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to write file, pool: %d", pool); 1698c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci kvp_release_lock(pool); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void kvp_update_mem_state(int pool) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci FILE *filep; 1788c2ecf20Sopenharmony_ci size_t records_read = 0; 1798c2ecf20Sopenharmony_ci struct kvp_record *record = kvp_file_info[pool].records; 1808c2ecf20Sopenharmony_ci struct kvp_record *readp; 1818c2ecf20Sopenharmony_ci int num_blocks = kvp_file_info[pool].num_blocks; 1828c2ecf20Sopenharmony_ci int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci kvp_acquire_lock(pool); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci filep = fopen(kvp_file_info[pool].fname, "re"); 1878c2ecf20Sopenharmony_ci if (!filep) { 1888c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, 1898c2ecf20Sopenharmony_ci errno, strerror(errno)); 1908c2ecf20Sopenharmony_ci kvp_release_lock(pool); 1918c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci for (;;) { 1948c2ecf20Sopenharmony_ci readp = &record[records_read]; 1958c2ecf20Sopenharmony_ci records_read += fread(readp, sizeof(struct kvp_record), 1968c2ecf20Sopenharmony_ci ENTRIES_PER_BLOCK * num_blocks - records_read, 1978c2ecf20Sopenharmony_ci filep); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (ferror(filep)) { 2008c2ecf20Sopenharmony_ci syslog(LOG_ERR, 2018c2ecf20Sopenharmony_ci "Failed to read file, pool: %d; error: %d %s", 2028c2ecf20Sopenharmony_ci pool, errno, strerror(errno)); 2038c2ecf20Sopenharmony_ci kvp_release_lock(pool); 2048c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (!feof(filep)) { 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * We have more data to read. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci num_blocks++; 2128c2ecf20Sopenharmony_ci record = realloc(record, alloc_unit * num_blocks); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (record == NULL) { 2158c2ecf20Sopenharmony_ci syslog(LOG_ERR, "malloc failed"); 2168c2ecf20Sopenharmony_ci kvp_release_lock(pool); 2178c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci continue; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci kvp_file_info[pool].num_blocks = num_blocks; 2258c2ecf20Sopenharmony_ci kvp_file_info[pool].records = record; 2268c2ecf20Sopenharmony_ci kvp_file_info[pool].num_records = records_read; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci fclose(filep); 2298c2ecf20Sopenharmony_ci kvp_release_lock(pool); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int kvp_file_init(void) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci int fd; 2358c2ecf20Sopenharmony_ci char *fname; 2368c2ecf20Sopenharmony_ci int i; 2378c2ecf20Sopenharmony_ci int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (access(KVP_CONFIG_LOC, F_OK)) { 2408c2ecf20Sopenharmony_ci if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { 2418c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC, 2428c2ecf20Sopenharmony_ci errno, strerror(errno)); 2438c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci for (i = 0; i < KVP_POOL_COUNT; i++) { 2488c2ecf20Sopenharmony_ci fname = kvp_file_info[i].fname; 2498c2ecf20Sopenharmony_ci sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); 2508c2ecf20Sopenharmony_ci fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (fd == -1) 2538c2ecf20Sopenharmony_ci return 1; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci kvp_file_info[i].fd = fd; 2568c2ecf20Sopenharmony_ci kvp_file_info[i].num_blocks = 1; 2578c2ecf20Sopenharmony_ci kvp_file_info[i].records = malloc(alloc_unit); 2588c2ecf20Sopenharmony_ci if (kvp_file_info[i].records == NULL) 2598c2ecf20Sopenharmony_ci return 1; 2608c2ecf20Sopenharmony_ci kvp_file_info[i].num_records = 0; 2618c2ecf20Sopenharmony_ci kvp_update_mem_state(i); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int kvp_key_delete(int pool, const __u8 *key, int key_size) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci int i; 2708c2ecf20Sopenharmony_ci int j, k; 2718c2ecf20Sopenharmony_ci int num_records; 2728c2ecf20Sopenharmony_ci struct kvp_record *record; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * First update the in-memory state. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci kvp_update_mem_state(pool); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci num_records = kvp_file_info[pool].num_records; 2808c2ecf20Sopenharmony_ci record = kvp_file_info[pool].records; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < num_records; i++) { 2838c2ecf20Sopenharmony_ci if (memcmp(key, record[i].key, key_size)) 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * Found a match; just move the remaining 2878c2ecf20Sopenharmony_ci * entries up. 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci if (i == (num_records - 1)) { 2908c2ecf20Sopenharmony_ci kvp_file_info[pool].num_records--; 2918c2ecf20Sopenharmony_ci kvp_update_file(pool); 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci j = i; 2968c2ecf20Sopenharmony_ci k = j + 1; 2978c2ecf20Sopenharmony_ci for (; k < num_records; k++) { 2988c2ecf20Sopenharmony_ci strcpy(record[j].key, record[k].key); 2998c2ecf20Sopenharmony_ci strcpy(record[j].value, record[k].value); 3008c2ecf20Sopenharmony_ci j++; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci kvp_file_info[pool].num_records--; 3048c2ecf20Sopenharmony_ci kvp_update_file(pool); 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci return 1; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size, 3118c2ecf20Sopenharmony_ci const __u8 *value, int value_size) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int i; 3148c2ecf20Sopenharmony_ci int num_records; 3158c2ecf20Sopenharmony_ci struct kvp_record *record; 3168c2ecf20Sopenharmony_ci int num_blocks; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 3198c2ecf20Sopenharmony_ci (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) 3208c2ecf20Sopenharmony_ci return 1; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * First update the in-memory state. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci kvp_update_mem_state(pool); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci num_records = kvp_file_info[pool].num_records; 3288c2ecf20Sopenharmony_ci record = kvp_file_info[pool].records; 3298c2ecf20Sopenharmony_ci num_blocks = kvp_file_info[pool].num_blocks; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci for (i = 0; i < num_records; i++) { 3328c2ecf20Sopenharmony_ci if (memcmp(key, record[i].key, key_size)) 3338c2ecf20Sopenharmony_ci continue; 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * Found a match; just update the value - 3368c2ecf20Sopenharmony_ci * this is the modify case. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci memcpy(record[i].value, value, value_size); 3398c2ecf20Sopenharmony_ci kvp_update_file(pool); 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Need to add a new entry; 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { 3478c2ecf20Sopenharmony_ci /* Need to allocate a larger array for reg entries. */ 3488c2ecf20Sopenharmony_ci record = realloc(record, sizeof(struct kvp_record) * 3498c2ecf20Sopenharmony_ci ENTRIES_PER_BLOCK * (num_blocks + 1)); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (record == NULL) 3528c2ecf20Sopenharmony_ci return 1; 3538c2ecf20Sopenharmony_ci kvp_file_info[pool].num_blocks++; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci memcpy(record[i].value, value, value_size); 3578c2ecf20Sopenharmony_ci memcpy(record[i].key, key, key_size); 3588c2ecf20Sopenharmony_ci kvp_file_info[pool].records = record; 3598c2ecf20Sopenharmony_ci kvp_file_info[pool].num_records++; 3608c2ecf20Sopenharmony_ci kvp_update_file(pool); 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value, 3658c2ecf20Sopenharmony_ci int value_size) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int i; 3688c2ecf20Sopenharmony_ci int num_records; 3698c2ecf20Sopenharmony_ci struct kvp_record *record; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 3728c2ecf20Sopenharmony_ci (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) 3738c2ecf20Sopenharmony_ci return 1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * First update the in-memory state. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci kvp_update_mem_state(pool); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci num_records = kvp_file_info[pool].num_records; 3818c2ecf20Sopenharmony_ci record = kvp_file_info[pool].records; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci for (i = 0; i < num_records; i++) { 3848c2ecf20Sopenharmony_ci if (memcmp(key, record[i].key, key_size)) 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Found a match; just copy the value out. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci memcpy(value, record[i].value, value_size); 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 1; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 3978c2ecf20Sopenharmony_ci __u8 *value, int value_size) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct kvp_record *record; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* 4028c2ecf20Sopenharmony_ci * First update our in-memory database. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci kvp_update_mem_state(pool); 4058c2ecf20Sopenharmony_ci record = kvp_file_info[pool].records; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (index >= kvp_file_info[pool].num_records) { 4088c2ecf20Sopenharmony_ci return 1; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci memcpy(key, record[index].key, key_size); 4128c2ecf20Sopenharmony_ci memcpy(value, record[index].value, value_size); 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_civoid kvp_get_os_info(void) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci FILE *file; 4208c2ecf20Sopenharmony_ci char *p, buf[512]; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci uname(&uts_buf); 4238c2ecf20Sopenharmony_ci os_version = uts_buf.release; 4248c2ecf20Sopenharmony_ci os_build = strdup(uts_buf.release); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci os_name = uts_buf.sysname; 4278c2ecf20Sopenharmony_ci processor_arch = uts_buf.machine; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* 4308c2ecf20Sopenharmony_ci * The current windows host (win7) expects the build 4318c2ecf20Sopenharmony_ci * string to be of the form: x.y.z 4328c2ecf20Sopenharmony_ci * Strip additional information we may have. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_ci p = strchr(os_version, '-'); 4358c2ecf20Sopenharmony_ci if (p) 4368c2ecf20Sopenharmony_ci *p = '\0'; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* 4398c2ecf20Sopenharmony_ci * Parse the /etc/os-release file if present: 4408c2ecf20Sopenharmony_ci * https://www.freedesktop.org/software/systemd/man/os-release.html 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci file = fopen("/etc/os-release", "r"); 4438c2ecf20Sopenharmony_ci if (file != NULL) { 4448c2ecf20Sopenharmony_ci while (fgets(buf, sizeof(buf), file)) { 4458c2ecf20Sopenharmony_ci char *value, *q; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Ignore comments */ 4488c2ecf20Sopenharmony_ci if (buf[0] == '#') 4498c2ecf20Sopenharmony_ci continue; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Split into name=value */ 4528c2ecf20Sopenharmony_ci p = strchr(buf, '='); 4538c2ecf20Sopenharmony_ci if (!p) 4548c2ecf20Sopenharmony_ci continue; 4558c2ecf20Sopenharmony_ci *p++ = 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Remove quotes and newline; un-escape */ 4588c2ecf20Sopenharmony_ci value = p; 4598c2ecf20Sopenharmony_ci q = p; 4608c2ecf20Sopenharmony_ci while (*p) { 4618c2ecf20Sopenharmony_ci if (*p == '\\') { 4628c2ecf20Sopenharmony_ci ++p; 4638c2ecf20Sopenharmony_ci if (!*p) 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci *q++ = *p++; 4668c2ecf20Sopenharmony_ci } else if (*p == '\'' || *p == '"' || 4678c2ecf20Sopenharmony_ci *p == '\n') { 4688c2ecf20Sopenharmony_ci ++p; 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci *q++ = *p++; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci *q = 0; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (!strcmp(buf, "NAME")) { 4768c2ecf20Sopenharmony_ci p = strdup(value); 4778c2ecf20Sopenharmony_ci if (!p) 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci os_name = p; 4808c2ecf20Sopenharmony_ci } else if (!strcmp(buf, "VERSION_ID")) { 4818c2ecf20Sopenharmony_ci p = strdup(value); 4828c2ecf20Sopenharmony_ci if (!p) 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci os_major = p; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci fclose(file); 4888c2ecf20Sopenharmony_ci return; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Fallback for older RH/SUSE releases */ 4928c2ecf20Sopenharmony_ci file = fopen("/etc/SuSE-release", "r"); 4938c2ecf20Sopenharmony_ci if (file != NULL) 4948c2ecf20Sopenharmony_ci goto kvp_osinfo_found; 4958c2ecf20Sopenharmony_ci file = fopen("/etc/redhat-release", "r"); 4968c2ecf20Sopenharmony_ci if (file != NULL) 4978c2ecf20Sopenharmony_ci goto kvp_osinfo_found; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * We don't have information about the os. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci return; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cikvp_osinfo_found: 5058c2ecf20Sopenharmony_ci /* up to three lines */ 5068c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 5078c2ecf20Sopenharmony_ci if (p) { 5088c2ecf20Sopenharmony_ci p = strchr(buf, '\n'); 5098c2ecf20Sopenharmony_ci if (p) 5108c2ecf20Sopenharmony_ci *p = '\0'; 5118c2ecf20Sopenharmony_ci p = strdup(buf); 5128c2ecf20Sopenharmony_ci if (!p) 5138c2ecf20Sopenharmony_ci goto done; 5148c2ecf20Sopenharmony_ci os_name = p; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* second line */ 5178c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 5188c2ecf20Sopenharmony_ci if (p) { 5198c2ecf20Sopenharmony_ci p = strchr(buf, '\n'); 5208c2ecf20Sopenharmony_ci if (p) 5218c2ecf20Sopenharmony_ci *p = '\0'; 5228c2ecf20Sopenharmony_ci p = strdup(buf); 5238c2ecf20Sopenharmony_ci if (!p) 5248c2ecf20Sopenharmony_ci goto done; 5258c2ecf20Sopenharmony_ci os_major = p; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* third line */ 5288c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 5298c2ecf20Sopenharmony_ci if (p) { 5308c2ecf20Sopenharmony_ci p = strchr(buf, '\n'); 5318c2ecf20Sopenharmony_ci if (p) 5328c2ecf20Sopenharmony_ci *p = '\0'; 5338c2ecf20Sopenharmony_ci p = strdup(buf); 5348c2ecf20Sopenharmony_ci if (p) 5358c2ecf20Sopenharmony_ci os_minor = p; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cidone: 5418c2ecf20Sopenharmony_ci fclose(file); 5428c2ecf20Sopenharmony_ci return; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci/* 5488c2ecf20Sopenharmony_ci * Retrieve an interface name corresponding to the specified guid. 5498c2ecf20Sopenharmony_ci * If there is a match, the function returns a pointer 5508c2ecf20Sopenharmony_ci * to the interface name and if not, a NULL is returned. 5518c2ecf20Sopenharmony_ci * If a match is found, the caller is responsible for 5528c2ecf20Sopenharmony_ci * freeing the memory. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic char *kvp_get_if_name(char *guid) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci DIR *dir; 5588c2ecf20Sopenharmony_ci struct dirent *entry; 5598c2ecf20Sopenharmony_ci FILE *file; 5608c2ecf20Sopenharmony_ci char *p, *x; 5618c2ecf20Sopenharmony_ci char *if_name = NULL; 5628c2ecf20Sopenharmony_ci char buf[256]; 5638c2ecf20Sopenharmony_ci char dev_id[PATH_MAX]; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci dir = opendir(KVP_NET_DIR); 5668c2ecf20Sopenharmony_ci if (dir == NULL) 5678c2ecf20Sopenharmony_ci return NULL; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci while ((entry = readdir(dir)) != NULL) { 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * Set the state for the next pass. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id", 5748c2ecf20Sopenharmony_ci KVP_NET_DIR, entry->d_name); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci file = fopen(dev_id, "r"); 5778c2ecf20Sopenharmony_ci if (file == NULL) 5788c2ecf20Sopenharmony_ci continue; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 5818c2ecf20Sopenharmony_ci if (p) { 5828c2ecf20Sopenharmony_ci x = strchr(p, '\n'); 5838c2ecf20Sopenharmony_ci if (x) 5848c2ecf20Sopenharmony_ci *x = '\0'; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!strcmp(p, guid)) { 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Found the guid match; return the interface 5898c2ecf20Sopenharmony_ci * name. The caller will free the memory. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if_name = strdup(entry->d_name); 5928c2ecf20Sopenharmony_ci fclose(file); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci fclose(file); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci closedir(dir); 6008c2ecf20Sopenharmony_ci return if_name; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* 6048c2ecf20Sopenharmony_ci * Retrieve the MAC address given the interface name. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic char *kvp_if_name_to_mac(char *if_name) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci FILE *file; 6108c2ecf20Sopenharmony_ci char *p, *x; 6118c2ecf20Sopenharmony_ci char buf[256]; 6128c2ecf20Sopenharmony_ci char addr_file[PATH_MAX]; 6138c2ecf20Sopenharmony_ci unsigned int i; 6148c2ecf20Sopenharmony_ci char *mac_addr = NULL; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR, 6178c2ecf20Sopenharmony_ci if_name, "/address"); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci file = fopen(addr_file, "r"); 6208c2ecf20Sopenharmony_ci if (file == NULL) 6218c2ecf20Sopenharmony_ci return NULL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 6248c2ecf20Sopenharmony_ci if (p) { 6258c2ecf20Sopenharmony_ci x = strchr(p, '\n'); 6268c2ecf20Sopenharmony_ci if (x) 6278c2ecf20Sopenharmony_ci *x = '\0'; 6288c2ecf20Sopenharmony_ci for (i = 0; i < strlen(p); i++) 6298c2ecf20Sopenharmony_ci p[i] = toupper(p[i]); 6308c2ecf20Sopenharmony_ci mac_addr = strdup(p); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci fclose(file); 6348c2ecf20Sopenharmony_ci return mac_addr; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic void kvp_process_ipconfig_file(char *cmd, 6388c2ecf20Sopenharmony_ci char *config_buf, unsigned int len, 6398c2ecf20Sopenharmony_ci int element_size, int offset) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci char buf[256]; 6428c2ecf20Sopenharmony_ci char *p; 6438c2ecf20Sopenharmony_ci char *x; 6448c2ecf20Sopenharmony_ci FILE *file; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* 6478c2ecf20Sopenharmony_ci * First execute the command. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci file = popen(cmd, "r"); 6508c2ecf20Sopenharmony_ci if (file == NULL) 6518c2ecf20Sopenharmony_ci return; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (offset == 0) 6548c2ecf20Sopenharmony_ci memset(config_buf, 0, len); 6558c2ecf20Sopenharmony_ci while ((p = fgets(buf, sizeof(buf), file)) != NULL) { 6568c2ecf20Sopenharmony_ci if (len < strlen(config_buf) + element_size + 1) 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci x = strchr(p, '\n'); 6608c2ecf20Sopenharmony_ci if (x) 6618c2ecf20Sopenharmony_ci *x = '\0'; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci strcat(config_buf, p); 6648c2ecf20Sopenharmony_ci strcat(config_buf, ";"); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci pclose(file); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic void kvp_get_ipconfig_info(char *if_name, 6708c2ecf20Sopenharmony_ci struct hv_kvp_ipaddr_value *buffer) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci char cmd[512]; 6738c2ecf20Sopenharmony_ci char dhcp_info[128]; 6748c2ecf20Sopenharmony_ci char *p; 6758c2ecf20Sopenharmony_ci FILE *file; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* 6788c2ecf20Sopenharmony_ci * Get the address of default gateway (ipv4). 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci sprintf(cmd, "%s %s", "ip route show dev", if_name); 6818c2ecf20Sopenharmony_ci strcat(cmd, " | awk '/default/ {print $3 }'"); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* 6848c2ecf20Sopenharmony_ci * Execute the command to gather gateway info. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 6878c2ecf20Sopenharmony_ci (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * Get the address of default gateway (ipv6). 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name); 6938c2ecf20Sopenharmony_ci strcat(cmd, " | awk '/default/ {print $3 }'"); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * Execute the command to gather gateway info (ipv6). 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, 6998c2ecf20Sopenharmony_ci (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * Gather the DNS state. 7048c2ecf20Sopenharmony_ci * Since there is no standard way to get this information 7058c2ecf20Sopenharmony_ci * across various distributions of interest; we just invoke 7068c2ecf20Sopenharmony_ci * an external script that needs to be ported across distros 7078c2ecf20Sopenharmony_ci * of interest. 7088c2ecf20Sopenharmony_ci * 7098c2ecf20Sopenharmony_ci * Following is the expected format of the information from the script: 7108c2ecf20Sopenharmony_ci * 7118c2ecf20Sopenharmony_ci * ipaddr1 (nameserver1) 7128c2ecf20Sopenharmony_ci * ipaddr2 (nameserver2) 7138c2ecf20Sopenharmony_ci * . 7148c2ecf20Sopenharmony_ci * . 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info"); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* 7208c2ecf20Sopenharmony_ci * Execute the command to gather DNS info. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, 7238c2ecf20Sopenharmony_ci (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* 7268c2ecf20Sopenharmony_ci * Gather the DHCP state. 7278c2ecf20Sopenharmony_ci * We will gather this state by invoking an external script. 7288c2ecf20Sopenharmony_ci * The parameter to the script is the interface name. 7298c2ecf20Sopenharmony_ci * Here is the expected output: 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Enabled: DHCP enabled. 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci file = popen(cmd, "r"); 7378c2ecf20Sopenharmony_ci if (file == NULL) 7388c2ecf20Sopenharmony_ci return; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci p = fgets(dhcp_info, sizeof(dhcp_info), file); 7418c2ecf20Sopenharmony_ci if (p == NULL) { 7428c2ecf20Sopenharmony_ci pclose(file); 7438c2ecf20Sopenharmony_ci return; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!strncmp(p, "Enabled", 7)) 7478c2ecf20Sopenharmony_ci buffer->dhcp_enabled = 1; 7488c2ecf20Sopenharmony_ci else 7498c2ecf20Sopenharmony_ci buffer->dhcp_enabled = 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci pclose(file); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic unsigned int hweight32(unsigned int *w) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci unsigned int res = *w - ((*w >> 1) & 0x55555555); 7588c2ecf20Sopenharmony_ci res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 7598c2ecf20Sopenharmony_ci res = (res + (res >> 4)) & 0x0F0F0F0F; 7608c2ecf20Sopenharmony_ci res = res + (res >> 8); 7618c2ecf20Sopenharmony_ci return (res + (res >> 16)) & 0x000000FF; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int kvp_process_ip_address(void *addrp, 7658c2ecf20Sopenharmony_ci int family, char *buffer, 7668c2ecf20Sopenharmony_ci int length, int *offset) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct sockaddr_in *addr; 7698c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 7708c2ecf20Sopenharmony_ci int addr_length; 7718c2ecf20Sopenharmony_ci char tmp[50]; 7728c2ecf20Sopenharmony_ci const char *str; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (family == AF_INET) { 7758c2ecf20Sopenharmony_ci addr = (struct sockaddr_in *)addrp; 7768c2ecf20Sopenharmony_ci str = inet_ntop(family, &addr->sin_addr, tmp, 50); 7778c2ecf20Sopenharmony_ci addr_length = INET_ADDRSTRLEN; 7788c2ecf20Sopenharmony_ci } else { 7798c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)addrp; 7808c2ecf20Sopenharmony_ci str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); 7818c2ecf20Sopenharmony_ci addr_length = INET6_ADDRSTRLEN; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if ((length - *offset) < addr_length + 2) 7858c2ecf20Sopenharmony_ci return HV_E_FAIL; 7868c2ecf20Sopenharmony_ci if (str == NULL) { 7878c2ecf20Sopenharmony_ci strcpy(buffer, "inet_ntop failed\n"); 7888c2ecf20Sopenharmony_ci return HV_E_FAIL; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci if (*offset == 0) 7918c2ecf20Sopenharmony_ci strcpy(buffer, tmp); 7928c2ecf20Sopenharmony_ci else { 7938c2ecf20Sopenharmony_ci strcat(buffer, ";"); 7948c2ecf20Sopenharmony_ci strcat(buffer, tmp); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci *offset += strlen(str) + 1; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int 8038c2ecf20Sopenharmony_cikvp_get_ip_info(int family, char *if_name, int op, 8048c2ecf20Sopenharmony_ci void *out_buffer, unsigned int length) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct ifaddrs *ifap; 8078c2ecf20Sopenharmony_ci struct ifaddrs *curp; 8088c2ecf20Sopenharmony_ci int offset = 0; 8098c2ecf20Sopenharmony_ci int sn_offset = 0; 8108c2ecf20Sopenharmony_ci int error = 0; 8118c2ecf20Sopenharmony_ci char *buffer; 8128c2ecf20Sopenharmony_ci struct hv_kvp_ipaddr_value *ip_buffer = NULL; 8138c2ecf20Sopenharmony_ci char cidr_mask[5]; /* /xyz */ 8148c2ecf20Sopenharmony_ci int weight; 8158c2ecf20Sopenharmony_ci int i; 8168c2ecf20Sopenharmony_ci unsigned int *w; 8178c2ecf20Sopenharmony_ci char *sn_str; 8188c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (op == KVP_OP_ENUMERATE) { 8218c2ecf20Sopenharmony_ci buffer = out_buffer; 8228c2ecf20Sopenharmony_ci } else { 8238c2ecf20Sopenharmony_ci ip_buffer = out_buffer; 8248c2ecf20Sopenharmony_ci buffer = (char *)ip_buffer->ip_addr; 8258c2ecf20Sopenharmony_ci ip_buffer->addr_family = 0; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci /* 8288c2ecf20Sopenharmony_ci * On entry into this function, the buffer is capable of holding the 8298c2ecf20Sopenharmony_ci * maximum key value. 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (getifaddrs(&ifap)) { 8338c2ecf20Sopenharmony_ci strcpy(buffer, "getifaddrs failed\n"); 8348c2ecf20Sopenharmony_ci return HV_E_FAIL; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci curp = ifap; 8388c2ecf20Sopenharmony_ci while (curp != NULL) { 8398c2ecf20Sopenharmony_ci if (curp->ifa_addr == NULL) { 8408c2ecf20Sopenharmony_ci curp = curp->ifa_next; 8418c2ecf20Sopenharmony_ci continue; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if ((if_name != NULL) && 8458c2ecf20Sopenharmony_ci (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { 8468c2ecf20Sopenharmony_ci /* 8478c2ecf20Sopenharmony_ci * We want info about a specific interface; 8488c2ecf20Sopenharmony_ci * just continue. 8498c2ecf20Sopenharmony_ci */ 8508c2ecf20Sopenharmony_ci curp = curp->ifa_next; 8518c2ecf20Sopenharmony_ci continue; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * We only support two address families: AF_INET and AF_INET6. 8568c2ecf20Sopenharmony_ci * If a family value of 0 is specified, we collect both 8578c2ecf20Sopenharmony_ci * supported address families; if not we gather info on 8588c2ecf20Sopenharmony_ci * the specified address family. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci if ((((family != 0) && 8618c2ecf20Sopenharmony_ci (curp->ifa_addr->sa_family != family))) || 8628c2ecf20Sopenharmony_ci (curp->ifa_flags & IFF_LOOPBACK)) { 8638c2ecf20Sopenharmony_ci curp = curp->ifa_next; 8648c2ecf20Sopenharmony_ci continue; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci if ((curp->ifa_addr->sa_family != AF_INET) && 8678c2ecf20Sopenharmony_ci (curp->ifa_addr->sa_family != AF_INET6)) { 8688c2ecf20Sopenharmony_ci curp = curp->ifa_next; 8698c2ecf20Sopenharmony_ci continue; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (op == KVP_OP_GET_IP_INFO) { 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * Gather info other than the IP address. 8758c2ecf20Sopenharmony_ci * IP address info will be gathered later. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci if (curp->ifa_addr->sa_family == AF_INET) { 8788c2ecf20Sopenharmony_ci ip_buffer->addr_family |= ADDR_FAMILY_IPV4; 8798c2ecf20Sopenharmony_ci /* 8808c2ecf20Sopenharmony_ci * Get subnet info. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci error = kvp_process_ip_address( 8838c2ecf20Sopenharmony_ci curp->ifa_netmask, 8848c2ecf20Sopenharmony_ci AF_INET, 8858c2ecf20Sopenharmony_ci (char *) 8868c2ecf20Sopenharmony_ci ip_buffer->sub_net, 8878c2ecf20Sopenharmony_ci length, 8888c2ecf20Sopenharmony_ci &sn_offset); 8898c2ecf20Sopenharmony_ci if (error) 8908c2ecf20Sopenharmony_ci goto gather_ipaddr; 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci ip_buffer->addr_family |= ADDR_FAMILY_IPV6; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* 8958c2ecf20Sopenharmony_ci * Get subnet info in CIDR format. 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci weight = 0; 8988c2ecf20Sopenharmony_ci sn_str = (char *)ip_buffer->sub_net; 8998c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *) 9008c2ecf20Sopenharmony_ci curp->ifa_netmask; 9018c2ecf20Sopenharmony_ci w = addr6->sin6_addr.s6_addr32; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 9048c2ecf20Sopenharmony_ci weight += hweight32(&w[i]); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci sprintf(cidr_mask, "/%d", weight); 9078c2ecf20Sopenharmony_ci if (length < sn_offset + strlen(cidr_mask) + 1) 9088c2ecf20Sopenharmony_ci goto gather_ipaddr; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (sn_offset == 0) 9118c2ecf20Sopenharmony_ci strcpy(sn_str, cidr_mask); 9128c2ecf20Sopenharmony_ci else { 9138c2ecf20Sopenharmony_ci strcat((char *)ip_buffer->sub_net, ";"); 9148c2ecf20Sopenharmony_ci strcat(sn_str, cidr_mask); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci sn_offset += strlen(sn_str) + 1; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* 9208c2ecf20Sopenharmony_ci * Collect other ip related configuration info. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci kvp_get_ipconfig_info(if_name, ip_buffer); 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cigather_ipaddr: 9278c2ecf20Sopenharmony_ci error = kvp_process_ip_address(curp->ifa_addr, 9288c2ecf20Sopenharmony_ci curp->ifa_addr->sa_family, 9298c2ecf20Sopenharmony_ci buffer, 9308c2ecf20Sopenharmony_ci length, &offset); 9318c2ecf20Sopenharmony_ci if (error) 9328c2ecf20Sopenharmony_ci goto getaddr_done; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci curp = curp->ifa_next; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cigetaddr_done: 9388c2ecf20Sopenharmony_ci freeifaddrs(ifap); 9398c2ecf20Sopenharmony_ci return error; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/* 9438c2ecf20Sopenharmony_ci * Retrieve the IP given the MAC address. 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_cistatic int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci char *mac = (char *)kvp_ip_val->adapter_id; 9488c2ecf20Sopenharmony_ci DIR *dir; 9498c2ecf20Sopenharmony_ci struct dirent *entry; 9508c2ecf20Sopenharmony_ci FILE *file; 9518c2ecf20Sopenharmony_ci char *p, *x; 9528c2ecf20Sopenharmony_ci char *if_name = NULL; 9538c2ecf20Sopenharmony_ci char buf[256]; 9548c2ecf20Sopenharmony_ci char dev_id[PATH_MAX]; 9558c2ecf20Sopenharmony_ci unsigned int i; 9568c2ecf20Sopenharmony_ci int error = HV_E_FAIL; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci dir = opendir(KVP_NET_DIR); 9598c2ecf20Sopenharmony_ci if (dir == NULL) 9608c2ecf20Sopenharmony_ci return HV_E_FAIL; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci while ((entry = readdir(dir)) != NULL) { 9638c2ecf20Sopenharmony_ci /* 9648c2ecf20Sopenharmony_ci * Set the state for the next pass. 9658c2ecf20Sopenharmony_ci */ 9668c2ecf20Sopenharmony_ci snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR, 9678c2ecf20Sopenharmony_ci entry->d_name); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci file = fopen(dev_id, "r"); 9708c2ecf20Sopenharmony_ci if (file == NULL) 9718c2ecf20Sopenharmony_ci continue; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci p = fgets(buf, sizeof(buf), file); 9748c2ecf20Sopenharmony_ci fclose(file); 9758c2ecf20Sopenharmony_ci if (!p) 9768c2ecf20Sopenharmony_ci continue; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci x = strchr(p, '\n'); 9798c2ecf20Sopenharmony_ci if (x) 9808c2ecf20Sopenharmony_ci *x = '\0'; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci for (i = 0; i < strlen(p); i++) 9838c2ecf20Sopenharmony_ci p[i] = toupper(p[i]); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (strcmp(p, mac)) 9868c2ecf20Sopenharmony_ci continue; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * Found the MAC match. 9908c2ecf20Sopenharmony_ci * A NIC (e.g. VF) matching the MAC, but without IP, is skipped. 9918c2ecf20Sopenharmony_ci */ 9928c2ecf20Sopenharmony_ci if_name = entry->d_name; 9938c2ecf20Sopenharmony_ci if (!if_name) 9948c2ecf20Sopenharmony_ci continue; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO, 9978c2ecf20Sopenharmony_ci kvp_ip_val, MAX_IP_ADDR_SIZE * 2); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (!error && strlen((char *)kvp_ip_val->ip_addr)) 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci closedir(dir); 10048c2ecf20Sopenharmony_ci return error; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int expand_ipv6(char *addr, int type) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci int ret; 10108c2ecf20Sopenharmony_ci struct in6_addr v6_addr; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci ret = inet_pton(AF_INET6, addr, &v6_addr); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (ret != 1) { 10158c2ecf20Sopenharmony_ci if (type == NETMASK) 10168c2ecf20Sopenharmony_ci return 1; 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 10218c2ecf20Sopenharmony_ci "%02x%02x:%02x%02x:%02x%02x", 10228c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], 10238c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], 10248c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], 10258c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], 10268c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], 10278c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], 10288c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], 10298c2ecf20Sopenharmony_ci (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return 1; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int is_ipv4(char *addr) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci int ret; 10388c2ecf20Sopenharmony_ci struct in_addr ipv4_addr; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci ret = inet_pton(AF_INET, addr, &ipv4_addr); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (ret == 1) 10438c2ecf20Sopenharmony_ci return 1; 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int parse_ip_val_buffer(char *in_buf, int *offset, 10488c2ecf20Sopenharmony_ci char *out_buf, int out_len) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci char *x; 10518c2ecf20Sopenharmony_ci char *start; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * in_buf has sequence of characters that are separated by 10558c2ecf20Sopenharmony_ci * the character ';'. The last sequence does not have the 10568c2ecf20Sopenharmony_ci * terminating ";" character. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci start = in_buf + *offset; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci x = strchr(start, ';'); 10618c2ecf20Sopenharmony_ci if (x) 10628c2ecf20Sopenharmony_ci *x = 0; 10638c2ecf20Sopenharmony_ci else 10648c2ecf20Sopenharmony_ci x = start + strlen(start); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (strlen(start) != 0) { 10678c2ecf20Sopenharmony_ci int i = 0; 10688c2ecf20Sopenharmony_ci /* 10698c2ecf20Sopenharmony_ci * Get rid of leading spaces. 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci while (start[i] == ' ') 10728c2ecf20Sopenharmony_ci i++; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if ((x - start) <= out_len) { 10758c2ecf20Sopenharmony_ci strcpy(out_buf, (start + i)); 10768c2ecf20Sopenharmony_ci *offset += (x - start) + 1; 10778c2ecf20Sopenharmony_ci return 1; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci return 0; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int kvp_write_file(FILE *f, char *s1, char *s2, char *s3) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci int ret; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (ret < 0) 10908c2ecf20Sopenharmony_ci return HV_E_FAIL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return 0; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic int process_ip_string(FILE *f, char *ip_string, int type) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci int error = 0; 10998c2ecf20Sopenharmony_ci char addr[INET6_ADDRSTRLEN]; 11008c2ecf20Sopenharmony_ci int i = 0; 11018c2ecf20Sopenharmony_ci int j = 0; 11028c2ecf20Sopenharmony_ci char str[256]; 11038c2ecf20Sopenharmony_ci char sub_str[13]; 11048c2ecf20Sopenharmony_ci int offset = 0; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci memset(addr, 0, sizeof(addr)); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci while (parse_ip_val_buffer(ip_string, &offset, addr, 11098c2ecf20Sopenharmony_ci (MAX_IP_ADDR_SIZE * 2))) { 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci sub_str[0] = 0; 11128c2ecf20Sopenharmony_ci if (is_ipv4(addr)) { 11138c2ecf20Sopenharmony_ci switch (type) { 11148c2ecf20Sopenharmony_ci case IPADDR: 11158c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "IPADDR"); 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci case NETMASK: 11188c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "NETMASK"); 11198c2ecf20Sopenharmony_ci break; 11208c2ecf20Sopenharmony_ci case GATEWAY: 11218c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "GATEWAY"); 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci case DNS: 11248c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "DNS"); 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (type == DNS) { 11298c2ecf20Sopenharmony_ci snprintf(sub_str, sizeof(sub_str), "%d", ++i); 11308c2ecf20Sopenharmony_ci } else if (type == GATEWAY && i == 0) { 11318c2ecf20Sopenharmony_ci ++i; 11328c2ecf20Sopenharmony_ci } else { 11338c2ecf20Sopenharmony_ci snprintf(sub_str, sizeof(sub_str), "%d", i++); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci } else if (expand_ipv6(addr, type)) { 11388c2ecf20Sopenharmony_ci switch (type) { 11398c2ecf20Sopenharmony_ci case IPADDR: 11408c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "IPV6ADDR"); 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci case NETMASK: 11438c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci case GATEWAY: 11468c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", 11478c2ecf20Sopenharmony_ci "IPV6_DEFAULTGW"); 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci case DNS: 11508c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "%s", "DNS"); 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (type == DNS) { 11558c2ecf20Sopenharmony_ci snprintf(sub_str, sizeof(sub_str), "%d", ++i); 11568c2ecf20Sopenharmony_ci } else if (j == 0) { 11578c2ecf20Sopenharmony_ci ++j; 11588c2ecf20Sopenharmony_ci } else { 11598c2ecf20Sopenharmony_ci snprintf(sub_str, sizeof(sub_str), "_%d", j++); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci return HV_INVALIDARG; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci error = kvp_write_file(f, str, sub_str, addr); 11668c2ecf20Sopenharmony_ci if (error) 11678c2ecf20Sopenharmony_ci return error; 11688c2ecf20Sopenharmony_ci memset(addr, 0, sizeof(addr)); 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return 0; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci int error = 0; 11778c2ecf20Sopenharmony_ci char if_file[PATH_MAX]; 11788c2ecf20Sopenharmony_ci FILE *file; 11798c2ecf20Sopenharmony_ci char cmd[PATH_MAX]; 11808c2ecf20Sopenharmony_ci char *mac_addr; 11818c2ecf20Sopenharmony_ci int str_len; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci /* 11848c2ecf20Sopenharmony_ci * Set the configuration for the specified interface with 11858c2ecf20Sopenharmony_ci * the information provided. Since there is no standard 11868c2ecf20Sopenharmony_ci * way to configure an interface, we will have an external 11878c2ecf20Sopenharmony_ci * script that does the job of configuring the interface and 11888c2ecf20Sopenharmony_ci * flushing the configuration. 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * The parameters passed to this external script are: 11918c2ecf20Sopenharmony_ci * 1. A configuration file that has the specified configuration. 11928c2ecf20Sopenharmony_ci * 11938c2ecf20Sopenharmony_ci * We will embed the name of the interface in the configuration 11948c2ecf20Sopenharmony_ci * file: ifcfg-ethx (where ethx is the interface name). 11958c2ecf20Sopenharmony_ci * 11968c2ecf20Sopenharmony_ci * The information provided here may be more than what is needed 11978c2ecf20Sopenharmony_ci * in a given distro to configure the interface and so are free 11988c2ecf20Sopenharmony_ci * ignore information that may not be relevant. 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * Here is the format of the ip configuration file: 12018c2ecf20Sopenharmony_ci * 12028c2ecf20Sopenharmony_ci * HWADDR=macaddr 12038c2ecf20Sopenharmony_ci * DEVICE=interface name 12048c2ecf20Sopenharmony_ci * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured 12058c2ecf20Sopenharmony_ci * or "none" if no boot-time protocol should be used) 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * IPADDR0=ipaddr1 12088c2ecf20Sopenharmony_ci * IPADDR1=ipaddr2 12098c2ecf20Sopenharmony_ci * IPADDRx=ipaddry (where y = x + 1) 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * NETMASK0=netmask1 12128c2ecf20Sopenharmony_ci * NETMASKx=netmasky (where y = x + 1) 12138c2ecf20Sopenharmony_ci * 12148c2ecf20Sopenharmony_ci * GATEWAY=ipaddr1 12158c2ecf20Sopenharmony_ci * GATEWAYx=ipaddry (where y = x + 1) 12168c2ecf20Sopenharmony_ci * 12178c2ecf20Sopenharmony_ci * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) 12188c2ecf20Sopenharmony_ci * 12198c2ecf20Sopenharmony_ci * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be 12208c2ecf20Sopenharmony_ci * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as 12218c2ecf20Sopenharmony_ci * IPV6NETMASK. 12228c2ecf20Sopenharmony_ci * 12238c2ecf20Sopenharmony_ci * The host can specify multiple ipv4 and ipv6 addresses to be 12248c2ecf20Sopenharmony_ci * configured for the interface. Furthermore, the configuration 12258c2ecf20Sopenharmony_ci * needs to be persistent. A subsequent GET call on the interface 12268c2ecf20Sopenharmony_ci * is expected to return the configuration that is set via the SET 12278c2ecf20Sopenharmony_ci * call. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, 12318c2ecf20Sopenharmony_ci "/ifcfg-", if_name); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci file = fopen(if_file, "w"); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if (file == NULL) { 12368c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to open config file; error: %d %s", 12378c2ecf20Sopenharmony_ci errno, strerror(errno)); 12388c2ecf20Sopenharmony_ci return HV_E_FAIL; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* 12428c2ecf20Sopenharmony_ci * First write out the MAC address. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci mac_addr = kvp_if_name_to_mac(if_name); 12468c2ecf20Sopenharmony_ci if (mac_addr == NULL) { 12478c2ecf20Sopenharmony_ci error = HV_E_FAIL; 12488c2ecf20Sopenharmony_ci goto setval_error; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci error = kvp_write_file(file, "HWADDR", "", mac_addr); 12528c2ecf20Sopenharmony_ci free(mac_addr); 12538c2ecf20Sopenharmony_ci if (error) 12548c2ecf20Sopenharmony_ci goto setval_error; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci error = kvp_write_file(file, "DEVICE", "", if_name); 12578c2ecf20Sopenharmony_ci if (error) 12588c2ecf20Sopenharmony_ci goto setval_error; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * The dhcp_enabled flag is only for IPv4. In the case the host only 12628c2ecf20Sopenharmony_ci * injects an IPv6 address, the flag is true, but we still need to 12638c2ecf20Sopenharmony_ci * proceed to parse and pass the IPv6 information to the 12648c2ecf20Sopenharmony_ci * disto-specific script hv_set_ifconfig. 12658c2ecf20Sopenharmony_ci */ 12668c2ecf20Sopenharmony_ci if (new_val->dhcp_enabled) { 12678c2ecf20Sopenharmony_ci error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); 12688c2ecf20Sopenharmony_ci if (error) 12698c2ecf20Sopenharmony_ci goto setval_error; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci } else { 12728c2ecf20Sopenharmony_ci error = kvp_write_file(file, "BOOTPROTO", "", "none"); 12738c2ecf20Sopenharmony_ci if (error) 12748c2ecf20Sopenharmony_ci goto setval_error; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* 12788c2ecf20Sopenharmony_ci * Write the configuration for ipaddress, netmask, gateway and 12798c2ecf20Sopenharmony_ci * name servers. 12808c2ecf20Sopenharmony_ci */ 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); 12838c2ecf20Sopenharmony_ci if (error) 12848c2ecf20Sopenharmony_ci goto setval_error; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); 12878c2ecf20Sopenharmony_ci if (error) 12888c2ecf20Sopenharmony_ci goto setval_error; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); 12918c2ecf20Sopenharmony_ci if (error) 12928c2ecf20Sopenharmony_ci goto setval_error; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci error = process_ip_string(file, (char *)new_val->dns_addr, DNS); 12958c2ecf20Sopenharmony_ci if (error) 12968c2ecf20Sopenharmony_ci goto setval_error; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci fclose(file); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* 13018c2ecf20Sopenharmony_ci * Now that we have populated the configuration file, 13028c2ecf20Sopenharmony_ci * invoke the external script to do its magic. 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s", 13068c2ecf20Sopenharmony_ci "hv_set_ifconfig", if_file); 13078c2ecf20Sopenharmony_ci /* 13088c2ecf20Sopenharmony_ci * This is a little overcautious, but it's necessary to suppress some 13098c2ecf20Sopenharmony_ci * false warnings from gcc 8.0.1. 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_ci if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) { 13128c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long", 13138c2ecf20Sopenharmony_ci cmd, str_len); 13148c2ecf20Sopenharmony_ci return HV_E_FAIL; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (system(cmd)) { 13188c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", 13198c2ecf20Sopenharmony_ci cmd, errno, strerror(errno)); 13208c2ecf20Sopenharmony_ci return HV_E_FAIL; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci return 0; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cisetval_error: 13258c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to write config file"); 13268c2ecf20Sopenharmony_ci fclose(file); 13278c2ecf20Sopenharmony_ci return error; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void 13328c2ecf20Sopenharmony_cikvp_get_domain_name(char *buffer, int length) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct addrinfo hints, *info ; 13358c2ecf20Sopenharmony_ci int error = 0; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci gethostname(buffer, length); 13388c2ecf20Sopenharmony_ci memset(&hints, 0, sizeof(hints)); 13398c2ecf20Sopenharmony_ci hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */ 13408c2ecf20Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 13418c2ecf20Sopenharmony_ci hints.ai_flags = AI_CANONNAME; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci error = getaddrinfo(buffer, NULL, &hints, &info); 13448c2ecf20Sopenharmony_ci if (error != 0) { 13458c2ecf20Sopenharmony_ci snprintf(buffer, length, "getaddrinfo failed: 0x%x %s", 13468c2ecf20Sopenharmony_ci error, gai_strerror(error)); 13478c2ecf20Sopenharmony_ci return; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci snprintf(buffer, length, "%s", info->ai_canonname); 13508c2ecf20Sopenharmony_ci freeaddrinfo(info); 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_civoid print_usage(char *argv[]) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: %s [options]\n" 13568c2ecf20Sopenharmony_ci "Options are:\n" 13578c2ecf20Sopenharmony_ci " -n, --no-daemon stay in foreground, don't daemonize\n" 13588c2ecf20Sopenharmony_ci " -h, --help print this help\n", argv[0]); 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci int kvp_fd = -1, len; 13648c2ecf20Sopenharmony_ci int error; 13658c2ecf20Sopenharmony_ci struct pollfd pfd; 13668c2ecf20Sopenharmony_ci char *p; 13678c2ecf20Sopenharmony_ci struct hv_kvp_msg hv_msg[1]; 13688c2ecf20Sopenharmony_ci char *key_value; 13698c2ecf20Sopenharmony_ci char *key_name; 13708c2ecf20Sopenharmony_ci int op; 13718c2ecf20Sopenharmony_ci int pool; 13728c2ecf20Sopenharmony_ci char *if_name; 13738c2ecf20Sopenharmony_ci struct hv_kvp_ipaddr_value *kvp_ip_val; 13748c2ecf20Sopenharmony_ci int daemonize = 1, long_index = 0, opt; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci static struct option long_options[] = { 13778c2ecf20Sopenharmony_ci {"help", no_argument, 0, 'h' }, 13788c2ecf20Sopenharmony_ci {"no-daemon", no_argument, 0, 'n' }, 13798c2ecf20Sopenharmony_ci {0, 0, 0, 0 } 13808c2ecf20Sopenharmony_ci }; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci while ((opt = getopt_long(argc, argv, "hn", long_options, 13838c2ecf20Sopenharmony_ci &long_index)) != -1) { 13848c2ecf20Sopenharmony_ci switch (opt) { 13858c2ecf20Sopenharmony_ci case 'n': 13868c2ecf20Sopenharmony_ci daemonize = 0; 13878c2ecf20Sopenharmony_ci break; 13888c2ecf20Sopenharmony_ci case 'h': 13898c2ecf20Sopenharmony_ci print_usage(argv); 13908c2ecf20Sopenharmony_ci exit(0); 13918c2ecf20Sopenharmony_ci default: 13928c2ecf20Sopenharmony_ci print_usage(argv); 13938c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (daemonize && daemon(1, 0)) 13988c2ecf20Sopenharmony_ci return 1; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci openlog("KVP", 0, LOG_USER); 14018c2ecf20Sopenharmony_ci syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* 14048c2ecf20Sopenharmony_ci * Retrieve OS release information. 14058c2ecf20Sopenharmony_ci */ 14068c2ecf20Sopenharmony_ci kvp_get_os_info(); 14078c2ecf20Sopenharmony_ci /* 14088c2ecf20Sopenharmony_ci * Cache Fully Qualified Domain Name because getaddrinfo takes an 14098c2ecf20Sopenharmony_ci * unpredictable amount of time to finish. 14108c2ecf20Sopenharmony_ci */ 14118c2ecf20Sopenharmony_ci kvp_get_domain_name(full_domain_name, sizeof(full_domain_name)); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (kvp_file_init()) { 14148c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Failed to initialize the pools"); 14158c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cireopen_kvp_fd: 14198c2ecf20Sopenharmony_ci if (kvp_fd != -1) 14208c2ecf20Sopenharmony_ci close(kvp_fd); 14218c2ecf20Sopenharmony_ci in_hand_shake = 1; 14228c2ecf20Sopenharmony_ci kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (kvp_fd < 0) { 14258c2ecf20Sopenharmony_ci syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", 14268c2ecf20Sopenharmony_ci errno, strerror(errno)); 14278c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* 14318c2ecf20Sopenharmony_ci * Register ourselves with the kernel. 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; 14348c2ecf20Sopenharmony_ci len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 14358c2ecf20Sopenharmony_ci if (len != sizeof(struct hv_kvp_msg)) { 14368c2ecf20Sopenharmony_ci syslog(LOG_ERR, "registration to kernel failed; error: %d %s", 14378c2ecf20Sopenharmony_ci errno, strerror(errno)); 14388c2ecf20Sopenharmony_ci close(kvp_fd); 14398c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci pfd.fd = kvp_fd; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci while (1) { 14458c2ecf20Sopenharmony_ci pfd.events = POLLIN; 14468c2ecf20Sopenharmony_ci pfd.revents = 0; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (poll(&pfd, 1, -1) < 0) { 14498c2ecf20Sopenharmony_ci syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno)); 14508c2ecf20Sopenharmony_ci if (errno == EINVAL) { 14518c2ecf20Sopenharmony_ci close(kvp_fd); 14528c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci else 14558c2ecf20Sopenharmony_ci continue; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (len != sizeof(struct hv_kvp_msg)) { 14618c2ecf20Sopenharmony_ci syslog(LOG_ERR, "read failed; error:%d %s", 14628c2ecf20Sopenharmony_ci errno, strerror(errno)); 14638c2ecf20Sopenharmony_ci goto reopen_kvp_fd; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci /* 14678c2ecf20Sopenharmony_ci * We will use the KVP header information to pass back 14688c2ecf20Sopenharmony_ci * the error from this daemon. So, first copy the state 14698c2ecf20Sopenharmony_ci * and set the error code to success. 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_ci op = hv_msg->kvp_hdr.operation; 14728c2ecf20Sopenharmony_ci pool = hv_msg->kvp_hdr.pool; 14738c2ecf20Sopenharmony_ci hv_msg->error = HV_S_OK; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { 14768c2ecf20Sopenharmony_ci /* 14778c2ecf20Sopenharmony_ci * Driver is registering with us; stash away the version 14788c2ecf20Sopenharmony_ci * information. 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_ci in_hand_shake = 0; 14818c2ecf20Sopenharmony_ci p = (char *)hv_msg->body.kvp_register.version; 14828c2ecf20Sopenharmony_ci lic_version = malloc(strlen(p) + 1); 14838c2ecf20Sopenharmony_ci if (lic_version) { 14848c2ecf20Sopenharmony_ci strcpy(lic_version, p); 14858c2ecf20Sopenharmony_ci syslog(LOG_INFO, "KVP LIC Version: %s", 14868c2ecf20Sopenharmony_ci lic_version); 14878c2ecf20Sopenharmony_ci } else { 14888c2ecf20Sopenharmony_ci syslog(LOG_ERR, "malloc failed"); 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci continue; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci switch (op) { 14948c2ecf20Sopenharmony_ci case KVP_OP_GET_IP_INFO: 14958c2ecf20Sopenharmony_ci kvp_ip_val = &hv_msg->body.kvp_ip_val; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci error = kvp_mac_to_ip(kvp_ip_val); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (error) 15008c2ecf20Sopenharmony_ci hv_msg->error = error; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci break; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci case KVP_OP_SET_IP_INFO: 15058c2ecf20Sopenharmony_ci kvp_ip_val = &hv_msg->body.kvp_ip_val; 15068c2ecf20Sopenharmony_ci if_name = kvp_get_if_name( 15078c2ecf20Sopenharmony_ci (char *)kvp_ip_val->adapter_id); 15088c2ecf20Sopenharmony_ci if (if_name == NULL) { 15098c2ecf20Sopenharmony_ci /* 15108c2ecf20Sopenharmony_ci * We could not map the guid to an 15118c2ecf20Sopenharmony_ci * interface name; return error. 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_ci hv_msg->error = HV_GUID_NOTFOUND; 15148c2ecf20Sopenharmony_ci break; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci error = kvp_set_ip_info(if_name, kvp_ip_val); 15178c2ecf20Sopenharmony_ci if (error) 15188c2ecf20Sopenharmony_ci hv_msg->error = error; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci free(if_name); 15218c2ecf20Sopenharmony_ci break; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci case KVP_OP_SET: 15248c2ecf20Sopenharmony_ci if (kvp_key_add_or_modify(pool, 15258c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.key, 15268c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.key_size, 15278c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.value, 15288c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.value_size)) 15298c2ecf20Sopenharmony_ci hv_msg->error = HV_S_CONT; 15308c2ecf20Sopenharmony_ci break; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci case KVP_OP_GET: 15338c2ecf20Sopenharmony_ci if (kvp_get_value(pool, 15348c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.key, 15358c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.key_size, 15368c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.value, 15378c2ecf20Sopenharmony_ci hv_msg->body.kvp_set.data.value_size)) 15388c2ecf20Sopenharmony_ci hv_msg->error = HV_S_CONT; 15398c2ecf20Sopenharmony_ci break; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci case KVP_OP_DELETE: 15428c2ecf20Sopenharmony_ci if (kvp_key_delete(pool, 15438c2ecf20Sopenharmony_ci hv_msg->body.kvp_delete.key, 15448c2ecf20Sopenharmony_ci hv_msg->body.kvp_delete.key_size)) 15458c2ecf20Sopenharmony_ci hv_msg->error = HV_S_CONT; 15468c2ecf20Sopenharmony_ci break; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci default: 15498c2ecf20Sopenharmony_ci break; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (op != KVP_OP_ENUMERATE) 15538c2ecf20Sopenharmony_ci goto kvp_done; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* 15568c2ecf20Sopenharmony_ci * If the pool is KVP_POOL_AUTO, dynamically generate 15578c2ecf20Sopenharmony_ci * both the key and the value; if not read from the 15588c2ecf20Sopenharmony_ci * appropriate pool. 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_ci if (pool != KVP_POOL_AUTO) { 15618c2ecf20Sopenharmony_ci if (kvp_pool_enumerate(pool, 15628c2ecf20Sopenharmony_ci hv_msg->body.kvp_enum_data.index, 15638c2ecf20Sopenharmony_ci hv_msg->body.kvp_enum_data.data.key, 15648c2ecf20Sopenharmony_ci HV_KVP_EXCHANGE_MAX_KEY_SIZE, 15658c2ecf20Sopenharmony_ci hv_msg->body.kvp_enum_data.data.value, 15668c2ecf20Sopenharmony_ci HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) 15678c2ecf20Sopenharmony_ci hv_msg->error = HV_S_CONT; 15688c2ecf20Sopenharmony_ci goto kvp_done; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci key_name = (char *)hv_msg->body.kvp_enum_data.data.key; 15728c2ecf20Sopenharmony_ci key_value = (char *)hv_msg->body.kvp_enum_data.data.value; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci switch (hv_msg->body.kvp_enum_data.index) { 15758c2ecf20Sopenharmony_ci case FullyQualifiedDomainName: 15768c2ecf20Sopenharmony_ci strcpy(key_value, full_domain_name); 15778c2ecf20Sopenharmony_ci strcpy(key_name, "FullyQualifiedDomainName"); 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci case IntegrationServicesVersion: 15808c2ecf20Sopenharmony_ci strcpy(key_name, "IntegrationServicesVersion"); 15818c2ecf20Sopenharmony_ci strcpy(key_value, lic_version); 15828c2ecf20Sopenharmony_ci break; 15838c2ecf20Sopenharmony_ci case NetworkAddressIPv4: 15848c2ecf20Sopenharmony_ci kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE, 15858c2ecf20Sopenharmony_ci key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 15868c2ecf20Sopenharmony_ci strcpy(key_name, "NetworkAddressIPv4"); 15878c2ecf20Sopenharmony_ci break; 15888c2ecf20Sopenharmony_ci case NetworkAddressIPv6: 15898c2ecf20Sopenharmony_ci kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE, 15908c2ecf20Sopenharmony_ci key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 15918c2ecf20Sopenharmony_ci strcpy(key_name, "NetworkAddressIPv6"); 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci case OSBuildNumber: 15948c2ecf20Sopenharmony_ci strcpy(key_value, os_build); 15958c2ecf20Sopenharmony_ci strcpy(key_name, "OSBuildNumber"); 15968c2ecf20Sopenharmony_ci break; 15978c2ecf20Sopenharmony_ci case OSName: 15988c2ecf20Sopenharmony_ci strcpy(key_value, os_name); 15998c2ecf20Sopenharmony_ci strcpy(key_name, "OSName"); 16008c2ecf20Sopenharmony_ci break; 16018c2ecf20Sopenharmony_ci case OSMajorVersion: 16028c2ecf20Sopenharmony_ci strcpy(key_value, os_major); 16038c2ecf20Sopenharmony_ci strcpy(key_name, "OSMajorVersion"); 16048c2ecf20Sopenharmony_ci break; 16058c2ecf20Sopenharmony_ci case OSMinorVersion: 16068c2ecf20Sopenharmony_ci strcpy(key_value, os_minor); 16078c2ecf20Sopenharmony_ci strcpy(key_name, "OSMinorVersion"); 16088c2ecf20Sopenharmony_ci break; 16098c2ecf20Sopenharmony_ci case OSVersion: 16108c2ecf20Sopenharmony_ci strcpy(key_value, os_version); 16118c2ecf20Sopenharmony_ci strcpy(key_name, "OSVersion"); 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci case ProcessorArchitecture: 16148c2ecf20Sopenharmony_ci strcpy(key_value, processor_arch); 16158c2ecf20Sopenharmony_ci strcpy(key_name, "ProcessorArchitecture"); 16168c2ecf20Sopenharmony_ci break; 16178c2ecf20Sopenharmony_ci default: 16188c2ecf20Sopenharmony_ci hv_msg->error = HV_S_CONT; 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* 16238c2ecf20Sopenharmony_ci * Send the value back to the kernel. Note: the write() may 16248c2ecf20Sopenharmony_ci * return an error due to hibernation; we can ignore the error 16258c2ecf20Sopenharmony_ci * by resetting the dev file, i.e. closing and re-opening it. 16268c2ecf20Sopenharmony_ci */ 16278c2ecf20Sopenharmony_cikvp_done: 16288c2ecf20Sopenharmony_ci len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 16298c2ecf20Sopenharmony_ci if (len != sizeof(struct hv_kvp_msg)) { 16308c2ecf20Sopenharmony_ci syslog(LOG_ERR, "write failed; error: %d %s", errno, 16318c2ecf20Sopenharmony_ci strerror(errno)); 16328c2ecf20Sopenharmony_ci goto reopen_kvp_fd; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci close(kvp_fd); 16378c2ecf20Sopenharmony_ci exit(0); 16388c2ecf20Sopenharmony_ci} 1639