linux/tools/hv/hv_kvp_daemon.c
<<
>>
Prefs
   1/*
   2 * An implementation of key value pair (KVP) functionality for Linux.
   3 *
   4 *
   5 * Copyright (C) 2010, Novell, Inc.
   6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License version 2 as published
  10 * by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  15 * NON INFRINGEMENT.  See the GNU General Public License for more
  16 * details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21 *
  22 */
  23
  24
  25#include <sys/types.h>
  26#include <sys/socket.h>
  27#include <sys/poll.h>
  28#include <sys/utsname.h>
  29#include <linux/types.h>
  30#include <stdio.h>
  31#include <stdlib.h>
  32#include <unistd.h>
  33#include <string.h>
  34#include <ctype.h>
  35#include <errno.h>
  36#include <arpa/inet.h>
  37#include <linux/connector.h>
  38#include <linux/hyperv.h>
  39#include <linux/netlink.h>
  40#include <ifaddrs.h>
  41#include <netdb.h>
  42#include <syslog.h>
  43#include <sys/stat.h>
  44#include <fcntl.h>
  45#include <dirent.h>
  46
  47/*
  48 * KVP protocol: The user mode component first registers with the
  49 * the kernel component. Subsequently, the kernel component requests, data
  50 * for the specified keys. In response to this message the user mode component
  51 * fills in the value corresponding to the specified key. We overload the
  52 * sequence field in the cn_msg header to define our KVP message types.
  53 *
  54 * We use this infrastructure for also supporting queries from user mode
  55 * application for state that may be maintained in the KVP kernel component.
  56 *
  57 */
  58
  59
  60enum key_index {
  61        FullyQualifiedDomainName = 0,
  62        IntegrationServicesVersion, /*This key is serviced in the kernel*/
  63        NetworkAddressIPv4,
  64        NetworkAddressIPv6,
  65        OSBuildNumber,
  66        OSName,
  67        OSMajorVersion,
  68        OSMinorVersion,
  69        OSVersion,
  70        ProcessorArchitecture
  71};
  72
  73
  74enum {
  75        IPADDR = 0,
  76        NETMASK,
  77        GATEWAY,
  78        DNS
  79};
  80
  81static char kvp_send_buffer[4096];
  82static char kvp_recv_buffer[4096 * 2];
  83static struct sockaddr_nl addr;
  84static int in_hand_shake = 1;
  85
  86static char *os_name = "";
  87static char *os_major = "";
  88static char *os_minor = "";
  89static char *processor_arch;
  90static char *os_build;
  91static char *lic_version = "Unknown version";
  92static struct utsname uts_buf;
  93
  94/*
  95 * The location of the interface configuration file.
  96 */
  97
  98#define KVP_CONFIG_LOC  "/var/opt/"
  99
 100#define MAX_FILE_NAME 100
 101#define ENTRIES_PER_BLOCK 50
 102
 103struct kvp_record {
 104        char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
 105        char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
 106};
 107
 108struct kvp_file_state {
 109        int fd;
 110        int num_blocks;
 111        struct kvp_record *records;
 112        int num_records;
 113        char fname[MAX_FILE_NAME];
 114};
 115
 116static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
 117
 118static void kvp_acquire_lock(int pool)
 119{
 120        struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
 121        fl.l_pid = getpid();
 122
 123        if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
 124                syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
 125                exit(EXIT_FAILURE);
 126        }
 127}
 128
 129static void kvp_release_lock(int pool)
 130{
 131        struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
 132        fl.l_pid = getpid();
 133
 134        if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
 135                perror("fcntl");
 136                syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
 137                exit(EXIT_FAILURE);
 138        }
 139}
 140
 141static void kvp_update_file(int pool)
 142{
 143        FILE *filep;
 144        size_t bytes_written;
 145
 146        /*
 147         * We are going to write our in-memory registry out to
 148         * disk; acquire the lock first.
 149         */
 150        kvp_acquire_lock(pool);
 151
 152        filep = fopen(kvp_file_info[pool].fname, "w");
 153        if (!filep) {
 154                kvp_release_lock(pool);
 155                syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
 156                exit(EXIT_FAILURE);
 157        }
 158
 159        bytes_written = fwrite(kvp_file_info[pool].records,
 160                                sizeof(struct kvp_record),
 161                                kvp_file_info[pool].num_records, filep);
 162
 163        if (ferror(filep) || fclose(filep)) {
 164                kvp_release_lock(pool);
 165                syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
 166                exit(EXIT_FAILURE);
 167        }
 168
 169        kvp_release_lock(pool);
 170}
 171
 172static void kvp_update_mem_state(int pool)
 173{
 174        FILE *filep;
 175        size_t records_read = 0;
 176        struct kvp_record *record = kvp_file_info[pool].records;
 177        struct kvp_record *readp;
 178        int num_blocks = kvp_file_info[pool].num_blocks;
 179        int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 180
 181        kvp_acquire_lock(pool);
 182
 183        filep = fopen(kvp_file_info[pool].fname, "r");
 184        if (!filep) {
 185                kvp_release_lock(pool);
 186                syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
 187                exit(EXIT_FAILURE);
 188        }
 189        for (;;) {
 190                readp = &record[records_read];
 191                records_read += fread(readp, sizeof(struct kvp_record),
 192                                        ENTRIES_PER_BLOCK * num_blocks,
 193                                        filep);
 194
 195                if (ferror(filep)) {
 196                        syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
 197                        exit(EXIT_FAILURE);
 198                }
 199
 200                if (!feof(filep)) {
 201                        /*
 202                         * We have more data to read.
 203                         */
 204                        num_blocks++;
 205                        record = realloc(record, alloc_unit * num_blocks);
 206
 207                        if (record == NULL) {
 208                                syslog(LOG_ERR, "malloc failed");
 209                                exit(EXIT_FAILURE);
 210                        }
 211                        continue;
 212                }
 213                break;
 214        }
 215
 216        kvp_file_info[pool].num_blocks = num_blocks;
 217        kvp_file_info[pool].records = record;
 218        kvp_file_info[pool].num_records = records_read;
 219
 220        fclose(filep);
 221        kvp_release_lock(pool);
 222}
 223static int kvp_file_init(void)
 224{
 225        int  fd;
 226        FILE *filep;
 227        size_t records_read;
 228        char *fname;
 229        struct kvp_record *record;
 230        struct kvp_record *readp;
 231        int num_blocks;
 232        int i;
 233        int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 234
 235        if (access("/var/opt/hyperv", F_OK)) {
 236                if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
 237                        syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
 238                        exit(EXIT_FAILURE);
 239                }
 240        }
 241
 242        for (i = 0; i < KVP_POOL_COUNT; i++) {
 243                fname = kvp_file_info[i].fname;
 244                records_read = 0;
 245                num_blocks = 1;
 246                sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
 247                fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
 248
 249                if (fd == -1)
 250                        return 1;
 251
 252
 253                filep = fopen(fname, "r");
 254                if (!filep)
 255                        return 1;
 256
 257                record = malloc(alloc_unit * num_blocks);
 258                if (record == NULL) {
 259                        fclose(filep);
 260                        return 1;
 261                }
 262                for (;;) {
 263                        readp = &record[records_read];
 264                        records_read += fread(readp, sizeof(struct kvp_record),
 265                                        ENTRIES_PER_BLOCK,
 266                                        filep);
 267
 268                        if (ferror(filep)) {
 269                                syslog(LOG_ERR, "Failed to read file, pool: %d",
 270                                       i);
 271                                exit(EXIT_FAILURE);
 272                        }
 273
 274                        if (!feof(filep)) {
 275                                /*
 276                                 * We have more data to read.
 277                                 */
 278                                num_blocks++;
 279                                record = realloc(record, alloc_unit *
 280                                                num_blocks);
 281                                if (record == NULL) {
 282                                        fclose(filep);
 283                                        return 1;
 284                                }
 285                                continue;
 286                        }
 287                        break;
 288                }
 289                kvp_file_info[i].fd = fd;
 290                kvp_file_info[i].num_blocks = num_blocks;
 291                kvp_file_info[i].records = record;
 292                kvp_file_info[i].num_records = records_read;
 293                fclose(filep);
 294
 295        }
 296
 297        return 0;
 298}
 299
 300static int kvp_key_delete(int pool, __u8 *key, int key_size)
 301{
 302        int i;
 303        int j, k;
 304        int num_records;
 305        struct kvp_record *record;
 306
 307        /*
 308         * First update the in-memory state.
 309         */
 310        kvp_update_mem_state(pool);
 311
 312        num_records = kvp_file_info[pool].num_records;
 313        record = kvp_file_info[pool].records;
 314
 315        for (i = 0; i < num_records; i++) {
 316                if (memcmp(key, record[i].key, key_size))
 317                        continue;
 318                /*
 319                 * Found a match; just move the remaining
 320                 * entries up.
 321                 */
 322                if (i == num_records) {
 323                        kvp_file_info[pool].num_records--;
 324                        kvp_update_file(pool);
 325                        return 0;
 326                }
 327
 328                j = i;
 329                k = j + 1;
 330                for (; k < num_records; k++) {
 331                        strcpy(record[j].key, record[k].key);
 332                        strcpy(record[j].value, record[k].value);
 333                        j++;
 334                }
 335
 336                kvp_file_info[pool].num_records--;
 337                kvp_update_file(pool);
 338                return 0;
 339        }
 340        return 1;
 341}
 342
 343static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
 344                        int value_size)
 345{
 346        int i;
 347        int num_records;
 348        struct kvp_record *record;
 349        int num_blocks;
 350
 351        if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 352                (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
 353                return 1;
 354
 355        /*
 356         * First update the in-memory state.
 357         */
 358        kvp_update_mem_state(pool);
 359
 360        num_records = kvp_file_info[pool].num_records;
 361        record = kvp_file_info[pool].records;
 362        num_blocks = kvp_file_info[pool].num_blocks;
 363
 364        for (i = 0; i < num_records; i++) {
 365                if (memcmp(key, record[i].key, key_size))
 366                        continue;
 367                /*
 368                 * Found a match; just update the value -
 369                 * this is the modify case.
 370                 */
 371                memcpy(record[i].value, value, value_size);
 372                kvp_update_file(pool);
 373                return 0;
 374        }
 375
 376        /*
 377         * Need to add a new entry;
 378         */
 379        if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
 380                /* Need to allocate a larger array for reg entries. */
 381                record = realloc(record, sizeof(struct kvp_record) *
 382                         ENTRIES_PER_BLOCK * (num_blocks + 1));
 383
 384                if (record == NULL)
 385                        return 1;
 386                kvp_file_info[pool].num_blocks++;
 387
 388        }
 389        memcpy(record[i].value, value, value_size);
 390        memcpy(record[i].key, key, key_size);
 391        kvp_file_info[pool].records = record;
 392        kvp_file_info[pool].num_records++;
 393        kvp_update_file(pool);
 394        return 0;
 395}
 396
 397static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
 398                        int value_size)
 399{
 400        int i;
 401        int num_records;
 402        struct kvp_record *record;
 403
 404        if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 405                (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
 406                return 1;
 407
 408        /*
 409         * First update the in-memory state.
 410         */
 411        kvp_update_mem_state(pool);
 412
 413        num_records = kvp_file_info[pool].num_records;
 414        record = kvp_file_info[pool].records;
 415
 416        for (i = 0; i < num_records; i++) {
 417                if (memcmp(key, record[i].key, key_size))
 418                        continue;
 419                /*
 420                 * Found a match; just copy the value out.
 421                 */
 422                memcpy(value, record[i].value, value_size);
 423                return 0;
 424        }
 425
 426        return 1;
 427}
 428
 429static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
 430                                __u8 *value, int value_size)
 431{
 432        struct kvp_record *record;
 433
 434        /*
 435         * First update our in-memory database.
 436         */
 437        kvp_update_mem_state(pool);
 438        record = kvp_file_info[pool].records;
 439
 440        if (index >= kvp_file_info[pool].num_records) {
 441                return 1;
 442        }
 443
 444        memcpy(key, record[index].key, key_size);
 445        memcpy(value, record[index].value, value_size);
 446        return 0;
 447}
 448
 449
 450void kvp_get_os_info(void)
 451{
 452        FILE    *file;
 453        char    *p, buf[512];
 454
 455        uname(&uts_buf);
 456        os_build = uts_buf.release;
 457        os_name = uts_buf.sysname;
 458        processor_arch = uts_buf.machine;
 459
 460        /*
 461         * The current windows host (win7) expects the build
 462         * string to be of the form: x.y.z
 463         * Strip additional information we may have.
 464         */
 465        p = strchr(os_build, '-');
 466        if (p)
 467                *p = '\0';
 468
 469        /*
 470         * Parse the /etc/os-release file if present:
 471         * http://www.freedesktop.org/software/systemd/man/os-release.html
 472         */
 473        file = fopen("/etc/os-release", "r");
 474        if (file != NULL) {
 475                while (fgets(buf, sizeof(buf), file)) {
 476                        char *value, *q;
 477
 478                        /* Ignore comments */
 479                        if (buf[0] == '#')
 480                                continue;
 481
 482                        /* Split into name=value */
 483                        p = strchr(buf, '=');
 484                        if (!p)
 485                                continue;
 486                        *p++ = 0;
 487
 488                        /* Remove quotes and newline; un-escape */
 489                        value = p;
 490                        q = p;
 491                        while (*p) {
 492                                if (*p == '\\') {
 493                                        ++p;
 494                                        if (!*p)
 495                                                break;
 496                                        *q++ = *p++;
 497                                } else if (*p == '\'' || *p == '"' ||
 498                                           *p == '\n') {
 499                                        ++p;
 500                                } else {
 501                                        *q++ = *p++;
 502                                }
 503                        }
 504                        *q = 0;
 505
 506                        if (!strcmp(buf, "NAME")) {
 507                                p = strdup(value);
 508                                if (!p)
 509                                        break;
 510                                os_name = p;
 511                        } else if (!strcmp(buf, "VERSION_ID")) {
 512                                p = strdup(value);
 513                                if (!p)
 514                                        break;
 515                                os_major = p;
 516                        }
 517                }
 518                fclose(file);
 519                return;
 520        }
 521
 522        /* Fallback for older RH/SUSE releases */
 523        file = fopen("/etc/SuSE-release", "r");
 524        if (file != NULL)
 525                goto kvp_osinfo_found;
 526        file  = fopen("/etc/redhat-release", "r");
 527        if (file != NULL)
 528                goto kvp_osinfo_found;
 529
 530        /*
 531         * We don't have information about the os.
 532         */
 533        return;
 534
 535kvp_osinfo_found:
 536        /* up to three lines */
 537        p = fgets(buf, sizeof(buf), file);
 538        if (p) {
 539                p = strchr(buf, '\n');
 540                if (p)
 541                        *p = '\0';
 542                p = strdup(buf);
 543                if (!p)
 544                        goto done;
 545                os_name = p;
 546
 547                /* second line */
 548                p = fgets(buf, sizeof(buf), file);
 549                if (p) {
 550                        p = strchr(buf, '\n');
 551                        if (p)
 552                                *p = '\0';
 553                        p = strdup(buf);
 554                        if (!p)
 555                                goto done;
 556                        os_major = p;
 557
 558                        /* third line */
 559                        p = fgets(buf, sizeof(buf), file);
 560                        if (p)  {
 561                                p = strchr(buf, '\n');
 562                                if (p)
 563                                        *p = '\0';
 564                                p = strdup(buf);
 565                                if (p)
 566                                        os_minor = p;
 567                        }
 568                }
 569        }
 570
 571done:
 572        fclose(file);
 573        return;
 574}
 575
 576
 577
 578/*
 579 * Retrieve an interface name corresponding to the specified guid.
 580 * If there is a match, the function returns a pointer
 581 * to the interface name and if not, a NULL is returned.
 582 * If a match is found, the caller is responsible for
 583 * freeing the memory.
 584 */
 585
 586static char *kvp_get_if_name(char *guid)
 587{
 588        DIR *dir;
 589        struct dirent *entry;
 590        FILE    *file;
 591        char    *p, *q, *x;
 592        char    *if_name = NULL;
 593        char    buf[256];
 594        char *kvp_net_dir = "/sys/class/net/";
 595        char dev_id[256];
 596
 597        dir = opendir(kvp_net_dir);
 598        if (dir == NULL)
 599                return NULL;
 600
 601        snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
 602        q = dev_id + strlen(kvp_net_dir);
 603
 604        while ((entry = readdir(dir)) != NULL) {
 605                /*
 606                 * Set the state for the next pass.
 607                 */
 608                *q = '\0';
 609                strcat(dev_id, entry->d_name);
 610                strcat(dev_id, "/device/device_id");
 611
 612                file = fopen(dev_id, "r");
 613                if (file == NULL)
 614                        continue;
 615
 616                p = fgets(buf, sizeof(buf), file);
 617                if (p) {
 618                        x = strchr(p, '\n');
 619                        if (x)
 620                                *x = '\0';
 621
 622                        if (!strcmp(p, guid)) {
 623                                /*
 624                                 * Found the guid match; return the interface
 625                                 * name. The caller will free the memory.
 626                                 */
 627                                if_name = strdup(entry->d_name);
 628                                fclose(file);
 629                                break;
 630                        }
 631                }
 632                fclose(file);
 633        }
 634
 635        closedir(dir);
 636        return if_name;
 637}
 638
 639/*
 640 * Retrieve the MAC address given the interface name.
 641 */
 642
 643static char *kvp_if_name_to_mac(char *if_name)
 644{
 645        FILE    *file;
 646        char    *p, *x;
 647        char    buf[256];
 648        char addr_file[256];
 649        int i;
 650        char *mac_addr = NULL;
 651
 652        snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
 653                if_name, "/address");
 654
 655        file = fopen(addr_file, "r");
 656        if (file == NULL)
 657                return NULL;
 658
 659        p = fgets(buf, sizeof(buf), file);
 660        if (p) {
 661                x = strchr(p, '\n');
 662                if (x)
 663                        *x = '\0';
 664                for (i = 0; i < strlen(p); i++)
 665                        p[i] = toupper(p[i]);
 666                mac_addr = strdup(p);
 667        }
 668
 669        fclose(file);
 670        return mac_addr;
 671}
 672
 673
 674/*
 675 * Retrieve the interface name given tha MAC address.
 676 */
 677
 678static char *kvp_mac_to_if_name(char *mac)
 679{
 680        DIR *dir;
 681        struct dirent *entry;
 682        FILE    *file;
 683        char    *p, *q, *x;
 684        char    *if_name = NULL;
 685        char    buf[256];
 686        char *kvp_net_dir = "/sys/class/net/";
 687        char dev_id[256];
 688        int i;
 689
 690        dir = opendir(kvp_net_dir);
 691        if (dir == NULL)
 692                return NULL;
 693
 694        snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
 695        q = dev_id + strlen(kvp_net_dir);
 696
 697        while ((entry = readdir(dir)) != NULL) {
 698                /*
 699                 * Set the state for the next pass.
 700                 */
 701                *q = '\0';
 702
 703                strcat(dev_id, entry->d_name);
 704                strcat(dev_id, "/address");
 705
 706                file = fopen(dev_id, "r");
 707                if (file == NULL)
 708                        continue;
 709
 710                p = fgets(buf, sizeof(buf), file);
 711                if (p) {
 712                        x = strchr(p, '\n');
 713                        if (x)
 714                                *x = '\0';
 715
 716                        for (i = 0; i < strlen(p); i++)
 717                                p[i] = toupper(p[i]);
 718
 719                        if (!strcmp(p, mac)) {
 720                                /*
 721                                 * Found the MAC match; return the interface
 722                                 * name. The caller will free the memory.
 723                                 */
 724                                if_name = strdup(entry->d_name);
 725                                fclose(file);
 726                                break;
 727                        }
 728                }
 729                fclose(file);
 730        }
 731
 732        closedir(dir);
 733        return if_name;
 734}
 735
 736
 737static void kvp_process_ipconfig_file(char *cmd,
 738                                        char *config_buf, int len,
 739                                        int element_size, int offset)
 740{
 741        char buf[256];
 742        char *p;
 743        char *x;
 744        FILE *file;
 745
 746        /*
 747         * First execute the command.
 748         */
 749        file = popen(cmd, "r");
 750        if (file == NULL)
 751                return;
 752
 753        if (offset == 0)
 754                memset(config_buf, 0, len);
 755        while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
 756                if ((len - strlen(config_buf)) < (element_size + 1))
 757                        break;
 758
 759                x = strchr(p, '\n');
 760                *x = '\0';
 761                strcat(config_buf, p);
 762                strcat(config_buf, ";");
 763        }
 764        pclose(file);
 765}
 766
 767static void kvp_get_ipconfig_info(char *if_name,
 768                                 struct hv_kvp_ipaddr_value *buffer)
 769{
 770        char cmd[512];
 771        char dhcp_info[128];
 772        char *p;
 773        FILE *file;
 774
 775        /*
 776         * Get the address of default gateway (ipv4).
 777         */
 778        sprintf(cmd, "%s %s", "ip route show dev", if_name);
 779        strcat(cmd, " | awk '/default/ {print $3 }'");
 780
 781        /*
 782         * Execute the command to gather gateway info.
 783         */
 784        kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
 785                                (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
 786
 787        /*
 788         * Get the address of default gateway (ipv6).
 789         */
 790        sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
 791        strcat(cmd, " | awk '/default/ {print $3 }'");
 792
 793        /*
 794         * Execute the command to gather gateway info (ipv6).
 795         */
 796        kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
 797                                (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
 798
 799
 800        /*
 801         * Gather the DNS  state.
 802         * Since there is no standard way to get this information
 803         * across various distributions of interest; we just invoke
 804         * an external script that needs to be ported across distros
 805         * of interest.
 806         *
 807         * Following is the expected format of the information from the script:
 808         *
 809         * ipaddr1 (nameserver1)
 810         * ipaddr2 (nameserver2)
 811         * .
 812         * .
 813         */
 814
 815        sprintf(cmd, "%s",  "hv_get_dns_info");
 816
 817        /*
 818         * Execute the command to gather DNS info.
 819         */
 820        kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
 821                                (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
 822
 823        /*
 824         * Gather the DHCP state.
 825         * We will gather this state by invoking an external script.
 826         * The parameter to the script is the interface name.
 827         * Here is the expected output:
 828         *
 829         * Enabled: DHCP enabled.
 830         */
 831
 832        sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
 833
 834        file = popen(cmd, "r");
 835        if (file == NULL)
 836                return;
 837
 838        p = fgets(dhcp_info, sizeof(dhcp_info), file);
 839        if (p == NULL) {
 840                pclose(file);
 841                return;
 842        }
 843
 844        if (!strncmp(p, "Enabled", 7))
 845                buffer->dhcp_enabled = 1;
 846        else
 847                buffer->dhcp_enabled = 0;
 848
 849        pclose(file);
 850}
 851
 852
 853static unsigned int hweight32(unsigned int *w)
 854{
 855        unsigned int res = *w - ((*w >> 1) & 0x55555555);
 856        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
 857        res = (res + (res >> 4)) & 0x0F0F0F0F;
 858        res = res + (res >> 8);
 859        return (res + (res >> 16)) & 0x000000FF;
 860}
 861
 862static int kvp_process_ip_address(void *addrp,
 863                                int family, char *buffer,
 864                                int length,  int *offset)
 865{
 866        struct sockaddr_in *addr;
 867        struct sockaddr_in6 *addr6;
 868        int addr_length;
 869        char tmp[50];
 870        const char *str;
 871
 872        if (family == AF_INET) {
 873                addr = (struct sockaddr_in *)addrp;
 874                str = inet_ntop(family, &addr->sin_addr, tmp, 50);
 875                addr_length = INET_ADDRSTRLEN;
 876        } else {
 877                addr6 = (struct sockaddr_in6 *)addrp;
 878                str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
 879                addr_length = INET6_ADDRSTRLEN;
 880        }
 881
 882        if ((length - *offset) < addr_length + 1)
 883                return HV_E_FAIL;
 884        if (str == NULL) {
 885                strcpy(buffer, "inet_ntop failed\n");
 886                return HV_E_FAIL;
 887        }
 888        if (*offset == 0)
 889                strcpy(buffer, tmp);
 890        else
 891                strcat(buffer, tmp);
 892        strcat(buffer, ";");
 893
 894        *offset += strlen(str) + 1;
 895        return 0;
 896}
 897
 898static int
 899kvp_get_ip_info(int family, char *if_name, int op,
 900                 void  *out_buffer, int length)
 901{
 902        struct ifaddrs *ifap;
 903        struct ifaddrs *curp;
 904        int offset = 0;
 905        int sn_offset = 0;
 906        int error = 0;
 907        char *buffer;
 908        struct hv_kvp_ipaddr_value *ip_buffer;
 909        char cidr_mask[5]; /* /xyz */
 910        int weight;
 911        int i;
 912        unsigned int *w;
 913        char *sn_str;
 914        struct sockaddr_in6 *addr6;
 915
 916        if (op == KVP_OP_ENUMERATE) {
 917                buffer = out_buffer;
 918        } else {
 919                ip_buffer = out_buffer;
 920                buffer = (char *)ip_buffer->ip_addr;
 921                ip_buffer->addr_family = 0;
 922        }
 923        /*
 924         * On entry into this function, the buffer is capable of holding the
 925         * maximum key value.
 926         */
 927
 928        if (getifaddrs(&ifap)) {
 929                strcpy(buffer, "getifaddrs failed\n");
 930                return HV_E_FAIL;
 931        }
 932
 933        curp = ifap;
 934        while (curp != NULL) {
 935                if (curp->ifa_addr == NULL) {
 936                        curp = curp->ifa_next;
 937                        continue;
 938                }
 939
 940                if ((if_name != NULL) &&
 941                        (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
 942                        /*
 943                         * We want info about a specific interface;
 944                         * just continue.
 945                         */
 946                        curp = curp->ifa_next;
 947                        continue;
 948                }
 949
 950                /*
 951                 * We only support two address families: AF_INET and AF_INET6.
 952                 * If a family value of 0 is specified, we collect both
 953                 * supported address families; if not we gather info on
 954                 * the specified address family.
 955                 */
 956                if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
 957                        curp = curp->ifa_next;
 958                        continue;
 959                }
 960                if ((curp->ifa_addr->sa_family != AF_INET) &&
 961                        (curp->ifa_addr->sa_family != AF_INET6)) {
 962                        curp = curp->ifa_next;
 963                        continue;
 964                }
 965
 966                if (op == KVP_OP_GET_IP_INFO) {
 967                        /*
 968                         * Gather info other than the IP address.
 969                         * IP address info will be gathered later.
 970                         */
 971                        if (curp->ifa_addr->sa_family == AF_INET) {
 972                                ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
 973                                /*
 974                                 * Get subnet info.
 975                                 */
 976                                error = kvp_process_ip_address(
 977                                                             curp->ifa_netmask,
 978                                                             AF_INET,
 979                                                             (char *)
 980                                                             ip_buffer->sub_net,
 981                                                             length,
 982                                                             &sn_offset);
 983                                if (error)
 984                                        goto gather_ipaddr;
 985                        } else {
 986                                ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
 987
 988                                /*
 989                                 * Get subnet info in CIDR format.
 990                                 */
 991                                weight = 0;
 992                                sn_str = (char *)ip_buffer->sub_net;
 993                                addr6 = (struct sockaddr_in6 *)
 994                                        curp->ifa_netmask;
 995                                w = addr6->sin6_addr.s6_addr32;
 996
 997                                for (i = 0; i < 4; i++)
 998                                        weight += hweight32(&w[i]);
 999
1000                                sprintf(cidr_mask, "/%d", weight);
1001                                if ((length - sn_offset) <
1002                                        (strlen(cidr_mask) + 1))
1003                                        goto gather_ipaddr;
1004
1005                                if (sn_offset == 0)
1006                                        strcpy(sn_str, cidr_mask);
1007                                else
1008                                        strcat(sn_str, cidr_mask);
1009                                strcat((char *)ip_buffer->sub_net, ";");
1010                                sn_offset += strlen(sn_str) + 1;
1011                        }
1012
1013                        /*
1014                         * Collect other ip related configuration info.
1015                         */
1016
1017                        kvp_get_ipconfig_info(if_name, ip_buffer);
1018                }
1019
1020gather_ipaddr:
1021                error = kvp_process_ip_address(curp->ifa_addr,
1022                                                curp->ifa_addr->sa_family,
1023                                                buffer,
1024                                                length, &offset);
1025                if (error)
1026                        goto getaddr_done;
1027
1028                curp = curp->ifa_next;
1029        }
1030
1031getaddr_done:
1032        freeifaddrs(ifap);
1033        return error;
1034}
1035
1036
1037static int expand_ipv6(char *addr, int type)
1038{
1039        int ret;
1040        struct in6_addr v6_addr;
1041
1042        ret = inet_pton(AF_INET6, addr, &v6_addr);
1043
1044        if (ret != 1) {
1045                if (type == NETMASK)
1046                        return 1;
1047                return 0;
1048        }
1049
1050        sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1051                "%02x%02x:%02x%02x:%02x%02x",
1052                (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1053                (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1054                (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1055                (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1056                (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1057                (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1058                (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1059                (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1060
1061        return 1;
1062
1063}
1064
1065static int is_ipv4(char *addr)
1066{
1067        int ret;
1068        struct in_addr ipv4_addr;
1069
1070        ret = inet_pton(AF_INET, addr, &ipv4_addr);
1071
1072        if (ret == 1)
1073                return 1;
1074        return 0;
1075}
1076
1077static int parse_ip_val_buffer(char *in_buf, int *offset,
1078                                char *out_buf, int out_len)
1079{
1080        char *x;
1081        char *start;
1082
1083        /*
1084         * in_buf has sequence of characters that are seperated by
1085         * the character ';'. The last sequence does not have the
1086         * terminating ";" character.
1087         */
1088        start = in_buf + *offset;
1089
1090        x = strchr(start, ';');
1091        if (x)
1092                *x = 0;
1093        else
1094                x = start + strlen(start);
1095
1096        if (strlen(start) != 0) {
1097                int i = 0;
1098                /*
1099                 * Get rid of leading spaces.
1100                 */
1101                while (start[i] == ' ')
1102                        i++;
1103
1104                if ((x - start) <= out_len) {
1105                        strcpy(out_buf, (start + i));
1106                        *offset += (x - start) + 1;
1107                        return 1;
1108                }
1109        }
1110        return 0;
1111}
1112
1113static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1114{
1115        int ret;
1116
1117        ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1118
1119        if (ret < 0)
1120                return HV_E_FAIL;
1121
1122        return 0;
1123}
1124
1125
1126static int process_ip_string(FILE *f, char *ip_string, int type)
1127{
1128        int error = 0;
1129        char addr[INET6_ADDRSTRLEN];
1130        int i = 0;
1131        int j = 0;
1132        char str[256];
1133        char sub_str[10];
1134        int offset = 0;
1135
1136        memset(addr, 0, sizeof(addr));
1137
1138        while (parse_ip_val_buffer(ip_string, &offset, addr,
1139                                        (MAX_IP_ADDR_SIZE * 2))) {
1140
1141                sub_str[0] = 0;
1142                if (is_ipv4(addr)) {
1143                        switch (type) {
1144                        case IPADDR:
1145                                snprintf(str, sizeof(str), "%s", "IPADDR");
1146                                break;
1147                        case NETMASK:
1148                                snprintf(str, sizeof(str), "%s", "NETMASK");
1149                                break;
1150                        case GATEWAY:
1151                                snprintf(str, sizeof(str), "%s", "GATEWAY");
1152                                break;
1153                        case DNS:
1154                                snprintf(str, sizeof(str), "%s", "DNS");
1155                                break;
1156                        }
1157                        if (i != 0) {
1158                                if (type != DNS) {
1159                                        snprintf(sub_str, sizeof(sub_str),
1160                                                "_%d", i++);
1161                                } else {
1162                                        snprintf(sub_str, sizeof(sub_str),
1163                                                "%d", ++i);
1164                                }
1165                        } else if (type == DNS) {
1166                                snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1167                        }
1168
1169
1170                } else if (expand_ipv6(addr, type)) {
1171                        switch (type) {
1172                        case IPADDR:
1173                                snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1174                                break;
1175                        case NETMASK:
1176                                snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1177                                break;
1178                        case GATEWAY:
1179                                snprintf(str, sizeof(str), "%s",
1180                                        "IPV6_DEFAULTGW");
1181                                break;
1182                        case DNS:
1183                                snprintf(str, sizeof(str), "%s",  "DNS");
1184                                break;
1185                        }
1186                        if ((j != 0) || (type == DNS)) {
1187                                if (type != DNS) {
1188                                        snprintf(sub_str, sizeof(sub_str),
1189                                                "_%d", j++);
1190                                } else {
1191                                        snprintf(sub_str, sizeof(sub_str),
1192                                                "%d", ++i);
1193                                }
1194                        } else if (type == DNS) {
1195                                snprintf(sub_str, sizeof(sub_str),
1196                                        "%d", ++i);
1197                        }
1198                } else {
1199                        return  HV_INVALIDARG;
1200                }
1201
1202                error = kvp_write_file(f, str, sub_str, addr);
1203                if (error)
1204                        return error;
1205                memset(addr, 0, sizeof(addr));
1206        }
1207
1208        return 0;
1209}
1210
1211static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1212{
1213        int error = 0;
1214        char if_file[128];
1215        FILE *file;
1216        char cmd[512];
1217        char *mac_addr;
1218
1219        /*
1220         * Set the configuration for the specified interface with
1221         * the information provided. Since there is no standard
1222         * way to configure an interface, we will have an external
1223         * script that does the job of configuring the interface and
1224         * flushing the configuration.
1225         *
1226         * The parameters passed to this external script are:
1227         * 1. A configuration file that has the specified configuration.
1228         *
1229         * We will embed the name of the interface in the configuration
1230         * file: ifcfg-ethx (where ethx is the interface name).
1231         *
1232         * The information provided here may be more than what is needed
1233         * in a given distro to configure the interface and so are free
1234         * ignore information that may not be relevant.
1235         *
1236         * Here is the format of the ip configuration file:
1237         *
1238         * HWADDR=macaddr
1239         * IF_NAME=interface name
1240         * DHCP=yes (This is optional; if yes, DHCP is configured)
1241         *
1242         * IPADDR=ipaddr1
1243         * IPADDR_1=ipaddr2
1244         * IPADDR_x=ipaddry (where y = x + 1)
1245         *
1246         * NETMASK=netmask1
1247         * NETMASK_x=netmasky (where y = x + 1)
1248         *
1249         * GATEWAY=ipaddr1
1250         * GATEWAY_x=ipaddry (where y = x + 1)
1251         *
1252         * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1253         *
1254         * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1255         * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1256         * IPV6NETMASK.
1257         *
1258         * The host can specify multiple ipv4 and ipv6 addresses to be
1259         * configured for the interface. Furthermore, the configuration
1260         * needs to be persistent. A subsequent GET call on the interface
1261         * is expected to return the configuration that is set via the SET
1262         * call.
1263         */
1264
1265        snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1266                "hyperv/ifcfg-", if_name);
1267
1268        file = fopen(if_file, "w");
1269
1270        if (file == NULL) {
1271                syslog(LOG_ERR, "Failed to open config file");
1272                return HV_E_FAIL;
1273        }
1274
1275        /*
1276         * First write out the MAC address.
1277         */
1278
1279        mac_addr = kvp_if_name_to_mac(if_name);
1280        if (mac_addr == NULL) {
1281                error = HV_E_FAIL;
1282                goto setval_error;
1283        }
1284
1285        error = kvp_write_file(file, "HWADDR", "", mac_addr);
1286        if (error)
1287                goto setval_error;
1288
1289        error = kvp_write_file(file, "IF_NAME", "", if_name);
1290        if (error)
1291                goto setval_error;
1292
1293        if (new_val->dhcp_enabled) {
1294                error = kvp_write_file(file, "DHCP", "", "yes");
1295                if (error)
1296                        goto setval_error;
1297
1298                /*
1299                 * We are done!.
1300                 */
1301                goto setval_done;
1302        }
1303
1304        /*
1305         * Write the configuration for ipaddress, netmask, gateway and
1306         * name servers.
1307         */
1308
1309        error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1310        if (error)
1311                goto setval_error;
1312
1313        error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1314        if (error)
1315                goto setval_error;
1316
1317        error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1318        if (error)
1319                goto setval_error;
1320
1321        error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1322        if (error)
1323                goto setval_error;
1324
1325setval_done:
1326        free(mac_addr);
1327        fclose(file);
1328
1329        /*
1330         * Now that we have populated the configuration file,
1331         * invoke the external script to do its magic.
1332         */
1333
1334        snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1335        system(cmd);
1336        return 0;
1337
1338setval_error:
1339        syslog(LOG_ERR, "Failed to write config file");
1340        free(mac_addr);
1341        fclose(file);
1342        return error;
1343}
1344
1345
1346static int
1347kvp_get_domain_name(char *buffer, int length)
1348{
1349        struct addrinfo hints, *info ;
1350        int error = 0;
1351
1352        gethostname(buffer, length);
1353        memset(&hints, 0, sizeof(hints));
1354        hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1355        hints.ai_socktype = SOCK_STREAM;
1356        hints.ai_flags = AI_CANONNAME;
1357
1358        error = getaddrinfo(buffer, NULL, &hints, &info);
1359        if (error != 0) {
1360                strcpy(buffer, "getaddrinfo failed\n");
1361                return error;
1362        }
1363        strcpy(buffer, info->ai_canonname);
1364        freeaddrinfo(info);
1365        return error;
1366}
1367
1368static int
1369netlink_send(int fd, struct cn_msg *msg)
1370{
1371        struct nlmsghdr *nlh;
1372        unsigned int size;
1373        struct msghdr message;
1374        char buffer[64];
1375        struct iovec iov[2];
1376
1377        size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
1378
1379        nlh = (struct nlmsghdr *)buffer;
1380        nlh->nlmsg_seq = 0;
1381        nlh->nlmsg_pid = getpid();
1382        nlh->nlmsg_type = NLMSG_DONE;
1383        nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
1384        nlh->nlmsg_flags = 0;
1385
1386        iov[0].iov_base = nlh;
1387        iov[0].iov_len = sizeof(*nlh);
1388
1389        iov[1].iov_base = msg;
1390        iov[1].iov_len = size;
1391
1392        memset(&message, 0, sizeof(message));
1393        message.msg_name = &addr;
1394        message.msg_namelen = sizeof(addr);
1395        message.msg_iov = iov;
1396        message.msg_iovlen = 2;
1397
1398        return sendmsg(fd, &message, 0);
1399}
1400
1401int main(void)
1402{
1403        int fd, len, sock_opt;
1404        int error;
1405        struct cn_msg *message;
1406        struct pollfd pfd;
1407        struct nlmsghdr *incoming_msg;
1408        struct cn_msg   *incoming_cn_msg;
1409        struct hv_kvp_msg *hv_msg;
1410        char    *p;
1411        char    *key_value;
1412        char    *key_name;
1413        int     op;
1414        int     pool;
1415        char    *if_name;
1416        struct hv_kvp_ipaddr_value *kvp_ip_val;
1417
1418        daemon(1, 0);
1419        openlog("KVP", 0, LOG_USER);
1420        syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1421        /*
1422         * Retrieve OS release information.
1423         */
1424        kvp_get_os_info();
1425
1426        if (kvp_file_init()) {
1427                syslog(LOG_ERR, "Failed to initialize the pools");
1428                exit(EXIT_FAILURE);
1429        }
1430
1431        fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1432        if (fd < 0) {
1433                syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
1434                exit(EXIT_FAILURE);
1435        }
1436        addr.nl_family = AF_NETLINK;
1437        addr.nl_pad = 0;
1438        addr.nl_pid = 0;
1439        addr.nl_groups = CN_KVP_IDX;
1440
1441
1442        error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1443        if (error < 0) {
1444                syslog(LOG_ERR, "bind failed; error:%d", error);
1445                close(fd);
1446                exit(EXIT_FAILURE);
1447        }
1448        sock_opt = addr.nl_groups;
1449        setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
1450        /*
1451         * Register ourselves with the kernel.
1452         */
1453        message = (struct cn_msg *)kvp_send_buffer;
1454        message->id.idx = CN_KVP_IDX;
1455        message->id.val = CN_KVP_VAL;
1456
1457        hv_msg = (struct hv_kvp_msg *)message->data;
1458        hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1459        message->ack = 0;
1460        message->len = sizeof(struct hv_kvp_msg);
1461
1462        len = netlink_send(fd, message);
1463        if (len < 0) {
1464                syslog(LOG_ERR, "netlink_send failed; error:%d", len);
1465                close(fd);
1466                exit(EXIT_FAILURE);
1467        }
1468
1469        pfd.fd = fd;
1470
1471        while (1) {
1472                struct sockaddr *addr_p = (struct sockaddr *) &addr;
1473                socklen_t addr_l = sizeof(addr);
1474                pfd.events = POLLIN;
1475                pfd.revents = 0;
1476                poll(&pfd, 1, -1);
1477
1478                len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
1479                                addr_p, &addr_l);
1480
1481                if (len < 0 || addr.nl_pid) {
1482                        syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1483                                        addr.nl_pid, errno, strerror(errno));
1484                        close(fd);
1485                        return -1;
1486                }
1487
1488                incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1489                incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1490                hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1491
1492                /*
1493                 * We will use the KVP header information to pass back
1494                 * the error from this daemon. So, first copy the state
1495                 * and set the error code to success.
1496                 */
1497                op = hv_msg->kvp_hdr.operation;
1498                pool = hv_msg->kvp_hdr.pool;
1499                hv_msg->error = HV_S_OK;
1500
1501                if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1502                        /*
1503                         * Driver is registering with us; stash away the version
1504                         * information.
1505                         */
1506                        in_hand_shake = 0;
1507                        p = (char *)hv_msg->body.kvp_register.version;
1508                        lic_version = malloc(strlen(p) + 1);
1509                        if (lic_version) {
1510                                strcpy(lic_version, p);
1511                                syslog(LOG_INFO, "KVP LIC Version: %s",
1512                                        lic_version);
1513                        } else {
1514                                syslog(LOG_ERR, "malloc failed");
1515                        }
1516                        continue;
1517                }
1518
1519                switch (op) {
1520                case KVP_OP_GET_IP_INFO:
1521                        kvp_ip_val = &hv_msg->body.kvp_ip_val;
1522                        if_name =
1523                        kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1524
1525                        if (if_name == NULL) {
1526                                /*
1527                                 * We could not map the mac address to an
1528                                 * interface name; return error.
1529                                 */
1530                                hv_msg->error = HV_E_FAIL;
1531                                break;
1532                        }
1533                        error = kvp_get_ip_info(
1534                                                0, if_name, KVP_OP_GET_IP_INFO,
1535                                                kvp_ip_val,
1536                                                (MAX_IP_ADDR_SIZE * 2));
1537
1538                        if (error)
1539                                hv_msg->error = error;
1540
1541                        free(if_name);
1542                        break;
1543
1544                case KVP_OP_SET_IP_INFO:
1545                        kvp_ip_val = &hv_msg->body.kvp_ip_val;
1546                        if_name = kvp_get_if_name(
1547                                        (char *)kvp_ip_val->adapter_id);
1548                        if (if_name == NULL) {
1549                                /*
1550                                 * We could not map the guid to an
1551                                 * interface name; return error.
1552                                 */
1553                                hv_msg->error = HV_GUID_NOTFOUND;
1554                                break;
1555                        }
1556                        error = kvp_set_ip_info(if_name, kvp_ip_val);
1557                        if (error)
1558                                hv_msg->error = error;
1559
1560                        free(if_name);
1561                        break;
1562
1563                case KVP_OP_SET:
1564                        if (kvp_key_add_or_modify(pool,
1565                                        hv_msg->body.kvp_set.data.key,
1566                                        hv_msg->body.kvp_set.data.key_size,
1567                                        hv_msg->body.kvp_set.data.value,
1568                                        hv_msg->body.kvp_set.data.value_size))
1569                                        hv_msg->error = HV_S_CONT;
1570                        break;
1571
1572                case KVP_OP_GET:
1573                        if (kvp_get_value(pool,
1574                                        hv_msg->body.kvp_set.data.key,
1575                                        hv_msg->body.kvp_set.data.key_size,
1576                                        hv_msg->body.kvp_set.data.value,
1577                                        hv_msg->body.kvp_set.data.value_size))
1578                                        hv_msg->error = HV_S_CONT;
1579                        break;
1580
1581                case KVP_OP_DELETE:
1582                        if (kvp_key_delete(pool,
1583                                        hv_msg->body.kvp_delete.key,
1584                                        hv_msg->body.kvp_delete.key_size))
1585                                        hv_msg->error = HV_S_CONT;
1586                        break;
1587
1588                default:
1589                        break;
1590                }
1591
1592                if (op != KVP_OP_ENUMERATE)
1593                        goto kvp_done;
1594
1595                /*
1596                 * If the pool is KVP_POOL_AUTO, dynamically generate
1597                 * both the key and the value; if not read from the
1598                 * appropriate pool.
1599                 */
1600                if (pool != KVP_POOL_AUTO) {
1601                        if (kvp_pool_enumerate(pool,
1602                                        hv_msg->body.kvp_enum_data.index,
1603                                        hv_msg->body.kvp_enum_data.data.key,
1604                                        HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1605                                        hv_msg->body.kvp_enum_data.data.value,
1606                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1607                                        hv_msg->error = HV_S_CONT;
1608                        goto kvp_done;
1609                }
1610
1611                hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1612                key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1613                key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1614
1615                switch (hv_msg->body.kvp_enum_data.index) {
1616                case FullyQualifiedDomainName:
1617                        kvp_get_domain_name(key_value,
1618                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1619                        strcpy(key_name, "FullyQualifiedDomainName");
1620                        break;
1621                case IntegrationServicesVersion:
1622                        strcpy(key_name, "IntegrationServicesVersion");
1623                        strcpy(key_value, lic_version);
1624                        break;
1625                case NetworkAddressIPv4:
1626                        kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1627                                key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1628                        strcpy(key_name, "NetworkAddressIPv4");
1629                        break;
1630                case NetworkAddressIPv6:
1631                        kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1632                                key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1633                        strcpy(key_name, "NetworkAddressIPv6");
1634                        break;
1635                case OSBuildNumber:
1636                        strcpy(key_value, os_build);
1637                        strcpy(key_name, "OSBuildNumber");
1638                        break;
1639                case OSName:
1640                        strcpy(key_value, os_name);
1641                        strcpy(key_name, "OSName");
1642                        break;
1643                case OSMajorVersion:
1644                        strcpy(key_value, os_major);
1645                        strcpy(key_name, "OSMajorVersion");
1646                        break;
1647                case OSMinorVersion:
1648                        strcpy(key_value, os_minor);
1649                        strcpy(key_name, "OSMinorVersion");
1650                        break;
1651                case OSVersion:
1652                        strcpy(key_value, os_build);
1653                        strcpy(key_name, "OSVersion");
1654                        break;
1655                case ProcessorArchitecture:
1656                        strcpy(key_value, processor_arch);
1657                        strcpy(key_name, "ProcessorArchitecture");
1658                        break;
1659                default:
1660                        hv_msg->error = HV_S_CONT;
1661                        break;
1662                }
1663                /*
1664                 * Send the value back to the kernel. The response is
1665                 * already in the receive buffer. Update the cn_msg header to
1666                 * reflect the key value that has been added to the message
1667                 */
1668kvp_done:
1669
1670                incoming_cn_msg->id.idx = CN_KVP_IDX;
1671                incoming_cn_msg->id.val = CN_KVP_VAL;
1672                incoming_cn_msg->ack = 0;
1673                incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1674
1675                len = netlink_send(fd, incoming_cn_msg);
1676                if (len < 0) {
1677                        syslog(LOG_ERR, "net_link send failed; error:%d", len);
1678                        exit(EXIT_FAILURE);
1679                }
1680        }
1681
1682}
1683
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.