1 /*-
2 * Copyright (c) 2014 Microsoft Corp.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
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.
14 *
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.
25 */
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/poll.h>
30 #include <sys/utsname.h>
31 #include <sys/stat.h>
32 #include <sys/un.h>
33
34 #include <arpa/inet.h>
35 #include <ifaddrs.h>
36 #include <netdb.h>
37
38 #include <netinet/in.h>
39 #include <net/ethernet.h>
40 #include <net/if_dl.h>
41 #include <net/if_types.h>
42
43 #include <assert.h>
44
45 #include <ctype.h>
46 #include <dirent.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <poll.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <unistd.h>
55 #include <assert.h>
56
57 #include "hv_kvp.h"
58 #include "hv_utilreg.h"
59 typedef uint8_t __u8;
60 typedef uint16_t __u16;
61 typedef uint32_t __u32;
62 typedef uint64_t __u64;
63
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"
67
68 /*
69 * ENUM Data
70 */
71
72 enum key_index {
73 FullyQualifiedDomainName = 0,
74 IntegrationServicesVersion, /*This key is serviced in the kernel*/
75 NetworkAddressIPv4,
76 NetworkAddressIPv6,
77 OSBuildNumber,
78 OSName,
79 OSMajorVersion,
80 OSMinorVersion,
81 OSVersion,
82 ProcessorArchitecture
83 };
84
85
86 enum {
87 IPADDR = 0,
88 NETMASK,
89 GATEWAY,
90 DNS
91 };
92
93
94 /* Global Variables */
95
96 /*
97 * The structure for operation handlers.
98 */
99 struct kvp_op_hdlr {
100 int kvp_op_key;
101 void (*kvp_op_init)(void);
102 int (*kvp_op_exec)(struct hv_kvp_msg *kvp_op_msg, void *data);
103 };
104
105 static struct kvp_op_hdlr kvp_op_hdlrs[HV_KVP_OP_COUNT];
106
107 /* OS information */
108
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;
116
117 /* Global flags */
118 static int is_daemon = 1;
119 static int is_debugging = 0;
120
121 #define KVP_LOG(priority, format, args...) do { \
122 if (is_debugging == 1) { \
123 if (is_daemon == 1) \
124 syslog(priority, format, ## args); \
125 else \
126 printf(format, ## args); \
127 } else { \
128 if (priority < LOG_DEBUG) { \
129 if (is_daemon == 1) \
130 syslog(priority, format, ## args); \
131 else \
132 printf(format, ## args); \
133 } \
134 } \
135 } while(0)
136
137 /*
138 * For KVP pool file
139 */
140
141 #define MAX_FILE_NAME 100
142 #define ENTRIES_PER_BLOCK 50
143
144 struct kvp_record {
145 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
146 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
147 };
148
149 struct kvp_pool {
150 int pool_fd;
151 int num_blocks;
152 struct kvp_record *records;
153 int num_records;
154 char fname[MAX_FILE_NAME];
155 };
156
157 static struct kvp_pool kvp_pools[HV_KVP_POOL_COUNT];
158
159
160 static void
kvp_acquire_lock(int pool)161 kvp_acquire_lock(int pool)
162 {
163 struct flock fl = { 0, 0, 0, F_WRLCK, SEEK_SET, 0 };
164
165 fl.l_pid = getpid();
166
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);
169 exit(EXIT_FAILURE);
170 }
171 }
172
173
174 static void
kvp_release_lock(int pool)175 kvp_release_lock(int pool)
176 {
177 struct flock fl = { 0, 0, 0, F_UNLCK, SEEK_SET, 0 };
178
179 fl.l_pid = getpid();
180
181 if (fcntl(kvp_pools[pool].pool_fd, F_SETLK, &fl) == -1) {
182 perror("fcntl");
183 KVP_LOG(LOG_ERR, "Failed to release the lock pool: %d\n", pool);
184 exit(EXIT_FAILURE);
185 }
186 }
187
188
189 /*
190 * Write in-memory copy of KVP to pool files
191 */
192 static void
kvp_update_file(int pool)193 kvp_update_file(int pool)
194 {
195 FILE *filep;
196
197 kvp_acquire_lock(pool);
198
199 filep = fopen(kvp_pools[pool].fname, "w");
200 if (!filep) {
201 kvp_release_lock(pool);
202 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
203 exit(EXIT_FAILURE);
204 }
205
206 fwrite(kvp_pools[pool].records,
207 sizeof(struct kvp_record),
208 kvp_pools[pool].num_records, filep);
209
210 if (ferror(filep) || fclose(filep)) {
211 kvp_release_lock(pool);
212 KVP_LOG(LOG_ERR, "Failed to write file, pool: %d\n", pool);
213 exit(EXIT_FAILURE);
214 }
215
216 kvp_release_lock(pool);
217 }
218
219
220 /*
221 * Read KVPs from pool files and store in memory
222 */
223 static void
kvp_update_mem_state(int pool)224 kvp_update_mem_state(int pool)
225 {
226 FILE *filep;
227 size_t records_read = 0;
228 struct kvp_record *record = kvp_pools[pool].records;
229 struct kvp_record *readp;
230 int num_blocks = kvp_pools[pool].num_blocks;
231 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
232
233 kvp_acquire_lock(pool);
234
235 filep = fopen(kvp_pools[pool].fname, "r");
236 if (!filep) {
237 kvp_release_lock(pool);
238 KVP_LOG(LOG_ERR, "Failed to open file, pool: %d\n", pool);
239 exit(EXIT_FAILURE);
240 }
241 for ( ; ; )
242 {
243 readp = &record[records_read];
244 records_read += fread(readp, sizeof(struct kvp_record),
245 ENTRIES_PER_BLOCK * num_blocks,
246 filep);
247
248 if (ferror(filep)) {
249 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n", pool);
250 exit(EXIT_FAILURE);
251 }
252
253 if (!feof(filep)) {
254 /*
255 * Have more data to read. Expand the memory.
256 */
257 num_blocks++;
258 record = realloc(record, alloc_unit * num_blocks);
259
260 if (record == NULL) {
261 KVP_LOG(LOG_ERR, "malloc failed\n");
262 exit(EXIT_FAILURE);
263 }
264 continue;
265 }
266 break;
267 }
268
269 kvp_pools[pool].num_blocks = num_blocks;
270 kvp_pools[pool].records = record;
271 kvp_pools[pool].num_records = records_read;
272
273 fclose(filep);
274 kvp_release_lock(pool);
275 }
276
277
278 static int
kvp_file_init(void)279 kvp_file_init(void)
280 {
281 int fd;
282 FILE *filep;
283 size_t records_read;
284 char *fname;
285 struct kvp_record *record;
286 struct kvp_record *readp;
287 int num_blocks;
288 int i;
289 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
290
291 if (mkdir(POOL_DIR, POOL_DIR_MODE) < 0 &&
292 (errno != EEXIST && errno != EISDIR)) {
293 KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n");
294 exit(EXIT_FAILURE);
295 }
296 chmod(POOL_DIR, POOL_DIR_MODE); /* fix old mistake */
297
298 for (i = 0; i < HV_KVP_POOL_COUNT; i++)
299 {
300 fname = kvp_pools[i].fname;
301 records_read = 0;
302 num_blocks = 1;
303 snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i);
304 fd = open(fname, O_RDWR | O_CREAT, POOL_FILE_MODE);
305
306 if (fd == -1) {
307 return (1);
308 }
309 fchmod(fd, POOL_FILE_MODE); /* fix old mistake */
310
311
312 filep = fopen(fname, "r");
313 if (!filep) {
314 close(fd);
315 return (1);
316 }
317
318 record = malloc(alloc_unit * num_blocks);
319 if (record == NULL) {
320 close(fd);
321 fclose(filep);
322 return (1);
323 }
324 for ( ; ; )
325 {
326 readp = &record[records_read];
327 records_read += fread(readp, sizeof(struct kvp_record),
328 ENTRIES_PER_BLOCK,
329 filep);
330
331 if (ferror(filep)) {
332 KVP_LOG(LOG_ERR, "Failed to read file, pool: %d\n",
333 i);
334 exit(EXIT_FAILURE);
335 }
336
337 if (!feof(filep)) {
338 /*
339 * More data to read.
340 */
341 num_blocks++;
342 record = realloc(record, alloc_unit *
343 num_blocks);
344 if (record == NULL) {
345 close(fd);
346 fclose(filep);
347 return (1);
348 }
349 continue;
350 }
351 break;
352 }
353 kvp_pools[i].pool_fd = fd;
354 kvp_pools[i].num_blocks = num_blocks;
355 kvp_pools[i].records = record;
356 kvp_pools[i].num_records = records_read;
357 fclose(filep);
358 }
359
360 return (0);
361 }
362
363
364 static int
kvp_key_delete(int pool,__u8 * key,int key_size)365 kvp_key_delete(int pool, __u8 *key, int key_size)
366 {
367 int i;
368 int j, k;
369 int num_records;
370 struct kvp_record *record;
371
372 KVP_LOG(LOG_DEBUG, "kvp_key_delete: pool = %d, "
373 "key = %s\n", pool, key);
374
375 /* Update in-memory state */
376 kvp_update_mem_state(pool);
377
378 num_records = kvp_pools[pool].num_records;
379 record = kvp_pools[pool].records;
380
381 for (i = 0; i < num_records; i++)
382 {
383 if (memcmp(key, record[i].key, key_size)) {
384 continue;
385 }
386
387 KVP_LOG(LOG_DEBUG, "Found delete key in pool %d.\n",
388 pool);
389 /*
390 * We found a match at the end; Just update the number of
391 * entries and we are done.
392 */
393 if (i == num_records) {
394 kvp_pools[pool].num_records--;
395 kvp_update_file(pool);
396 return (0);
397 }
398
399 /*
400 * We found a match in the middle; Move the remaining
401 * entries up.
402 */
403 j = i;
404 k = j + 1;
405 for ( ; k < num_records; k++)
406 {
407 strcpy(record[j].key, record[k].key);
408 strcpy(record[j].value, record[k].value);
409 j++;
410 }
411 kvp_pools[pool].num_records--;
412 kvp_update_file(pool);
413 return (0);
414 }
415 KVP_LOG(LOG_DEBUG, "Not found delete key in pool %d.\n",
416 pool);
417 return (1);
418 }
419
420
421 static int
kvp_key_add_or_modify(int pool,__u8 * key,__u32 key_size,__u8 * value,__u32 value_size)422 kvp_key_add_or_modify(int pool, __u8 *key, __u32 key_size, __u8 *value,
423 __u32 value_size)
424 {
425 int i;
426 int num_records;
427 struct kvp_record *record;
428 int num_blocks;
429
430 KVP_LOG(LOG_DEBUG, "kvp_key_add_or_modify: pool = %d, "
431 "key = %s, value = %s\n,", pool, key, value);
432
433 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
434 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
435 KVP_LOG(LOG_ERR, "kvp_key_add_or_modify: returning 1\n");
436 return (1);
437 }
438
439 /* Update the in-memory state. */
440 kvp_update_mem_state(pool);
441
442 num_records = kvp_pools[pool].num_records;
443 record = kvp_pools[pool].records;
444 num_blocks = kvp_pools[pool].num_blocks;
445
446 for (i = 0; i < num_records; i++)
447 {
448 if (memcmp(key, record[i].key, key_size)) {
449 continue;
450 }
451
452 /*
453 * Key exists. Just update the value and we are done.
454 */
455 memcpy(record[i].value, value, value_size);
456 kvp_update_file(pool);
457 return (0);
458 }
459
460 /*
461 * Key doesn't exist; Add a new KVP.
462 */
463 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
464 /* Increase the size of the recodrd array. */
465 record = realloc(record, sizeof(struct kvp_record) *
466 ENTRIES_PER_BLOCK * (num_blocks + 1));
467
468 if (record == NULL) {
469 return (1);
470 }
471 kvp_pools[pool].num_blocks++;
472 }
473 memcpy(record[i].value, value, value_size);
474 memcpy(record[i].key, key, key_size);
475 kvp_pools[pool].records = record;
476 kvp_pools[pool].num_records++;
477 kvp_update_file(pool);
478 return (0);
479 }
480
481
482 static int
kvp_get_value(int pool,__u8 * key,int key_size,__u8 * value,int value_size)483 kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
484 int value_size)
485 {
486 int i;
487 int num_records;
488 struct kvp_record *record;
489
490 KVP_LOG(LOG_DEBUG, "kvp_get_value: pool = %d, key = %s\n,",
491 pool, key);
492
493 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
494 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
495 return (1);
496 }
497
498 /* Update the in-memory state first. */
499 kvp_update_mem_state(pool);
500
501 num_records = kvp_pools[pool].num_records;
502 record = kvp_pools[pool].records;
503
504 for (i = 0; i < num_records; i++)
505 {
506 if (memcmp(key, record[i].key, key_size)) {
507 continue;
508 }
509
510 /* Found the key */
511 memcpy(value, record[i].value, value_size);
512 return (0);
513 }
514
515 return (1);
516 }
517
518
519 static int
kvp_pool_enumerate(int pool,int idx,__u8 * key,int key_size,__u8 * value,int value_size)520 kvp_pool_enumerate(int pool, int idx, __u8 *key, int key_size,
521 __u8 *value, int value_size)
522 {
523 struct kvp_record *record;
524
525 KVP_LOG(LOG_DEBUG, "kvp_pool_enumerate: pool = %d, index = %d\n,",
526 pool, idx);
527
528 /* First update our in-memory state first. */
529 kvp_update_mem_state(pool);
530 record = kvp_pools[pool].records;
531
532 /* Index starts with 0 */
533 if (idx >= kvp_pools[pool].num_records) {
534 return (1);
535 }
536
537 memcpy(key, record[idx].key, key_size);
538 memcpy(value, record[idx].value, value_size);
539 return (0);
540 }
541
542
543 static void
kvp_get_os_info(void)544 kvp_get_os_info(void)
545 {
546 char *p;
547
548 uname(&uts_buf);
549 os_build = uts_buf.release;
550 os_name = uts_buf.sysname;
551 processor_arch = uts_buf.machine;
552
553 /*
554 * Win7 host expects the build string to be of the form: x.y.z
555 * Strip additional information we may have.
556 */
557 p = strchr(os_build, '-');
558 if (p) {
559 *p = '\0';
560 }
561
562 /*
563 * We don't have any other information about the FreeBSD os.
564 */
565 return;
566 }
567
568 /*
569 * Given the interface name, return the MAC address.
570 */
571 static char *
kvp_if_name_to_mac(char * if_name)572 kvp_if_name_to_mac(char *if_name)
573 {
574 char *mac_addr = NULL;
575 struct ifaddrs *ifaddrs_ptr;
576 struct ifaddrs *head_ifaddrs_ptr;
577 struct sockaddr_dl *sdl;
578 int status;
579
580 status = getifaddrs(&ifaddrs_ptr);
581
582 if (status >= 0) {
583 head_ifaddrs_ptr = ifaddrs_ptr;
584 do {
585 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
586 if ((sdl->sdl_type == IFT_ETHER) &&
587 (strcmp(ifaddrs_ptr->ifa_name, if_name) == 0)) {
588 mac_addr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
589 break;
590 }
591 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
592 freeifaddrs(head_ifaddrs_ptr);
593 }
594
595 return (mac_addr);
596 }
597
598
599 /*
600 * Given the MAC address, return the interface name.
601 */
602 static char *
kvp_mac_to_if_name(char * mac)603 kvp_mac_to_if_name(char *mac)
604 {
605 char *if_name = NULL;
606 struct ifaddrs *ifaddrs_ptr;
607 struct ifaddrs *head_ifaddrs_ptr;
608 struct sockaddr_dl *sdl;
609 int status;
610 char *buf_ptr, *p;
611
612 status = getifaddrs(&ifaddrs_ptr);
613
614 if (status >= 0) {
615 head_ifaddrs_ptr = ifaddrs_ptr;
616 do {
617 sdl = (struct sockaddr_dl *)(uintptr_t)ifaddrs_ptr->ifa_addr;
618 if (sdl->sdl_type == IFT_ETHER) {
619 buf_ptr = strdup(ether_ntoa((struct ether_addr *)(LLADDR(sdl))));
620 if (buf_ptr != NULL) {
621 for (p = buf_ptr; *p != '\0'; p++)
622 *p = toupper(*p);
623
624 if (strncmp(buf_ptr, mac, strlen(mac)) == 0) {
625 /* Caller will free the memory */
626 if_name = strdup(ifaddrs_ptr->ifa_name);
627 free(buf_ptr);
628 break;
629 } else
630 free(buf_ptr);
631 }
632 }
633 } while ((ifaddrs_ptr = ifaddrs_ptr->ifa_next) != NULL);
634 freeifaddrs(head_ifaddrs_ptr);
635 }
636 return (if_name);
637 }
638
639
640 static void
kvp_process_ipconfig_file(char * cmd,char * config_buf,size_t len,size_t element_size,int offset)641 kvp_process_ipconfig_file(char *cmd,
642 char *config_buf, size_t len,
643 size_t element_size, int offset)
644 {
645 char buf[256];
646 char *p;
647 char *x;
648 FILE *file;
649
650 /*
651 * First execute the command.
652 */
653 file = popen(cmd, "r");
654 if (file == NULL) {
655 return;
656 }
657
658 if (offset == 0) {
659 memset(config_buf, 0, len);
660 }
661 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
662 if ((len - strlen(config_buf)) < (element_size + 1)) {
663 break;
664 }
665
666 x = strchr(p, '\n');
667 *x = '\0';
668 strlcat(config_buf, p, len);
669 strlcat(config_buf, ";", len);
670 }
671 pclose(file);
672 }
673
674
675 static void
kvp_get_ipconfig_info(char * if_name,struct hv_kvp_ipaddr_value * buffer)676 kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer)
677 {
678 char cmd[512];
679 char dhcp_info[128];
680 char *p;
681 FILE *file;
682
683 /*
684 * Retrieve the IPV4 address of default gateway.
685 */
686 snprintf(cmd, sizeof(cmd), "netstat -rn | grep %s | awk '/default/ {print $2 }'", if_name);
687
688 /*
689 * Execute the command to gather gateway IPV4 info.
690 */
691 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
692 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
693 /*
694 * Retrieve the IPV6 address of default gateway.
695 */
696 snprintf(cmd, sizeof(cmd), "netstat -rn inet6 | grep %s | awk '/default/ {print $2 }'", if_name);
697
698 /*
699 * Execute the command to gather gateway IPV6 info.
700 */
701 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
702 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
703 /*
704 * we just invoke an external script to get the DNS info.
705 *
706 * Following is the expected format of the information from the script:
707 *
708 * ipaddr1 (nameserver1)
709 * ipaddr2 (nameserver2)
710 * .
711 * .
712 */
713 /* Scripts are stored in /usr/libexec/hyperv/ directory */
714 snprintf(cmd, sizeof(cmd), "%s", "sh /usr/libexec/hyperv/hv_get_dns_info");
715
716 /*
717 * Execute the command to get DNS info.
718 */
719 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
720 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
721
722 /*
723 * Invoke an external script to get the DHCP state info.
724 * The parameter to the script is the interface name.
725 * Here is the expected output:
726 *
727 * Enabled: DHCP enabled.
728 */
729
730
731 snprintf(cmd, sizeof(cmd), "%s %s",
732 "sh /usr/libexec/hyperv/hv_get_dhcp_info", if_name);
733
734 file = popen(cmd, "r");
735 if (file == NULL) {
736 return;
737 }
738
739 p = fgets(dhcp_info, sizeof(dhcp_info), file);
740 if (p == NULL) {
741 pclose(file);
742 return;
743 }
744
745 if (!strncmp(p, "Enabled", 7)) {
746 buffer->dhcp_enabled = 1;
747 } else{
748 buffer->dhcp_enabled = 0;
749 }
750
751 pclose(file);
752 }
753
754
755 static unsigned int
hweight32(unsigned int * w)756 hweight32(unsigned int *w)
757 {
758 unsigned int res = *w - ((*w >> 1) & 0x55555555);
759
760 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
761 res = (res + (res >> 4)) & 0x0F0F0F0F;
762 res = res + (res >> 8);
763 return ((res + (res >> 16)) & 0x000000FF);
764 }
765
766
767 static int
kvp_process_ip_address(void * addrp,int family,char * buffer,int length,int * offset)768 kvp_process_ip_address(void *addrp,
769 int family, char *buffer,
770 int length, int *offset)
771 {
772 struct sockaddr_in *addr;
773 struct sockaddr_in6 *addr6;
774 int addr_length;
775 char tmp[50];
776 const char *str;
777
778 if (family == AF_INET) {
779 addr = (struct sockaddr_in *)addrp;
780 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
781 addr_length = INET_ADDRSTRLEN;
782 } else {
783 addr6 = (struct sockaddr_in6 *)addrp;
784 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
785 addr_length = INET6_ADDRSTRLEN;
786 }
787
788 if ((length - *offset) < addr_length + 1) {
789 return (EINVAL);
790 }
791 if (str == NULL) {
792 strlcpy(buffer, "inet_ntop failed\n", length);
793 return (errno);
794 }
795 if (*offset == 0) {
796 strlcpy(buffer, tmp, length);
797 } else{
798 strlcat(buffer, tmp, length);
799 }
800 strlcat(buffer, ";", length);
801
802 *offset += strlen(str) + 1;
803 return (0);
804 }
805
806
807 static int
kvp_get_ip_info(int family,char * if_name,int op,void * out_buffer,size_t length)808 kvp_get_ip_info(int family, char *if_name, int op,
809 void *out_buffer, size_t length)
810 {
811 struct ifaddrs *ifap;
812 struct ifaddrs *curp;
813 int offset = 0;
814 int sn_offset = 0;
815 int error = 0;
816 char *buffer;
817 size_t buffer_length;
818 struct hv_kvp_ipaddr_value *ip_buffer = NULL;
819 char cidr_mask[5];
820 int weight;
821 int i;
822 unsigned int *w = NULL;
823 char *sn_str;
824 size_t sn_str_length;
825 struct sockaddr_in6 *addr6;
826
827 if (op == HV_KVP_OP_ENUMERATE) {
828 buffer = out_buffer;
829 buffer_length = length;
830 } else {
831 ip_buffer = out_buffer;
832 buffer = (char *)ip_buffer->ip_addr;
833 buffer_length = sizeof(ip_buffer->ip_addr);
834 ip_buffer->addr_family = 0;
835 }
836
837 if (getifaddrs(&ifap)) {
838 strlcpy(buffer, "getifaddrs failed\n", buffer_length);
839 return (errno);
840 }
841
842 curp = ifap;
843 while (curp != NULL) {
844 if (curp->ifa_addr == NULL) {
845 curp = curp->ifa_next;
846 continue;
847 }
848
849 if ((if_name != NULL) &&
850 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
851 /*
852 * We want info about a specific interface;
853 * just continue.
854 */
855 curp = curp->ifa_next;
856 continue;
857 }
858
859 /*
860 * We support two address families: AF_INET and AF_INET6.
861 * If family value is 0, we gather both supported
862 * address families; if not we gather info on
863 * the specified address family.
864 */
865 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
866 curp = curp->ifa_next;
867 continue;
868 }
869 if ((curp->ifa_addr->sa_family != AF_INET) &&
870 (curp->ifa_addr->sa_family != AF_INET6)) {
871 curp = curp->ifa_next;
872 continue;
873 }
874
875 if (op == HV_KVP_OP_GET_IP_INFO) {
876 /*
877 * Get the info other than the IP address.
878 */
879 if (curp->ifa_addr->sa_family == AF_INET) {
880 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
881
882 /*
883 * Get subnet info.
884 */
885 error = kvp_process_ip_address(
886 curp->ifa_netmask,
887 AF_INET,
888 (char *)
889 ip_buffer->sub_net,
890 length,
891 &sn_offset);
892 if (error) {
893 goto kvp_get_ip_info_ipaddr;
894 }
895 } else {
896 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
897
898 /*
899 * Get subnet info in CIDR format.
900 */
901 weight = 0;
902 sn_str = (char *)ip_buffer->sub_net;
903 sn_str_length = sizeof(ip_buffer->sub_net);
904 addr6 = (struct sockaddr_in6 *)(uintptr_t)
905 curp->ifa_netmask;
906 w = (unsigned int *)(uintptr_t)addr6->sin6_addr.s6_addr;
907
908 for (i = 0; i < 4; i++)
909 {
910 weight += hweight32(&w[i]);
911 }
912
913 snprintf(cidr_mask, sizeof(cidr_mask), "/%d", weight);
914 if ((length - sn_offset) <
915 (strlen(cidr_mask) + 1)) {
916 goto kvp_get_ip_info_ipaddr;
917 }
918
919 if (sn_offset == 0) {
920 strlcpy(sn_str, cidr_mask, sn_str_length);
921 } else{
922 strlcat(sn_str, cidr_mask, sn_str_length);
923 }
924 strlcat((char *)ip_buffer->sub_net, ";", sn_str_length);
925 sn_offset += strlen(sn_str) + 1;
926 }
927
928 /*
929 * Collect other ip configuration info.
930 */
931 kvp_get_ipconfig_info(if_name, ip_buffer);
932 }
933
934 kvp_get_ip_info_ipaddr:
935 error = kvp_process_ip_address(curp->ifa_addr,
936 curp->ifa_addr->sa_family,
937 buffer,
938 length, &offset);
939 if (error) {
940 goto kvp_get_ip_info_done;
941 }
942
943 curp = curp->ifa_next;
944 }
945
946 kvp_get_ip_info_done:
947 freeifaddrs(ifap);
948 return (error);
949 }
950
951
952 static int
kvp_write_file(FILE * f,const char * s1,const char * s2,const char * s3)953 kvp_write_file(FILE *f, const char *s1, const char *s2, const char *s3)
954 {
955 int ret;
956
957 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
958
959 if (ret < 0) {
960 return (EIO);
961 }
962
963 return (0);
964 }
965
966
967 static int
kvp_set_ip_info(char * if_name,struct hv_kvp_ipaddr_value * new_val)968 kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
969 {
970 int error = 0;
971 char if_file[128];
972 FILE *file;
973 char cmd[512];
974 char *mac_addr;
975
976 /*
977 * FreeBSD - Configuration File
978 */
979 snprintf(if_file, sizeof(if_file), "%s%s", "/var/db/hyperv",
980 "hv_set_ip_data");
981 file = fopen(if_file, "w");
982
983 if (file == NULL) {
984 KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
985 return (errno);
986 }
987
988 /*
989 * Write out the MAC address.
990 */
991
992 mac_addr = kvp_if_name_to_mac(if_name);
993 if (mac_addr == NULL) {
994 error = EINVAL;
995 goto kvp_set_ip_info_error;
996 }
997 /* MAC Address */
998 error = kvp_write_file(file, "HWADDR", "", mac_addr);
999 if (error) {
1000 goto kvp_set_ip_info_error;
1001 }
1002
1003 /* Interface Name */
1004 error = kvp_write_file(file, "IF_NAME", "", if_name);
1005 if (error) {
1006 goto kvp_set_ip_info_error;
1007 }
1008
1009 /* IP Address */
1010 error = kvp_write_file(file, "IP_ADDR", "",
1011 (char *)new_val->ip_addr);
1012 if (error) {
1013 goto kvp_set_ip_info_error;
1014 }
1015
1016 /* Subnet Mask */
1017 error = kvp_write_file(file, "SUBNET", "",
1018 (char *)new_val->sub_net);
1019 if (error) {
1020 goto kvp_set_ip_info_error;
1021 }
1022
1023
1024 /* Gateway */
1025 error = kvp_write_file(file, "GATEWAY", "",
1026 (char *)new_val->gate_way);
1027 if (error) {
1028 goto kvp_set_ip_info_error;
1029 }
1030
1031 /* DNS */
1032 error = kvp_write_file(file, "DNS", "", (char *)new_val->dns_addr);
1033 if (error) {
1034 goto kvp_set_ip_info_error;
1035 }
1036
1037 /* DHCP */
1038 if (new_val->dhcp_enabled) {
1039 error = kvp_write_file(file, "DHCP", "", "1");
1040 } else{
1041 error = kvp_write_file(file, "DHCP", "", "0");
1042 }
1043
1044 if (error) {
1045 goto kvp_set_ip_info_error;
1046 }
1047
1048 free(mac_addr);
1049 fclose(file);
1050
1051 /*
1052 * Invoke the external script with the populated
1053 * configuration file.
1054 */
1055
1056 snprintf(cmd, sizeof(cmd), "%s %s",
1057 "sh /usr/libexec/hyperv/hv_set_ifconfig", if_file);
1058 system(cmd);
1059 return (0);
1060
1061 kvp_set_ip_info_error:
1062 KVP_LOG(LOG_ERR, "Failed to write config file\n");
1063 free(mac_addr);
1064 fclose(file);
1065 return (error);
1066 }
1067
1068
1069 static int
kvp_get_domain_name(char * buffer,int length)1070 kvp_get_domain_name(char *buffer, int length)
1071 {
1072 struct addrinfo hints, *info;
1073 int error = 0;
1074
1075 gethostname(buffer, length);
1076 memset(&hints, 0, sizeof(hints));
1077 hints.ai_family = AF_INET; /* Get only ipv4 addrinfo. */
1078 hints.ai_socktype = SOCK_STREAM;
1079 hints.ai_flags = AI_CANONNAME;
1080
1081 error = getaddrinfo(buffer, NULL, &hints, &info);
1082 if (error != 0) {
1083 strlcpy(buffer, "getaddrinfo failed\n", length);
1084 return (error);
1085 }
1086 strlcpy(buffer, info->ai_canonname, length);
1087 freeaddrinfo(info);
1088 return (error);
1089 }
1090
1091
1092 static int
kvp_op_getipinfo(struct hv_kvp_msg * op_msg,void * data __unused)1093 kvp_op_getipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1094 {
1095 struct hv_kvp_ipaddr_value *ip_val;
1096 char *if_name;
1097 int error = 0;
1098
1099 assert(op_msg != NULL);
1100 KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
1101
1102 ip_val = &op_msg->body.kvp_ip_val;
1103 op_msg->hdr.error = HV_S_OK;
1104
1105 if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
1106
1107 if (if_name == NULL) {
1108 /* No interface found with the mac address. */
1109 op_msg->hdr.error = HV_E_FAIL;
1110 goto kvp_op_getipinfo_done;
1111 }
1112
1113 error = kvp_get_ip_info(0, if_name,
1114 HV_KVP_OP_GET_IP_INFO, ip_val, (MAX_IP_ADDR_SIZE * 2));
1115 if (error)
1116 op_msg->hdr.error = HV_E_FAIL;
1117 free(if_name);
1118
1119 kvp_op_getipinfo_done:
1120 return (error);
1121 }
1122
1123
1124 static int
kvp_op_setipinfo(struct hv_kvp_msg * op_msg,void * data __unused)1125 kvp_op_setipinfo(struct hv_kvp_msg *op_msg, void *data __unused)
1126 {
1127 struct hv_kvp_ipaddr_value *ip_val;
1128 char *if_name;
1129 int error = 0;
1130
1131 assert(op_msg != NULL);
1132 KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
1133
1134 ip_val = &op_msg->body.kvp_ip_val;
1135 op_msg->hdr.error = HV_S_OK;
1136
1137 if_name = (char *)ip_val->adapter_id;
1138
1139 if (if_name == NULL) {
1140 /* No adapter provided. */
1141 op_msg->hdr.error = HV_GUID_NOTFOUND;
1142 goto kvp_op_setipinfo_done;
1143 }
1144
1145 error = kvp_set_ip_info(if_name, ip_val);
1146 if (error)
1147 op_msg->hdr.error = HV_E_FAIL;
1148 kvp_op_setipinfo_done:
1149 return (error);
1150 }
1151
1152
1153 static int
kvp_op_setgetdel(struct hv_kvp_msg * op_msg,void * data)1154 kvp_op_setgetdel(struct hv_kvp_msg *op_msg, void *data)
1155 {
1156 struct kvp_op_hdlr *op_hdlr = (struct kvp_op_hdlr *)data;
1157 int error = 0;
1158 int op_pool;
1159
1160 assert(op_msg != NULL);
1161 assert(op_hdlr != NULL);
1162
1163 op_pool = op_msg->hdr.kvp_hdr.pool;
1164 op_msg->hdr.error = HV_S_OK;
1165
1166 switch(op_hdlr->kvp_op_key) {
1167 case HV_KVP_OP_SET:
1168 if (op_pool == HV_KVP_POOL_AUTO) {
1169 /* Auto Pool is not writeable from host side. */
1170 error = 1;
1171 KVP_LOG(LOG_ERR, "Ilegal to write to pool %d from host\n",
1172 op_pool);
1173 } else {
1174 error = kvp_key_add_or_modify(op_pool,
1175 op_msg->body.kvp_set.data.key,
1176 op_msg->body.kvp_set.data.key_size,
1177 op_msg->body.kvp_set.data.msg_value.value,
1178 op_msg->body.kvp_set.data.value_size);
1179 }
1180 break;
1181
1182 case HV_KVP_OP_GET:
1183 error = kvp_get_value(op_pool,
1184 op_msg->body.kvp_get.data.key,
1185 op_msg->body.kvp_get.data.key_size,
1186 op_msg->body.kvp_get.data.msg_value.value,
1187 op_msg->body.kvp_get.data.value_size);
1188 break;
1189
1190 case HV_KVP_OP_DELETE:
1191 if (op_pool == HV_KVP_POOL_AUTO) {
1192 /* Auto Pool is not writeable from host side. */
1193 error = 1;
1194 KVP_LOG(LOG_ERR, "Ilegal to change pool %d from host\n",
1195 op_pool);
1196 } else {
1197 error = kvp_key_delete(op_pool,
1198 op_msg->body.kvp_delete.key,
1199 op_msg->body.kvp_delete.key_size);
1200 }
1201 break;
1202
1203 default:
1204 break;
1205 }
1206
1207 if (error != 0)
1208 op_msg->hdr.error = HV_S_CONT;
1209 return(error);
1210 }
1211
1212
1213 static int
kvp_op_enumerate(struct hv_kvp_msg * op_msg,void * data __unused)1214 kvp_op_enumerate(struct hv_kvp_msg *op_msg, void *data __unused)
1215 {
1216 char *key_name, *key_value;
1217 int error = 0;
1218 int op_pool;
1219
1220 assert(op_msg != NULL);
1221
1222 op_pool = op_msg->hdr.kvp_hdr.pool;
1223 op_msg->hdr.error = HV_S_OK;
1224
1225 /*
1226 * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
1227 * pool and return the KVP according to the index requested.
1228 */
1229 if (op_pool != HV_KVP_POOL_AUTO) {
1230 if (kvp_pool_enumerate(op_pool,
1231 op_msg->body.kvp_enum_data.index,
1232 op_msg->body.kvp_enum_data.data.key,
1233 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1234 op_msg->body.kvp_enum_data.data.msg_value.value,
1235 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
1236 op_msg->hdr.error = HV_S_CONT;
1237 error = -1;
1238 }
1239 goto kvp_op_enumerate_done;
1240 }
1241
1242 key_name = (char *)op_msg->body.kvp_enum_data.data.key;
1243 key_value = (char *)op_msg->body.kvp_enum_data.data.msg_value.value;
1244
1245 switch (op_msg->body.kvp_enum_data.index)
1246 {
1247 case FullyQualifiedDomainName:
1248 kvp_get_domain_name(key_value,
1249 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1250 strcpy(key_name, "FullyQualifiedDomainName");
1251 break;
1252
1253 case IntegrationServicesVersion:
1254 strcpy(key_name, "IntegrationServicesVersion");
1255 strlcpy(key_value, lic_version, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1256 break;
1257
1258 case NetworkAddressIPv4:
1259 kvp_get_ip_info(AF_INET, NULL, HV_KVP_OP_ENUMERATE,
1260 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1261 strcpy(key_name, "NetworkAddressIPv4");
1262 break;
1263
1264 case NetworkAddressIPv6:
1265 kvp_get_ip_info(AF_INET6, NULL, HV_KVP_OP_ENUMERATE,
1266 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1267 strcpy(key_name, "NetworkAddressIPv6");
1268 break;
1269
1270 case OSBuildNumber:
1271 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1272 strcpy(key_name, "OSBuildNumber");
1273 break;
1274
1275 case OSName:
1276 strlcpy(key_value, os_name, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1277 strcpy(key_name, "OSName");
1278 break;
1279
1280 case OSMajorVersion:
1281 strlcpy(key_value, os_major, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1282 strcpy(key_name, "OSMajorVersion");
1283 break;
1284
1285 case OSMinorVersion:
1286 strlcpy(key_value, os_minor, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1287 strcpy(key_name, "OSMinorVersion");
1288 break;
1289
1290 case OSVersion:
1291 strlcpy(key_value, os_build, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1292 strcpy(key_name, "OSVersion");
1293 break;
1294
1295 case ProcessorArchitecture:
1296 strlcpy(key_value, processor_arch, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1297 strcpy(key_name, "ProcessorArchitecture");
1298 break;
1299
1300 default:
1301 #ifdef DEBUG
1302 KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
1303 op_msg->body.kvp_enum_data.index);
1304 #endif
1305 op_msg->hdr.error = HV_S_CONT;
1306 error = -1;
1307 break;
1308 }
1309
1310 kvp_op_enumerate_done:
1311 if (error != 0)
1312 op_msg->hdr.error = HV_S_CONT;
1313 return(error);
1314 }
1315
1316
1317 /*
1318 * Load handler, and call init routine if provided.
1319 */
1320 static int
kvp_op_load(int key,void (* init)(void),int (* exec)(struct hv_kvp_msg *,void *))1321 kvp_op_load(int key, void (*init)(void),
1322 int (*exec)(struct hv_kvp_msg *, void *))
1323 {
1324 int error = 0;
1325
1326 if (key < 0 || key >= HV_KVP_OP_COUNT) {
1327 KVP_LOG(LOG_ERR, "Operation key out of supported range\n");
1328 error = -1;
1329 goto kvp_op_load_done;
1330 }
1331
1332 kvp_op_hdlrs[key].kvp_op_key = key;
1333 kvp_op_hdlrs[key].kvp_op_init = init;
1334 kvp_op_hdlrs[key].kvp_op_exec = exec;
1335
1336 if (kvp_op_hdlrs[key].kvp_op_init != NULL)
1337 kvp_op_hdlrs[key].kvp_op_init();
1338
1339 kvp_op_load_done:
1340 return(error);
1341 }
1342
1343
1344 /*
1345 * Initialize the operation hanlders.
1346 */
1347 static int
kvp_ops_init(void)1348 kvp_ops_init(void)
1349 {
1350 int i;
1351
1352 /* Set the initial values. */
1353 for (i = 0; i < HV_KVP_OP_COUNT; i++) {
1354 kvp_op_hdlrs[i].kvp_op_key = -1;
1355 kvp_op_hdlrs[i].kvp_op_init = NULL;
1356 kvp_op_hdlrs[i].kvp_op_exec = NULL;
1357 }
1358
1359 return(kvp_op_load(HV_KVP_OP_GET, NULL, kvp_op_setgetdel) |
1360 kvp_op_load(HV_KVP_OP_SET, NULL, kvp_op_setgetdel) |
1361 kvp_op_load(HV_KVP_OP_DELETE, NULL, kvp_op_setgetdel) |
1362 kvp_op_load(HV_KVP_OP_ENUMERATE, kvp_get_os_info,
1363 kvp_op_enumerate) |
1364 kvp_op_load(HV_KVP_OP_GET_IP_INFO, NULL, kvp_op_getipinfo) |
1365 kvp_op_load(HV_KVP_OP_SET_IP_INFO, NULL, kvp_op_setipinfo));
1366 }
1367
1368
1369 int
main(int argc,char * argv[])1370 main(int argc, char *argv[])
1371 {
1372 struct hv_kvp_msg *hv_kvp_dev_buf;
1373 struct hv_kvp_msg *hv_msg;
1374 struct pollfd hv_kvp_poll_fd[1];
1375 int op;
1376 int hv_kvp_dev_fd, error, len, r;
1377 int ch;
1378
1379 while ((ch = getopt(argc, argv, "dn")) != -1) {
1380 switch (ch) {
1381 case 'n':
1382 /* Run as regular process for debugging purpose. */
1383 is_daemon = 0;
1384 break;
1385 case 'd':
1386 /* Generate debugging output */
1387 is_debugging = 1;
1388 break;
1389 default:
1390 break;
1391 }
1392 }
1393
1394 openlog("HV_KVP", 0, LOG_USER);
1395
1396 /* Become daemon first. */
1397 if (is_daemon == 1)
1398 daemon(1, 0);
1399 else
1400 KVP_LOG(LOG_DEBUG, "Run as regular process.\n");
1401
1402 KVP_LOG(LOG_INFO, "HV_KVP starting; pid is: %d\n", getpid());
1403
1404 /* Communication buffer hv_kvp_dev_buf */
1405 hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf));
1406 /* Buffer for daemon internal use */
1407 hv_msg = malloc(sizeof(*hv_msg));
1408
1409 /* Memory allocation failed */
1410 if (hv_kvp_dev_buf == NULL || hv_msg == NULL) {
1411 KVP_LOG(LOG_ERR, "Failed to allocate memory for hv buffer\n");
1412 exit(EXIT_FAILURE);
1413 }
1414
1415 /* Initialize op handlers */
1416 if (kvp_ops_init() != 0) {
1417 KVP_LOG(LOG_ERR, "Failed to initizlize operation handlers\n");
1418 exit(EXIT_FAILURE);
1419 }
1420
1421 if (kvp_file_init()) {
1422 KVP_LOG(LOG_ERR, "Failed to initialize the pools\n");
1423 exit(EXIT_FAILURE);
1424 }
1425
1426 /* Open the Character Device */
1427 hv_kvp_dev_fd = open("/dev/hv_kvp_dev", O_RDWR);
1428
1429 if (hv_kvp_dev_fd < 0) {
1430 KVP_LOG(LOG_ERR, "open /dev/hv_kvp_dev failed; error: %d %s\n",
1431 errno, strerror(errno));
1432 exit(EXIT_FAILURE);
1433 }
1434
1435 /* Initialize the struct for polling the char device */
1436 hv_kvp_poll_fd[0].fd = hv_kvp_dev_fd;
1437 hv_kvp_poll_fd[0].events = (POLLIN | POLLRDNORM);
1438
1439 /* Register the daemon to the KVP driver */
1440 memset(hv_kvp_dev_buf, 0, sizeof(*hv_kvp_dev_buf));
1441 hv_kvp_dev_buf->hdr.kvp_hdr.operation = HV_KVP_OP_REGISTER;
1442 len = write(hv_kvp_dev_fd, hv_kvp_dev_buf, sizeof(*hv_kvp_dev_buf));
1443
1444
1445 for (;;) {
1446 r = poll (hv_kvp_poll_fd, 1, INFTIM);
1447
1448 KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
1449 r, hv_kvp_poll_fd[0].revents);
1450
1451 if (r == 0 || (r < 0 && errno == EAGAIN) ||
1452 (r < 0 && errno == EINTR)) {
1453 /* Nothing to read */
1454 continue;
1455 }
1456
1457 if (r < 0) {
1458 /*
1459 * For pread return failure other than EAGAIN,
1460 * we want to exit.
1461 */
1462 KVP_LOG(LOG_ERR, "Poll failed.\n");
1463 perror("poll");
1464 exit(EIO);
1465 }
1466
1467 /* Read from character device */
1468 len = pread(hv_kvp_dev_fd, hv_kvp_dev_buf,
1469 sizeof(*hv_kvp_dev_buf), 0);
1470
1471 if (len < 0) {
1472 KVP_LOG(LOG_ERR, "Read failed.\n");
1473 perror("pread");
1474 exit(EIO);
1475 }
1476
1477 if (len != sizeof(struct hv_kvp_msg)) {
1478 KVP_LOG(LOG_ERR, "read len is: %d\n", len);
1479 continue;
1480 }
1481
1482 /* Copy hv_kvp_dev_buf to hv_msg */
1483 memcpy(hv_msg, hv_kvp_dev_buf, sizeof(*hv_msg));
1484
1485 /*
1486 * We will use the KVP header information to pass back
1487 * the error from this daemon. So, first save the op
1488 * to a local variable.
1489 */
1490
1491 op = hv_msg->hdr.kvp_hdr.operation;
1492
1493 if (op < 0 || op >= HV_KVP_OP_COUNT ||
1494 kvp_op_hdlrs[op].kvp_op_exec == NULL) {
1495 KVP_LOG(LOG_WARNING,
1496 "Unsupported operation OP = %d\n", op);
1497 hv_msg->hdr.error = HV_ERROR_NOT_SUPPORTED;
1498 } else {
1499 /*
1500 * Call the operateion handler's execution routine.
1501 */
1502 error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
1503 (void *)&kvp_op_hdlrs[op]);
1504 if (error != 0) {
1505 assert(hv_msg->hdr.error != HV_S_OK);
1506 if (hv_msg->hdr.error != HV_S_CONT)
1507 KVP_LOG(LOG_WARNING,
1508 "Operation failed OP = %d, error = 0x%x\n",
1509 op, error);
1510 }
1511 }
1512
1513 /*
1514 * Send the value back to the kernel. The response is
1515 * already in the receive buffer.
1516 */
1517 hv_kvp_done:
1518 len = pwrite(hv_kvp_dev_fd, hv_msg, sizeof(*hv_kvp_dev_buf), 0);
1519
1520 if (len != sizeof(struct hv_kvp_msg)) {
1521 KVP_LOG(LOG_ERR, "write len is: %d\n", len);
1522 goto hv_kvp_done;
1523 }
1524 }
1525 }
1526