]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/hv/hv_kvp_daemon.c
Merge branch 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.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 }