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 <errno.h>
  35#include <arpa/inet.h>
  36#include <linux/connector.h>
  37#include <linux/hyperv.h>
  38#include <linux/netlink.h>
  39#include <ifaddrs.h>
  40#include <netdb.h>
  41#include <syslog.h>
  42#include <sys/stat.h>
  43#include <fcntl.h>
  44
  45/*
  46 * KVP protocol: The user mode component first registers with the
  47 * the kernel component. Subsequently, the kernel component requests, data
  48 * for the specified keys. In response to this message the user mode component
  49 * fills in the value corresponding to the specified key. We overload the
  50 * sequence field in the cn_msg header to define our KVP message types.
  51 *
  52 * We use this infrastructure for also supporting queries from user mode
  53 * application for state that may be maintained in the KVP kernel component.
  54 *
  55 */
  56
  57
  58enum key_index {
  59        FullyQualifiedDomainName = 0,
  60        IntegrationServicesVersion, /*This key is serviced in the kernel*/
  61        NetworkAddressIPv4,
  62        NetworkAddressIPv6,
  63        OSBuildNumber,
  64        OSName,
  65        OSMajorVersion,
  66        OSMinorVersion,
  67        OSVersion,
  68        ProcessorArchitecture
  69};
  70
  71static char kvp_send_buffer[4096];
  72static char kvp_recv_buffer[4096];
  73static struct sockaddr_nl addr;
  74
  75static char *os_name = "";
  76static char *os_major = "";
  77static char *os_minor = "";
  78static char *processor_arch;
  79static char *os_build;
  80static char *lic_version;
  81static struct utsname uts_buf;
  82
  83
  84#define MAX_FILE_NAME 100
  85#define ENTRIES_PER_BLOCK 50
  86
  87struct kvp_record {
  88        __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
  89        __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
  90};
  91
  92struct kvp_file_state {
  93        int fd;
  94        int num_blocks;
  95        struct kvp_record *records;
  96        int num_records;
  97        __u8 fname[MAX_FILE_NAME];
  98};
  99
 100static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
 101
 102static void kvp_acquire_lock(int pool)
 103{
 104        struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
 105        fl.l_pid = getpid();
 106
 107        if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
 108                syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
 109                exit(EXIT_FAILURE);
 110        }
 111}
 112
 113static void kvp_release_lock(int pool)
 114{
 115        struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
 116        fl.l_pid = getpid();
 117
 118        if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
 119                perror("fcntl");
 120                syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
 121                exit(EXIT_FAILURE);
 122        }
 123}
 124
 125static void kvp_update_file(int pool)
 126{
 127        FILE *filep;
 128        size_t bytes_written;
 129
 130        /*
 131         * We are going to write our in-memory registry out to
 132         * disk; acquire the lock first.
 133         */
 134        kvp_acquire_lock(pool);
 135
 136        filep = fopen(kvp_file_info[pool].fname, "w");
 137        if (!filep) {
 138                kvp_release_lock(pool);
 139                syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
 140                exit(EXIT_FAILURE);
 141        }
 142
 143        bytes_written = fwrite(kvp_file_info[pool].records,
 144                                sizeof(struct kvp_record),
 145                                kvp_file_info[pool].num_records, filep);
 146
 147        if (ferror(filep) || fclose(filep)) {
 148                kvp_release_lock(pool);
 149                syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
 150                exit(EXIT_FAILURE);
 151        }
 152
 153        kvp_release_lock(pool);
 154}
 155
 156static void kvp_update_mem_state(int pool)
 157{
 158        FILE *filep;
 159        size_t records_read = 0;
 160        struct kvp_record *record = kvp_file_info[pool].records;
 161        struct kvp_record *readp;
 162        int num_blocks = kvp_file_info[pool].num_blocks;
 163        int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 164
 165        kvp_acquire_lock(pool);
 166
 167        filep = fopen(kvp_file_info[pool].fname, "r");
 168        if (!filep) {
 169                kvp_release_lock(pool);
 170                syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
 171                exit(EXIT_FAILURE);
 172        }
 173        for (;;) {
 174                readp = &record[records_read];
 175                records_read += fread(readp, sizeof(struct kvp_record),
 176                                        ENTRIES_PER_BLOCK * num_blocks,
 177                                        filep);
 178
 179                if (ferror(filep)) {
 180                        syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
 181                        exit(EXIT_FAILURE);
 182                }
 183
 184                if (!feof(filep)) {
 185                        /*
 186                         * We have more data to read.
 187                         */
 188                        num_blocks++;
 189                        record = realloc(record, alloc_unit * num_blocks);
 190
 191                        if (record == NULL) {
 192                                syslog(LOG_ERR, "malloc failed");
 193                                exit(EXIT_FAILURE);
 194                        }
 195                        continue;
 196                }
 197                break;
 198        }
 199
 200        kvp_file_info[pool].num_blocks = num_blocks;
 201        kvp_file_info[pool].records = record;
 202        kvp_file_info[pool].num_records = records_read;
 203
 204        fclose(filep);
 205        kvp_release_lock(pool);
 206}
 207static int kvp_file_init(void)
 208{
 209        int ret, fd;
 210        FILE *filep;
 211        size_t records_read;
 212        __u8 *fname;
 213        struct kvp_record *record;
 214        struct kvp_record *readp;
 215        int num_blocks;
 216        int i;
 217        int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
 218
 219        if (access("/var/opt/hyperv", F_OK)) {
 220                if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
 221                        syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
 222                        exit(EXIT_FAILURE);
 223                }
 224        }
 225
 226        for (i = 0; i < KVP_POOL_COUNT; i++) {
 227                fname = kvp_file_info[i].fname;
 228                records_read = 0;
 229                num_blocks = 1;
 230                sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
 231                fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
 232
 233                if (fd == -1)
 234                        return 1;
 235
 236
 237                filep = fopen(fname, "r");
 238                if (!filep)
 239                        return 1;
 240
 241                record = malloc(alloc_unit * num_blocks);
 242                if (record == NULL) {
 243                        fclose(filep);
 244                        return 1;
 245                }
 246                for (;;) {
 247                        readp = &record[records_read];
 248                        records_read += fread(readp, sizeof(struct kvp_record),
 249                                        ENTRIES_PER_BLOCK,
 250                                        filep);
 251
 252                        if (ferror(filep)) {
 253                                syslog(LOG_ERR, "Failed to read file, pool: %d",
 254                                       i);
 255                                exit(EXIT_FAILURE);
 256                        }
 257
 258                        if (!feof(filep)) {
 259                                /*
 260                                 * We have more data to read.
 261                                 */
 262                                num_blocks++;
 263                                record = realloc(record, alloc_unit *
 264                                                num_blocks);
 265                                if (record == NULL) {
 266                                        fclose(filep);
 267                                        return 1;
 268                                }
 269                                continue;
 270                        }
 271                        break;
 272                }
 273                kvp_file_info[i].fd = fd;
 274                kvp_file_info[i].num_blocks = num_blocks;
 275                kvp_file_info[i].records = record;
 276                kvp_file_info[i].num_records = records_read;
 277                fclose(filep);
 278
 279        }
 280
 281        return 0;
 282}
 283
 284static int kvp_key_delete(int pool, __u8 *key, int key_size)
 285{
 286        int i;
 287        int j, k;
 288        int num_records;
 289        struct kvp_record *record;
 290
 291        /*
 292         * First update the in-memory state.
 293         */
 294        kvp_update_mem_state(pool);
 295
 296        num_records = kvp_file_info[pool].num_records;
 297        record = kvp_file_info[pool].records;
 298
 299        for (i = 0; i < num_records; i++) {
 300                if (memcmp(key, record[i].key, key_size))
 301                        continue;
 302                /*
 303                 * Found a match; just move the remaining
 304                 * entries up.
 305                 */
 306                if (i == num_records) {
 307                        kvp_file_info[pool].num_records--;
 308                        kvp_update_file(pool);
 309                        return 0;
 310                }
 311
 312                j = i;
 313                k = j + 1;
 314                for (; k < num_records; k++) {
 315                        strcpy(record[j].key, record[k].key);
 316                        strcpy(record[j].value, record[k].value);
 317                        j++;
 318                }
 319
 320                kvp_file_info[pool].num_records--;
 321                kvp_update_file(pool);
 322                return 0;
 323        }
 324        return 1;
 325}
 326
 327static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
 328                        int value_size)
 329{
 330        int i;
 331        int j, k;
 332        int num_records;
 333        struct kvp_record *record;
 334        int num_blocks;
 335
 336        if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 337                (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
 338                return 1;
 339
 340        /*
 341         * First update the in-memory state.
 342         */
 343        kvp_update_mem_state(pool);
 344
 345        num_records = kvp_file_info[pool].num_records;
 346        record = kvp_file_info[pool].records;
 347        num_blocks = kvp_file_info[pool].num_blocks;
 348
 349        for (i = 0; i < num_records; i++) {
 350                if (memcmp(key, record[i].key, key_size))
 351                        continue;
 352                /*
 353                 * Found a match; just update the value -
 354                 * this is the modify case.
 355                 */
 356                memcpy(record[i].value, value, value_size);
 357                kvp_update_file(pool);
 358                return 0;
 359        }
 360
 361        /*
 362         * Need to add a new entry;
 363         */
 364        if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
 365                /* Need to allocate a larger array for reg entries. */
 366                record = realloc(record, sizeof(struct kvp_record) *
 367                         ENTRIES_PER_BLOCK * (num_blocks + 1));
 368
 369                if (record == NULL)
 370                        return 1;
 371                kvp_file_info[pool].num_blocks++;
 372
 373        }
 374        memcpy(record[i].value, value, value_size);
 375        memcpy(record[i].key, key, key_size);
 376        kvp_file_info[pool].records = record;
 377        kvp_file_info[pool].num_records++;
 378        kvp_update_file(pool);
 379        return 0;
 380}
 381
 382static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
 383                        int value_size)
 384{
 385        int i;
 386        int num_records;
 387        struct kvp_record *record;
 388
 389        if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
 390                (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
 391                return 1;
 392
 393        /*
 394         * First update the in-memory state.
 395         */
 396        kvp_update_mem_state(pool);
 397
 398        num_records = kvp_file_info[pool].num_records;
 399        record = kvp_file_info[pool].records;
 400
 401        for (i = 0; i < num_records; i++) {
 402                if (memcmp(key, record[i].key, key_size))
 403                        continue;
 404                /*
 405                 * Found a match; just copy the value out.
 406                 */
 407                memcpy(value, record[i].value, value_size);
 408                return 0;
 409        }
 410
 411        return 1;
 412}
 413
 414static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
 415                                __u8 *value, int value_size)
 416{
 417        struct kvp_record *record;
 418
 419        /*
 420         * First update our in-memory database.
 421         */
 422        kvp_update_mem_state(pool);
 423        record = kvp_file_info[pool].records;
 424
 425        if (index >= kvp_file_info[pool].num_records) {
 426                /*
 427                 * This is an invalid index; terminate enumeration;
 428                 * - a NULL value will do the trick.
 429                 */
 430                strcpy(value, "");
 431                return;
 432        }
 433
 434        memcpy(key, record[index].key, key_size);
 435        memcpy(value, record[index].value, value_size);
 436}
 437
 438
 439void kvp_get_os_info(void)
 440{
 441        FILE    *file;
 442        char    *p, buf[512];
 443
 444        uname(&uts_buf);
 445        os_build = uts_buf.release;
 446        processor_arch = uts_buf.machine;
 447
 448        /*
 449         * The current windows host (win7) expects the build
 450         * string to be of the form: x.y.z
 451         * Strip additional information we may have.
 452         */
 453        p = strchr(os_build, '-');
 454        if (p)
 455                *p = '\0';
 456
 457        file = fopen("/etc/SuSE-release", "r");
 458        if (file != NULL)
 459                goto kvp_osinfo_found;
 460        file  = fopen("/etc/redhat-release", "r");
 461        if (file != NULL)
 462                goto kvp_osinfo_found;
 463        /*
 464         * Add code for other supported platforms.
 465         */
 466
 467        /*
 468         * We don't have information about the os.
 469         */
 470        os_name = uts_buf.sysname;
 471        return;
 472
 473kvp_osinfo_found:
 474        /* up to three lines */
 475        p = fgets(buf, sizeof(buf), file);
 476        if (p) {
 477                p = strchr(buf, '\n');
 478                if (p)
 479                        *p = '\0';
 480                p = strdup(buf);
 481                if (!p)
 482                        goto done;
 483                os_name = p;
 484
 485                /* second line */
 486                p = fgets(buf, sizeof(buf), file);
 487                if (p) {
 488                        p = strchr(buf, '\n');
 489                        if (p)
 490                                *p = '\0';
 491                        p = strdup(buf);
 492                        if (!p)
 493                                goto done;
 494                        os_major = p;
 495
 496                        /* third line */
 497                        p = fgets(buf, sizeof(buf), file);
 498                        if (p)  {
 499                                p = strchr(buf, '\n');
 500                                if (p)
 501                                        *p = '\0';
 502                                p = strdup(buf);
 503                                if (p)
 504                                        os_minor = p;
 505                        }
 506                }
 507        }
 508
 509done:
 510        fclose(file);
 511        return;
 512}
 513
 514static int
 515kvp_get_ip_address(int family, char *buffer, int length)
 516{
 517        struct ifaddrs *ifap;
 518        struct ifaddrs *curp;
 519        int ipv4_len = strlen("255.255.255.255") + 1;
 520        int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
 521        int offset = 0;
 522        const char *str;
 523        char tmp[50];
 524        int error = 0;
 525
 526        /*
 527         * On entry into this function, the buffer is capable of holding the
 528         * maximum key value (2048 bytes).
 529         */
 530
 531        if (getifaddrs(&ifap)) {
 532                strcpy(buffer, "getifaddrs failed\n");
 533                return 1;
 534        }
 535
 536        curp = ifap;
 537        while (curp != NULL) {
 538                if ((curp->ifa_addr != NULL) &&
 539                   (curp->ifa_addr->sa_family == family)) {
 540                        if (family == AF_INET) {
 541                                struct sockaddr_in *addr =
 542                                (struct sockaddr_in *) curp->ifa_addr;
 543
 544                                str = inet_ntop(family, &addr->sin_addr,
 545                                                tmp, 50);
 546                                if (str == NULL) {
 547                                        strcpy(buffer, "inet_ntop failed\n");
 548                                        error = 1;
 549                                        goto getaddr_done;
 550                                }
 551                                if (offset == 0)
 552                                        strcpy(buffer, tmp);
 553                                else
 554                                        strcat(buffer, tmp);
 555                                strcat(buffer, ";");
 556
 557                                offset += strlen(str) + 1;
 558                                if ((length - offset) < (ipv4_len + 1))
 559                                        goto getaddr_done;
 560
 561                        } else {
 562
 563                        /*
 564                         * We only support AF_INET and AF_INET6
 565                         * and the list of addresses is separated by a ";".
 566                         */
 567                                struct sockaddr_in6 *addr =
 568                                (struct sockaddr_in6 *) curp->ifa_addr;
 569
 570                                str = inet_ntop(family,
 571                                        &addr->sin6_addr.s6_addr,
 572                                        tmp, 50);
 573                                if (str == NULL) {
 574                                        strcpy(buffer, "inet_ntop failed\n");
 575                                        error = 1;
 576                                        goto getaddr_done;
 577                                }
 578                                if (offset == 0)
 579                                        strcpy(buffer, tmp);
 580                                else
 581                                        strcat(buffer, tmp);
 582                                strcat(buffer, ";");
 583                                offset += strlen(str) + 1;
 584                                if ((length - offset) < (ipv6_len + 1))
 585                                        goto getaddr_done;
 586
 587                        }
 588
 589                }
 590                curp = curp->ifa_next;
 591        }
 592
 593getaddr_done:
 594        freeifaddrs(ifap);
 595        return error;
 596}
 597
 598
 599static int
 600kvp_get_domain_name(char *buffer, int length)
 601{
 602        struct addrinfo hints, *info ;
 603        int error = 0;
 604
 605        gethostname(buffer, length);
 606        memset(&hints, 0, sizeof(hints));
 607        hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
 608        hints.ai_socktype = SOCK_STREAM;
 609        hints.ai_flags = AI_CANONNAME;
 610
 611        error = getaddrinfo(buffer, NULL, &hints, &info);
 612        if (error != 0) {
 613                strcpy(buffer, "getaddrinfo failed\n");
 614                return error;
 615        }
 616        strcpy(buffer, info->ai_canonname);
 617        freeaddrinfo(info);
 618        return error;
 619}
 620
 621static int
 622netlink_send(int fd, struct cn_msg *msg)
 623{
 624        struct nlmsghdr *nlh;
 625        unsigned int size;
 626        struct msghdr message;
 627        char buffer[64];
 628        struct iovec iov[2];
 629
 630        size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
 631
 632        nlh = (struct nlmsghdr *)buffer;
 633        nlh->nlmsg_seq = 0;
 634        nlh->nlmsg_pid = getpid();
 635        nlh->nlmsg_type = NLMSG_DONE;
 636        nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
 637        nlh->nlmsg_flags = 0;
 638
 639        iov[0].iov_base = nlh;
 640        iov[0].iov_len = sizeof(*nlh);
 641
 642        iov[1].iov_base = msg;
 643        iov[1].iov_len = size;
 644
 645        memset(&message, 0, sizeof(message));
 646        message.msg_name = &addr;
 647        message.msg_namelen = sizeof(addr);
 648        message.msg_iov = iov;
 649        message.msg_iovlen = 2;
 650
 651        return sendmsg(fd, &message, 0);
 652}
 653
 654int main(void)
 655{
 656        int fd, len, sock_opt;
 657        int error;
 658        struct cn_msg *message;
 659        struct pollfd pfd;
 660        struct nlmsghdr *incoming_msg;
 661        struct cn_msg   *incoming_cn_msg;
 662        struct hv_kvp_msg *hv_msg;
 663        char    *p;
 664        char    *key_value;
 665        char    *key_name;
 666
 667        daemon(1, 0);
 668        openlog("KVP", 0, LOG_USER);
 669        syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
 670        /*
 671         * Retrieve OS release information.
 672         */
 673        kvp_get_os_info();
 674
 675        if (kvp_file_init()) {
 676                syslog(LOG_ERR, "Failed to initialize the pools");
 677                exit(EXIT_FAILURE);
 678        }
 679
 680        fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
 681        if (fd < 0) {
 682                syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
 683                exit(EXIT_FAILURE);
 684        }
 685        addr.nl_family = AF_NETLINK;
 686        addr.nl_pad = 0;
 687        addr.nl_pid = 0;
 688        addr.nl_groups = CN_KVP_IDX;
 689
 690
 691        error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
 692        if (error < 0) {
 693                syslog(LOG_ERR, "bind failed; error:%d", error);
 694                close(fd);
 695                exit(EXIT_FAILURE);
 696        }
 697        sock_opt = addr.nl_groups;
 698        setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
 699        /*
 700         * Register ourselves with the kernel.
 701         */
 702        message = (struct cn_msg *)kvp_send_buffer;
 703        message->id.idx = CN_KVP_IDX;
 704        message->id.val = CN_KVP_VAL;
 705
 706        hv_msg = (struct hv_kvp_msg *)message->data;
 707        hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
 708        message->ack = 0;
 709        message->len = sizeof(struct hv_kvp_msg);
 710
 711        len = netlink_send(fd, message);
 712        if (len < 0) {
 713                syslog(LOG_ERR, "netlink_send failed; error:%d", len);
 714                close(fd);
 715                exit(EXIT_FAILURE);
 716        }
 717
 718        pfd.fd = fd;
 719
 720        while (1) {
 721                struct sockaddr *addr_p = (struct sockaddr *) &addr;
 722                socklen_t addr_l = sizeof(addr);
 723                pfd.events = POLLIN;
 724                pfd.revents = 0;
 725                poll(&pfd, 1, -1);
 726
 727                len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
 728                                addr_p, &addr_l);
 729
 730                if (len < 0 || addr.nl_pid) {
 731                        syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
 732                                        addr.nl_pid, errno, strerror(errno));
 733                        close(fd);
 734                        return -1;
 735                }
 736
 737                incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
 738                incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
 739                hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 740
 741                switch (hv_msg->kvp_hdr.operation) {
 742                case KVP_OP_REGISTER:
 743                        /*
 744                         * Driver is registering with us; stash away the version
 745                         * information.
 746                         */
 747                        p = (char *)hv_msg->body.kvp_register.version;
 748                        lic_version = malloc(strlen(p) + 1);
 749                        if (lic_version) {
 750                                strcpy(lic_version, p);
 751                                syslog(LOG_INFO, "KVP LIC Version: %s",
 752                                        lic_version);
 753                        } else {
 754                                syslog(LOG_ERR, "malloc failed");
 755                        }
 756                        continue;
 757
 758                /*
 759                 * The current protocol with the kernel component uses a
 760                 * NULL key name to pass an error condition.
 761                 * For the SET, GET and DELETE operations,
 762                 * use the existing protocol to pass back error.
 763                 */
 764
 765                case KVP_OP_SET:
 766                        if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
 767                                        hv_msg->body.kvp_set.data.key,
 768                                        hv_msg->body.kvp_set.data.key_size,
 769                                        hv_msg->body.kvp_set.data.value,
 770                                        hv_msg->body.kvp_set.data.value_size))
 771                                strcpy(hv_msg->body.kvp_set.data.key, "");
 772                        break;
 773
 774                case KVP_OP_GET:
 775                        if (kvp_get_value(hv_msg->kvp_hdr.pool,
 776                                        hv_msg->body.kvp_set.data.key,
 777                                        hv_msg->body.kvp_set.data.key_size,
 778                                        hv_msg->body.kvp_set.data.value,
 779                                        hv_msg->body.kvp_set.data.value_size))
 780                                strcpy(hv_msg->body.kvp_set.data.key, "");
 781                        break;
 782
 783                case KVP_OP_DELETE:
 784                        if (kvp_key_delete(hv_msg->kvp_hdr.pool,
 785                                        hv_msg->body.kvp_delete.key,
 786                                        hv_msg->body.kvp_delete.key_size))
 787                                strcpy(hv_msg->body.kvp_delete.key, "");
 788                        break;
 789
 790                default:
 791                        break;
 792                }
 793
 794                if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
 795                        goto kvp_done;
 796
 797                /*
 798                 * If the pool is KVP_POOL_AUTO, dynamically generate
 799                 * both the key and the value; if not read from the
 800                 * appropriate pool.
 801                 */
 802                if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
 803                        kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
 804                                        hv_msg->body.kvp_enum_data.index,
 805                                        hv_msg->body.kvp_enum_data.data.key,
 806                                        HV_KVP_EXCHANGE_MAX_KEY_SIZE,
 807                                        hv_msg->body.kvp_enum_data.data.value,
 808                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 809                        goto kvp_done;
 810                }
 811
 812                hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 813                key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
 814                key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
 815
 816                switch (hv_msg->body.kvp_enum_data.index) {
 817                case FullyQualifiedDomainName:
 818                        kvp_get_domain_name(key_value,
 819                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 820                        strcpy(key_name, "FullyQualifiedDomainName");
 821                        break;
 822                case IntegrationServicesVersion:
 823                        strcpy(key_name, "IntegrationServicesVersion");
 824                        strcpy(key_value, lic_version);
 825                        break;
 826                case NetworkAddressIPv4:
 827                        kvp_get_ip_address(AF_INET, key_value,
 828                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 829                        strcpy(key_name, "NetworkAddressIPv4");
 830                        break;
 831                case NetworkAddressIPv6:
 832                        kvp_get_ip_address(AF_INET6, key_value,
 833                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 834                        strcpy(key_name, "NetworkAddressIPv6");
 835                        break;
 836                case OSBuildNumber:
 837                        strcpy(key_value, os_build);
 838                        strcpy(key_name, "OSBuildNumber");
 839                        break;
 840                case OSName:
 841                        strcpy(key_value, os_name);
 842                        strcpy(key_name, "OSName");
 843                        break;
 844                case OSMajorVersion:
 845                        strcpy(key_value, os_major);
 846                        strcpy(key_name, "OSMajorVersion");
 847                        break;
 848                case OSMinorVersion:
 849                        strcpy(key_value, os_minor);
 850                        strcpy(key_name, "OSMinorVersion");
 851                        break;
 852                case OSVersion:
 853                        strcpy(key_value, os_build);
 854                        strcpy(key_name, "OSVersion");
 855                        break;
 856                case ProcessorArchitecture:
 857                        strcpy(key_value, processor_arch);
 858                        strcpy(key_name, "ProcessorArchitecture");
 859                        break;
 860                default:
 861                        strcpy(key_value, "Unknown Key");
 862                        /*
 863                         * We use a null key name to terminate enumeration.
 864                         */
 865                        strcpy(key_name, "");
 866                        break;
 867                }
 868                /*
 869                 * Send the value back to the kernel. The response is
 870                 * already in the receive buffer. Update the cn_msg header to
 871                 * reflect the key value that has been added to the message
 872                 */
 873kvp_done:
 874
 875                incoming_cn_msg->id.idx = CN_KVP_IDX;
 876                incoming_cn_msg->id.val = CN_KVP_VAL;
 877                incoming_cn_msg->ack = 0;
 878                incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
 879
 880                len = netlink_send(fd, incoming_cn_msg);
 881                if (len < 0) {
 882                        syslog(LOG_ERR, "net_link send failed; error:%d", len);
 883                        exit(EXIT_FAILURE);
 884                }
 885        }
 886
 887}
 888
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.