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 (mkdir("/var/db/hyperv/pool", S_IRUSR | S_IWUSR | S_IROTH) < 0 &&
289 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
293 for (i = 0; i < HV_KVP_POOL_COUNT; i++)
295 fname = kvp_pools[i].fname;
298 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
299 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
306 filep = fopen(fname, "r");
312 record = malloc(alloc_unit * num_blocks);
313 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) {
347 kvp_pools[i].pool_fd = fd;
348 kvp_pools[i].num_blocks = num_blocks;
349 kvp_pools[i].records = record;
350 kvp_pools[i].num_records = records_read;
359 kvp_key_delete(int pool, __u8 *key, int key_size)
364 struct kvp_record *record;
366 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, "
367 "key = %s\n", pool, key);
369 /* Update in-memory state */
370 kvp_update_mem_state(pool);
372 num_records = kvp_pools[pool].num_records;
373 record = kvp_pools[pool].records;
375 for (i = 0; i < num_records; i++)
377 if (memcmp(key, record[i].key, key_size)) {
381 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
384 * We found a match at the end; Just update the number of
385 * entries and we are done.
387 if (i == num_records) {
388 kvp_pools[pool].num_records--;
389 kvp_update_file(pool);
394 * We found a match in the middle; Move the remaining
399 for ( ; k < num_records; k++)
401 strcpy(record[j].key, record[k].key);
402 strcpy(record[j].value, record[k].value);
405 kvp_pools[pool].num_records--;
406 kvp_update_file(pool);
409 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
416 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
421 struct kvp_record *record;
424 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, "
425 "key = %s, value = %s\n,", pool, key, value);
427 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
428 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
429 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
433 /* Update the in-memory state. */
434 kvp_update_mem_state(pool);
436 num_records = kvp_pools[pool].num_records;
437 record = kvp_pools[pool].records;
438 num_blocks = kvp_pools[pool].num_blocks;
440 for (i = 0; i < num_records; i++)
442 if (memcmp(key, record[i].key, key_size)) {
447 * Key exists. Just update the value and we are done.
449 memcpy(record[i].value, value, value_size);
450 kvp_update_file(pool);
455 * Key doesn't exist; Add a new KVP.
457 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
458 /* Increase the size of the recodrd array. */
459 record = realloc(record, sizeof(struct kvp_record) *
460 ENTRIES_PER_BLOCK * (num_blocks + 1));
462 if (record == NULL) {
465 kvp_pools[pool].num_blocks++;
467 memcpy(record[i].value, value, value_size);
468 memcpy(record[i].key, key, key_size);
469 kvp_pools[pool].records = record;
470 kvp_pools[pool].num_records++;
471 kvp_update_file(pool);
477 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
482 struct kvp_record *record;
484 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,",
487 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
488 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
492 /* Update the in-memory state first. */
493 kvp_update_mem_state(pool);
495 num_records = kvp_pools[pool].num_records;
496 record = kvp_pools[pool].records;
498 for (i = 0; i < num_records; i++)
500 if (memcmp(key, record[i].key, key_size)) {
505 memcpy(value, record[i].value, value_size);
514 kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
515 __u8 *value, int value_size)
517 struct kvp_record *record;
519 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
522 /* First update our in-memory state first. */
523 kvp_update_mem_state(pool);
524 record = kvp_pools[pool].records;
526 /* Index starts with 0 */
527 if (index >= kvp_pools[pool].num_records) {
531 memcpy(key, record[index].key, key_size);
532 memcpy(value, record[index].value, value_size);
538 kvp_get_os_info(void)
543 os_build = uts_buf.release;
544 os_name = uts_buf.sysname;
545 processor_arch = uts_buf.machine;
548 * Win7 host expects the build string to be of the form: x.y.z
549 * Strip additional information we may have.
551 p = strchr(os_build, '-');
557 * We don't have any other information about the FreeBSD os.
563 * Given the interface name, return the MAC address.
566 kvp_if_name_to_mac(char *if_name)
568 char *mac_addr = NULL;
569 struct ifaddrs *ifaddrs_ptr;
570 struct ifaddrs *head_ifaddrs_ptr;
571 struct sockaddr_dl *sdl;
574 status = getifaddrs(&ifaddrs_ptr);
577 head_ifaddrs_ptr = ifaddrs_ptr;
579 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
580 if ((sdl->sdl_type == IFT_ETHER) &&
581 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
582 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
585 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
586 freeifaddrs(head_ifaddrs_ptr);
594 * Given the MAC address, return the interface name.
597 kvp_mac_to_if_name(char *mac)
599 char *if_name = NULL;
600 struct ifaddrs *ifaddrs_ptr;
601 struct ifaddrs *head_ifaddrs_ptr;
602 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 if (buf_ptr != NULL) {
615 for (p = buf_ptr; *p != '\0'; p++)
618 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
619 /* Caller will free the memory */
620 if_name = strdup(ifaddrs_ptr->ifa_name);
627 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
628 freeifaddrs(head_ifaddrs_ptr);
635 kvp_process_ipconfig_file(char *cmd,
636 char *config_buf, size_t len,
637 size_t element_size, int offset)
645 * First execute the command.
647 file = popen(cmd, "r");
653 memset(config_buf, 0, len);
655 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
656 if ((len - strlen(config_buf)) < (element_size + 1)) {
662 strlcat(config_buf, p, len);
663 strlcat(config_buf, ";", len);
670 kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer)
678 * Retrieve the IPV4 address of default gateway.
680 snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
683 * Execute the command to gather gateway IPV4 info.
685 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
686 (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);
700 * we just invoke an external script to get the DNS info.
702 * Following is the expected format of the information from the script:
704 * ipaddr1 (nameserver1)
705 * ipaddr2 (nameserver2)
709 /* Scripts are stored in /usr/libexec/hyperv/ directory */
710 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
713 * Execute the command to get DNS info.
715 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
716 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
719 * Invoke an external script to get the DHCP state info.
720 * The parameter to the script is the interface name.
721 * Here is the expected output:
723 * Enabled: DHCP enabled.
727 snprintf(cmd, sizeof(cmd), "%s %s",
728 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
730 file = popen(cmd, "r");
735 p = fgets(dhcp_info, sizeof(dhcp_info), file);
741 if (!strncmp(p, "Enabled", 7)) {
742 buffer->dhcp_enabled = 1;
744 buffer->dhcp_enabled = 0;
752 hweight32(unsigned int *w)
754 unsigned int res = *w - ((*w >> 1) & 0x55555555);
756 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
757 res = (res + (res >> 4)) & 0x0F0F0F0F;
758 res = res + (res >> 8);
759 return ((res + (res >> 16)) & 0x000000FF);
764 kvp_process_ip_address(void *addrp,
765 int family, char *buffer,
766 int length, int *offset)
768 struct sockaddr_in *addr;
769 struct sockaddr_in6 *addr6;
774 if (family == AF_INET) {
775 addr = (struct sockaddr_in *)addrp;
776 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
777 addr_length = INET_ADDRSTRLEN;
779 addr6 = (struct sockaddr_in6 *)addrp;
780 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
781 addr_length = INET6_ADDRSTRLEN;
784 if ((length - *offset) < addr_length + 1) {
785 return (HV_KVP_E_FAIL);
788 strlcpy(buffer, "inet_ntop failed\n", length);
789 return (HV_KVP_E_FAIL);
792 strlcpy(buffer, tmp, length);
794 strlcat(buffer, tmp, length);
796 strlcat(buffer, ";", length);
798 *offset += strlen(str) + 1;
804 kvp_get_ip_info(int family, char *if_name, int op,
805 void *out_buffer, size_t length)
807 struct ifaddrs *ifap;
808 struct ifaddrs *curp;
813 size_t buffer_length;
814 struct hv_kvp_ipaddr_value *ip_buffer;
818 unsigned int *w = NULL;
820 size_t sn_str_length;
821 struct sockaddr_in6 *addr6;
823 if (op == HV_KVP_OP_ENUMERATE) {
825 buffer_length = length;
827 ip_buffer = out_buffer;
828 buffer = (char *)ip_buffer->ip_addr;
829 buffer_length = sizeof(ip_buffer->ip_addr);
830 ip_buffer->addr_family = 0;
833 if (getifaddrs(&ifap)) {
834 strlcpy(buffer, "getifaddrs failed\n", buffer_length);
835 return (HV_KVP_E_FAIL);
839 while (curp != NULL) {
840 if (curp->ifa_addr == NULL) {
841 curp = curp->ifa_next;
845 if ((if_name != NULL) &&
846 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
848 * We want info about a specific interface;
851 curp = curp->ifa_next;
856 * We support two address families: AF_INET and AF_INET6.
857 * If family value is 0, we gather both supported
858 * address families; if not we gather info on
859 * the specified address family.
861 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
862 curp = curp->ifa_next;
865 if ((curp->ifa_addr->sa_family != AF_INET) &&
866 (curp->ifa_addr->sa_family != AF_INET6)) {
867 curp = curp->ifa_next;
871 if (op == HV_KVP_OP_GET_IP_INFO) {
873 * Get the info other than the IP address.
875 if (curp->ifa_addr->sa_family == AF_INET) {
876 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
881 error = kvp_process_ip_address(
889 goto kvp_get_ip_info_ipaddr;
892 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
895 * Get subnet info in CIDR format.
898 sn_str = (char *)ip_buffer->sub_net;
899 sn_str_length = sizeof(ip_buffer->sub_net);
900 addr6 = (struct sockaddr_in6 *)(uintptr_t)
902 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
904 for (i = 0; i < 4; i++)
906 weight += hweight32(&w[i]);
909 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
910 if ((length - sn_offset) <
911 (strlen(cidr_mask) + 1)) {
912 goto kvp_get_ip_info_ipaddr;
915 if (sn_offset == 0) {
916 strlcpy(sn_str, cidr_mask, sn_str_length);
918 strlcat(sn_str, cidr_mask, sn_str_length);
920 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
921 sn_offset += strlen(sn_str) + 1;
925 * Collect other ip configuration info.
928 kvp_get_ipconfig_info(if_name, ip_buffer);
931 kvp_get_ip_info_ipaddr:
932 error = kvp_process_ip_address(curp->ifa_addr,
933 curp->ifa_addr->sa_family,
937 goto kvp_get_ip_info_done;
940 curp = curp->ifa_next;
943 kvp_get_ip_info_done:
950 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
954 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
957 return (HV_KVP_E_FAIL);
965 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
974 * FreeBSD - Configuration File
976 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
978 file = fopen(if_file, "w");
981 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
982 return (HV_KVP_E_FAIL);
986 * Write out the MAC address.
989 mac_addr = kvp_if_name_to_mac(if_name);
990 if (mac_addr == NULL) {
991 error = HV_KVP_E_FAIL;
992 goto kvp_set_ip_info_error;
995 error = kvp_write_file(file, "HWADDR", "", mac_addr);
997 goto kvp_set_ip_info_error;
1000 /* Interface Name */
1001 error = kvp_write_file(file, "IF_NAME", "", if_name);
1003 goto kvp_set_ip_info_error;
1007 error = kvp_write_file(file, "IP_ADDR", "",
1008 (char *)new_val->ip_addr);
1010 goto kvp_set_ip_info_error;
1014 error = kvp_write_file(file, "SUBNET", "",
1015 (char *)new_val->sub_net);
1017 goto kvp_set_ip_info_error;
1022 error = kvp_write_file(file, "GATEWAY", "",
1023 (char *)new_val->gate_way);
1025 goto kvp_set_ip_info_error;
1029 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1031 goto kvp_set_ip_info_error;
1035 if (new_val->dhcp_enabled) {
1036 error = kvp_write_file(file, "DHCP", "", "1");
1038 error = kvp_write_file(file, "DHCP", "", "0");
1042 goto kvp_set_ip_info_error;
1049 * Invoke the external script with the populated
1050 * configuration file.
1053 snprintf(cmd, sizeof(cmd), "%s %s",
1054 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1058 kvp_set_ip_info_error:
1059 KVP_LOG(LOG_ERR, "Failed to write config file\n");
1067 kvp_get_domain_name(char *buffer, int length)
1069 struct addrinfo hints, *info;
1072 gethostname(buffer, length);
1073 memset(&hints, 0, sizeof(hints));
1074 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */
1075 hints.ai_socktype = SOCK_STREAM;
1076 hints.ai_flags = AI_CANONNAME;
1078 error = getaddrinfo(buffer, NULL, &hints, &info);
1080 strlcpy(buffer, "getaddrinfo failed\n", length);
1083 strlcpy(buffer, info->ai_canonname, length);
1090 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1092 struct hv_kvp_ipaddr_value *ip_val;
1095 assert(op_msg != NULL);
1096 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1098 ip_val = &op_msg->body.kvp_ip_val;
1099 op_msg->hdr.error = HV_KVP_S_OK;
1101 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1103 if (if_name == NULL) {
1104 /* No interface found with the mac address. */
1105 op_msg->hdr.error = HV_KVP_E_FAIL;
1106 goto kvp_op_getipinfo_done;
1109 op_msg->hdr.error = kvp_get_ip_info(0, if_name,
1110 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1114 kvp_op_getipinfo_done:
1115 return(op_msg->hdr.error);
1120 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1122 struct hv_kvp_ipaddr_value *ip_val;
1125 assert(op_msg != NULL);
1126 KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1128 ip_val = &op_msg->body.kvp_ip_val;
1129 op_msg->hdr.error = HV_KVP_S_OK;
1131 if_name = (char *)ip_val->adapter_id;
1133 if (if_name == NULL) {
1134 /* No adapter provided. */
1135 op_msg->hdr.error = HV_KVP_GUID_NOTFOUND;
1136 goto kvp_op_setipinfo_done;
1139 op_msg->hdr.error = kvp_set_ip_info(if_name, ip_val);
1141 kvp_op_setipinfo_done:
1142 return(op_msg->hdr.error);
1147 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1149 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1153 assert(op_msg != NULL);
1154 assert(op_hdlr != NULL);
1156 op_pool = op_msg->hdr.kvp_hdr.pool;
1157 op_msg->hdr.error = HV_KVP_S_OK;
1159 switch(op_hdlr->kvp_op_key) {
1161 if (op_pool == HV_KVP_POOL_AUTO) {
1162 /* Auto Pool is not writeable from host side. */
1164 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1167 error = kvp_key_add_or_modify(op_pool,
1168 op_msg->body.kvp_set.data.key,
1169 op_msg->body.kvp_set.data.key_size,
1170 op_msg->body.kvp_set.data.msg_value.value,
1171 op_msg->body.kvp_set.data.value_size);
1176 error = kvp_get_value(op_pool,
1177 op_msg->body.kvp_get.data.key,
1178 op_msg->body.kvp_get.data.key_size,
1179 op_msg->body.kvp_get.data.msg_value.value,
1180 op_msg->body.kvp_get.data.value_size);
1183 case HV_KVP_OP_DELETE:
1184 if (op_pool == HV_KVP_POOL_AUTO) {
1185 /* Auto Pool is not writeable from host side. */
1187 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1190 error = kvp_key_delete(op_pool,
1191 op_msg->body.kvp_delete.key,
1192 op_msg->body.kvp_delete.key_size);
1201 op_msg->hdr.error = HV_KVP_S_CONT;
1208 kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1210 char *key_name, *key_value;
1215 assert(op_msg != NULL);
1217 op = op_msg->hdr.kvp_hdr.operation;
1218 op_pool = op_msg->hdr.kvp_hdr.pool;
1219 op_msg->hdr.error = HV_KVP_S_OK;
1222 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1223 * pool and return the KVP according to the index requested.
1225 if (op_pool != HV_KVP_POOL_AUTO) {
1226 if (kvp_pool_enumerate(op_pool,
1227 op_msg->body.kvp_enum_data.index,
1228 op_msg->body.kvp_enum_data.data.key,
1229 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1230 op_msg->body.kvp_enum_data.data.msg_value.value,
1231 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1232 op_msg->hdr.error = HV_KVP_S_CONT;
1235 goto kvp_op_enumerate_done;
1238 key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1239 key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1241 switch (op_msg->body.kvp_enum_data.index)
1243 case FullyQualifiedDomainName:
1244 kvp_get_domain_name(key_value,
1245 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1246 strcpy(key_name, "FullyQualifiedDomainName");
1249 case IntegrationServicesVersion:
1250 strcpy(key_name, "IntegrationServicesVersion");
1251 strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1254 case NetworkAddressIPv4:
1255 kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1256 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1257 strcpy(key_name, "NetworkAddressIPv4");
1260 case NetworkAddressIPv6:
1261 kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1262 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1263 strcpy(key_name, "NetworkAddressIPv6");
1267 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1268 strcpy(key_name, "OSBuildNumber");
1272 strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1273 strcpy(key_name, "OSName");
1276 case OSMajorVersion:
1277 strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1278 strcpy(key_name, "OSMajorVersion");
1281 case OSMinorVersion:
1282 strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1283 strcpy(key_name, "OSMinorVersion");
1287 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1288 strcpy(key_name, "OSVersion");
1291 case ProcessorArchitecture:
1292 strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1293 strcpy(key_name, "ProcessorArchitecture");
1298 KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1299 op_msg->body.kvp_enum_data.index);
1301 op_msg->hdr.error = HV_KVP_S_CONT;
1306 kvp_op_enumerate_done:
1312 * Load handler, and call init routine if provided.
1315 kvp_op_load(int key, void (*init)(void),
1316 int (*exec)(struct hv_kvp_msg *, void *))
1320 if (key < 0 || key >= HV_KVP_OP_COUNT) {
1321 KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1323 goto kvp_op_load_done;
1326 kvp_op_hdlrs[key].kvp_op_key = key;
1327 kvp_op_hdlrs[key].kvp_op_init = init;
1328 kvp_op_hdlrs[key].kvp_op_exec = exec;
1330 if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1331 kvp_op_hdlrs[key].kvp_op_init();
1339 * Initialize the operation hanlders.
1346 /* Set the initial values. */
1347 for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1348 kvp_op_hdlrs[i].kvp_op_key = -1;
1349 kvp_op_hdlrs[i].kvp_op_init = NULL;
1350 kvp_op_hdlrs[i].kvp_op_exec = NULL;
1353 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1354 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1355 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1356 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1358 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1359 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1364 main(int argc, char *argv[])
1366 struct hv_kvp_msg *hv_kvp_dev_buf;
1367 struct hv_kvp_msg *hv_msg;
1368 struct pollfd hv_kvp_poll_fd[1];
1370 int hv_kvp_dev_fd, error, len, r;
1373 while ((ch = getopt(argc, argv, "dn")) != -1) {
1376 /* Run as regular process for debugging purpose. */
1380 /* Generate debugging output */
1388 openlog("HV_KVP", 0, LOG_USER);
1390 /* Become daemon first. */
1394 KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1396 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1398 /* Communication buffer hv_kvp_dev_buf */
1399 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1400 /* Buffer for daemon internal use */
1401 hv_msg = malloc(sizeof(*hv_msg));
1403 /* Memory allocation failed */
1404 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1405 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1409 /* Initialize op handlers */
1410 if (kvp_ops_init() != 0) {
1411 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1415 if (kvp_file_init()) {
1416 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1420 /* Open the Character Device */
1421 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1423 if (hv_kvp_dev_fd < 0) {
1424 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1425 errno, strerror(errno));
1429 /* Initialize the struct for polling the char device */
1430 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1431 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1433 /* Register the daemon to the KVP driver */
1434 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1435 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1436 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1440 r = poll (hv_kvp_poll_fd, 1, 100);
1442 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1443 r, hv_kvp_poll_fd[0].revents);
1445 if (r == 0 || (r < 0 && errno == EAGAIN) ||
1446 (r < 0 && errno == EINTR)) {
1447 /* Nothing to read */
1453 * For pread return failure other than EAGAIN,
1456 KVP_LOG(LOG_ERR, "Poll failed.\n");
1461 /* Read from character device */
1462 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1463 sizeof(*hv_kvp_dev_buf), 0);
1466 KVP_LOG(LOG_ERR, "Read failed.\n");
1471 if (len != sizeof(struct hv_kvp_msg)) {
1472 KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1476 /* Copy hv_kvp_dev_buf to hv_msg */
1477 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1480 * We will use the KVP header information to pass back
1481 * the error from this daemon. So, first save the op
1482 * and pool info to local variables.
1485 op = hv_msg->hdr.kvp_hdr.operation;
1486 pool = hv_msg->hdr.kvp_hdr.pool;
1488 if (op < 0 || op >= HV_KVP_OP_COUNT ||
1489 kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1490 KVP_LOG(LOG_WARNING,
1491 "Unsupported operation OP = %d\n", op);
1492 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1495 * Call the operateion handler's execution routine.
1497 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1498 (void *)&kvp_op_hdlrs[op]);
1499 if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT)
1500 KVP_LOG(LOG_WARNING,
1501 "Operation failed OP = %d, error = 0x%x\n",
1506 * Send the value back to the kernel. The response is
1507 * already in the receive buffer.
1510 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1512 if (len != sizeof(struct hv_kvp_msg)) {
1513 KVP_LOG(LOG_ERR, "write len is: %d\n", len);