Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * An implementation of key value pair (KVP) functionality for Linux.
0003  *
0004  *
0005  * Copyright (C) 2010, Novell, Inc.
0006  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
0007  *
0008  * This program is free software; you can redistribute it and/or modify it
0009  * under the terms of the GNU General Public License version 2 as published
0010  * by the Free Software Foundation.
0011  *
0012  * This program is distributed in the hope that it will be useful, but
0013  * WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
0015  * NON INFRINGEMENT.  See the GNU General Public License for more
0016  * details.
0017  *
0018  * You should have received a copy of the GNU General Public License
0019  * along with this program; if not, write to the Free Software
0020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0021  *
0022  */
0023 
0024 
0025 #include <sys/poll.h>
0026 #include <sys/utsname.h>
0027 #include <stdio.h>
0028 #include <stdlib.h>
0029 #include <unistd.h>
0030 #include <string.h>
0031 #include <ctype.h>
0032 #include <errno.h>
0033 #include <arpa/inet.h>
0034 #include <linux/hyperv.h>
0035 #include <ifaddrs.h>
0036 #include <netdb.h>
0037 #include <syslog.h>
0038 #include <sys/stat.h>
0039 #include <fcntl.h>
0040 #include <dirent.h>
0041 #include <net/if.h>
0042 #include <limits.h>
0043 #include <getopt.h>
0044 
0045 /*
0046  * KVP protocol: The user mode component first registers with the
0047  * kernel component. Subsequently, the kernel component requests, data
0048  * for the specified keys. In response to this message the user mode component
0049  * fills in the value corresponding to the specified key. We overload the
0050  * sequence field in the cn_msg header to define our KVP message types.
0051  *
0052  * We use this infrastructure for also supporting queries from user mode
0053  * application for state that may be maintained in the KVP kernel component.
0054  *
0055  */
0056 
0057 
0058 enum key_index {
0059     FullyQualifiedDomainName = 0,
0060     IntegrationServicesVersion, /*This key is serviced in the kernel*/
0061     NetworkAddressIPv4,
0062     NetworkAddressIPv6,
0063     OSBuildNumber,
0064     OSName,
0065     OSMajorVersion,
0066     OSMinorVersion,
0067     OSVersion,
0068     ProcessorArchitecture
0069 };
0070 
0071 
0072 enum {
0073     IPADDR = 0,
0074     NETMASK,
0075     GATEWAY,
0076     DNS
0077 };
0078 
0079 static int in_hand_shake;
0080 
0081 static char *os_name = "";
0082 static char *os_major = "";
0083 static char *os_minor = "";
0084 static char *processor_arch;
0085 static char *os_build;
0086 static char *os_version;
0087 static char *lic_version = "Unknown version";
0088 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
0089 static struct utsname uts_buf;
0090 
0091 /*
0092  * The location of the interface configuration file.
0093  */
0094 
0095 #define KVP_CONFIG_LOC  "/var/lib/hyperv"
0096 
0097 #ifndef KVP_SCRIPTS_PATH
0098 #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
0099 #endif
0100 
0101 #define KVP_NET_DIR "/sys/class/net/"
0102 
0103 #define MAX_FILE_NAME 100
0104 #define ENTRIES_PER_BLOCK 50
0105 
0106 struct kvp_record {
0107     char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
0108     char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
0109 };
0110 
0111 struct kvp_file_state {
0112     int fd;
0113     int num_blocks;
0114     struct kvp_record *records;
0115     int num_records;
0116     char fname[MAX_FILE_NAME];
0117 };
0118 
0119 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
0120 
0121 static void kvp_acquire_lock(int pool)
0122 {
0123     struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
0124     fl.l_pid = getpid();
0125 
0126     if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
0127         syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
0128                 errno, strerror(errno));
0129         exit(EXIT_FAILURE);
0130     }
0131 }
0132 
0133 static void kvp_release_lock(int pool)
0134 {
0135     struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
0136     fl.l_pid = getpid();
0137 
0138     if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
0139         syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
0140                 errno, strerror(errno));
0141         exit(EXIT_FAILURE);
0142     }
0143 }
0144 
0145 static void kvp_update_file(int pool)
0146 {
0147     FILE *filep;
0148 
0149     /*
0150      * We are going to write our in-memory registry out to
0151      * disk; acquire the lock first.
0152      */
0153     kvp_acquire_lock(pool);
0154 
0155     filep = fopen(kvp_file_info[pool].fname, "we");
0156     if (!filep) {
0157         syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
0158                 errno, strerror(errno));
0159         kvp_release_lock(pool);
0160         exit(EXIT_FAILURE);
0161     }
0162 
0163     fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
0164                 kvp_file_info[pool].num_records, filep);
0165 
0166     if (ferror(filep) || fclose(filep)) {
0167         kvp_release_lock(pool);
0168         syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
0169         exit(EXIT_FAILURE);
0170     }
0171 
0172     kvp_release_lock(pool);
0173 }
0174 
0175 static void kvp_update_mem_state(int pool)
0176 {
0177     FILE *filep;
0178     size_t records_read = 0;
0179     struct kvp_record *record = kvp_file_info[pool].records;
0180     struct kvp_record *readp;
0181     int num_blocks = kvp_file_info[pool].num_blocks;
0182     int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
0183 
0184     kvp_acquire_lock(pool);
0185 
0186     filep = fopen(kvp_file_info[pool].fname, "re");
0187     if (!filep) {
0188         syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
0189                 errno, strerror(errno));
0190         kvp_release_lock(pool);
0191         exit(EXIT_FAILURE);
0192     }
0193     for (;;) {
0194         readp = &record[records_read];
0195         records_read += fread(readp, sizeof(struct kvp_record),
0196                 ENTRIES_PER_BLOCK * num_blocks - records_read,
0197                 filep);
0198 
0199         if (ferror(filep)) {
0200             syslog(LOG_ERR,
0201                 "Failed to read file, pool: %d; error: %d %s",
0202                  pool, errno, strerror(errno));
0203             kvp_release_lock(pool);
0204             exit(EXIT_FAILURE);
0205         }
0206 
0207         if (!feof(filep)) {
0208             /*
0209              * We have more data to read.
0210              */
0211             num_blocks++;
0212             record = realloc(record, alloc_unit * num_blocks);
0213 
0214             if (record == NULL) {
0215                 syslog(LOG_ERR, "malloc failed");
0216                 kvp_release_lock(pool);
0217                 exit(EXIT_FAILURE);
0218             }
0219             continue;
0220         }
0221         break;
0222     }
0223 
0224     kvp_file_info[pool].num_blocks = num_blocks;
0225     kvp_file_info[pool].records = record;
0226     kvp_file_info[pool].num_records = records_read;
0227 
0228     fclose(filep);
0229     kvp_release_lock(pool);
0230 }
0231 
0232 static int kvp_file_init(void)
0233 {
0234     int  fd;
0235     char *fname;
0236     int i;
0237     int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
0238 
0239     if (access(KVP_CONFIG_LOC, F_OK)) {
0240         if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
0241             syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
0242                     errno, strerror(errno));
0243             exit(EXIT_FAILURE);
0244         }
0245     }
0246 
0247     for (i = 0; i < KVP_POOL_COUNT; i++) {
0248         fname = kvp_file_info[i].fname;
0249         sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
0250         fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
0251 
0252         if (fd == -1)
0253             return 1;
0254 
0255         kvp_file_info[i].fd = fd;
0256         kvp_file_info[i].num_blocks = 1;
0257         kvp_file_info[i].records = malloc(alloc_unit);
0258         if (kvp_file_info[i].records == NULL)
0259             return 1;
0260         kvp_file_info[i].num_records = 0;
0261         kvp_update_mem_state(i);
0262     }
0263 
0264     return 0;
0265 }
0266 
0267 static int kvp_key_delete(int pool, const __u8 *key, int key_size)
0268 {
0269     int i;
0270     int j, k;
0271     int num_records;
0272     struct kvp_record *record;
0273 
0274     /*
0275      * First update the in-memory state.
0276      */
0277     kvp_update_mem_state(pool);
0278 
0279     num_records = kvp_file_info[pool].num_records;
0280     record = kvp_file_info[pool].records;
0281 
0282     for (i = 0; i < num_records; i++) {
0283         if (memcmp(key, record[i].key, key_size))
0284             continue;
0285         /*
0286          * Found a match; just move the remaining
0287          * entries up.
0288          */
0289         if (i == (num_records - 1)) {
0290             kvp_file_info[pool].num_records--;
0291             kvp_update_file(pool);
0292             return 0;
0293         }
0294 
0295         j = i;
0296         k = j + 1;
0297         for (; k < num_records; k++) {
0298             strcpy(record[j].key, record[k].key);
0299             strcpy(record[j].value, record[k].value);
0300             j++;
0301         }
0302 
0303         kvp_file_info[pool].num_records--;
0304         kvp_update_file(pool);
0305         return 0;
0306     }
0307     return 1;
0308 }
0309 
0310 static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
0311                  const __u8 *value, int value_size)
0312 {
0313     int i;
0314     int num_records;
0315     struct kvp_record *record;
0316     int num_blocks;
0317 
0318     if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
0319         (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
0320         return 1;
0321 
0322     /*
0323      * First update the in-memory state.
0324      */
0325     kvp_update_mem_state(pool);
0326 
0327     num_records = kvp_file_info[pool].num_records;
0328     record = kvp_file_info[pool].records;
0329     num_blocks = kvp_file_info[pool].num_blocks;
0330 
0331     for (i = 0; i < num_records; i++) {
0332         if (memcmp(key, record[i].key, key_size))
0333             continue;
0334         /*
0335          * Found a match; just update the value -
0336          * this is the modify case.
0337          */
0338         memcpy(record[i].value, value, value_size);
0339         kvp_update_file(pool);
0340         return 0;
0341     }
0342 
0343     /*
0344      * Need to add a new entry;
0345      */
0346     if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
0347         /* Need to allocate a larger array for reg entries. */
0348         record = realloc(record, sizeof(struct kvp_record) *
0349              ENTRIES_PER_BLOCK * (num_blocks + 1));
0350 
0351         if (record == NULL)
0352             return 1;
0353         kvp_file_info[pool].num_blocks++;
0354 
0355     }
0356     memcpy(record[i].value, value, value_size);
0357     memcpy(record[i].key, key, key_size);
0358     kvp_file_info[pool].records = record;
0359     kvp_file_info[pool].num_records++;
0360     kvp_update_file(pool);
0361     return 0;
0362 }
0363 
0364 static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
0365             int value_size)
0366 {
0367     int i;
0368     int num_records;
0369     struct kvp_record *record;
0370 
0371     if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
0372         (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
0373         return 1;
0374 
0375     /*
0376      * First update the in-memory state.
0377      */
0378     kvp_update_mem_state(pool);
0379 
0380     num_records = kvp_file_info[pool].num_records;
0381     record = kvp_file_info[pool].records;
0382 
0383     for (i = 0; i < num_records; i++) {
0384         if (memcmp(key, record[i].key, key_size))
0385             continue;
0386         /*
0387          * Found a match; just copy the value out.
0388          */
0389         memcpy(value, record[i].value, value_size);
0390         return 0;
0391     }
0392 
0393     return 1;
0394 }
0395 
0396 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
0397                 __u8 *value, int value_size)
0398 {
0399     struct kvp_record *record;
0400 
0401     /*
0402      * First update our in-memory database.
0403      */
0404     kvp_update_mem_state(pool);
0405     record = kvp_file_info[pool].records;
0406 
0407     if (index >= kvp_file_info[pool].num_records) {
0408         return 1;
0409     }
0410 
0411     memcpy(key, record[index].key, key_size);
0412     memcpy(value, record[index].value, value_size);
0413     return 0;
0414 }
0415 
0416 
0417 void kvp_get_os_info(void)
0418 {
0419     FILE    *file;
0420     char    *p, buf[512];
0421 
0422     uname(&uts_buf);
0423     os_version = uts_buf.release;
0424     os_build = strdup(uts_buf.release);
0425 
0426     os_name = uts_buf.sysname;
0427     processor_arch = uts_buf.machine;
0428 
0429     /*
0430      * The current windows host (win7) expects the build
0431      * string to be of the form: x.y.z
0432      * Strip additional information we may have.
0433      */
0434     p = strchr(os_version, '-');
0435     if (p)
0436         *p = '\0';
0437 
0438     /*
0439      * Parse the /etc/os-release file if present:
0440      * https://www.freedesktop.org/software/systemd/man/os-release.html
0441      */
0442     file = fopen("/etc/os-release", "r");
0443     if (file != NULL) {
0444         while (fgets(buf, sizeof(buf), file)) {
0445             char *value, *q;
0446 
0447             /* Ignore comments */
0448             if (buf[0] == '#')
0449                 continue;
0450 
0451             /* Split into name=value */
0452             p = strchr(buf, '=');
0453             if (!p)
0454                 continue;
0455             *p++ = 0;
0456 
0457             /* Remove quotes and newline; un-escape */
0458             value = p;
0459             q = p;
0460             while (*p) {
0461                 if (*p == '\\') {
0462                     ++p;
0463                     if (!*p)
0464                         break;
0465                     *q++ = *p++;
0466                 } else if (*p == '\'' || *p == '"' ||
0467                        *p == '\n') {
0468                     ++p;
0469                 } else {
0470                     *q++ = *p++;
0471                 }
0472             }
0473             *q = 0;
0474 
0475             if (!strcmp(buf, "NAME")) {
0476                 p = strdup(value);
0477                 if (!p)
0478                     break;
0479                 os_name = p;
0480             } else if (!strcmp(buf, "VERSION_ID")) {
0481                 p = strdup(value);
0482                 if (!p)
0483                     break;
0484                 os_major = p;
0485             }
0486         }
0487         fclose(file);
0488         return;
0489     }
0490 
0491     /* Fallback for older RH/SUSE releases */
0492     file = fopen("/etc/SuSE-release", "r");
0493     if (file != NULL)
0494         goto kvp_osinfo_found;
0495     file  = fopen("/etc/redhat-release", "r");
0496     if (file != NULL)
0497         goto kvp_osinfo_found;
0498 
0499     /*
0500      * We don't have information about the os.
0501      */
0502     return;
0503 
0504 kvp_osinfo_found:
0505     /* up to three lines */
0506     p = fgets(buf, sizeof(buf), file);
0507     if (p) {
0508         p = strchr(buf, '\n');
0509         if (p)
0510             *p = '\0';
0511         p = strdup(buf);
0512         if (!p)
0513             goto done;
0514         os_name = p;
0515 
0516         /* second line */
0517         p = fgets(buf, sizeof(buf), file);
0518         if (p) {
0519             p = strchr(buf, '\n');
0520             if (p)
0521                 *p = '\0';
0522             p = strdup(buf);
0523             if (!p)
0524                 goto done;
0525             os_major = p;
0526 
0527             /* third line */
0528             p = fgets(buf, sizeof(buf), file);
0529             if (p)  {
0530                 p = strchr(buf, '\n');
0531                 if (p)
0532                     *p = '\0';
0533                 p = strdup(buf);
0534                 if (p)
0535                     os_minor = p;
0536             }
0537         }
0538     }
0539 
0540 done:
0541     fclose(file);
0542     return;
0543 }
0544 
0545 
0546 
0547 /*
0548  * Retrieve an interface name corresponding to the specified guid.
0549  * If there is a match, the function returns a pointer
0550  * to the interface name and if not, a NULL is returned.
0551  * If a match is found, the caller is responsible for
0552  * freeing the memory.
0553  */
0554 
0555 static char *kvp_get_if_name(char *guid)
0556 {
0557     DIR *dir;
0558     struct dirent *entry;
0559     FILE    *file;
0560     char    *p, *x;
0561     char    *if_name = NULL;
0562     char    buf[256];
0563     char dev_id[PATH_MAX];
0564 
0565     dir = opendir(KVP_NET_DIR);
0566     if (dir == NULL)
0567         return NULL;
0568 
0569     while ((entry = readdir(dir)) != NULL) {
0570         /*
0571          * Set the state for the next pass.
0572          */
0573         snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
0574              KVP_NET_DIR, entry->d_name);
0575 
0576         file = fopen(dev_id, "r");
0577         if (file == NULL)
0578             continue;
0579 
0580         p = fgets(buf, sizeof(buf), file);
0581         if (p) {
0582             x = strchr(p, '\n');
0583             if (x)
0584                 *x = '\0';
0585 
0586             if (!strcmp(p, guid)) {
0587                 /*
0588                  * Found the guid match; return the interface
0589                  * name. The caller will free the memory.
0590                  */
0591                 if_name = strdup(entry->d_name);
0592                 fclose(file);
0593                 break;
0594             }
0595         }
0596         fclose(file);
0597     }
0598 
0599     closedir(dir);
0600     return if_name;
0601 }
0602 
0603 /*
0604  * Retrieve the MAC address given the interface name.
0605  */
0606 
0607 static char *kvp_if_name_to_mac(char *if_name)
0608 {
0609     FILE    *file;
0610     char    *p, *x;
0611     char    buf[256];
0612     char addr_file[PATH_MAX];
0613     unsigned int i;
0614     char *mac_addr = NULL;
0615 
0616     snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
0617          if_name, "/address");
0618 
0619     file = fopen(addr_file, "r");
0620     if (file == NULL)
0621         return NULL;
0622 
0623     p = fgets(buf, sizeof(buf), file);
0624     if (p) {
0625         x = strchr(p, '\n');
0626         if (x)
0627             *x = '\0';
0628         for (i = 0; i < strlen(p); i++)
0629             p[i] = toupper(p[i]);
0630         mac_addr = strdup(p);
0631     }
0632 
0633     fclose(file);
0634     return mac_addr;
0635 }
0636 
0637 static void kvp_process_ipconfig_file(char *cmd,
0638                     char *config_buf, unsigned int len,
0639                     int element_size, int offset)
0640 {
0641     char buf[256];
0642     char *p;
0643     char *x;
0644     FILE *file;
0645 
0646     /*
0647      * First execute the command.
0648      */
0649     file = popen(cmd, "r");
0650     if (file == NULL)
0651         return;
0652 
0653     if (offset == 0)
0654         memset(config_buf, 0, len);
0655     while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
0656         if (len < strlen(config_buf) + element_size + 1)
0657             break;
0658 
0659         x = strchr(p, '\n');
0660         if (x)
0661             *x = '\0';
0662 
0663         strcat(config_buf, p);
0664         strcat(config_buf, ";");
0665     }
0666     pclose(file);
0667 }
0668 
0669 static void kvp_get_ipconfig_info(char *if_name,
0670                  struct hv_kvp_ipaddr_value *buffer)
0671 {
0672     char cmd[512];
0673     char dhcp_info[128];
0674     char *p;
0675     FILE *file;
0676 
0677     /*
0678      * Get the address of default gateway (ipv4).
0679      */
0680     sprintf(cmd, "%s %s", "ip route show dev", if_name);
0681     strcat(cmd, " | awk '/default/ {print $3 }'");
0682 
0683     /*
0684      * Execute the command to gather gateway info.
0685      */
0686     kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
0687                 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
0688 
0689     /*
0690      * Get the address of default gateway (ipv6).
0691      */
0692     sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
0693     strcat(cmd, " | awk '/default/ {print $3 }'");
0694 
0695     /*
0696      * Execute the command to gather gateway info (ipv6).
0697      */
0698     kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
0699                 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
0700 
0701 
0702     /*
0703      * Gather the DNS state.
0704      * Since there is no standard way to get this information
0705      * across various distributions of interest; we just invoke
0706      * an external script that needs to be ported across distros
0707      * of interest.
0708      *
0709      * Following is the expected format of the information from the script:
0710      *
0711      * ipaddr1 (nameserver1)
0712      * ipaddr2 (nameserver2)
0713      * .
0714      * .
0715      */
0716 
0717     sprintf(cmd, KVP_SCRIPTS_PATH "%s",  "hv_get_dns_info");
0718 
0719     /*
0720      * Execute the command to gather DNS info.
0721      */
0722     kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
0723                 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
0724 
0725     /*
0726      * Gather the DHCP state.
0727      * We will gather this state by invoking an external script.
0728      * The parameter to the script is the interface name.
0729      * Here is the expected output:
0730      *
0731      * Enabled: DHCP enabled.
0732      */
0733 
0734     sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name);
0735 
0736     file = popen(cmd, "r");
0737     if (file == NULL)
0738         return;
0739 
0740     p = fgets(dhcp_info, sizeof(dhcp_info), file);
0741     if (p == NULL) {
0742         pclose(file);
0743         return;
0744     }
0745 
0746     if (!strncmp(p, "Enabled", 7))
0747         buffer->dhcp_enabled = 1;
0748     else
0749         buffer->dhcp_enabled = 0;
0750 
0751     pclose(file);
0752 }
0753 
0754 
0755 static unsigned int hweight32(unsigned int *w)
0756 {
0757     unsigned int res = *w - ((*w >> 1) & 0x55555555);
0758     res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
0759     res = (res + (res >> 4)) & 0x0F0F0F0F;
0760     res = res + (res >> 8);
0761     return (res + (res >> 16)) & 0x000000FF;
0762 }
0763 
0764 static int kvp_process_ip_address(void *addrp,
0765                 int family, char *buffer,
0766                 int length,  int *offset)
0767 {
0768     struct sockaddr_in *addr;
0769     struct sockaddr_in6 *addr6;
0770     int addr_length;
0771     char tmp[50];
0772     const char *str;
0773 
0774     if (family == AF_INET) {
0775         addr = addrp;
0776         str = inet_ntop(family, &addr->sin_addr, tmp, 50);
0777         addr_length = INET_ADDRSTRLEN;
0778     } else {
0779         addr6 = addrp;
0780         str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
0781         addr_length = INET6_ADDRSTRLEN;
0782     }
0783 
0784     if ((length - *offset) < addr_length + 2)
0785         return HV_E_FAIL;
0786     if (str == NULL) {
0787         strcpy(buffer, "inet_ntop failed\n");
0788         return HV_E_FAIL;
0789     }
0790     if (*offset == 0)
0791         strcpy(buffer, tmp);
0792     else {
0793         strcat(buffer, ";");
0794         strcat(buffer, tmp);
0795     }
0796 
0797     *offset += strlen(str) + 1;
0798 
0799     return 0;
0800 }
0801 
0802 static int
0803 kvp_get_ip_info(int family, char *if_name, int op,
0804          void  *out_buffer, unsigned int length)
0805 {
0806     struct ifaddrs *ifap;
0807     struct ifaddrs *curp;
0808     int offset = 0;
0809     int sn_offset = 0;
0810     int error = 0;
0811     char *buffer;
0812     struct hv_kvp_ipaddr_value *ip_buffer = NULL;
0813     char cidr_mask[5]; /* /xyz */
0814     int weight;
0815     int i;
0816     unsigned int *w;
0817     char *sn_str;
0818     struct sockaddr_in6 *addr6;
0819 
0820     if (op == KVP_OP_ENUMERATE) {
0821         buffer = out_buffer;
0822     } else {
0823         ip_buffer = out_buffer;
0824         buffer = (char *)ip_buffer->ip_addr;
0825         ip_buffer->addr_family = 0;
0826     }
0827     /*
0828      * On entry into this function, the buffer is capable of holding the
0829      * maximum key value.
0830      */
0831 
0832     if (getifaddrs(&ifap)) {
0833         strcpy(buffer, "getifaddrs failed\n");
0834         return HV_E_FAIL;
0835     }
0836 
0837     curp = ifap;
0838     while (curp != NULL) {
0839         if (curp->ifa_addr == NULL) {
0840             curp = curp->ifa_next;
0841             continue;
0842         }
0843 
0844         if ((if_name != NULL) &&
0845             (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
0846             /*
0847              * We want info about a specific interface;
0848              * just continue.
0849              */
0850             curp = curp->ifa_next;
0851             continue;
0852         }
0853 
0854         /*
0855          * We only support two address families: AF_INET and AF_INET6.
0856          * If a family value of 0 is specified, we collect both
0857          * supported address families; if not we gather info on
0858          * the specified address family.
0859          */
0860         if ((((family != 0) &&
0861              (curp->ifa_addr->sa_family != family))) ||
0862              (curp->ifa_flags & IFF_LOOPBACK)) {
0863             curp = curp->ifa_next;
0864             continue;
0865         }
0866         if ((curp->ifa_addr->sa_family != AF_INET) &&
0867             (curp->ifa_addr->sa_family != AF_INET6)) {
0868             curp = curp->ifa_next;
0869             continue;
0870         }
0871 
0872         if (op == KVP_OP_GET_IP_INFO) {
0873             /*
0874              * Gather info other than the IP address.
0875              * IP address info will be gathered later.
0876              */
0877             if (curp->ifa_addr->sa_family == AF_INET) {
0878                 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
0879                 /*
0880                  * Get subnet info.
0881                  */
0882                 error = kvp_process_ip_address(
0883                                  curp->ifa_netmask,
0884                                  AF_INET,
0885                                  (char *)
0886                                  ip_buffer->sub_net,
0887                                  length,
0888                                  &sn_offset);
0889                 if (error)
0890                     goto gather_ipaddr;
0891             } else {
0892                 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
0893 
0894                 /*
0895                  * Get subnet info in CIDR format.
0896                  */
0897                 weight = 0;
0898                 sn_str = (char *)ip_buffer->sub_net;
0899                 addr6 = (struct sockaddr_in6 *)
0900                     curp->ifa_netmask;
0901                 w = addr6->sin6_addr.s6_addr32;
0902 
0903                 for (i = 0; i < 4; i++)
0904                     weight += hweight32(&w[i]);
0905 
0906                 sprintf(cidr_mask, "/%d", weight);
0907                 if (length < sn_offset + strlen(cidr_mask) + 1)
0908                     goto gather_ipaddr;
0909 
0910                 if (sn_offset == 0)
0911                     strcpy(sn_str, cidr_mask);
0912                 else {
0913                     strcat((char *)ip_buffer->sub_net, ";");
0914                     strcat(sn_str, cidr_mask);
0915                 }
0916                 sn_offset += strlen(sn_str) + 1;
0917             }
0918 
0919             /*
0920              * Collect other ip related configuration info.
0921              */
0922 
0923             kvp_get_ipconfig_info(if_name, ip_buffer);
0924         }
0925 
0926 gather_ipaddr:
0927         error = kvp_process_ip_address(curp->ifa_addr,
0928                         curp->ifa_addr->sa_family,
0929                         buffer,
0930                         length, &offset);
0931         if (error)
0932             goto getaddr_done;
0933 
0934         curp = curp->ifa_next;
0935     }
0936 
0937 getaddr_done:
0938     freeifaddrs(ifap);
0939     return error;
0940 }
0941 
0942 /*
0943  * Retrieve the IP given the MAC address.
0944  */
0945 static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
0946 {
0947     char *mac = (char *)kvp_ip_val->adapter_id;
0948     DIR *dir;
0949     struct dirent *entry;
0950     FILE    *file;
0951     char    *p, *x;
0952     char    *if_name = NULL;
0953     char    buf[256];
0954     char dev_id[PATH_MAX];
0955     unsigned int i;
0956     int error = HV_E_FAIL;
0957 
0958     dir = opendir(KVP_NET_DIR);
0959     if (dir == NULL)
0960         return HV_E_FAIL;
0961 
0962     while ((entry = readdir(dir)) != NULL) {
0963         /*
0964          * Set the state for the next pass.
0965          */
0966         snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
0967              entry->d_name);
0968 
0969         file = fopen(dev_id, "r");
0970         if (file == NULL)
0971             continue;
0972 
0973         p = fgets(buf, sizeof(buf), file);
0974         fclose(file);
0975         if (!p)
0976             continue;
0977 
0978         x = strchr(p, '\n');
0979         if (x)
0980             *x = '\0';
0981 
0982         for (i = 0; i < strlen(p); i++)
0983             p[i] = toupper(p[i]);
0984 
0985         if (strcmp(p, mac))
0986             continue;
0987 
0988         /*
0989          * Found the MAC match.
0990          * A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
0991          */
0992         if_name = entry->d_name;
0993         if (!if_name)
0994             continue;
0995 
0996         error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
0997                     kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
0998 
0999         if (!error && strlen((char *)kvp_ip_val->ip_addr))
1000             break;
1001     }
1002 
1003     closedir(dir);
1004     return error;
1005 }
1006 
1007 static int expand_ipv6(char *addr, int type)
1008 {
1009     int ret;
1010     struct in6_addr v6_addr;
1011 
1012     ret = inet_pton(AF_INET6, addr, &v6_addr);
1013 
1014     if (ret != 1) {
1015         if (type == NETMASK)
1016             return 1;
1017         return 0;
1018     }
1019 
1020     sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1021         "%02x%02x:%02x%02x:%02x%02x",
1022         (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1023         (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1024         (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1025         (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1026         (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1027         (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1028         (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1029         (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1030 
1031     return 1;
1032 
1033 }
1034 
1035 static int is_ipv4(char *addr)
1036 {
1037     int ret;
1038     struct in_addr ipv4_addr;
1039 
1040     ret = inet_pton(AF_INET, addr, &ipv4_addr);
1041 
1042     if (ret == 1)
1043         return 1;
1044     return 0;
1045 }
1046 
1047 static int parse_ip_val_buffer(char *in_buf, int *offset,
1048                 char *out_buf, int out_len)
1049 {
1050     char *x;
1051     char *start;
1052 
1053     /*
1054      * in_buf has sequence of characters that are separated by
1055      * the character ';'. The last sequence does not have the
1056      * terminating ";" character.
1057      */
1058     start = in_buf + *offset;
1059 
1060     x = strchr(start, ';');
1061     if (x)
1062         *x = 0;
1063     else
1064         x = start + strlen(start);
1065 
1066     if (strlen(start) != 0) {
1067         int i = 0;
1068         /*
1069          * Get rid of leading spaces.
1070          */
1071         while (start[i] == ' ')
1072             i++;
1073 
1074         if ((x - start) <= out_len) {
1075             strcpy(out_buf, (start + i));
1076             *offset += (x - start) + 1;
1077             return 1;
1078         }
1079     }
1080     return 0;
1081 }
1082 
1083 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1084 {
1085     int ret;
1086 
1087     ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1088 
1089     if (ret < 0)
1090         return HV_E_FAIL;
1091 
1092     return 0;
1093 }
1094 
1095 
1096 static int process_ip_string(FILE *f, char *ip_string, int type)
1097 {
1098     int error = 0;
1099     char addr[INET6_ADDRSTRLEN];
1100     int i = 0;
1101     int j = 0;
1102     char str[256];
1103     char sub_str[13];
1104     int offset = 0;
1105 
1106     memset(addr, 0, sizeof(addr));
1107 
1108     while (parse_ip_val_buffer(ip_string, &offset, addr,
1109                     (MAX_IP_ADDR_SIZE * 2))) {
1110 
1111         sub_str[0] = 0;
1112         if (is_ipv4(addr)) {
1113             switch (type) {
1114             case IPADDR:
1115                 snprintf(str, sizeof(str), "%s", "IPADDR");
1116                 break;
1117             case NETMASK:
1118                 snprintf(str, sizeof(str), "%s", "NETMASK");
1119                 break;
1120             case GATEWAY:
1121                 snprintf(str, sizeof(str), "%s", "GATEWAY");
1122                 break;
1123             case DNS:
1124                 snprintf(str, sizeof(str), "%s", "DNS");
1125                 break;
1126             }
1127 
1128             if (type == DNS) {
1129                 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1130             } else if (type == GATEWAY && i == 0) {
1131                 ++i;
1132             } else {
1133                 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1134             }
1135 
1136 
1137         } else if (expand_ipv6(addr, type)) {
1138             switch (type) {
1139             case IPADDR:
1140                 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1141                 break;
1142             case NETMASK:
1143                 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1144                 break;
1145             case GATEWAY:
1146                 snprintf(str, sizeof(str), "%s",
1147                     "IPV6_DEFAULTGW");
1148                 break;
1149             case DNS:
1150                 snprintf(str, sizeof(str), "%s",  "DNS");
1151                 break;
1152             }
1153 
1154             if (type == DNS) {
1155                 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1156             } else if (j == 0) {
1157                 ++j;
1158             } else {
1159                 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1160             }
1161         } else {
1162             return  HV_INVALIDARG;
1163         }
1164 
1165         error = kvp_write_file(f, str, sub_str, addr);
1166         if (error)
1167             return error;
1168         memset(addr, 0, sizeof(addr));
1169     }
1170 
1171     return 0;
1172 }
1173 
1174 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1175 {
1176     int error = 0;
1177     char if_file[PATH_MAX];
1178     FILE *file;
1179     char cmd[PATH_MAX];
1180     char *mac_addr;
1181     int str_len;
1182 
1183     /*
1184      * Set the configuration for the specified interface with
1185      * the information provided. Since there is no standard
1186      * way to configure an interface, we will have an external
1187      * script that does the job of configuring the interface and
1188      * flushing the configuration.
1189      *
1190      * The parameters passed to this external script are:
1191      * 1. A configuration file that has the specified configuration.
1192      *
1193      * We will embed the name of the interface in the configuration
1194      * file: ifcfg-ethx (where ethx is the interface name).
1195      *
1196      * The information provided here may be more than what is needed
1197      * in a given distro to configure the interface and so are free
1198      * ignore information that may not be relevant.
1199      *
1200      * Here is the format of the ip configuration file:
1201      *
1202      * HWADDR=macaddr
1203      * DEVICE=interface name
1204      * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
1205      *                       or "none" if no boot-time protocol should be used)
1206      *
1207      * IPADDR0=ipaddr1
1208      * IPADDR1=ipaddr2
1209      * IPADDRx=ipaddry (where y = x + 1)
1210      *
1211      * NETMASK0=netmask1
1212      * NETMASKx=netmasky (where y = x + 1)
1213      *
1214      * GATEWAY=ipaddr1
1215      * GATEWAYx=ipaddry (where y = x + 1)
1216      *
1217      * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1218      *
1219      * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1220      * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1221      * IPV6NETMASK.
1222      *
1223      * The host can specify multiple ipv4 and ipv6 addresses to be
1224      * configured for the interface. Furthermore, the configuration
1225      * needs to be persistent. A subsequent GET call on the interface
1226      * is expected to return the configuration that is set via the SET
1227      * call.
1228      */
1229 
1230     snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1231         "/ifcfg-", if_name);
1232 
1233     file = fopen(if_file, "w");
1234 
1235     if (file == NULL) {
1236         syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1237                 errno, strerror(errno));
1238         return HV_E_FAIL;
1239     }
1240 
1241     /*
1242      * First write out the MAC address.
1243      */
1244 
1245     mac_addr = kvp_if_name_to_mac(if_name);
1246     if (mac_addr == NULL) {
1247         error = HV_E_FAIL;
1248         goto setval_error;
1249     }
1250 
1251     error = kvp_write_file(file, "HWADDR", "", mac_addr);
1252     free(mac_addr);
1253     if (error)
1254         goto setval_error;
1255 
1256     error = kvp_write_file(file, "DEVICE", "", if_name);
1257     if (error)
1258         goto setval_error;
1259 
1260     /*
1261      * The dhcp_enabled flag is only for IPv4. In the case the host only
1262      * injects an IPv6 address, the flag is true, but we still need to
1263      * proceed to parse and pass the IPv6 information to the
1264      * disto-specific script hv_set_ifconfig.
1265      */
1266     if (new_val->dhcp_enabled) {
1267         error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1268         if (error)
1269             goto setval_error;
1270 
1271     } else {
1272         error = kvp_write_file(file, "BOOTPROTO", "", "none");
1273         if (error)
1274             goto setval_error;
1275     }
1276 
1277     /*
1278      * Write the configuration for ipaddress, netmask, gateway and
1279      * name servers.
1280      */
1281 
1282     error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1283     if (error)
1284         goto setval_error;
1285 
1286     error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1287     if (error)
1288         goto setval_error;
1289 
1290     error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1291     if (error)
1292         goto setval_error;
1293 
1294     error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1295     if (error)
1296         goto setval_error;
1297 
1298     fclose(file);
1299 
1300     /*
1301      * Now that we have populated the configuration file,
1302      * invoke the external script to do its magic.
1303      */
1304 
1305     str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
1306                "hv_set_ifconfig", if_file);
1307     /*
1308      * This is a little overcautious, but it's necessary to suppress some
1309      * false warnings from gcc 8.0.1.
1310      */
1311     if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
1312         syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
1313                cmd, str_len);
1314         return HV_E_FAIL;
1315     }
1316 
1317     if (system(cmd)) {
1318         syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1319                 cmd, errno, strerror(errno));
1320         return HV_E_FAIL;
1321     }
1322     return 0;
1323 
1324 setval_error:
1325     syslog(LOG_ERR, "Failed to write config file");
1326     fclose(file);
1327     return error;
1328 }
1329 
1330 
1331 static void
1332 kvp_get_domain_name(char *buffer, int length)
1333 {
1334     struct addrinfo hints, *info ;
1335     int error = 0;
1336 
1337     gethostname(buffer, length);
1338     memset(&hints, 0, sizeof(hints));
1339     hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1340     hints.ai_socktype = SOCK_STREAM;
1341     hints.ai_flags = AI_CANONNAME;
1342 
1343     error = getaddrinfo(buffer, NULL, &hints, &info);
1344     if (error != 0) {
1345         snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1346             error, gai_strerror(error));
1347         return;
1348     }
1349     snprintf(buffer, length, "%s", info->ai_canonname);
1350     freeaddrinfo(info);
1351 }
1352 
1353 void print_usage(char *argv[])
1354 {
1355     fprintf(stderr, "Usage: %s [options]\n"
1356         "Options are:\n"
1357         "  -n, --no-daemon        stay in foreground, don't daemonize\n"
1358         "  -h, --help             print this help\n", argv[0]);
1359 }
1360 
1361 int main(int argc, char *argv[])
1362 {
1363     int kvp_fd = -1, len;
1364     int error;
1365     struct pollfd pfd;
1366     char    *p;
1367     struct hv_kvp_msg hv_msg[1];
1368     char    *key_value;
1369     char    *key_name;
1370     int op;
1371     int pool;
1372     char    *if_name;
1373     struct hv_kvp_ipaddr_value *kvp_ip_val;
1374     int daemonize = 1, long_index = 0, opt;
1375 
1376     static struct option long_options[] = {
1377         {"help",    no_argument,       0,  'h' },
1378         {"no-daemon",   no_argument,       0,  'n' },
1379         {0,     0,         0,  0   }
1380     };
1381 
1382     while ((opt = getopt_long(argc, argv, "hn", long_options,
1383                   &long_index)) != -1) {
1384         switch (opt) {
1385         case 'n':
1386             daemonize = 0;
1387             break;
1388         case 'h':
1389             print_usage(argv);
1390             exit(0);
1391         default:
1392             print_usage(argv);
1393             exit(EXIT_FAILURE);
1394         }
1395     }
1396 
1397     if (daemonize && daemon(1, 0))
1398         return 1;
1399 
1400     openlog("KVP", 0, LOG_USER);
1401     syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1402 
1403     /*
1404      * Retrieve OS release information.
1405      */
1406     kvp_get_os_info();
1407     /*
1408      * Cache Fully Qualified Domain Name because getaddrinfo takes an
1409      * unpredictable amount of time to finish.
1410      */
1411     kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1412 
1413     if (kvp_file_init()) {
1414         syslog(LOG_ERR, "Failed to initialize the pools");
1415         exit(EXIT_FAILURE);
1416     }
1417 
1418 reopen_kvp_fd:
1419     if (kvp_fd != -1)
1420         close(kvp_fd);
1421     in_hand_shake = 1;
1422     kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1423 
1424     if (kvp_fd < 0) {
1425         syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1426                errno, strerror(errno));
1427         exit(EXIT_FAILURE);
1428     }
1429 
1430     /*
1431      * Register ourselves with the kernel.
1432      */
1433     hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1434     len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1435     if (len != sizeof(struct hv_kvp_msg)) {
1436         syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1437                errno, strerror(errno));
1438         close(kvp_fd);
1439         exit(EXIT_FAILURE);
1440     }
1441 
1442     pfd.fd = kvp_fd;
1443 
1444     while (1) {
1445         pfd.events = POLLIN;
1446         pfd.revents = 0;
1447 
1448         if (poll(&pfd, 1, -1) < 0) {
1449             syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1450             if (errno == EINVAL) {
1451                 close(kvp_fd);
1452                 exit(EXIT_FAILURE);
1453             }
1454             else
1455                 continue;
1456         }
1457 
1458         len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1459 
1460         if (len != sizeof(struct hv_kvp_msg)) {
1461             syslog(LOG_ERR, "read failed; error:%d %s",
1462                    errno, strerror(errno));
1463             goto reopen_kvp_fd;
1464         }
1465 
1466         /*
1467          * We will use the KVP header information to pass back
1468          * the error from this daemon. So, first copy the state
1469          * and set the error code to success.
1470          */
1471         op = hv_msg->kvp_hdr.operation;
1472         pool = hv_msg->kvp_hdr.pool;
1473         hv_msg->error = HV_S_OK;
1474 
1475         if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1476             /*
1477              * Driver is registering with us; stash away the version
1478              * information.
1479              */
1480             in_hand_shake = 0;
1481             p = (char *)hv_msg->body.kvp_register.version;
1482             lic_version = malloc(strlen(p) + 1);
1483             if (lic_version) {
1484                 strcpy(lic_version, p);
1485                 syslog(LOG_INFO, "KVP LIC Version: %s",
1486                        lic_version);
1487             } else {
1488                 syslog(LOG_ERR, "malloc failed");
1489             }
1490             continue;
1491         }
1492 
1493         switch (op) {
1494         case KVP_OP_GET_IP_INFO:
1495             kvp_ip_val = &hv_msg->body.kvp_ip_val;
1496 
1497             error = kvp_mac_to_ip(kvp_ip_val);
1498 
1499             if (error)
1500                 hv_msg->error = error;
1501 
1502             break;
1503 
1504         case KVP_OP_SET_IP_INFO:
1505             kvp_ip_val = &hv_msg->body.kvp_ip_val;
1506             if_name = kvp_get_if_name(
1507                     (char *)kvp_ip_val->adapter_id);
1508             if (if_name == NULL) {
1509                 /*
1510                  * We could not map the guid to an
1511                  * interface name; return error.
1512                  */
1513                 hv_msg->error = HV_GUID_NOTFOUND;
1514                 break;
1515             }
1516             error = kvp_set_ip_info(if_name, kvp_ip_val);
1517             if (error)
1518                 hv_msg->error = error;
1519 
1520             free(if_name);
1521             break;
1522 
1523         case KVP_OP_SET:
1524             if (kvp_key_add_or_modify(pool,
1525                     hv_msg->body.kvp_set.data.key,
1526                     hv_msg->body.kvp_set.data.key_size,
1527                     hv_msg->body.kvp_set.data.value,
1528                     hv_msg->body.kvp_set.data.value_size))
1529                     hv_msg->error = HV_S_CONT;
1530             break;
1531 
1532         case KVP_OP_GET:
1533             if (kvp_get_value(pool,
1534                     hv_msg->body.kvp_set.data.key,
1535                     hv_msg->body.kvp_set.data.key_size,
1536                     hv_msg->body.kvp_set.data.value,
1537                     hv_msg->body.kvp_set.data.value_size))
1538                     hv_msg->error = HV_S_CONT;
1539             break;
1540 
1541         case KVP_OP_DELETE:
1542             if (kvp_key_delete(pool,
1543                     hv_msg->body.kvp_delete.key,
1544                     hv_msg->body.kvp_delete.key_size))
1545                     hv_msg->error = HV_S_CONT;
1546             break;
1547 
1548         default:
1549             break;
1550         }
1551 
1552         if (op != KVP_OP_ENUMERATE)
1553             goto kvp_done;
1554 
1555         /*
1556          * If the pool is KVP_POOL_AUTO, dynamically generate
1557          * both the key and the value; if not read from the
1558          * appropriate pool.
1559          */
1560         if (pool != KVP_POOL_AUTO) {
1561             if (kvp_pool_enumerate(pool,
1562                     hv_msg->body.kvp_enum_data.index,
1563                     hv_msg->body.kvp_enum_data.data.key,
1564                     HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1565                     hv_msg->body.kvp_enum_data.data.value,
1566                     HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1567                     hv_msg->error = HV_S_CONT;
1568             goto kvp_done;
1569         }
1570 
1571         key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1572         key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1573 
1574         switch (hv_msg->body.kvp_enum_data.index) {
1575         case FullyQualifiedDomainName:
1576             strcpy(key_value, full_domain_name);
1577             strcpy(key_name, "FullyQualifiedDomainName");
1578             break;
1579         case IntegrationServicesVersion:
1580             strcpy(key_name, "IntegrationServicesVersion");
1581             strcpy(key_value, lic_version);
1582             break;
1583         case NetworkAddressIPv4:
1584             kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1585                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1586             strcpy(key_name, "NetworkAddressIPv4");
1587             break;
1588         case NetworkAddressIPv6:
1589             kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1590                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1591             strcpy(key_name, "NetworkAddressIPv6");
1592             break;
1593         case OSBuildNumber:
1594             strcpy(key_value, os_build);
1595             strcpy(key_name, "OSBuildNumber");
1596             break;
1597         case OSName:
1598             strcpy(key_value, os_name);
1599             strcpy(key_name, "OSName");
1600             break;
1601         case OSMajorVersion:
1602             strcpy(key_value, os_major);
1603             strcpy(key_name, "OSMajorVersion");
1604             break;
1605         case OSMinorVersion:
1606             strcpy(key_value, os_minor);
1607             strcpy(key_name, "OSMinorVersion");
1608             break;
1609         case OSVersion:
1610             strcpy(key_value, os_version);
1611             strcpy(key_name, "OSVersion");
1612             break;
1613         case ProcessorArchitecture:
1614             strcpy(key_value, processor_arch);
1615             strcpy(key_name, "ProcessorArchitecture");
1616             break;
1617         default:
1618             hv_msg->error = HV_S_CONT;
1619             break;
1620         }
1621 
1622         /*
1623          * Send the value back to the kernel. Note: the write() may
1624          * return an error due to hibernation; we can ignore the error
1625          * by resetting the dev file, i.e. closing and re-opening it.
1626          */
1627 kvp_done:
1628         len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1629         if (len != sizeof(struct hv_kvp_msg)) {
1630             syslog(LOG_ERR, "write failed; error: %d %s", errno,
1631                    strerror(errno));
1632             goto reopen_kvp_fd;
1633         }
1634     }
1635 
1636     close(kvp_fd);
1637     exit(0);
1638 }