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