Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / tools / hv / hv_kvp_daemon.c
1 /*
2 * An implementation of key value pair (KVP) functionality for Linux.
3 *
4 *
5 * Copyright (C) 2010, Novell, Inc.
6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/poll.h>
28 #include <sys/utsname.h>
29 #include <linux/types.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
39 #include <ifaddrs.h>
40 #include <netdb.h>
41 #include <syslog.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44
45 /*
46 * KVP protocol: The user mode component first registers with the
47 * the kernel component. Subsequently, the kernel component requests, data
48 * for the specified keys. In response to this message the user mode component
49 * fills in the value corresponding to the specified key. We overload the
50 * sequence field in the cn_msg header to define our KVP message types.
51 *
52 * We use this infrastructure for also supporting queries from user mode
53 * application for state that may be maintained in the KVP kernel component.
54 *
55 */
56
57
58 enum key_index {
59 FullyQualifiedDomainName = 0,
60 IntegrationServicesVersion, /*This key is serviced in the kernel*/
61 NetworkAddressIPv4,
62 NetworkAddressIPv6,
63 OSBuildNumber,
64 OSName,
65 OSMajorVersion,
66 OSMinorVersion,
67 OSVersion,
68 ProcessorArchitecture
69 };
70
71 static char kvp_send_buffer[4096];
72 static char kvp_recv_buffer[4096];
73 static struct sockaddr_nl addr;
74
75 static char *os_name = "";
76 static char *os_major = "";
77 static char *os_minor = "";
78 static char *processor_arch;
79 static char *os_build;
80 static char *lic_version;
81 static struct utsname uts_buf;
82
83
84 #define MAX_FILE_NAME 100
85 #define ENTRIES_PER_BLOCK 50
86
87 struct kvp_record {
88 __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89 __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
90 };
91
92 struct kvp_file_state {
93 int fd;
94 int num_blocks;
95 struct kvp_record *records;
96 int num_records;
97 __u8 fname[MAX_FILE_NAME];
98 };
99
100 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
101
102 static void kvp_acquire_lock(int pool)
103 {
104 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
105 fl.l_pid = getpid();
106
107 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
109 exit(-1);
110 }
111 }
112
113 static void kvp_release_lock(int pool)
114 {
115 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
116 fl.l_pid = getpid();
117
118 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
119 perror("fcntl");
120 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
121 exit(-1);
122 }
123 }
124
125 static void kvp_update_file(int pool)
126 {
127 FILE *filep;
128 size_t bytes_written;
129
130 /*
131 * We are going to write our in-memory registry out to
132 * disk; acquire the lock first.
133 */
134 kvp_acquire_lock(pool);
135
136 filep = fopen(kvp_file_info[pool].fname, "w");
137 if (!filep) {
138 kvp_release_lock(pool);
139 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
140 exit(-1);
141 }
142
143 bytes_written = fwrite(kvp_file_info[pool].records,
144 sizeof(struct kvp_record),
145 kvp_file_info[pool].num_records, filep);
146
147 fflush(filep);
148 kvp_release_lock(pool);
149 }
150
151 static void kvp_update_mem_state(int pool)
152 {
153 FILE *filep;
154 size_t records_read = 0;
155 struct kvp_record *record = kvp_file_info[pool].records;
156 struct kvp_record *readp;
157 int num_blocks = kvp_file_info[pool].num_blocks;
158 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
159
160 kvp_acquire_lock(pool);
161
162 filep = fopen(kvp_file_info[pool].fname, "r");
163 if (!filep) {
164 kvp_release_lock(pool);
165 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
166 exit(-1);
167 }
168 while (!feof(filep)) {
169 readp = &record[records_read];
170 records_read += fread(readp, sizeof(struct kvp_record),
171 ENTRIES_PER_BLOCK * num_blocks,
172 filep);
173
174 if (!feof(filep)) {
175 /*
176 * We have more data to read.
177 */
178 num_blocks++;
179 record = realloc(record, alloc_unit * num_blocks);
180
181 if (record == NULL) {
182 syslog(LOG_ERR, "malloc failed");
183 exit(-1);
184 }
185 continue;
186 }
187 break;
188 }
189
190 kvp_file_info[pool].num_blocks = num_blocks;
191 kvp_file_info[pool].records = record;
192 kvp_file_info[pool].num_records = records_read;
193
194 kvp_release_lock(pool);
195 }
196 static int kvp_file_init(void)
197 {
198 int ret, fd;
199 FILE *filep;
200 size_t records_read;
201 __u8 *fname;
202 struct kvp_record *record;
203 struct kvp_record *readp;
204 int num_blocks;
205 int i;
206 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
207
208 if (access("/var/opt/hyperv", F_OK)) {
209 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
210 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
211 exit(-1);
212 }
213 }
214
215 for (i = 0; i < KVP_POOL_COUNT; i++) {
216 fname = kvp_file_info[i].fname;
217 records_read = 0;
218 num_blocks = 1;
219 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
220 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
221
222 if (fd == -1)
223 return 1;
224
225
226 filep = fopen(fname, "r");
227 if (!filep)
228 return 1;
229
230 record = malloc(alloc_unit * num_blocks);
231 if (record == NULL) {
232 fclose(filep);
233 return 1;
234 }
235 while (!feof(filep)) {
236 readp = &record[records_read];
237 records_read += fread(readp, sizeof(struct kvp_record),
238 ENTRIES_PER_BLOCK,
239 filep);
240
241 if (!feof(filep)) {
242 /*
243 * We have more data to read.
244 */
245 num_blocks++;
246 record = realloc(record, alloc_unit *
247 num_blocks);
248 if (record == NULL) {
249 fclose(filep);
250 return 1;
251 }
252 continue;
253 }
254 break;
255 }
256 kvp_file_info[i].fd = fd;
257 kvp_file_info[i].num_blocks = num_blocks;
258 kvp_file_info[i].records = record;
259 kvp_file_info[i].num_records = records_read;
260 fclose(filep);
261
262 }
263
264 return 0;
265 }
266
267 static int kvp_key_delete(int pool, __u8 *key, int key_size)
268 {
269 int i;
270 int j, k;
271 int num_records;
272 struct kvp_record *record;
273
274 /*
275 * First update the in-memory state.
276 */
277 kvp_update_mem_state(pool);
278
279 num_records = kvp_file_info[pool].num_records;
280 record = kvp_file_info[pool].records;
281
282 for (i = 0; i < num_records; i++) {
283 if (memcmp(key, record[i].key, key_size))
284 continue;
285 /*
286 * Found a match; just move the remaining
287 * entries up.
288 */
289 if (i == num_records) {
290 kvp_file_info[pool].num_records--;
291 kvp_update_file(pool);
292 return 0;
293 }
294
295 j = i;
296 k = j + 1;
297 for (; k < num_records; k++) {
298 strcpy(record[j].key, record[k].key);
299 strcpy(record[j].value, record[k].value);
300 j++;
301 }
302
303 kvp_file_info[pool].num_records--;
304 kvp_update_file(pool);
305 return 0;
306 }
307 return 1;
308 }
309
310 static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
311 int value_size)
312 {
313 int i;
314 int j, k;
315 int num_records;
316 struct kvp_record *record;
317 int num_blocks;
318
319 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
320 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
321 return 1;
322
323 /*
324 * First update the in-memory state.
325 */
326 kvp_update_mem_state(pool);
327
328 num_records = kvp_file_info[pool].num_records;
329 record = kvp_file_info[pool].records;
330 num_blocks = kvp_file_info[pool].num_blocks;
331
332 for (i = 0; i < num_records; i++) {
333 if (memcmp(key, record[i].key, key_size))
334 continue;
335 /*
336 * Found a match; just update the value -
337 * this is the modify case.
338 */
339 memcpy(record[i].value, value, value_size);
340 kvp_update_file(pool);
341 return 0;
342 }
343
344 /*
345 * Need to add a new entry;
346 */
347 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
348 /* Need to allocate a larger array for reg entries. */
349 record = realloc(record, sizeof(struct kvp_record) *
350 ENTRIES_PER_BLOCK * (num_blocks + 1));
351
352 if (record == NULL)
353 return 1;
354 kvp_file_info[pool].num_blocks++;
355
356 }
357 memcpy(record[i].value, value, value_size);
358 memcpy(record[i].key, key, key_size);
359 kvp_file_info[pool].records = record;
360 kvp_file_info[pool].num_records++;
361 kvp_update_file(pool);
362 return 0;
363 }
364
365 static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
366 int value_size)
367 {
368 int i;
369 int num_records;
370 struct kvp_record *record;
371
372 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
373 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
374 return 1;
375
376 /*
377 * First update the in-memory state.
378 */
379 kvp_update_mem_state(pool);
380
381 num_records = kvp_file_info[pool].num_records;
382 record = kvp_file_info[pool].records;
383
384 for (i = 0; i < num_records; i++) {
385 if (memcmp(key, record[i].key, key_size))
386 continue;
387 /*
388 * Found a match; just copy the value out.
389 */
390 memcpy(value, record[i].value, value_size);
391 return 0;
392 }
393
394 return 1;
395 }
396
397 static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
398 __u8 *value, int value_size)
399 {
400 struct kvp_record *record;
401
402 /*
403 * First update our in-memory database.
404 */
405 kvp_update_mem_state(pool);
406 record = kvp_file_info[pool].records;
407
408 if (index >= kvp_file_info[pool].num_records) {
409 /*
410 * This is an invalid index; terminate enumeration;
411 * - a NULL value will do the trick.
412 */
413 strcpy(value, "");
414 return;
415 }
416
417 memcpy(key, record[index].key, key_size);
418 memcpy(value, record[index].value, value_size);
419 }
420
421
422 void kvp_get_os_info(void)
423 {
424 FILE *file;
425 char *p, buf[512];
426
427 uname(&uts_buf);
428 os_build = uts_buf.release;
429 processor_arch = uts_buf.machine;
430
431 /*
432 * The current windows host (win7) expects the build
433 * string to be of the form: x.y.z
434 * Strip additional information we may have.
435 */
436 p = strchr(os_build, '-');
437 if (p)
438 *p = '\0';
439
440 file = fopen("/etc/SuSE-release", "r");
441 if (file != NULL)
442 goto kvp_osinfo_found;
443 file = fopen("/etc/redhat-release", "r");
444 if (file != NULL)
445 goto kvp_osinfo_found;
446 /*
447 * Add code for other supported platforms.
448 */
449
450 /*
451 * We don't have information about the os.
452 */
453 os_name = uts_buf.sysname;
454 return;
455
456 kvp_osinfo_found:
457 /* up to three lines */
458 p = fgets(buf, sizeof(buf), file);
459 if (p) {
460 p = strchr(buf, '\n');
461 if (p)
462 *p = '\0';
463 p = strdup(buf);
464 if (!p)
465 goto done;
466 os_name = p;
467
468 /* second line */
469 p = fgets(buf, sizeof(buf), file);
470 if (p) {
471 p = strchr(buf, '\n');
472 if (p)
473 *p = '\0';
474 p = strdup(buf);
475 if (!p)
476 goto done;
477 os_major = p;
478
479 /* third line */
480 p = fgets(buf, sizeof(buf), file);
481 if (p) {
482 p = strchr(buf, '\n');
483 if (p)
484 *p = '\0';
485 p = strdup(buf);
486 if (p)
487 os_minor = p;
488 }
489 }
490 }
491
492 done:
493 fclose(file);
494 return;
495 }
496
497 static int
498 kvp_get_ip_address(int family, char *buffer, int length)
499 {
500 struct ifaddrs *ifap;
501 struct ifaddrs *curp;
502 int ipv4_len = strlen("255.255.255.255") + 1;
503 int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
504 int offset = 0;
505 const char *str;
506 char tmp[50];
507 int error = 0;
508
509 /*
510 * On entry into this function, the buffer is capable of holding the
511 * maximum key value (2048 bytes).
512 */
513
514 if (getifaddrs(&ifap)) {
515 strcpy(buffer, "getifaddrs failed\n");
516 return 1;
517 }
518
519 curp = ifap;
520 while (curp != NULL) {
521 if ((curp->ifa_addr != NULL) &&
522 (curp->ifa_addr->sa_family == family)) {
523 if (family == AF_INET) {
524 struct sockaddr_in *addr =
525 (struct sockaddr_in *) curp->ifa_addr;
526
527 str = inet_ntop(family, &addr->sin_addr,
528 tmp, 50);
529 if (str == NULL) {
530 strcpy(buffer, "inet_ntop failed\n");
531 error = 1;
532 goto getaddr_done;
533 }
534 if (offset == 0)
535 strcpy(buffer, tmp);
536 else
537 strcat(buffer, tmp);
538 strcat(buffer, ";");
539
540 offset += strlen(str) + 1;
541 if ((length - offset) < (ipv4_len + 1))
542 goto getaddr_done;
543
544 } else {
545
546 /*
547 * We only support AF_INET and AF_INET6
548 * and the list of addresses is separated by a ";".
549 */
550 struct sockaddr_in6 *addr =
551 (struct sockaddr_in6 *) curp->ifa_addr;
552
553 str = inet_ntop(family,
554 &addr->sin6_addr.s6_addr,
555 tmp, 50);
556 if (str == NULL) {
557 strcpy(buffer, "inet_ntop failed\n");
558 error = 1;
559 goto getaddr_done;
560 }
561 if (offset == 0)
562 strcpy(buffer, tmp);
563 else
564 strcat(buffer, tmp);
565 strcat(buffer, ";");
566 offset += strlen(str) + 1;
567 if ((length - offset) < (ipv6_len + 1))
568 goto getaddr_done;
569
570 }
571
572 }
573 curp = curp->ifa_next;
574 }
575
576 getaddr_done:
577 freeifaddrs(ifap);
578 return error;
579 }
580
581
582 static int
583 kvp_get_domain_name(char *buffer, int length)
584 {
585 struct addrinfo hints, *info ;
586 int error = 0;
587
588 gethostname(buffer, length);
589 memset(&hints, 0, sizeof(hints));
590 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
591 hints.ai_socktype = SOCK_STREAM;
592 hints.ai_flags = AI_CANONNAME;
593
594 error = getaddrinfo(buffer, NULL, &hints, &info);
595 if (error != 0) {
596 strcpy(buffer, "getaddrinfo failed\n");
597 return error;
598 }
599 strcpy(buffer, info->ai_canonname);
600 freeaddrinfo(info);
601 return error;
602 }
603
604 static int
605 netlink_send(int fd, struct cn_msg *msg)
606 {
607 struct nlmsghdr *nlh;
608 unsigned int size;
609 struct msghdr message;
610 char buffer[64];
611 struct iovec iov[2];
612
613 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
614
615 nlh = (struct nlmsghdr *)buffer;
616 nlh->nlmsg_seq = 0;
617 nlh->nlmsg_pid = getpid();
618 nlh->nlmsg_type = NLMSG_DONE;
619 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
620 nlh->nlmsg_flags = 0;
621
622 iov[0].iov_base = nlh;
623 iov[0].iov_len = sizeof(*nlh);
624
625 iov[1].iov_base = msg;
626 iov[1].iov_len = size;
627
628 memset(&message, 0, sizeof(message));
629 message.msg_name = &addr;
630 message.msg_namelen = sizeof(addr);
631 message.msg_iov = iov;
632 message.msg_iovlen = 2;
633
634 return sendmsg(fd, &message, 0);
635 }
636
637 int main(void)
638 {
639 int fd, len, sock_opt;
640 int error;
641 struct cn_msg *message;
642 struct pollfd pfd;
643 struct nlmsghdr *incoming_msg;
644 struct cn_msg *incoming_cn_msg;
645 struct hv_kvp_msg *hv_msg;
646 char *p;
647 char *key_value;
648 char *key_name;
649
650 daemon(1, 0);
651 openlog("KVP", 0, LOG_USER);
652 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
653 /*
654 * Retrieve OS release information.
655 */
656 kvp_get_os_info();
657
658 if (kvp_file_init()) {
659 syslog(LOG_ERR, "Failed to initialize the pools");
660 exit(-1);
661 }
662
663 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
664 if (fd < 0) {
665 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
666 exit(-1);
667 }
668 addr.nl_family = AF_NETLINK;
669 addr.nl_pad = 0;
670 addr.nl_pid = 0;
671 addr.nl_groups = CN_KVP_IDX;
672
673
674 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
675 if (error < 0) {
676 syslog(LOG_ERR, "bind failed; error:%d", error);
677 close(fd);
678 exit(-1);
679 }
680 sock_opt = addr.nl_groups;
681 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
682 /*
683 * Register ourselves with the kernel.
684 */
685 message = (struct cn_msg *)kvp_send_buffer;
686 message->id.idx = CN_KVP_IDX;
687 message->id.val = CN_KVP_VAL;
688
689 hv_msg = (struct hv_kvp_msg *)message->data;
690 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
691 message->ack = 0;
692 message->len = sizeof(struct hv_kvp_msg);
693
694 len = netlink_send(fd, message);
695 if (len < 0) {
696 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
697 close(fd);
698 exit(-1);
699 }
700
701 pfd.fd = fd;
702
703 while (1) {
704 pfd.events = POLLIN;
705 pfd.revents = 0;
706 poll(&pfd, 1, -1);
707
708 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
709
710 if (len < 0) {
711 syslog(LOG_ERR, "recv failed; error:%d", len);
712 close(fd);
713 return -1;
714 }
715
716 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
717 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
718 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
719
720 switch (hv_msg->kvp_hdr.operation) {
721 case KVP_OP_REGISTER:
722 /*
723 * Driver is registering with us; stash away the version
724 * information.
725 */
726 p = (char *)hv_msg->body.kvp_register.version;
727 lic_version = malloc(strlen(p) + 1);
728 if (lic_version) {
729 strcpy(lic_version, p);
730 syslog(LOG_INFO, "KVP LIC Version: %s",
731 lic_version);
732 } else {
733 syslog(LOG_ERR, "malloc failed");
734 }
735 continue;
736
737 /*
738 * The current protocol with the kernel component uses a
739 * NULL key name to pass an error condition.
740 * For the SET, GET and DELETE operations,
741 * use the existing protocol to pass back error.
742 */
743
744 case KVP_OP_SET:
745 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
746 hv_msg->body.kvp_set.data.key,
747 hv_msg->body.kvp_set.data.key_size,
748 hv_msg->body.kvp_set.data.value,
749 hv_msg->body.kvp_set.data.value_size))
750 strcpy(hv_msg->body.kvp_set.data.key, "");
751 break;
752
753 case KVP_OP_GET:
754 if (kvp_get_value(hv_msg->kvp_hdr.pool,
755 hv_msg->body.kvp_set.data.key,
756 hv_msg->body.kvp_set.data.key_size,
757 hv_msg->body.kvp_set.data.value,
758 hv_msg->body.kvp_set.data.value_size))
759 strcpy(hv_msg->body.kvp_set.data.key, "");
760 break;
761
762 case KVP_OP_DELETE:
763 if (kvp_key_delete(hv_msg->kvp_hdr.pool,
764 hv_msg->body.kvp_delete.key,
765 hv_msg->body.kvp_delete.key_size))
766 strcpy(hv_msg->body.kvp_delete.key, "");
767 break;
768
769 default:
770 break;
771 }
772
773 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
774 goto kvp_done;
775
776 /*
777 * If the pool is KVP_POOL_AUTO, dynamically generate
778 * both the key and the value; if not read from the
779 * appropriate pool.
780 */
781 if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
782 kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
783 hv_msg->body.kvp_enum_data.index,
784 hv_msg->body.kvp_enum_data.data.key,
785 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
786 hv_msg->body.kvp_enum_data.data.value,
787 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
788 goto kvp_done;
789 }
790
791 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
792 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
793 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
794
795 switch (hv_msg->body.kvp_enum_data.index) {
796 case FullyQualifiedDomainName:
797 kvp_get_domain_name(key_value,
798 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
799 strcpy(key_name, "FullyQualifiedDomainName");
800 break;
801 case IntegrationServicesVersion:
802 strcpy(key_name, "IntegrationServicesVersion");
803 strcpy(key_value, lic_version);
804 break;
805 case NetworkAddressIPv4:
806 kvp_get_ip_address(AF_INET, key_value,
807 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
808 strcpy(key_name, "NetworkAddressIPv4");
809 break;
810 case NetworkAddressIPv6:
811 kvp_get_ip_address(AF_INET6, key_value,
812 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
813 strcpy(key_name, "NetworkAddressIPv6");
814 break;
815 case OSBuildNumber:
816 strcpy(key_value, os_build);
817 strcpy(key_name, "OSBuildNumber");
818 break;
819 case OSName:
820 strcpy(key_value, os_name);
821 strcpy(key_name, "OSName");
822 break;
823 case OSMajorVersion:
824 strcpy(key_value, os_major);
825 strcpy(key_name, "OSMajorVersion");
826 break;
827 case OSMinorVersion:
828 strcpy(key_value, os_minor);
829 strcpy(key_name, "OSMinorVersion");
830 break;
831 case OSVersion:
832 strcpy(key_value, os_build);
833 strcpy(key_name, "OSVersion");
834 break;
835 case ProcessorArchitecture:
836 strcpy(key_value, processor_arch);
837 strcpy(key_name, "ProcessorArchitecture");
838 break;
839 default:
840 strcpy(key_value, "Unknown Key");
841 /*
842 * We use a null key name to terminate enumeration.
843 */
844 strcpy(key_name, "");
845 break;
846 }
847 /*
848 * Send the value back to the kernel. The response is
849 * already in the receive buffer. Update the cn_msg header to
850 * reflect the key value that has been added to the message
851 */
852 kvp_done:
853
854 incoming_cn_msg->id.idx = CN_KVP_IDX;
855 incoming_cn_msg->id.val = CN_KVP_VAL;
856 incoming_cn_msg->ack = 0;
857 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
858
859 len = netlink_send(fd, incoming_cn_msg);
860 if (len < 0) {
861 syslog(LOG_ERR, "net_link send failed; error:%d", len);
862 exit(-1);
863 }
864 }
865
866 }