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;
69 FullyQualifiedDomainName = 0,
70 IntegrationServicesVersion, /*This key is serviced in the kernel*/
90 /* Global Variables */
93 * The structure for operation handlers.
97 void (*kvp_op_init)(void);
98 int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
101 static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
105 static const char *os_name = "";
106 static const char *os_major = "";
107 static const char *os_minor = "";
108 static const char *processor_arch;
109 static const char *os_build;
110 static const char *lic_version = "BSD Pre-Release version";
111 static struct utsname uts_buf;
114 static int is_daemon = 1;
115 static int is_debugging = 0;
117 #define KVP_LOG(priority, format, args...) do { \
118 if (is_debugging == 1) { \
119 if (is_daemon == 1) \
120 syslog(priority, format, ## args); \
122 printf(format, ## args); \
124 if (priority < LOG_DEBUG) { \
125 if (is_daemon == 1) \
126 syslog(priority, format, ## args); \
128 printf(format, ## args); \
137 #define MAX_FILE_NAME 100
138 #define ENTRIES_PER_BLOCK 50
141 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
142 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
148 struct kvp_record *records;
150 char fname[MAX_FILE_NAME];
153 static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
157 kvp_acquire_lock(int pool)
159 struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
163 if (fcntl(kvp_pools[pool].pool_fd, F_SETLKW, &fl) == -1) {
164 KVP_LOG(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
171 kvp_release_lock(int pool)
173 struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
177 if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
179 KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
186 * Write in-memory copy of KVP to pool files
189 kvp_update_file(int pool)
192 size_t bytes_written;
194 kvp_acquire_lock(pool);
196 filep = fopen(kvp_pools[pool].fname, "w");
198 kvp_release_lock(pool);
199 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
203 bytes_written = fwrite(kvp_pools[pool].records,
204 sizeof(struct kvp_record),
205 kvp_pools[pool].num_records, filep);
207 if (ferror(filep) || fclose(filep)) {
208 kvp_release_lock(pool);
209 KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
213 kvp_release_lock(pool);
218 * Read KVPs from pool files and store in memory
221 kvp_update_mem_state(int pool)
224 size_t records_read = 0;
225 struct kvp_record *record = kvp_pools[pool].records;
226 struct kvp_record *readp;
227 int num_blocks = kvp_pools[pool].num_blocks;
228 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
230 kvp_acquire_lock(pool);
232 filep = fopen(kvp_pools[pool].fname, "r");
234 kvp_release_lock(pool);
235 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
240 readp = &record[records_read];
241 records_read += fread(readp, sizeof(struct kvp_record),
242 ENTRIES_PER_BLOCK * num_blocks,
246 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
252 * Have more data to read. Expand the memory.
255 record = realloc(record, alloc_unit * num_blocks);
257 if (record == NULL) {
258 KVP_LOG(LOG_ERR, "malloc failed\n");
266 kvp_pools[pool].num_blocks = num_blocks;
267 kvp_pools[pool].records = record;
268 kvp_pools[pool].num_records = records_read;
271 kvp_release_lock(pool);
282 struct kvp_record *record;
283 struct kvp_record *readp;
286 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
288 if (mkdir("/var/db/hyperv/pool", S_IRUSR | S_IWUSR | S_IROTH) < 0 &&
289 (errno != EEXIST && errno != EISDIR)) {
290 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
294 for (i = 0; i < HV_KVP_POOL_COUNT; i++)
296 fname = kvp_pools[i].fname;
299 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
300 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
307 filep = fopen(fname, "r");
313 record = malloc(alloc_unit * num_blocks);
314 if (record == NULL) {
321 readp = &record[records_read];
322 records_read += fread(readp, sizeof(struct kvp_record),
327 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
337 record = realloc(record, alloc_unit *
339 if (record == NULL) {
348 kvp_pools[i].pool_fd = fd;
349 kvp_pools[i].num_blocks = num_blocks;
350 kvp_pools[i].records = record;
351 kvp_pools[i].num_records = records_read;
360 kvp_key_delete(int pool, __u8 *key, int key_size)
365 struct kvp_record *record;
367 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, "
368 "key = %s\n", pool, key);
370 /* Update in-memory state */
371 kvp_update_mem_state(pool);
373 num_records = kvp_pools[pool].num_records;
374 record = kvp_pools[pool].records;
376 for (i = 0; i < num_records; i++)
378 if (memcmp(key, record[i].key, key_size)) {
382 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
385 * We found a match at the end; Just update the number of
386 * entries and we are done.
388 if (i == num_records) {
389 kvp_pools[pool].num_records--;
390 kvp_update_file(pool);
395 * We found a match in the middle; Move the remaining
400 for ( ; k < num_records; k++)
402 strcpy(record[j].key, record[k].key);
403 strcpy(record[j].value, record[k].value);
406 kvp_pools[pool].num_records--;
407 kvp_update_file(pool);
410 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
417 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
422 struct kvp_record *record;
425 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, "
426 "key = %s, value = %s\n,", pool, key, value);
428 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
429 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
430 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
434 /* Update the in-memory state. */
435 kvp_update_mem_state(pool);
437 num_records = kvp_pools[pool].num_records;
438 record = kvp_pools[pool].records;
439 num_blocks = kvp_pools[pool].num_blocks;
441 for (i = 0; i < num_records; i++)
443 if (memcmp(key, record[i].key, key_size)) {
448 * Key exists. Just update the value and we are done.
450 memcpy(record[i].value, value, value_size);
451 kvp_update_file(pool);
456 * Key doesn't exist; Add a new KVP.
458 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
459 /* Increase the size of the recodrd array. */
460 record = realloc(record, sizeof(struct kvp_record) *
461 ENTRIES_PER_BLOCK * (num_blocks + 1));
463 if (record == NULL) {
466 kvp_pools[pool].num_blocks++;
468 memcpy(record[i].value, value, value_size);
469 memcpy(record[i].key, key, key_size);
470 kvp_pools[pool].records = record;
471 kvp_pools[pool].num_records++;
472 kvp_update_file(pool);
478 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
483 struct kvp_record *record;
485 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,",
488 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
489 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
493 /* Update the in-memory state first. */
494 kvp_update_mem_state(pool);
496 num_records = kvp_pools[pool].num_records;
497 record = kvp_pools[pool].records;
499 for (i = 0; i < num_records; i++)
501 if (memcmp(key, record[i].key, key_size)) {
506 memcpy(value, record[i].value, value_size);
515 kvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size,
516 __u8 *value, int value_size)
518 struct kvp_record *record;
520 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
523 /* First update our in-memory state first. */
524 kvp_update_mem_state(pool);
525 record = kvp_pools[pool].records;
527 /* Index starts with 0 */
528 if (idx >= kvp_pools[pool].num_records) {
532 memcpy(key, record[idx].key, key_size);
533 memcpy(value, record[idx].value, value_size);
539 kvp_get_os_info(void)
544 os_build = uts_buf.release;
545 os_name = uts_buf.sysname;
546 processor_arch = uts_buf.machine;
549 * Win7 host expects the build string to be of the form: x.y.z
550 * Strip additional information we may have.
552 p = strchr(os_build, '-');
558 * We don't have any other information about the FreeBSD os.
564 * Given the interface name, return the MAC address.
567 kvp_if_name_to_mac(char *if_name)
569 char *mac_addr = NULL;
570 struct ifaddrs *ifaddrs_ptr;
571 struct ifaddrs *head_ifaddrs_ptr;
572 struct sockaddr_dl *sdl;
575 status = getifaddrs(&ifaddrs_ptr);
578 head_ifaddrs_ptr = ifaddrs_ptr;
580 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
581 if ((sdl->sdl_type == IFT_ETHER) &&
582 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
583 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
586 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
587 freeifaddrs(head_ifaddrs_ptr);
595 * Given the MAC address, return the interface name.
598 kvp_mac_to_if_name(char *mac)
600 char *if_name = NULL;
601 struct ifaddrs *ifaddrs_ptr;
602 struct ifaddrs *head_ifaddrs_ptr;
603 struct sockaddr_dl *sdl;
607 status = getifaddrs(&ifaddrs_ptr);
610 head_ifaddrs_ptr = ifaddrs_ptr;
612 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
613 if (sdl->sdl_type == IFT_ETHER) {
614 buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
615 if (buf_ptr != NULL) {
616 for (p = buf_ptr; *p != '\0'; p++)
619 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
620 /* Caller will free the memory */
621 if_name = strdup(ifaddrs_ptr->ifa_name);
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);
689 * Retrieve the IPV6 address of default gateway.
691 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }'", if_name);
694 * Execute the command to gather gateway IPV6 info.
696 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
697 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
699 * we just invoke an external script to get the DNS info.
701 * Following is the expected format of the information from the script:
703 * ipaddr1 (nameserver1)
704 * ipaddr2 (nameserver2)
708 /* Scripts are stored in /usr/libexec/hyperv/ directory */
709 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
712 * Execute the command to get DNS info.
714 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
715 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
718 * Invoke an external script to get the DHCP state info.
719 * The parameter to the script is the interface name.
720 * Here is the expected output:
722 * Enabled: DHCP enabled.
726 snprintf(cmd, sizeof(cmd), "%s %s",
727 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
729 file = popen(cmd, "r");
734 p = fgets(dhcp_info, sizeof(dhcp_info), file);
740 if (!strncmp(p, "Enabled", 7)) {
741 buffer->dhcp_enabled = 1;
743 buffer->dhcp_enabled = 0;
751 hweight32(unsigned int *w)
753 unsigned int res = *w - ((*w >> 1) & 0x55555555);
755 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
756 res = (res + (res >> 4)) & 0x0F0F0F0F;
757 res = res + (res >> 8);
758 return ((res + (res >> 16)) & 0x000000FF);
763 kvp_process_ip_address(void *addrp,
764 int family, char *buffer,
765 int length, int *offset)
767 struct sockaddr_in *addr;
768 struct sockaddr_in6 *addr6;
773 if (family == AF_INET) {
774 addr = (struct sockaddr_in *)addrp;
775 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
776 addr_length = INET_ADDRSTRLEN;
778 addr6 = (struct sockaddr_in6 *)addrp;
779 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
780 addr_length = INET6_ADDRSTRLEN;
783 if ((length - *offset) < addr_length + 1) {
787 strlcpy(buffer, "inet_ntop failed\n", length);
791 strlcpy(buffer, tmp, length);
793 strlcat(buffer, tmp, length);
795 strlcat(buffer, ";", length);
797 *offset += strlen(str) + 1;
803 kvp_get_ip_info(int family, char *if_name, int op,
804 void *out_buffer, size_t length)
806 struct ifaddrs *ifap;
807 struct ifaddrs *curp;
812 size_t buffer_length;
813 struct hv_kvp_ipaddr_value *ip_buffer;
817 unsigned int *w = NULL;
819 size_t sn_str_length;
820 struct sockaddr_in6 *addr6;
822 if (op == HV_KVP_OP_ENUMERATE) {
824 buffer_length = length;
826 ip_buffer = out_buffer;
827 buffer = (char *)ip_buffer->ip_addr;
828 buffer_length = sizeof(ip_buffer->ip_addr);
829 ip_buffer->addr_family = 0;
832 if (getifaddrs(&ifap)) {
833 strlcpy(buffer, "getifaddrs failed\n", buffer_length);
838 while (curp != NULL) {
839 if (curp->ifa_addr == NULL) {
840 curp = curp->ifa_next;
844 if ((if_name != NULL) &&
845 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
847 * We want info about a specific interface;
850 curp = curp->ifa_next;
855 * We support two address families: AF_INET and AF_INET6.
856 * If family value is 0, we gather both supported
857 * address families; if not we gather info on
858 * the specified address family.
860 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
861 curp = curp->ifa_next;
864 if ((curp->ifa_addr->sa_family != AF_INET) &&
865 (curp->ifa_addr->sa_family != AF_INET6)) {
866 curp = curp->ifa_next;
870 if (op == HV_KVP_OP_GET_IP_INFO) {
872 * Get the info other than the IP address.
874 if (curp->ifa_addr->sa_family == AF_INET) {
875 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
880 error = kvp_process_ip_address(
888 goto kvp_get_ip_info_ipaddr;
891 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
894 * Get subnet info in CIDR format.
897 sn_str = (char *)ip_buffer->sub_net;
898 sn_str_length = sizeof(ip_buffer->sub_net);
899 addr6 = (struct sockaddr_in6 *)(uintptr_t)
901 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
903 for (i = 0; i < 4; i++)
905 weight += hweight32(&w[i]);
908 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
909 if ((length - sn_offset) <
910 (strlen(cidr_mask) + 1)) {
911 goto kvp_get_ip_info_ipaddr;
914 if (sn_offset == 0) {
915 strlcpy(sn_str, cidr_mask, sn_str_length);
917 strlcat(sn_str, cidr_mask, sn_str_length);
919 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
920 sn_offset += strlen(sn_str) + 1;
924 * Collect other ip configuration info.
926 kvp_get_ipconfig_info(if_name, ip_buffer);
929 kvp_get_ip_info_ipaddr:
930 error = kvp_process_ip_address(curp->ifa_addr,
931 curp->ifa_addr->sa_family,
935 goto kvp_get_ip_info_done;
938 curp = curp->ifa_next;
941 kvp_get_ip_info_done:
948 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
952 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
963 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
972 * FreeBSD - Configuration File
974 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
976 file = fopen(if_file, "w");
979 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
984 * Write out the MAC address.
987 mac_addr = kvp_if_name_to_mac(if_name);
988 if (mac_addr == NULL) {
990 goto kvp_set_ip_info_error;
993 error = kvp_write_file(file, "HWADDR", "", mac_addr);
995 goto kvp_set_ip_info_error;
999 error = kvp_write_file(file, "IF_NAME", "", if_name);
1001 goto kvp_set_ip_info_error;
1005 error = kvp_write_file(file, "IP_ADDR", "",
1006 (char *)new_val->ip_addr);
1008 goto kvp_set_ip_info_error;
1012 error = kvp_write_file(file, "SUBNET", "",
1013 (char *)new_val->sub_net);
1015 goto kvp_set_ip_info_error;
1020 error = kvp_write_file(file, "GATEWAY", "",
1021 (char *)new_val->gate_way);
1023 goto kvp_set_ip_info_error;
1027 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1029 goto kvp_set_ip_info_error;
1033 if (new_val->dhcp_enabled) {
1034 error = kvp_write_file(file, "DHCP", "", "1");
1036 error = kvp_write_file(file, "DHCP", "", "0");
1040 goto kvp_set_ip_info_error;
1047 * Invoke the external script with the populated
1048 * configuration file.
1051 snprintf(cmd, sizeof(cmd), "%s %s",
1052 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1056 kvp_set_ip_info_error:
1057 KVP_LOG(LOG_ERR, "Failed to write config file\n");
1065 kvp_get_domain_name(char *buffer, int length)
1067 struct addrinfo hints, *info;
1070 gethostname(buffer, length);
1071 memset(&hints, 0, sizeof(hints));
1072 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */
1073 hints.ai_socktype = SOCK_STREAM;
1074 hints.ai_flags = AI_CANONNAME;
1076 error = getaddrinfo(buffer, NULL, &hints, &info);
1078 strlcpy(buffer, "getaddrinfo failed\n", length);
1081 strlcpy(buffer, info->ai_canonname, length);
1088 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1090 struct hv_kvp_ipaddr_value *ip_val;
1094 assert(op_msg != NULL);
1095 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1097 ip_val = &op_msg->body.kvp_ip_val;
1098 op_msg->hdr.error = HV_S_OK;
1100 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1102 if (if_name == NULL) {
1103 /* No interface found with the mac address. */
1104 op_msg->hdr.error = HV_E_FAIL;
1105 goto kvp_op_getipinfo_done;
1108 error = kvp_get_ip_info(0, if_name,
1109 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1111 op_msg->hdr.error = HV_E_FAIL;
1114 kvp_op_getipinfo_done:
1120 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1122 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_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_GUID_NOTFOUND;
1137 goto kvp_op_setipinfo_done;
1140 error = kvp_set_ip_info(if_name, ip_val);
1142 op_msg->hdr.error = HV_E_FAIL;
1143 kvp_op_setipinfo_done:
1149 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1151 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1155 assert(op_msg != NULL);
1156 assert(op_hdlr != NULL);
1158 op_pool = op_msg->hdr.kvp_hdr.pool;
1159 op_msg->hdr.error = HV_S_OK;
1161 switch(op_hdlr->kvp_op_key) {
1163 if (op_pool == HV_KVP_POOL_AUTO) {
1164 /* Auto Pool is not writeable from host side. */
1166 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1169 error = kvp_key_add_or_modify(op_pool,
1170 op_msg->body.kvp_set.data.key,
1171 op_msg->body.kvp_set.data.key_size,
1172 op_msg->body.kvp_set.data.msg_value.value,
1173 op_msg->body.kvp_set.data.value_size);
1178 error = kvp_get_value(op_pool,
1179 op_msg->body.kvp_get.data.key,
1180 op_msg->body.kvp_get.data.key_size,
1181 op_msg->body.kvp_get.data.msg_value.value,
1182 op_msg->body.kvp_get.data.value_size);
1185 case HV_KVP_OP_DELETE:
1186 if (op_pool == HV_KVP_POOL_AUTO) {
1187 /* Auto Pool is not writeable from host side. */
1189 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1192 error = kvp_key_delete(op_pool,
1193 op_msg->body.kvp_delete.key,
1194 op_msg->body.kvp_delete.key_size);
1203 op_msg->hdr.error = HV_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_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_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 strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
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 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1269 strcpy(key_name, "OSBuildNumber");
1273 strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1274 strcpy(key_name, "OSName");
1277 case OSMajorVersion:
1278 strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1279 strcpy(key_name, "OSMajorVersion");
1282 case OSMinorVersion:
1283 strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1284 strcpy(key_name, "OSMinorVersion");
1288 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1289 strcpy(key_name, "OSVersion");
1292 case ProcessorArchitecture:
1293 strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
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_S_CONT;
1307 kvp_op_enumerate_done:
1309 op_msg->hdr.error = HV_S_CONT;
1315 * Load handler, and call init routine if provided.
1318 kvp_op_load(int key, void (*init)(void),
1319 int (*exec)(struct hv_kvp_msg *, void *))
1323 if (key < 0 || key >= HV_KVP_OP_COUNT) {
1324 KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1326 goto kvp_op_load_done;
1329 kvp_op_hdlrs[key].kvp_op_key = key;
1330 kvp_op_hdlrs[key].kvp_op_init = init;
1331 kvp_op_hdlrs[key].kvp_op_exec = exec;
1333 if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1334 kvp_op_hdlrs[key].kvp_op_init();
1342 * Initialize the operation hanlders.
1349 /* Set the initial values. */
1350 for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1351 kvp_op_hdlrs[i].kvp_op_key = -1;
1352 kvp_op_hdlrs[i].kvp_op_init = NULL;
1353 kvp_op_hdlrs[i].kvp_op_exec = NULL;
1356 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1357 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1358 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1359 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1361 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1362 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1367 main(int argc, char *argv[])
1369 struct hv_kvp_msg *hv_kvp_dev_buf;
1370 struct hv_kvp_msg *hv_msg;
1371 struct pollfd hv_kvp_poll_fd[1];
1373 int hv_kvp_dev_fd, error, len, r;
1376 while ((ch = getopt(argc, argv, "dn")) != -1) {
1379 /* Run as regular process for debugging purpose. */
1383 /* Generate debugging output */
1391 openlog("HV_KVP", 0, LOG_USER);
1393 /* Become daemon first. */
1397 KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1399 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1401 /* Communication buffer hv_kvp_dev_buf */
1402 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1403 /* Buffer for daemon internal use */
1404 hv_msg = malloc(sizeof(*hv_msg));
1406 /* Memory allocation failed */
1407 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1408 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1412 /* Initialize op handlers */
1413 if (kvp_ops_init() != 0) {
1414 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1418 if (kvp_file_init()) {
1419 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1423 /* Open the Character Device */
1424 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1426 if (hv_kvp_dev_fd < 0) {
1427 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1428 errno, strerror(errno));
1432 /* Initialize the struct for polling the char device */
1433 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1434 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1436 /* Register the daemon to the KVP driver */
1437 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1438 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1439 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1443 r = poll (hv_kvp_poll_fd, 1, INFTIM);
1445 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1446 r, hv_kvp_poll_fd[0].revents);
1448 if (r == 0 || (r < 0 && errno == EAGAIN) ||
1449 (r < 0 && errno == EINTR)) {
1450 /* Nothing to read */
1456 * For pread return failure other than EAGAIN,
1459 KVP_LOG(LOG_ERR, "Poll failed.\n");
1464 /* Read from character device */
1465 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1466 sizeof(*hv_kvp_dev_buf), 0);
1469 KVP_LOG(LOG_ERR, "Read failed.\n");
1474 if (len != sizeof(struct hv_kvp_msg)) {
1475 KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1479 /* Copy hv_kvp_dev_buf to hv_msg */
1480 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1483 * We will use the KVP header information to pass back
1484 * the error from this daemon. So, first save the op
1485 * and pool info to local variables.
1488 op = hv_msg->hdr.kvp_hdr.operation;
1489 pool = hv_msg->hdr.kvp_hdr.pool;
1491 if (op < 0 || op >= HV_KVP_OP_COUNT ||
1492 kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1493 KVP_LOG(LOG_WARNING,
1494 "Unsupported operation OP = %d\n", op);
1495 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1498 * Call the operateion handler's execution routine.
1500 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1501 (void *)&kvp_op_hdlrs[op]);
1503 assert(hv_msg->hdr.error != HV_S_OK);
1504 if (hv_msg->hdr.error != HV_S_CONT)
1505 KVP_LOG(LOG_WARNING,
1506 "Operation failed OP = %d, error = 0x%x\n",
1512 * Send the value back to the kernel. The response is
1513 * already in the receive buffer.
1516 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1518 if (len != sizeof(struct hv_kvp_msg)) {
1519 KVP_LOG(LOG_ERR, "write len is: %d\n", len);