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