2 * Copyright (c) 2014 Microsoft Corp.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <sys/utsname.h>
34 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <net/ethernet.h>
40 #include <net/if_dl.h>
41 #include <net/if_types.h>
58 #include "hv_utilreg.h"
60 typedef uint16_t __u16;
61 typedef uint32_t __u32;
62 typedef uint64_t __u64;
64 #define POOL_FILE_MODE (S_IRUSR | S_IWUSR)
65 #define POOL_DIR_MODE (POOL_FILE_MODE | S_IXUSR)
66 #define POOL_DIR "/var/db/hyperv/pool"
73 FullyQualifiedDomainName = 0,
74 IntegrationServicesVersion, /*This key is serviced in the kernel*/
94 /* Global Variables */
97 * The structure for operation handlers.
101 void (*kvp_op_init)(void);
102 int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
105 static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
109 static const char *os_name = "";
110 static const char *os_major = "";
111 static const char *os_minor = "";
112 static const char *processor_arch;
113 static const char *os_build;
114 static const char *lic_version = "BSD Pre-Release version";
115 static struct utsname uts_buf;
118 static int is_daemon = 1;
119 static int is_debugging = 0;
121 #define KVP_LOG(priority, format, args...) do { \
122 if (is_debugging == 1) { \
123 if (is_daemon == 1) \
124 syslog(priority, format, ## args); \
126 printf(format, ## args); \
128 if (priority < LOG_DEBUG) { \
129 if (is_daemon == 1) \
130 syslog(priority, format, ## args); \
132 printf(format, ## args); \
141 #define MAX_FILE_NAME 100
142 #define ENTRIES_PER_BLOCK 50
145 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
146 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
152 struct kvp_record *records;
154 char fname[MAX_FILE_NAME];
157 static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
161 kvp_acquire_lock(int pool)
163 struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
167 if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) {
168 KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
175 kvp_release_lock(int pool)
177 struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
181 if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
183 KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
190 * Write in-memory copy of KVP to pool files
193 kvp_update_file(int pool)
196 size_t bytes_written;
198 kvp_acquire_lock(pool);
200 filep = fopen(kvp_pools[pool].fname, "w");
202 kvp_release_lock(pool);
203 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
207 bytes_written = fwrite(kvp_pools[pool].records,
208 sizeof(struct kvp_record),
209 kvp_pools[pool].num_records, filep);
211 if (ferror(filep) || fclose(filep)) {
212 kvp_release_lock(pool);
213 KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
217 kvp_release_lock(pool);
222 * Read KVPs from pool files and store in memory
225 kvp_update_mem_state(int pool)
228 size_t records_read = 0;
229 struct kvp_record *record = kvp_pools[pool].records;
230 struct kvp_record *readp;
231 int num_blocks = kvp_pools[pool].num_blocks;
232 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
234 kvp_acquire_lock(pool);
236 filep = fopen(kvp_pools[pool].fname, "r");
238 kvp_release_lock(pool);
239 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
244 readp = &record[records_read];
245 records_read += fread(readp, sizeof(struct kvp_record),
246 ENTRIES_PER_BLOCK * num_blocks,
250 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
256 * Have more data to read. Expand the memory.
259 record = realloc(record, alloc_unit * num_blocks);
261 if (record == NULL) {
262 KVP_LOG(LOG_ERR, "malloc failed\n");
270 kvp_pools[pool].num_blocks = num_blocks;
271 kvp_pools[pool].records = record;
272 kvp_pools[pool].num_records = records_read;
275 kvp_release_lock(pool);
286 struct kvp_record *record;
287 struct kvp_record *readp;
290 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
292 if (mkdir(POOL_DIR, POOL_DIR_MODE) < 0 &&
293 (errno != EEXIST && errno != EISDIR)) {
294 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
297 chmod(POOL_DIR, POOL_DIR_MODE); /* fix old mistake */
299 for (i = 0; i < HV_KVP_POOL_COUNT; i++)
301 fname = kvp_pools[i].fname;
304 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
305 fd = open(fname, O_RDWR | O_CREAT, POOL_FILE_MODE);
310 fchmod(fd, POOL_FILE_MODE); /* fix old mistake */
313 filep = fopen(fname, "r");
319 record = malloc(alloc_unit * num_blocks);
320 if (record == NULL) {
327 readp = &record[records_read];
328 records_read += fread(readp, sizeof(struct kvp_record),
333 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
343 record = realloc(record, alloc_unit *
345 if (record == NULL) {
354 kvp_pools[i].pool_fd = fd;
355 kvp_pools[i].num_blocks = num_blocks;
356 kvp_pools[i].records = record;
357 kvp_pools[i].num_records = records_read;
366 kvp_key_delete(int pool, __u8 *key, int key_size)
371 struct kvp_record *record;
373 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, "
374 "key = %s\n", pool, key);
376 /* Update in-memory state */
377 kvp_update_mem_state(pool);
379 num_records = kvp_pools[pool].num_records;
380 record = kvp_pools[pool].records;
382 for (i = 0; i < num_records; i++)
384 if (memcmp(key, record[i].key, key_size)) {
388 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
391 * We found a match at the end; Just update the number of
392 * entries and we are done.
394 if (i == num_records) {
395 kvp_pools[pool].num_records--;
396 kvp_update_file(pool);
401 * We found a match in the middle; Move the remaining
406 for ( ; k < num_records; k++)
408 strcpy(record[j].key, record[k].key);
409 strcpy(record[j].value, record[k].value);
412 kvp_pools[pool].num_records--;
413 kvp_update_file(pool);
416 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
423 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
428 struct kvp_record *record;
431 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, "
432 "key = %s, value = %s\n,", pool, key, value);
434 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
435 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
436 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
440 /* Update the in-memory state. */
441 kvp_update_mem_state(pool);
443 num_records = kvp_pools[pool].num_records;
444 record = kvp_pools[pool].records;
445 num_blocks = kvp_pools[pool].num_blocks;
447 for (i = 0; i < num_records; i++)
449 if (memcmp(key, record[i].key, key_size)) {
454 * Key exists. Just update the value and we are done.
456 memcpy(record[i].value, value, value_size);
457 kvp_update_file(pool);
462 * Key doesn't exist; Add a new KVP.
464 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
465 /* Increase the size of the recodrd array. */
466 record = realloc(record, sizeof(struct kvp_record) *
467 ENTRIES_PER_BLOCK * (num_blocks + 1));
469 if (record == NULL) {
472 kvp_pools[pool].num_blocks++;
474 memcpy(record[i].value, value, value_size);
475 memcpy(record[i].key, key, key_size);
476 kvp_pools[pool].records = record;
477 kvp_pools[pool].num_records++;
478 kvp_update_file(pool);
484 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
489 struct kvp_record *record;
491 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,",
494 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
495 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
499 /* Update the in-memory state first. */
500 kvp_update_mem_state(pool);
502 num_records = kvp_pools[pool].num_records;
503 record = kvp_pools[pool].records;
505 for (i = 0; i < num_records; i++)
507 if (memcmp(key, record[i].key, key_size)) {
512 memcpy(value, record[i].value, value_size);
521 kvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size,
522 __u8 *value, int value_size)
524 struct kvp_record *record;
526 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
529 /* First update our in-memory state first. */
530 kvp_update_mem_state(pool);
531 record = kvp_pools[pool].records;
533 /* Index starts with 0 */
534 if (idx >= kvp_pools[pool].num_records) {
538 memcpy(key, record[idx].key, key_size);
539 memcpy(value, record[idx].value, value_size);
545 kvp_get_os_info(void)
550 os_build = uts_buf.release;
551 os_name = uts_buf.sysname;
552 processor_arch = uts_buf.machine;
555 * Win7 host expects the build string to be of the form: x.y.z
556 * Strip additional information we may have.
558 p = strchr(os_build, '-');
564 * We don't have any other information about the FreeBSD os.
570 * Given the interface name, return the MAC address.
573 kvp_if_name_to_mac(char *if_name)
575 char *mac_addr = NULL;
576 struct ifaddrs *ifaddrs_ptr;
577 struct ifaddrs *head_ifaddrs_ptr;
578 struct sockaddr_dl *sdl;
581 status = getifaddrs(&ifaddrs_ptr);
584 head_ifaddrs_ptr = ifaddrs_ptr;
586 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
587 if ((sdl->sdl_type == IFT_ETHER) &&
588 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
589 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
592 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
593 freeifaddrs(head_ifaddrs_ptr);
601 * Given the MAC address, return the interface name.
604 kvp_mac_to_if_name(char *mac)
606 char *if_name = NULL;
607 struct ifaddrs *ifaddrs_ptr;
608 struct ifaddrs *head_ifaddrs_ptr;
609 struct sockaddr_dl *sdl;
613 status = getifaddrs(&ifaddrs_ptr);
616 head_ifaddrs_ptr = ifaddrs_ptr;
618 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
619 if (sdl->sdl_type == IFT_ETHER) {
620 buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
621 if (buf_ptr != NULL) {
622 for (p = buf_ptr; *p != '\0'; p++)
625 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
626 /* Caller will free the memory */
627 if_name = strdup(ifaddrs_ptr->ifa_name);
634 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
635 freeifaddrs(head_ifaddrs_ptr);
642 kvp_process_ipconfig_file(char *cmd,
643 char *config_buf, size_t len,
644 size_t element_size, int offset)
652 * First execute the command.
654 file = popen(cmd, "r");
660 memset(config_buf, 0, len);
662 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
663 if ((len - strlen(config_buf)) < (element_size + 1)) {
669 strlcat(config_buf, p, len);
670 strlcat(config_buf, ";", len);
677 kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer)
685 * Retrieve the IPV4 address of default gateway.
687 snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
690 * Execute the command to gather gateway IPV4 info.
692 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
693 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
695 * Retrieve the IPV6 address of default gateway.
697 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }'", if_name);
700 * Execute the command to gather gateway IPV6 info.
702 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
703 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
705 * we just invoke an external script to get the DNS info.
707 * Following is the expected format of the information from the script:
709 * ipaddr1 (nameserver1)
710 * ipaddr2 (nameserver2)
714 /* Scripts are stored in /usr/libexec/hyperv/ directory */
715 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
718 * Execute the command to get DNS info.
720 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
721 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
724 * Invoke an external script to get the DHCP state info.
725 * The parameter to the script is the interface name.
726 * Here is the expected output:
728 * Enabled: DHCP enabled.
732 snprintf(cmd, sizeof(cmd), "%s %s",
733 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
735 file = popen(cmd, "r");
740 p = fgets(dhcp_info, sizeof(dhcp_info), file);
746 if (!strncmp(p, "Enabled", 7)) {
747 buffer->dhcp_enabled = 1;
749 buffer->dhcp_enabled = 0;
757 hweight32(unsigned int *w)
759 unsigned int res = *w - ((*w >> 1) & 0x55555555);
761 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
762 res = (res + (res >> 4)) & 0x0F0F0F0F;
763 res = res + (res >> 8);
764 return ((res + (res >> 16)) & 0x000000FF);
769 kvp_process_ip_address(void *addrp,
770 int family, char *buffer,
771 int length, int *offset)
773 struct sockaddr_in *addr;
774 struct sockaddr_in6 *addr6;
779 if (family == AF_INET) {
780 addr = (struct sockaddr_in *)addrp;
781 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
782 addr_length = INET_ADDRSTRLEN;
784 addr6 = (struct sockaddr_in6 *)addrp;
785 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
786 addr_length = INET6_ADDRSTRLEN;
789 if ((length - *offset) < addr_length + 1) {
793 strlcpy(buffer, "inet_ntop failed\n", length);
797 strlcpy(buffer, tmp, length);
799 strlcat(buffer, tmp, length);
801 strlcat(buffer, ";", length);
803 *offset += strlen(str) + 1;
809 kvp_get_ip_info(int family, char *if_name, int op,
810 void *out_buffer, size_t length)
812 struct ifaddrs *ifap;
813 struct ifaddrs *curp;
818 size_t buffer_length;
819 struct hv_kvp_ipaddr_value *ip_buffer;
823 unsigned int *w = NULL;
825 size_t sn_str_length;
826 struct sockaddr_in6 *addr6;
828 if (op == HV_KVP_OP_ENUMERATE) {
830 buffer_length = length;
832 ip_buffer = out_buffer;
833 buffer = (char *)ip_buffer->ip_addr;
834 buffer_length = sizeof(ip_buffer->ip_addr);
835 ip_buffer->addr_family = 0;
838 if (getifaddrs(&ifap)) {
839 strlcpy(buffer, "getifaddrs failed\n", buffer_length);
844 while (curp != NULL) {
845 if (curp->ifa_addr == NULL) {
846 curp = curp->ifa_next;
850 if ((if_name != NULL) &&
851 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
853 * We want info about a specific interface;
856 curp = curp->ifa_next;
861 * We support two address families: AF_INET and AF_INET6.
862 * If family value is 0, we gather both supported
863 * address families; if not we gather info on
864 * the specified address family.
866 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
867 curp = curp->ifa_next;
870 if ((curp->ifa_addr->sa_family != AF_INET) &&
871 (curp->ifa_addr->sa_family != AF_INET6)) {
872 curp = curp->ifa_next;
876 if (op == HV_KVP_OP_GET_IP_INFO) {
878 * Get the info other than the IP address.
880 if (curp->ifa_addr->sa_family == AF_INET) {
881 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
886 error = kvp_process_ip_address(
894 goto kvp_get_ip_info_ipaddr;
897 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
900 * Get subnet info in CIDR format.
903 sn_str = (char *)ip_buffer->sub_net;
904 sn_str_length = sizeof(ip_buffer->sub_net);
905 addr6 = (struct sockaddr_in6 *)(uintptr_t)
907 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
909 for (i = 0; i < 4; i++)
911 weight += hweight32(&w[i]);
914 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
915 if ((length - sn_offset) <
916 (strlen(cidr_mask) + 1)) {
917 goto kvp_get_ip_info_ipaddr;
920 if (sn_offset == 0) {
921 strlcpy(sn_str, cidr_mask, sn_str_length);
923 strlcat(sn_str, cidr_mask, sn_str_length);
925 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
926 sn_offset += strlen(sn_str) + 1;
930 * Collect other ip configuration info.
932 kvp_get_ipconfig_info(if_name, ip_buffer);
935 kvp_get_ip_info_ipaddr:
936 error = kvp_process_ip_address(curp->ifa_addr,
937 curp->ifa_addr->sa_family,
941 goto kvp_get_ip_info_done;
944 curp = curp->ifa_next;
947 kvp_get_ip_info_done:
954 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
958 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
969 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
978 * FreeBSD - Configuration File
980 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
982 file = fopen(if_file, "w");
985 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
990 * Write out the MAC address.
993 mac_addr = kvp_if_name_to_mac(if_name);
994 if (mac_addr == NULL) {
996 goto kvp_set_ip_info_error;
999 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1001 goto kvp_set_ip_info_error;
1004 /* Interface Name */
1005 error = kvp_write_file(file, "IF_NAME", "", if_name);
1007 goto kvp_set_ip_info_error;
1011 error = kvp_write_file(file, "IP_ADDR", "",
1012 (char *)new_val->ip_addr);
1014 goto kvp_set_ip_info_error;
1018 error = kvp_write_file(file, "SUBNET", "",
1019 (char *)new_val->sub_net);
1021 goto kvp_set_ip_info_error;
1026 error = kvp_write_file(file, "GATEWAY", "",
1027 (char *)new_val->gate_way);
1029 goto kvp_set_ip_info_error;
1033 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1035 goto kvp_set_ip_info_error;
1039 if (new_val->dhcp_enabled) {
1040 error = kvp_write_file(file, "DHCP", "", "1");
1042 error = kvp_write_file(file, "DHCP", "", "0");
1046 goto kvp_set_ip_info_error;
1053 * Invoke the external script with the populated
1054 * configuration file.
1057 snprintf(cmd, sizeof(cmd), "%s %s",
1058 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1062 kvp_set_ip_info_error:
1063 KVP_LOG(LOG_ERR, "Failed to write config file\n");
1071 kvp_get_domain_name(char *buffer, int length)
1073 struct addrinfo hints, *info;
1076 gethostname(buffer, length);
1077 memset(&hints, 0, sizeof(hints));
1078 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */
1079 hints.ai_socktype = SOCK_STREAM;
1080 hints.ai_flags = AI_CANONNAME;
1082 error = getaddrinfo(buffer, NULL, &hints, &info);
1084 strlcpy(buffer, "getaddrinfo failed\n", length);
1087 strlcpy(buffer, info->ai_canonname, length);
1094 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1096 struct hv_kvp_ipaddr_value *ip_val;
1100 assert(op_msg != NULL);
1101 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1103 ip_val = &op_msg->body.kvp_ip_val;
1104 op_msg->hdr.error = HV_S_OK;
1106 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1108 if (if_name == NULL) {
1109 /* No interface found with the mac address. */
1110 op_msg->hdr.error = HV_E_FAIL;
1111 goto kvp_op_getipinfo_done;
1114 error = kvp_get_ip_info(0, if_name,
1115 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1117 op_msg->hdr.error = HV_E_FAIL;
1120 kvp_op_getipinfo_done:
1126 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1128 struct hv_kvp_ipaddr_value *ip_val;
1132 assert(op_msg != NULL);
1133 KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1135 ip_val = &op_msg->body.kvp_ip_val;
1136 op_msg->hdr.error = HV_S_OK;
1138 if_name = (char *)ip_val->adapter_id;
1140 if (if_name == NULL) {
1141 /* No adapter provided. */
1142 op_msg->hdr.error = HV_GUID_NOTFOUND;
1143 goto kvp_op_setipinfo_done;
1146 error = kvp_set_ip_info(if_name, ip_val);
1148 op_msg->hdr.error = HV_E_FAIL;
1149 kvp_op_setipinfo_done:
1155 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1157 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1161 assert(op_msg != NULL);
1162 assert(op_hdlr != NULL);
1164 op_pool = op_msg->hdr.kvp_hdr.pool;
1165 op_msg->hdr.error = HV_S_OK;
1167 switch(op_hdlr->kvp_op_key) {
1169 if (op_pool == HV_KVP_POOL_AUTO) {
1170 /* Auto Pool is not writeable from host side. */
1172 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1175 error = kvp_key_add_or_modify(op_pool,
1176 op_msg->body.kvp_set.data.key,
1177 op_msg->body.kvp_set.data.key_size,
1178 op_msg->body.kvp_set.data.msg_value.value,
1179 op_msg->body.kvp_set.data.value_size);
1184 error = kvp_get_value(op_pool,
1185 op_msg->body.kvp_get.data.key,
1186 op_msg->body.kvp_get.data.key_size,
1187 op_msg->body.kvp_get.data.msg_value.value,
1188 op_msg->body.kvp_get.data.value_size);
1191 case HV_KVP_OP_DELETE:
1192 if (op_pool == HV_KVP_POOL_AUTO) {
1193 /* Auto Pool is not writeable from host side. */
1195 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1198 error = kvp_key_delete(op_pool,
1199 op_msg->body.kvp_delete.key,
1200 op_msg->body.kvp_delete.key_size);
1209 op_msg->hdr.error = HV_S_CONT;
1215 kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1217 char *key_name, *key_value;
1222 assert(op_msg != NULL);
1224 op = op_msg->hdr.kvp_hdr.operation;
1225 op_pool = op_msg->hdr.kvp_hdr.pool;
1226 op_msg->hdr.error = HV_S_OK;
1229 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1230 * pool and return the KVP according to the index requested.
1232 if (op_pool != HV_KVP_POOL_AUTO) {
1233 if (kvp_pool_enumerate(op_pool,
1234 op_msg->body.kvp_enum_data.index,
1235 op_msg->body.kvp_enum_data.data.key,
1236 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1237 op_msg->body.kvp_enum_data.data.msg_value.value,
1238 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1239 op_msg->hdr.error = HV_S_CONT;
1242 goto kvp_op_enumerate_done;
1245 key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1246 key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1248 switch (op_msg->body.kvp_enum_data.index)
1250 case FullyQualifiedDomainName:
1251 kvp_get_domain_name(key_value,
1252 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1253 strcpy(key_name, "FullyQualifiedDomainName");
1256 case IntegrationServicesVersion:
1257 strcpy(key_name, "IntegrationServicesVersion");
1258 strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1261 case NetworkAddressIPv4:
1262 kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1263 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1264 strcpy(key_name, "NetworkAddressIPv4");
1267 case NetworkAddressIPv6:
1268 kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1269 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1270 strcpy(key_name, "NetworkAddressIPv6");
1274 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1275 strcpy(key_name, "OSBuildNumber");
1279 strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1280 strcpy(key_name, "OSName");
1283 case OSMajorVersion:
1284 strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1285 strcpy(key_name, "OSMajorVersion");
1288 case OSMinorVersion:
1289 strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1290 strcpy(key_name, "OSMinorVersion");
1294 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1295 strcpy(key_name, "OSVersion");
1298 case ProcessorArchitecture:
1299 strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1300 strcpy(key_name, "ProcessorArchitecture");
1305 KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1306 op_msg->body.kvp_enum_data.index);
1308 op_msg->hdr.error = HV_S_CONT;
1313 kvp_op_enumerate_done:
1315 op_msg->hdr.error = HV_S_CONT;
1321 * Load handler, and call init routine if provided.
1324 kvp_op_load(int key, void (*init)(void),
1325 int (*exec)(struct hv_kvp_msg *, void *))
1329 if (key < 0 || key >= HV_KVP_OP_COUNT) {
1330 KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1332 goto kvp_op_load_done;
1335 kvp_op_hdlrs[key].kvp_op_key = key;
1336 kvp_op_hdlrs[key].kvp_op_init = init;
1337 kvp_op_hdlrs[key].kvp_op_exec = exec;
1339 if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1340 kvp_op_hdlrs[key].kvp_op_init();
1348 * Initialize the operation hanlders.
1355 /* Set the initial values. */
1356 for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1357 kvp_op_hdlrs[i].kvp_op_key = -1;
1358 kvp_op_hdlrs[i].kvp_op_init = NULL;
1359 kvp_op_hdlrs[i].kvp_op_exec = NULL;
1362 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1363 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1364 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1365 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1367 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1368 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1373 main(int argc, char *argv[])
1375 struct hv_kvp_msg *hv_kvp_dev_buf;
1376 struct hv_kvp_msg *hv_msg;
1377 struct pollfd hv_kvp_poll_fd[1];
1379 int hv_kvp_dev_fd, error, len, r;
1382 while ((ch = getopt(argc, argv, "dn")) != -1) {
1385 /* Run as regular process for debugging purpose. */
1389 /* Generate debugging output */
1397 openlog("HV_KVP", 0, LOG_USER);
1399 /* Become daemon first. */
1403 KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1405 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1407 /* Communication buffer hv_kvp_dev_buf */
1408 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1409 /* Buffer for daemon internal use */
1410 hv_msg = malloc(sizeof(*hv_msg));
1412 /* Memory allocation failed */
1413 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1414 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1418 /* Initialize op handlers */
1419 if (kvp_ops_init() != 0) {
1420 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1424 if (kvp_file_init()) {
1425 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1429 /* Open the Character Device */
1430 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1432 if (hv_kvp_dev_fd < 0) {
1433 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1434 errno, strerror(errno));
1438 /* Initialize the struct for polling the char device */
1439 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1440 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1442 /* Register the daemon to the KVP driver */
1443 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1444 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1445 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1449 r = poll (hv_kvp_poll_fd, 1, INFTIM);
1451 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1452 r, hv_kvp_poll_fd[0].revents);
1454 if (r == 0 || (r < 0 && errno == EAGAIN) ||
1455 (r < 0 && errno == EINTR)) {
1456 /* Nothing to read */
1462 * For pread return failure other than EAGAIN,
1465 KVP_LOG(LOG_ERR, "Poll failed.\n");
1470 /* Read from character device */
1471 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1472 sizeof(*hv_kvp_dev_buf), 0);
1475 KVP_LOG(LOG_ERR, "Read failed.\n");
1480 if (len != sizeof(struct hv_kvp_msg)) {
1481 KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1485 /* Copy hv_kvp_dev_buf to hv_msg */
1486 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1489 * We will use the KVP header information to pass back
1490 * the error from this daemon. So, first save the op
1491 * and pool info to local variables.
1494 op = hv_msg->hdr.kvp_hdr.operation;
1495 pool = hv_msg->hdr.kvp_hdr.pool;
1497 if (op < 0 || op >= HV_KVP_OP_COUNT ||
1498 kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1499 KVP_LOG(LOG_WARNING,
1500 "Unsupported operation OP = %d\n", op);
1501 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1504 * Call the operateion handler's execution routine.
1506 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1507 (void *)&kvp_op_hdlrs[op]);
1509 assert(hv_msg->hdr.error != HV_S_OK);
1510 if (hv_msg->hdr.error != HV_S_CONT)
1511 KVP_LOG(LOG_WARNING,
1512 "Operation failed OP = %d, error = 0x%x\n",
1518 * Send the value back to the kernel. The response is
1519 * already in the receive buffer.
1522 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1524 if (len != sizeof(struct hv_kvp_msg)) {
1525 KVP_LOG(LOG_ERR, "write len is: %d\n", len);