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>
59 typedef uint16_t __u16;
60 typedef uint32_t __u32;
61 typedef uint64_t __u64;
68 FullyQualifiedDomainName = 0,
69 IntegrationServicesVersion, /*This key is serviced in the kernel*/
89 /* Global Variables */
92 * The structure for operation handlers.
96 void (*kvp_op_init)(void);
97 int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
100 static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
104 static const char *os_name = "";
105 static const char *os_major = "";
106 static const char *os_minor = "";
107 static const char *processor_arch;
108 static const char *os_build;
109 static const char *lic_version = "BSD Pre-Release version";
110 static struct utsname uts_buf;
113 static int is_daemon = 1;
114 static int is_debugging = 0;
116 #define KVP_LOG(priority, format, args...) do { \
117 if (is_debugging == 1) { \
118 if (is_daemon == 1) \
119 syslog(priority, format, ## args); \
121 printf(format, ## args); \
123 if (priority < LOG_DEBUG) { \
124 if (is_daemon == 1) \
125 syslog(priority, format, ## args); \
127 printf(format, ## args); \
136 #define MAX_FILE_NAME 100
137 #define ENTRIES_PER_BLOCK 50
140 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
141 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
147 struct kvp_record *records;
149 char fname[MAX_FILE_NAME];
152 static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
156 kvp_acquire_lock(int pool)
158 struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
162 if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) {
163 KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
170 kvp_release_lock(int pool)
172 struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
176 if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
178 KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
185 * Write in-memory copy of KVP to pool files
188 kvp_update_file(int pool)
191 size_t bytes_written;
193 kvp_acquire_lock(pool);
195 filep = fopen(kvp_pools[pool].fname, "w");
197 kvp_release_lock(pool);
198 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
202 bytes_written = fwrite(kvp_pools[pool].records,
203 sizeof(struct kvp_record),
204 kvp_pools[pool].num_records, filep);
206 if (ferror(filep) || fclose(filep)) {
207 kvp_release_lock(pool);
208 KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
212 kvp_release_lock(pool);
217 * Read KVPs from pool files and store in memory
220 kvp_update_mem_state(int pool)
223 size_t records_read = 0;
224 struct kvp_record *record = kvp_pools[pool].records;
225 struct kvp_record *readp;
226 int num_blocks = kvp_pools[pool].num_blocks;
227 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
229 kvp_acquire_lock(pool);
231 filep = fopen(kvp_pools[pool].fname, "r");
233 kvp_release_lock(pool);
234 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
239 readp = &record[records_read];
240 records_read += fread(readp, sizeof(struct kvp_record),
241 ENTRIES_PER_BLOCK * num_blocks,
245 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
251 * Have more data to read. Expand the memory.
254 record = realloc(record, alloc_unit * num_blocks);
256 if (record == NULL) {
257 KVP_LOG(LOG_ERR, "malloc failed\n");
265 kvp_pools[pool].num_blocks = num_blocks;
266 kvp_pools[pool].records = record;
267 kvp_pools[pool].num_records = records_read;
270 kvp_release_lock(pool);
281 struct kvp_record *record;
282 struct kvp_record *readp;
285 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
287 if (access("/var/db/hyperv/pool", F_OK)) {
288 if (mkdir("/var/db/hyperv/pool",
289 S_IRUSR | S_IWUSR | S_IROTH)) {
290 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
295 for (i = 0; i < HV_KVP_POOL_COUNT; i++)
297 fname = kvp_pools[i].fname;
300 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
301 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
308 filep = fopen(fname, "r");
313 record = malloc(alloc_unit * num_blocks);
314 if (record == NULL) {
320 readp = &record[records_read];
321 records_read += fread(readp, sizeof(struct kvp_record),
326 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
336 record = realloc(record, alloc_unit *
338 if (record == NULL) {
346 kvp_pools[i].pool_fd = fd;
347 kvp_pools[i].num_blocks = num_blocks;
348 kvp_pools[i].records = record;
349 kvp_pools[i].num_records = records_read;
358 kvp_key_delete(int pool, __u8 *key, int key_size)
363 struct kvp_record *record;
365 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, "
366 "key = %s\n", pool, key);
368 /* Update in-memory state */
369 kvp_update_mem_state(pool);
371 num_records = kvp_pools[pool].num_records;
372 record = kvp_pools[pool].records;
374 for (i = 0; i < num_records; i++)
376 if (memcmp(key, record[i].key, key_size)) {
380 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
383 * We found a match at the end; Just update the number of
384 * entries and we are done.
386 if (i == num_records) {
387 kvp_pools[pool].num_records--;
388 kvp_update_file(pool);
393 * We found a match in the middle; Move the remaining
398 for ( ; k < num_records; k++)
400 strcpy(record[j].key, record[k].key);
401 strcpy(record[j].value, record[k].value);
404 kvp_pools[pool].num_records--;
405 kvp_update_file(pool);
408 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
415 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
420 struct kvp_record *record;
423 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, "
424 "key = %s, value = %s\n,", pool, key, value);
426 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
427 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
428 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
432 /* Update the in-memory state. */
433 kvp_update_mem_state(pool);
435 num_records = kvp_pools[pool].num_records;
436 record = kvp_pools[pool].records;
437 num_blocks = kvp_pools[pool].num_blocks;
439 for (i = 0; i < num_records; i++)
441 if (memcmp(key, record[i].key, key_size)) {
446 * Key exists. Just update the value and we are done.
448 memcpy(record[i].value, value, value_size);
449 kvp_update_file(pool);
454 * Key doesn't exist; Add a new KVP.
456 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
457 /* Increase the size of the recodrd array. */
458 record = realloc(record, sizeof(struct kvp_record) *
459 ENTRIES_PER_BLOCK * (num_blocks + 1));
461 if (record == NULL) {
464 kvp_pools[pool].num_blocks++;
466 memcpy(record[i].value, value, value_size);
467 memcpy(record[i].key, key, key_size);
468 kvp_pools[pool].records = record;
469 kvp_pools[pool].num_records++;
470 kvp_update_file(pool);
476 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
481 struct kvp_record *record;
483 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,",
486 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
487 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
491 /* Update the in-memory state first. */
492 kvp_update_mem_state(pool);
494 num_records = kvp_pools[pool].num_records;
495 record = kvp_pools[pool].records;
497 for (i = 0; i < num_records; i++)
499 if (memcmp(key, record[i].key, key_size)) {
504 memcpy(value, record[i].value, value_size);
513 kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
514 __u8 *value, int value_size)
516 struct kvp_record *record;
518 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
521 /* First update our in-memory state first. */
522 kvp_update_mem_state(pool);
523 record = kvp_pools[pool].records;
525 /* Index starts with 0 */
526 if (index >= kvp_pools[pool].num_records) {
530 memcpy(key, record[index].key, key_size);
531 memcpy(value, record[index].value, value_size);
537 kvp_get_os_info(void)
542 os_build = uts_buf.release;
543 os_name = uts_buf.sysname;
544 processor_arch = uts_buf.machine;
547 * Win7 host expects the build string to be of the form: x.y.z
548 * Strip additional information we may have.
550 p = strchr(os_build, '-');
556 * We don't have any other information about the FreeBSD os.
562 * Given the interface name, return the MAC address.
565 kvp_if_name_to_mac(char *if_name)
567 char *mac_addr = NULL;
568 struct ifaddrs *ifaddrs_ptr;
569 struct ifaddrs *head_ifaddrs_ptr;
570 struct sockaddr_dl *sdl;
573 status = getifaddrs(&ifaddrs_ptr);
576 head_ifaddrs_ptr = ifaddrs_ptr;
578 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
579 if ((sdl->sdl_type == IFT_ETHER) &&
580 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
581 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
584 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
585 freeifaddrs(head_ifaddrs_ptr);
593 * Given the MAC address, return the interface name.
596 kvp_mac_to_if_name(char *mac)
598 char *if_name = NULL;
599 struct ifaddrs *ifaddrs_ptr;
600 struct ifaddrs *head_ifaddrs_ptr;
601 struct sockaddr_dl *sdl;
606 status = getifaddrs(&ifaddrs_ptr);
609 head_ifaddrs_ptr = ifaddrs_ptr;
611 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
612 if (sdl->sdl_type == IFT_ETHER) {
613 buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
614 for (i = 0; i < strlen(buf_ptr); i++)
616 buf_ptr[i] = toupper(buf_ptr[i]);
619 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
620 /* Caller will free the memory */
621 if_name = strdup(ifaddrs_ptr->ifa_name);
624 }else if (buf_ptr != NULL) {
628 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
629 freeifaddrs(head_ifaddrs_ptr);
636 kvp_process_ipconfig_file(char *cmd,
637 char *config_buf, size_t len,
638 size_t element_size, int offset)
646 * First execute the command.
648 file = popen(cmd, "r");
654 memset(config_buf, 0, len);
656 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
657 if ((len - strlen(config_buf)) < (element_size + 1)) {
663 strlcat(config_buf, p, len);
664 strlcat(config_buf, ";", len);
671 kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer)
679 * Retrieve the IPV4 address of default gateway.
681 snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
684 * Execute the command to gather gateway IPV4 info.
686 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
687 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
690 * Retrieve the IPV6 address of default gateway.
692 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }", if_name);
695 * Execute the command to gather gateway IPV6 info.
697 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
698 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
701 * we just invoke an external script to get the DNS info.
703 * Following is the expected format of the information from the script:
705 * ipaddr1 (nameserver1)
706 * ipaddr2 (nameserver2)
710 /* Scripts are stored in /usr/libexec/hyperv/ directory */
711 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
714 * Execute the command to get DNS info.
716 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
717 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
720 * Invoke an external script to get the DHCP state info.
721 * The parameter to the script is the interface name.
722 * Here is the expected output:
724 * Enabled: DHCP enabled.
728 snprintf(cmd, sizeof(cmd), "%s %s",
729 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
731 file = popen(cmd, "r");
736 p = fgets(dhcp_info, sizeof(dhcp_info), file);
742 if (!strncmp(p, "Enabled", 7)) {
743 buffer->dhcp_enabled = 1;
745 buffer->dhcp_enabled = 0;
753 hweight32(unsigned int *w)
755 unsigned int res = *w - ((*w >> 1) & 0x55555555);
757 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
758 res = (res + (res >> 4)) & 0x0F0F0F0F;
759 res = res + (res >> 8);
760 return ((res + (res >> 16)) & 0x000000FF);
765 kvp_process_ip_address(void *addrp,
766 int family, char *buffer,
767 int length, int *offset)
769 struct sockaddr_in *addr;
770 struct sockaddr_in6 *addr6;
775 if (family == AF_INET) {
776 addr = (struct sockaddr_in *)addrp;
777 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
778 addr_length = INET_ADDRSTRLEN;
780 addr6 = (struct sockaddr_in6 *)addrp;
781 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
782 addr_length = INET6_ADDRSTRLEN;
785 if ((length - *offset) < addr_length + 1) {
786 return (HV_KVP_E_FAIL);
789 strlcpy(buffer, "inet_ntop failed\n", length);
790 return (HV_KVP_E_FAIL);
793 strlcpy(buffer, tmp, length);
795 strlcat(buffer, tmp, length);
797 strlcat(buffer, ";", length);
799 *offset += strlen(str) + 1;
805 kvp_get_ip_info(int family, char *if_name, int op,
806 void *out_buffer, size_t length)
808 struct ifaddrs *ifap;
809 struct ifaddrs *curp;
814 size_t buffer_length;
815 struct hv_kvp_ipaddr_value *ip_buffer;
819 unsigned int *w = NULL;
821 size_t sn_str_length;
822 struct sockaddr_in6 *addr6;
824 if (op == HV_KVP_OP_ENUMERATE) {
826 buffer_length = length;
828 ip_buffer = out_buffer;
829 buffer = (char *)ip_buffer->ip_addr;
830 buffer_length = sizeof(ip_buffer->ip_addr);
831 ip_buffer->addr_family = 0;
834 if (getifaddrs(&ifap)) {
835 strlcpy(buffer, "getifaddrs failed\n", buffer_length);
836 return (HV_KVP_E_FAIL);
840 while (curp != NULL) {
841 if (curp->ifa_addr == NULL) {
842 curp = curp->ifa_next;
846 if ((if_name != NULL) &&
847 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
849 * We want info about a specific interface;
852 curp = curp->ifa_next;
857 * We support two address families: AF_INET and AF_INET6.
858 * If family value is 0, we gather both supported
859 * address families; if not we gather info on
860 * the specified address family.
862 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
863 curp = curp->ifa_next;
866 if ((curp->ifa_addr->sa_family != AF_INET) &&
867 (curp->ifa_addr->sa_family != AF_INET6)) {
868 curp = curp->ifa_next;
872 if (op == HV_KVP_OP_GET_IP_INFO) {
874 * Get the info other than the IP address.
876 if (curp->ifa_addr->sa_family == AF_INET) {
877 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
882 error = kvp_process_ip_address(
890 goto kvp_get_ip_info_ipaddr;
893 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
896 * Get subnet info in CIDR format.
899 sn_str = (char *)ip_buffer->sub_net;
900 sn_str_length = sizeof(ip_buffer->sub_net);
901 addr6 = (struct sockaddr_in6 *)(uintptr_t)
903 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
905 for (i = 0; i < 4; i++)
907 weight += hweight32(&w[i]);
910 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
911 if ((length - sn_offset) <
912 (strlen(cidr_mask) + 1)) {
913 goto kvp_get_ip_info_ipaddr;
916 if (sn_offset == 0) {
917 strlcpy(sn_str, cidr_mask, sn_str_length);
919 strlcat(sn_str, cidr_mask, sn_str_length);
921 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
922 sn_offset += strlen(sn_str) + 1;
926 * Collect other ip configuration info.
929 kvp_get_ipconfig_info(if_name, ip_buffer);
932 kvp_get_ip_info_ipaddr:
933 error = kvp_process_ip_address(curp->ifa_addr,
934 curp->ifa_addr->sa_family,
938 goto kvp_get_ip_info_done;
941 curp = curp->ifa_next;
944 kvp_get_ip_info_done:
951 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
955 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
958 return (HV_KVP_E_FAIL);
966 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
975 * FreeBSD - Configuration File
977 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
979 file = fopen(if_file, "w");
982 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
983 return (HV_KVP_E_FAIL);
987 * Write out the MAC address.
990 mac_addr = kvp_if_name_to_mac(if_name);
991 if (mac_addr == NULL) {
992 error = HV_KVP_E_FAIL;
993 goto kvp_set_ip_info_error;
996 error = kvp_write_file(file, "HWADDR", "", mac_addr);
998 goto kvp_set_ip_info_error;
1001 /* Interface Name */
1002 error = kvp_write_file(file, "IF_NAME", "", if_name);
1004 goto kvp_set_ip_info_error;
1008 error = kvp_write_file(file, "IP_ADDR", "",
1009 (char *)new_val->ip_addr);
1011 goto kvp_set_ip_info_error;
1015 error = kvp_write_file(file, "SUBNET", "",
1016 (char *)new_val->sub_net);
1018 goto kvp_set_ip_info_error;
1023 error = kvp_write_file(file, "GATEWAY", "",
1024 (char *)new_val->gate_way);
1026 goto kvp_set_ip_info_error;
1030 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1032 goto kvp_set_ip_info_error;
1036 if (new_val->dhcp_enabled) {
1037 error = kvp_write_file(file, "DHCP", "", "1");
1039 error = kvp_write_file(file, "DHCP", "", "0");
1043 goto kvp_set_ip_info_error;
1050 * Invoke the external script with the populated
1051 * configuration file.
1054 snprintf(cmd, sizeof(cmd), "%s %s",
1055 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1059 kvp_set_ip_info_error:
1060 KVP_LOG(LOG_ERR, "Failed to write config file\n");
1068 kvp_get_domain_name(char *buffer, int length)
1070 struct addrinfo hints, *info;
1073 gethostname(buffer, length);
1074 memset(&hints, 0, sizeof(hints));
1075 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */
1076 hints.ai_socktype = SOCK_STREAM;
1077 hints.ai_flags = AI_CANONNAME;
1079 error = getaddrinfo(buffer, NULL, &hints, &info);
1081 strlcpy(buffer, "getaddrinfo failed\n", length);
1084 strlcpy(buffer, info->ai_canonname, length);
1091 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1093 struct hv_kvp_ipaddr_value *ip_val;
1096 assert(op_msg != NULL);
1097 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1099 ip_val = &op_msg->body.kvp_ip_val;
1100 op_msg->hdr.error = HV_KVP_S_OK;
1102 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1104 if (if_name == NULL) {
1105 /* No interface found with the mac address. */
1106 op_msg->hdr.error = HV_KVP_E_FAIL;
1107 goto kvp_op_getipinfo_done;
1110 op_msg->hdr.error = kvp_get_ip_info(0, if_name,
1111 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1115 kvp_op_getipinfo_done:
1116 return(op_msg->hdr.error);
1121 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1123 struct hv_kvp_ipaddr_value *ip_val;
1126 assert(op_msg != NULL);
1127 KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1129 ip_val = &op_msg->body.kvp_ip_val;
1130 op_msg->hdr.error = HV_KVP_S_OK;
1132 if_name = (char *)ip_val->adapter_id;
1134 if (if_name == NULL) {
1135 /* No adapter provided. */
1136 op_msg->hdr.error = HV_KVP_GUID_NOTFOUND;
1137 goto kvp_op_setipinfo_done;
1140 op_msg->hdr.error = kvp_set_ip_info(if_name, ip_val);
1142 kvp_op_setipinfo_done:
1143 return(op_msg->hdr.error);
1148 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1150 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1154 assert(op_msg != NULL);
1155 assert(op_hdlr != NULL);
1157 op_pool = op_msg->hdr.kvp_hdr.pool;
1158 op_msg->hdr.error = HV_KVP_S_OK;
1160 switch(op_hdlr->kvp_op_key) {
1162 if (op_pool == HV_KVP_POOL_AUTO) {
1163 /* Auto Pool is not writeable from host side. */
1165 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1168 error = kvp_key_add_or_modify(op_pool,
1169 op_msg->body.kvp_set.data.key,
1170 op_msg->body.kvp_set.data.key_size,
1171 op_msg->body.kvp_set.data.msg_value.value,
1172 op_msg->body.kvp_set.data.value_size);
1177 error = kvp_get_value(op_pool,
1178 op_msg->body.kvp_get.data.key,
1179 op_msg->body.kvp_get.data.key_size,
1180 op_msg->body.kvp_get.data.msg_value.value,
1181 op_msg->body.kvp_get.data.value_size);
1184 case HV_KVP_OP_DELETE:
1185 if (op_pool == HV_KVP_POOL_AUTO) {
1186 /* Auto Pool is not writeable from host side. */
1188 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1191 error = kvp_key_delete(op_pool,
1192 op_msg->body.kvp_delete.key,
1193 op_msg->body.kvp_delete.key_size);
1202 op_msg->hdr.error = HV_KVP_S_CONT;
1209 kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1211 char *key_name, *key_value;
1216 assert(op_msg != NULL);
1218 op = op_msg->hdr.kvp_hdr.operation;
1219 op_pool = op_msg->hdr.kvp_hdr.pool;
1220 op_msg->hdr.error = HV_KVP_S_OK;
1223 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1224 * pool and return the KVP according to the index requested.
1226 if (op_pool != HV_KVP_POOL_AUTO) {
1227 if (kvp_pool_enumerate(op_pool,
1228 op_msg->body.kvp_enum_data.index,
1229 op_msg->body.kvp_enum_data.data.key,
1230 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1231 op_msg->body.kvp_enum_data.data.msg_value.value,
1232 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1233 op_msg->hdr.error = HV_KVP_S_CONT;
1236 goto kvp_op_enumerate_done;
1239 key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1240 key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1242 switch (op_msg->body.kvp_enum_data.index)
1244 case FullyQualifiedDomainName:
1245 kvp_get_domain_name(key_value,
1246 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1247 strcpy(key_name, "FullyQualifiedDomainName");
1250 case IntegrationServicesVersion:
1251 strcpy(key_name, "IntegrationServicesVersion");
1252 strcpy(key_value, lic_version);
1255 case NetworkAddressIPv4:
1256 kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1257 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1258 strcpy(key_name, "NetworkAddressIPv4");
1261 case NetworkAddressIPv6:
1262 kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1263 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1264 strcpy(key_name, "NetworkAddressIPv6");
1268 strcpy(key_value, os_build);
1269 strcpy(key_name, "OSBuildNumber");
1273 strcpy(key_value, os_name);
1274 strcpy(key_name, "OSName");
1277 case OSMajorVersion:
1278 strcpy(key_value, os_major);
1279 strcpy(key_name, "OSMajorVersion");
1282 case OSMinorVersion:
1283 strcpy(key_value, os_minor);
1284 strcpy(key_name, "OSMinorVersion");
1288 strcpy(key_value, os_build);
1289 strcpy(key_name, "OSVersion");
1292 case ProcessorArchitecture:
1293 strcpy(key_value, processor_arch);
1294 strcpy(key_name, "ProcessorArchitecture");
1299 KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1300 op_msg->body.kvp_enum_data.index);
1302 op_msg->hdr.error = HV_KVP_S_CONT;
1307 kvp_op_enumerate_done:
1313 * Load handler, and call init routine if provided.
1316 kvp_op_load(int key, void (*init)(void),
1317 int (*exec)(struct hv_kvp_msg *, void *))
1321 if (key < 0 || key >= HV_KVP_OP_COUNT) {
1322 KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1324 goto kvp_op_load_done;
1327 kvp_op_hdlrs[key].kvp_op_key = key;
1328 kvp_op_hdlrs[key].kvp_op_init = init;
1329 kvp_op_hdlrs[key].kvp_op_exec = exec;
1331 if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1332 kvp_op_hdlrs[key].kvp_op_init();
1340 * Initialize the operation hanlders.
1347 /* Set the initial values. */
1348 for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1349 kvp_op_hdlrs[i].kvp_op_key = -1;
1350 kvp_op_hdlrs[i].kvp_op_init = NULL;
1351 kvp_op_hdlrs[i].kvp_op_exec = NULL;
1354 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1355 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1356 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1357 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1359 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1360 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1365 main(int argc, char *argv[])
1367 struct hv_kvp_msg *hv_kvp_dev_buf;
1368 struct hv_kvp_msg *hv_msg;
1369 struct pollfd hv_kvp_poll_fd[1];
1371 int hv_kvp_dev_fd, error, len, r;
1374 while ((ch = getopt(argc, argv, "dn")) != -1) {
1377 /* Run as regular process for debugging purpose. */
1381 /* Generate debugging output */
1389 openlog("HV_KVP", 0, LOG_USER);
1391 /* Become daemon first. */
1395 KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1397 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1399 /* Communication buffer hv_kvp_dev_buf */
1400 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1401 /* Buffer for daemon internal use */
1402 hv_msg = malloc(sizeof(*hv_msg));
1404 /* Memory allocation failed */
1405 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1406 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1410 /* Initialize op handlers */
1411 if (kvp_ops_init() != 0) {
1412 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1416 if (kvp_file_init()) {
1417 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1421 /* Open the Character Device */
1422 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1424 if (hv_kvp_dev_fd < 0) {
1425 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1426 errno, strerror(errno));
1430 /* Initialize the struct for polling the char device */
1431 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1432 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1434 /* Register the daemon to the KVP driver */
1435 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1436 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1437 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1441 r = poll (hv_kvp_poll_fd, 1, 100);
1443 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1444 r, hv_kvp_poll_fd[0].revents);
1446 if (r == 0 || (r < 0 && errno == EAGAIN) ||
1447 (r < 0 && errno == EINTR)) {
1448 /* Nothing to read */
1454 * For pread return failure other than EAGAIN,
1457 KVP_LOG(LOG_ERR, "Poll failed.\n");
1462 /* Read from character device */
1463 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1464 sizeof(*hv_kvp_dev_buf), 0);
1467 KVP_LOG(LOG_ERR, "Read failed.\n");
1472 if (len != sizeof(struct hv_kvp_msg)) {
1473 KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1477 /* Copy hv_kvp_dev_buf to hv_msg */
1478 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1481 * We will use the KVP header information to pass back
1482 * the error from this daemon. So, first save the op
1483 * and pool info to local variables.
1486 op = hv_msg->hdr.kvp_hdr.operation;
1487 pool = hv_msg->hdr.kvp_hdr.pool;
1489 if (op < 0 || op >= HV_KVP_OP_COUNT ||
1490 kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1491 KVP_LOG(LOG_WARNING,
1492 "Unsupported operation OP = %d\n", op);
1493 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1496 * Call the operateion handler's execution routine.
1498 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1499 (void *)&kvp_op_hdlrs[op]);
1500 if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT)
1501 KVP_LOG(LOG_WARNING,
1502 "Operation failed OP = %d, error = 0x%x\n",
1507 * Send the value back to the kernel. The response is
1508 * already in the receive buffer.
1511 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1513 if (len != sizeof(struct hv_kvp_msg)) {
1514 KVP_LOG(LOG_ERR, "write len is: %d\n", len);