]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/hv/hv_kvp_daemon.c
tools/hv: Check for read/write errors
[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 <ctype.h>
35 #include <errno.h>
36 #include <arpa/inet.h>
37 #include <linux/connector.h>
38 #include <linux/hyperv.h>
39 #include <linux/netlink.h>
40 #include <ifaddrs.h>
41 #include <netdb.h>
42 #include <syslog.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <dirent.h>
46
47 /*
48  * KVP protocol: The user mode component first registers with the
49  * the kernel component. Subsequently, the kernel component requests, data
50  * for the specified keys. In response to this message the user mode component
51  * fills in the value corresponding to the specified key. We overload the
52  * sequence field in the cn_msg header to define our KVP message types.
53  *
54  * We use this infrastructure for also supporting queries from user mode
55  * application for state that may be maintained in the KVP kernel component.
56  *
57  */
58
59
60 enum key_index {
61         FullyQualifiedDomainName = 0,
62         IntegrationServicesVersion, /*This key is serviced in the kernel*/
63         NetworkAddressIPv4,
64         NetworkAddressIPv6,
65         OSBuildNumber,
66         OSName,
67         OSMajorVersion,
68         OSMinorVersion,
69         OSVersion,
70         ProcessorArchitecture
71 };
72
73
74 enum {
75         IPADDR = 0,
76         NETMASK,
77         GATEWAY,
78         DNS
79 };
80
81 static char kvp_send_buffer[4096];
82 static char kvp_recv_buffer[4096 * 2];
83 static struct sockaddr_nl addr;
84 static int in_hand_shake = 1;
85
86 static char *os_name = "";
87 static char *os_major = "";
88 static char *os_minor = "";
89 static char *processor_arch;
90 static char *os_build;
91 static char *lic_version = "Unknown version";
92 static struct utsname uts_buf;
93
94 /*
95  * The location of the interface configuration file.
96  */
97
98 #define KVP_CONFIG_LOC  "/var/opt/"
99
100 #define MAX_FILE_NAME 100
101 #define ENTRIES_PER_BLOCK 50
102
103 struct kvp_record {
104         char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
105         char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
106 };
107
108 struct kvp_file_state {
109         int fd;
110         int num_blocks;
111         struct kvp_record *records;
112         int num_records;
113         char fname[MAX_FILE_NAME];
114 };
115
116 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
117
118 static void kvp_acquire_lock(int pool)
119 {
120         struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
121         fl.l_pid = getpid();
122
123         if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
124                 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
125                 exit(EXIT_FAILURE);
126         }
127 }
128
129 static void kvp_release_lock(int pool)
130 {
131         struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
132         fl.l_pid = getpid();
133
134         if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
135                 perror("fcntl");
136                 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
137                 exit(EXIT_FAILURE);
138         }
139 }
140
141 static void kvp_update_file(int pool)
142 {
143         FILE *filep;
144         size_t bytes_written;
145
146         /*
147          * We are going to write our in-memory registry out to
148          * disk; acquire the lock first.
149          */
150         kvp_acquire_lock(pool);
151
152         filep = fopen(kvp_file_info[pool].fname, "w");
153         if (!filep) {
154                 kvp_release_lock(pool);
155                 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
156                 exit(EXIT_FAILURE);
157         }
158
159         bytes_written = fwrite(kvp_file_info[pool].records,
160                                 sizeof(struct kvp_record),
161                                 kvp_file_info[pool].num_records, filep);
162
163         if (ferror(filep) || fclose(filep)) {
164                 kvp_release_lock(pool);
165                 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
166                 exit(EXIT_FAILURE);
167         }
168
169         kvp_release_lock(pool);
170 }
171
172 static void kvp_update_mem_state(int pool)
173 {
174         FILE *filep;
175         size_t records_read = 0;
176         struct kvp_record *record = kvp_file_info[pool].records;
177         struct kvp_record *readp;
178         int num_blocks = kvp_file_info[pool].num_blocks;
179         int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
180
181         kvp_acquire_lock(pool);
182
183         filep = fopen(kvp_file_info[pool].fname, "r");
184         if (!filep) {
185                 kvp_release_lock(pool);
186                 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
187                 exit(EXIT_FAILURE);
188         }
189         for (;;) {
190                 readp = &record[records_read];
191                 records_read += fread(readp, sizeof(struct kvp_record),
192                                         ENTRIES_PER_BLOCK * num_blocks,
193                                         filep);
194
195                 if (ferror(filep)) {
196                         syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
197                         exit(EXIT_FAILURE);
198                 }
199
200                 if (!feof(filep)) {
201                         /*
202                          * We have more data to read.
203                          */
204                         num_blocks++;
205                         record = realloc(record, alloc_unit * num_blocks);
206
207                         if (record == NULL) {
208                                 syslog(LOG_ERR, "malloc failed");
209                                 exit(EXIT_FAILURE);
210                         }
211                         continue;
212                 }
213                 break;
214         }
215
216         kvp_file_info[pool].num_blocks = num_blocks;
217         kvp_file_info[pool].records = record;
218         kvp_file_info[pool].num_records = records_read;
219
220         fclose(filep);
221         kvp_release_lock(pool);
222 }
223 static int kvp_file_init(void)
224 {
225         int  fd;
226         FILE *filep;
227         size_t records_read;
228         char *fname;
229         struct kvp_record *record;
230         struct kvp_record *readp;
231         int num_blocks;
232         int i;
233         int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
234
235         if (access("/var/opt/hyperv", F_OK)) {
236                 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
237                         syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
238                         exit(EXIT_FAILURE);
239                 }
240         }
241
242         for (i = 0; i < KVP_POOL_COUNT; i++) {
243                 fname = kvp_file_info[i].fname;
244                 records_read = 0;
245                 num_blocks = 1;
246                 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
247                 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
248
249                 if (fd == -1)
250                         return 1;
251
252
253                 filep = fopen(fname, "r");
254                 if (!filep)
255                         return 1;
256
257                 record = malloc(alloc_unit * num_blocks);
258                 if (record == NULL) {
259                         fclose(filep);
260                         return 1;
261                 }
262                 for (;;) {
263                         readp = &record[records_read];
264                         records_read += fread(readp, sizeof(struct kvp_record),
265                                         ENTRIES_PER_BLOCK,
266                                         filep);
267
268                         if (ferror(filep)) {
269                                 syslog(LOG_ERR, "Failed to read file, pool: %d",
270                                        i);
271                                 exit(EXIT_FAILURE);
272                         }
273
274                         if (!feof(filep)) {
275                                 /*
276                                  * We have more data to read.
277                                  */
278                                 num_blocks++;
279                                 record = realloc(record, alloc_unit *
280                                                 num_blocks);
281                                 if (record == NULL) {
282                                         fclose(filep);
283                                         return 1;
284                                 }
285                                 continue;
286                         }
287                         break;
288                 }
289                 kvp_file_info[i].fd = fd;
290                 kvp_file_info[i].num_blocks = num_blocks;
291                 kvp_file_info[i].records = record;
292                 kvp_file_info[i].num_records = records_read;
293                 fclose(filep);
294
295         }
296
297         return 0;
298 }
299
300 static int kvp_key_delete(int pool, __u8 *key, int key_size)
301 {
302         int i;
303         int j, k;
304         int num_records;
305         struct kvp_record *record;
306
307         /*
308          * First update the in-memory state.
309          */
310         kvp_update_mem_state(pool);
311
312         num_records = kvp_file_info[pool].num_records;
313         record = kvp_file_info[pool].records;
314
315         for (i = 0; i < num_records; i++) {
316                 if (memcmp(key, record[i].key, key_size))
317                         continue;
318                 /*
319                  * Found a match; just move the remaining
320                  * entries up.
321                  */
322                 if (i == num_records) {
323                         kvp_file_info[pool].num_records--;
324                         kvp_update_file(pool);
325                         return 0;
326                 }
327
328                 j = i;
329                 k = j + 1;
330                 for (; k < num_records; k++) {
331                         strcpy(record[j].key, record[k].key);
332                         strcpy(record[j].value, record[k].value);
333                         j++;
334                 }
335
336                 kvp_file_info[pool].num_records--;
337                 kvp_update_file(pool);
338                 return 0;
339         }
340         return 1;
341 }
342
343 static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
344                         int value_size)
345 {
346         int i;
347         int num_records;
348         struct kvp_record *record;
349         int num_blocks;
350
351         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
352                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
353                 return 1;
354
355         /*
356          * First update the in-memory state.
357          */
358         kvp_update_mem_state(pool);
359
360         num_records = kvp_file_info[pool].num_records;
361         record = kvp_file_info[pool].records;
362         num_blocks = kvp_file_info[pool].num_blocks;
363
364         for (i = 0; i < num_records; i++) {
365                 if (memcmp(key, record[i].key, key_size))
366                         continue;
367                 /*
368                  * Found a match; just update the value -
369                  * this is the modify case.
370                  */
371                 memcpy(record[i].value, value, value_size);
372                 kvp_update_file(pool);
373                 return 0;
374         }
375
376         /*
377          * Need to add a new entry;
378          */
379         if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
380                 /* Need to allocate a larger array for reg entries. */
381                 record = realloc(record, sizeof(struct kvp_record) *
382                          ENTRIES_PER_BLOCK * (num_blocks + 1));
383
384                 if (record == NULL)
385                         return 1;
386                 kvp_file_info[pool].num_blocks++;
387
388         }
389         memcpy(record[i].value, value, value_size);
390         memcpy(record[i].key, key, key_size);
391         kvp_file_info[pool].records = record;
392         kvp_file_info[pool].num_records++;
393         kvp_update_file(pool);
394         return 0;
395 }
396
397 static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
398                         int value_size)
399 {
400         int i;
401         int num_records;
402         struct kvp_record *record;
403
404         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
405                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
406                 return 1;
407
408         /*
409          * First update the in-memory state.
410          */
411         kvp_update_mem_state(pool);
412
413         num_records = kvp_file_info[pool].num_records;
414         record = kvp_file_info[pool].records;
415
416         for (i = 0; i < num_records; i++) {
417                 if (memcmp(key, record[i].key, key_size))
418                         continue;
419                 /*
420                  * Found a match; just copy the value out.
421                  */
422                 memcpy(value, record[i].value, value_size);
423                 return 0;
424         }
425
426         return 1;
427 }
428
429 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
430                                 __u8 *value, int value_size)
431 {
432         struct kvp_record *record;
433
434         /*
435          * First update our in-memory database.
436          */
437         kvp_update_mem_state(pool);
438         record = kvp_file_info[pool].records;
439
440         if (index >= kvp_file_info[pool].num_records) {
441                 return 1;
442         }
443
444         memcpy(key, record[index].key, key_size);
445         memcpy(value, record[index].value, value_size);
446         return 0;
447 }
448
449
450 void kvp_get_os_info(void)
451 {
452         FILE    *file;
453         char    *p, buf[512];
454
455         uname(&uts_buf);
456         os_build = uts_buf.release;
457         processor_arch = uts_buf.machine;
458
459         /*
460          * The current windows host (win7) expects the build
461          * string to be of the form: x.y.z
462          * Strip additional information we may have.
463          */
464         p = strchr(os_build, '-');
465         if (p)
466                 *p = '\0';
467
468         file = fopen("/etc/SuSE-release", "r");
469         if (file != NULL)
470                 goto kvp_osinfo_found;
471         file  = fopen("/etc/redhat-release", "r");
472         if (file != NULL)
473                 goto kvp_osinfo_found;
474         /*
475          * Add code for other supported platforms.
476          */
477
478         /*
479          * We don't have information about the os.
480          */
481         os_name = uts_buf.sysname;
482         return;
483
484 kvp_osinfo_found:
485         /* up to three lines */
486         p = fgets(buf, sizeof(buf), file);
487         if (p) {
488                 p = strchr(buf, '\n');
489                 if (p)
490                         *p = '\0';
491                 p = strdup(buf);
492                 if (!p)
493                         goto done;
494                 os_name = p;
495
496                 /* second line */
497                 p = fgets(buf, sizeof(buf), file);
498                 if (p) {
499                         p = strchr(buf, '\n');
500                         if (p)
501                                 *p = '\0';
502                         p = strdup(buf);
503                         if (!p)
504                                 goto done;
505                         os_major = p;
506
507                         /* third line */
508                         p = fgets(buf, sizeof(buf), file);
509                         if (p)  {
510                                 p = strchr(buf, '\n');
511                                 if (p)
512                                         *p = '\0';
513                                 p = strdup(buf);
514                                 if (p)
515                                         os_minor = p;
516                         }
517                 }
518         }
519
520 done:
521         fclose(file);
522         return;
523 }
524
525
526
527 /*
528  * Retrieve an interface name corresponding to the specified guid.
529  * If there is a match, the function returns a pointer
530  * to the interface name and if not, a NULL is returned.
531  * If a match is found, the caller is responsible for
532  * freeing the memory.
533  */
534
535 static char *kvp_get_if_name(char *guid)
536 {
537         DIR *dir;
538         struct dirent *entry;
539         FILE    *file;
540         char    *p, *q, *x;
541         char    *if_name = NULL;
542         char    buf[256];
543         char *kvp_net_dir = "/sys/class/net/";
544         char dev_id[256];
545
546         dir = opendir(kvp_net_dir);
547         if (dir == NULL)
548                 return NULL;
549
550         snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
551         q = dev_id + strlen(kvp_net_dir);
552
553         while ((entry = readdir(dir)) != NULL) {
554                 /*
555                  * Set the state for the next pass.
556                  */
557                 *q = '\0';
558                 strcat(dev_id, entry->d_name);
559                 strcat(dev_id, "/device/device_id");
560
561                 file = fopen(dev_id, "r");
562                 if (file == NULL)
563                         continue;
564
565                 p = fgets(buf, sizeof(buf), file);
566                 if (p) {
567                         x = strchr(p, '\n');
568                         if (x)
569                                 *x = '\0';
570
571                         if (!strcmp(p, guid)) {
572                                 /*
573                                  * Found the guid match; return the interface
574                                  * name. The caller will free the memory.
575                                  */
576                                 if_name = strdup(entry->d_name);
577                                 fclose(file);
578                                 break;
579                         }
580                 }
581                 fclose(file);
582         }
583
584         closedir(dir);
585         return if_name;
586 }
587
588 /*
589  * Retrieve the MAC address given the interface name.
590  */
591
592 static char *kvp_if_name_to_mac(char *if_name)
593 {
594         FILE    *file;
595         char    *p, *x;
596         char    buf[256];
597         char addr_file[256];
598         int i;
599         char *mac_addr = NULL;
600
601         snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
602                 if_name, "/address");
603
604         file = fopen(addr_file, "r");
605         if (file == NULL)
606                 return NULL;
607
608         p = fgets(buf, sizeof(buf), file);
609         if (p) {
610                 x = strchr(p, '\n');
611                 if (x)
612                         *x = '\0';
613                 for (i = 0; i < strlen(p); i++)
614                         p[i] = toupper(p[i]);
615                 mac_addr = strdup(p);
616         }
617
618         fclose(file);
619         return mac_addr;
620 }
621
622
623 /*
624  * Retrieve the interface name given tha MAC address.
625  */
626
627 static char *kvp_mac_to_if_name(char *mac)
628 {
629         DIR *dir;
630         struct dirent *entry;
631         FILE    *file;
632         char    *p, *q, *x;
633         char    *if_name = NULL;
634         char    buf[256];
635         char *kvp_net_dir = "/sys/class/net/";
636         char dev_id[256];
637         int i;
638
639         dir = opendir(kvp_net_dir);
640         if (dir == NULL)
641                 return NULL;
642
643         snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
644         q = dev_id + strlen(kvp_net_dir);
645
646         while ((entry = readdir(dir)) != NULL) {
647                 /*
648                  * Set the state for the next pass.
649                  */
650                 *q = '\0';
651
652                 strcat(dev_id, entry->d_name);
653                 strcat(dev_id, "/address");
654
655                 file = fopen(dev_id, "r");
656                 if (file == NULL)
657                         continue;
658
659                 p = fgets(buf, sizeof(buf), file);
660                 if (p) {
661                         x = strchr(p, '\n');
662                         if (x)
663                                 *x = '\0';
664
665                         for (i = 0; i < strlen(p); i++)
666                                 p[i] = toupper(p[i]);
667
668                         if (!strcmp(p, mac)) {
669                                 /*
670                                  * Found the MAC match; return the interface
671                                  * name. The caller will free the memory.
672                                  */
673                                 if_name = strdup(entry->d_name);
674                                 fclose(file);
675                                 break;
676                         }
677                 }
678                 fclose(file);
679         }
680
681         closedir(dir);
682         return if_name;
683 }
684
685
686 static void kvp_process_ipconfig_file(char *cmd,
687                                         char *config_buf, int len,
688                                         int element_size, int offset)
689 {
690         char buf[256];
691         char *p;
692         char *x;
693         FILE *file;
694
695         /*
696          * First execute the command.
697          */
698         file = popen(cmd, "r");
699         if (file == NULL)
700                 return;
701
702         if (offset == 0)
703                 memset(config_buf, 0, len);
704         while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
705                 if ((len - strlen(config_buf)) < (element_size + 1))
706                         break;
707
708                 x = strchr(p, '\n');
709                 *x = '\0';
710                 strcat(config_buf, p);
711                 strcat(config_buf, ";");
712         }
713         pclose(file);
714 }
715
716 static void kvp_get_ipconfig_info(char *if_name,
717                                  struct hv_kvp_ipaddr_value *buffer)
718 {
719         char cmd[512];
720         char dhcp_info[128];
721         char *p;
722         FILE *file;
723
724         /*
725          * Get the address of default gateway (ipv4).
726          */
727         sprintf(cmd, "%s %s", "ip route show dev", if_name);
728         strcat(cmd, " | awk '/default/ {print $3 }'");
729
730         /*
731          * Execute the command to gather gateway info.
732          */
733         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
734                                 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
735
736         /*
737          * Get the address of default gateway (ipv6).
738          */
739         sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
740         strcat(cmd, " | awk '/default/ {print $3 }'");
741
742         /*
743          * Execute the command to gather gateway info (ipv6).
744          */
745         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
746                                 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
747
748
749         /*
750          * Gather the DNS  state.
751          * Since there is no standard way to get this information
752          * across various distributions of interest; we just invoke
753          * an external script that needs to be ported across distros
754          * of interest.
755          *
756          * Following is the expected format of the information from the script:
757          *
758          * ipaddr1 (nameserver1)
759          * ipaddr2 (nameserver2)
760          * .
761          * .
762          */
763
764         sprintf(cmd, "%s",  "hv_get_dns_info");
765
766         /*
767          * Execute the command to gather DNS info.
768          */
769         kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
770                                 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
771
772         /*
773          * Gather the DHCP state.
774          * We will gather this state by invoking an external script.
775          * The parameter to the script is the interface name.
776          * Here is the expected output:
777          *
778          * Enabled: DHCP enabled.
779          */
780
781         sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
782
783         file = popen(cmd, "r");
784         if (file == NULL)
785                 return;
786
787         p = fgets(dhcp_info, sizeof(dhcp_info), file);
788         if (p == NULL) {
789                 pclose(file);
790                 return;
791         }
792
793         if (!strncmp(p, "Enabled", 7))
794                 buffer->dhcp_enabled = 1;
795         else
796                 buffer->dhcp_enabled = 0;
797
798         pclose(file);
799 }
800
801
802 static unsigned int hweight32(unsigned int *w)
803 {
804         unsigned int res = *w - ((*w >> 1) & 0x55555555);
805         res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
806         res = (res + (res >> 4)) & 0x0F0F0F0F;
807         res = res + (res >> 8);
808         return (res + (res >> 16)) & 0x000000FF;
809 }
810
811 static int kvp_process_ip_address(void *addrp,
812                                 int family, char *buffer,
813                                 int length,  int *offset)
814 {
815         struct sockaddr_in *addr;
816         struct sockaddr_in6 *addr6;
817         int addr_length;
818         char tmp[50];
819         const char *str;
820
821         if (family == AF_INET) {
822                 addr = (struct sockaddr_in *)addrp;
823                 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
824                 addr_length = INET_ADDRSTRLEN;
825         } else {
826                 addr6 = (struct sockaddr_in6 *)addrp;
827                 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
828                 addr_length = INET6_ADDRSTRLEN;
829         }
830
831         if ((length - *offset) < addr_length + 1)
832                 return HV_E_FAIL;
833         if (str == NULL) {
834                 strcpy(buffer, "inet_ntop failed\n");
835                 return HV_E_FAIL;
836         }
837         if (*offset == 0)
838                 strcpy(buffer, tmp);
839         else
840                 strcat(buffer, tmp);
841         strcat(buffer, ";");
842
843         *offset += strlen(str) + 1;
844         return 0;
845 }
846
847 static int
848 kvp_get_ip_info(int family, char *if_name, int op,
849                  void  *out_buffer, int length)
850 {
851         struct ifaddrs *ifap;
852         struct ifaddrs *curp;
853         int offset = 0;
854         int sn_offset = 0;
855         int error = 0;
856         char *buffer;
857         struct hv_kvp_ipaddr_value *ip_buffer;
858         char cidr_mask[5]; /* /xyz */
859         int weight;
860         int i;
861         unsigned int *w;
862         char *sn_str;
863         struct sockaddr_in6 *addr6;
864
865         if (op == KVP_OP_ENUMERATE) {
866                 buffer = out_buffer;
867         } else {
868                 ip_buffer = out_buffer;
869                 buffer = (char *)ip_buffer->ip_addr;
870                 ip_buffer->addr_family = 0;
871         }
872         /*
873          * On entry into this function, the buffer is capable of holding the
874          * maximum key value.
875          */
876
877         if (getifaddrs(&ifap)) {
878                 strcpy(buffer, "getifaddrs failed\n");
879                 return HV_E_FAIL;
880         }
881
882         curp = ifap;
883         while (curp != NULL) {
884                 if (curp->ifa_addr == NULL) {
885                         curp = curp->ifa_next;
886                         continue;
887                 }
888
889                 if ((if_name != NULL) &&
890                         (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
891                         /*
892                          * We want info about a specific interface;
893                          * just continue.
894                          */
895                         curp = curp->ifa_next;
896                         continue;
897                 }
898
899                 /*
900                  * We only support two address families: AF_INET and AF_INET6.
901                  * If a family value of 0 is specified, we collect both
902                  * supported address families; if not we gather info on
903                  * the specified address family.
904                  */
905                 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
906                         curp = curp->ifa_next;
907                         continue;
908                 }
909                 if ((curp->ifa_addr->sa_family != AF_INET) &&
910                         (curp->ifa_addr->sa_family != AF_INET6)) {
911                         curp = curp->ifa_next;
912                         continue;
913                 }
914
915                 if (op == KVP_OP_GET_IP_INFO) {
916                         /*
917                          * Gather info other than the IP address.
918                          * IP address info will be gathered later.
919                          */
920                         if (curp->ifa_addr->sa_family == AF_INET) {
921                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
922                                 /*
923                                  * Get subnet info.
924                                  */
925                                 error = kvp_process_ip_address(
926                                                              curp->ifa_netmask,
927                                                              AF_INET,
928                                                              (char *)
929                                                              ip_buffer->sub_net,
930                                                              length,
931                                                              &sn_offset);
932                                 if (error)
933                                         goto gather_ipaddr;
934                         } else {
935                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
936
937                                 /*
938                                  * Get subnet info in CIDR format.
939                                  */
940                                 weight = 0;
941                                 sn_str = (char *)ip_buffer->sub_net;
942                                 addr6 = (struct sockaddr_in6 *)
943                                         curp->ifa_netmask;
944                                 w = addr6->sin6_addr.s6_addr32;
945
946                                 for (i = 0; i < 4; i++)
947                                         weight += hweight32(&w[i]);
948
949                                 sprintf(cidr_mask, "/%d", weight);
950                                 if ((length - sn_offset) <
951                                         (strlen(cidr_mask) + 1))
952                                         goto gather_ipaddr;
953
954                                 if (sn_offset == 0)
955                                         strcpy(sn_str, cidr_mask);
956                                 else
957                                         strcat(sn_str, cidr_mask);
958                                 strcat((char *)ip_buffer->sub_net, ";");
959                                 sn_offset += strlen(sn_str) + 1;
960                         }
961
962                         /*
963                          * Collect other ip related configuration info.
964                          */
965
966                         kvp_get_ipconfig_info(if_name, ip_buffer);
967                 }
968
969 gather_ipaddr:
970                 error = kvp_process_ip_address(curp->ifa_addr,
971                                                 curp->ifa_addr->sa_family,
972                                                 buffer,
973                                                 length, &offset);
974                 if (error)
975                         goto getaddr_done;
976
977                 curp = curp->ifa_next;
978         }
979
980 getaddr_done:
981         freeifaddrs(ifap);
982         return error;
983 }
984
985
986 static int expand_ipv6(char *addr, int type)
987 {
988         int ret;
989         struct in6_addr v6_addr;
990
991         ret = inet_pton(AF_INET6, addr, &v6_addr);
992
993         if (ret != 1) {
994                 if (type == NETMASK)
995                         return 1;
996                 return 0;
997         }
998
999         sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1000                 "%02x%02x:%02x%02x:%02x%02x",
1001                 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1002                 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1003                 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1004                 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1005                 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1006                 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1007                 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1008                 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1009
1010         return 1;
1011
1012 }
1013
1014 static int is_ipv4(char *addr)
1015 {
1016         int ret;
1017         struct in_addr ipv4_addr;
1018
1019         ret = inet_pton(AF_INET, addr, &ipv4_addr);
1020
1021         if (ret == 1)
1022                 return 1;
1023         return 0;
1024 }
1025
1026 static int parse_ip_val_buffer(char *in_buf, int *offset,
1027                                 char *out_buf, int out_len)
1028 {
1029         char *x;
1030         char *start;
1031
1032         /*
1033          * in_buf has sequence of characters that are seperated by
1034          * the character ';'. The last sequence does not have the
1035          * terminating ";" character.
1036          */
1037         start = in_buf + *offset;
1038
1039         x = strchr(start, ';');
1040         if (x)
1041                 *x = 0;
1042         else
1043                 x = start + strlen(start);
1044
1045         if (strlen(start) != 0) {
1046                 int i = 0;
1047                 /*
1048                  * Get rid of leading spaces.
1049                  */
1050                 while (start[i] == ' ')
1051                         i++;
1052
1053                 if ((x - start) <= out_len) {
1054                         strcpy(out_buf, (start + i));
1055                         *offset += (x - start) + 1;
1056                         return 1;
1057                 }
1058         }
1059         return 0;
1060 }
1061
1062 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1063 {
1064         int ret;
1065
1066         ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1067
1068         if (ret < 0)
1069                 return HV_E_FAIL;
1070
1071         return 0;
1072 }
1073
1074
1075 static int process_ip_string(FILE *f, char *ip_string, int type)
1076 {
1077         int error = 0;
1078         char addr[INET6_ADDRSTRLEN];
1079         int i = 0;
1080         int j = 0;
1081         char str[256];
1082         char sub_str[10];
1083         int offset = 0;
1084
1085         memset(addr, 0, sizeof(addr));
1086
1087         while (parse_ip_val_buffer(ip_string, &offset, addr,
1088                                         (MAX_IP_ADDR_SIZE * 2))) {
1089
1090                 sub_str[0] = 0;
1091                 if (is_ipv4(addr)) {
1092                         switch (type) {
1093                         case IPADDR:
1094                                 snprintf(str, sizeof(str), "%s", "IPADDR");
1095                                 break;
1096                         case NETMASK:
1097                                 snprintf(str, sizeof(str), "%s", "NETMASK");
1098                                 break;
1099                         case GATEWAY:
1100                                 snprintf(str, sizeof(str), "%s", "GATEWAY");
1101                                 break;
1102                         case DNS:
1103                                 snprintf(str, sizeof(str), "%s", "DNS");
1104                                 break;
1105                         }
1106                         if (i != 0) {
1107                                 if (type != DNS) {
1108                                         snprintf(sub_str, sizeof(sub_str),
1109                                                 "_%d", i++);
1110                                 } else {
1111                                         snprintf(sub_str, sizeof(sub_str),
1112                                                 "%d", ++i);
1113                                 }
1114                         } else if (type == DNS) {
1115                                 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1116                         }
1117
1118
1119                 } else if (expand_ipv6(addr, type)) {
1120                         switch (type) {
1121                         case IPADDR:
1122                                 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1123                                 break;
1124                         case NETMASK:
1125                                 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1126                                 break;
1127                         case GATEWAY:
1128                                 snprintf(str, sizeof(str), "%s",
1129                                         "IPV6_DEFAULTGW");
1130                                 break;
1131                         case DNS:
1132                                 snprintf(str, sizeof(str), "%s",  "DNS");
1133                                 break;
1134                         }
1135                         if ((j != 0) || (type == DNS)) {
1136                                 if (type != DNS) {
1137                                         snprintf(sub_str, sizeof(sub_str),
1138                                                 "_%d", j++);
1139                                 } else {
1140                                         snprintf(sub_str, sizeof(sub_str),
1141                                                 "%d", ++i);
1142                                 }
1143                         } else if (type == DNS) {
1144                                 snprintf(sub_str, sizeof(sub_str),
1145                                         "%d", ++i);
1146                         }
1147                 } else {
1148                         return  HV_INVALIDARG;
1149                 }
1150
1151                 error = kvp_write_file(f, str, sub_str, addr);
1152                 if (error)
1153                         return error;
1154                 memset(addr, 0, sizeof(addr));
1155         }
1156
1157         return 0;
1158 }
1159
1160 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1161 {
1162         int error = 0;
1163         char if_file[128];
1164         FILE *file;
1165         char cmd[512];
1166         char *mac_addr;
1167
1168         /*
1169          * Set the configuration for the specified interface with
1170          * the information provided. Since there is no standard
1171          * way to configure an interface, we will have an external
1172          * script that does the job of configuring the interface and
1173          * flushing the configuration.
1174          *
1175          * The parameters passed to this external script are:
1176          * 1. A configuration file that has the specified configuration.
1177          *
1178          * We will embed the name of the interface in the configuration
1179          * file: ifcfg-ethx (where ethx is the interface name).
1180          *
1181          * The information provided here may be more than what is needed
1182          * in a given distro to configure the interface and so are free
1183          * ignore information that may not be relevant.
1184          *
1185          * Here is the format of the ip configuration file:
1186          *
1187          * HWADDR=macaddr
1188          * IF_NAME=interface name
1189          * DHCP=yes (This is optional; if yes, DHCP is configured)
1190          *
1191          * IPADDR=ipaddr1
1192          * IPADDR_1=ipaddr2
1193          * IPADDR_x=ipaddry (where y = x + 1)
1194          *
1195          * NETMASK=netmask1
1196          * NETMASK_x=netmasky (where y = x + 1)
1197          *
1198          * GATEWAY=ipaddr1
1199          * GATEWAY_x=ipaddry (where y = x + 1)
1200          *
1201          * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1202          *
1203          * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1204          * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1205          * IPV6NETMASK.
1206          *
1207          * The host can specify multiple ipv4 and ipv6 addresses to be
1208          * configured for the interface. Furthermore, the configuration
1209          * needs to be persistent. A subsequent GET call on the interface
1210          * is expected to return the configuration that is set via the SET
1211          * call.
1212          */
1213
1214         snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1215                 "hyperv/ifcfg-", if_name);
1216
1217         file = fopen(if_file, "w");
1218
1219         if (file == NULL) {
1220                 syslog(LOG_ERR, "Failed to open config file");
1221                 return HV_E_FAIL;
1222         }
1223
1224         /*
1225          * First write out the MAC address.
1226          */
1227
1228         mac_addr = kvp_if_name_to_mac(if_name);
1229         if (mac_addr == NULL) {
1230                 error = HV_E_FAIL;
1231                 goto setval_error;
1232         }
1233
1234         error = kvp_write_file(file, "HWADDR", "", mac_addr);
1235         if (error)
1236                 goto setval_error;
1237
1238         error = kvp_write_file(file, "IF_NAME", "", if_name);
1239         if (error)
1240                 goto setval_error;
1241
1242         if (new_val->dhcp_enabled) {
1243                 error = kvp_write_file(file, "DHCP", "", "yes");
1244                 if (error)
1245                         goto setval_error;
1246
1247                 /*
1248                  * We are done!.
1249                  */
1250                 goto setval_done;
1251         }
1252
1253         /*
1254          * Write the configuration for ipaddress, netmask, gateway and
1255          * name servers.
1256          */
1257
1258         error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1259         if (error)
1260                 goto setval_error;
1261
1262         error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1263         if (error)
1264                 goto setval_error;
1265
1266         error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1267         if (error)
1268                 goto setval_error;
1269
1270         error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1271         if (error)
1272                 goto setval_error;
1273
1274 setval_done:
1275         free(mac_addr);
1276         fclose(file);
1277
1278         /*
1279          * Now that we have populated the configuration file,
1280          * invoke the external script to do its magic.
1281          */
1282
1283         snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1284         system(cmd);
1285         return 0;
1286
1287 setval_error:
1288         syslog(LOG_ERR, "Failed to write config file");
1289         free(mac_addr);
1290         fclose(file);
1291         return error;
1292 }
1293
1294
1295 static int
1296 kvp_get_domain_name(char *buffer, int length)
1297 {
1298         struct addrinfo hints, *info ;
1299         int error = 0;
1300
1301         gethostname(buffer, length);
1302         memset(&hints, 0, sizeof(hints));
1303         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1304         hints.ai_socktype = SOCK_STREAM;
1305         hints.ai_flags = AI_CANONNAME;
1306
1307         error = getaddrinfo(buffer, NULL, &hints, &info);
1308         if (error != 0) {
1309                 strcpy(buffer, "getaddrinfo failed\n");
1310                 return error;
1311         }
1312         strcpy(buffer, info->ai_canonname);
1313         freeaddrinfo(info);
1314         return error;
1315 }
1316
1317 static int
1318 netlink_send(int fd, struct cn_msg *msg)
1319 {
1320         struct nlmsghdr *nlh;
1321         unsigned int size;
1322         struct msghdr message;
1323         char buffer[64];
1324         struct iovec iov[2];
1325
1326         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
1327
1328         nlh = (struct nlmsghdr *)buffer;
1329         nlh->nlmsg_seq = 0;
1330         nlh->nlmsg_pid = getpid();
1331         nlh->nlmsg_type = NLMSG_DONE;
1332         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
1333         nlh->nlmsg_flags = 0;
1334
1335         iov[0].iov_base = nlh;
1336         iov[0].iov_len = sizeof(*nlh);
1337
1338         iov[1].iov_base = msg;
1339         iov[1].iov_len = size;
1340
1341         memset(&message, 0, sizeof(message));
1342         message.msg_name = &addr;
1343         message.msg_namelen = sizeof(addr);
1344         message.msg_iov = iov;
1345         message.msg_iovlen = 2;
1346
1347         return sendmsg(fd, &message, 0);
1348 }
1349
1350 int main(void)
1351 {
1352         int fd, len, sock_opt;
1353         int error;
1354         struct cn_msg *message;
1355         struct pollfd pfd;
1356         struct nlmsghdr *incoming_msg;
1357         struct cn_msg   *incoming_cn_msg;
1358         struct hv_kvp_msg *hv_msg;
1359         char    *p;
1360         char    *key_value;
1361         char    *key_name;
1362         int     op;
1363         int     pool;
1364         char    *if_name;
1365         struct hv_kvp_ipaddr_value *kvp_ip_val;
1366
1367         daemon(1, 0);
1368         openlog("KVP", 0, LOG_USER);
1369         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1370         /*
1371          * Retrieve OS release information.
1372          */
1373         kvp_get_os_info();
1374
1375         if (kvp_file_init()) {
1376                 syslog(LOG_ERR, "Failed to initialize the pools");
1377                 exit(EXIT_FAILURE);
1378         }
1379
1380         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1381         if (fd < 0) {
1382                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
1383                 exit(EXIT_FAILURE);
1384         }
1385         addr.nl_family = AF_NETLINK;
1386         addr.nl_pad = 0;
1387         addr.nl_pid = 0;
1388         addr.nl_groups = CN_KVP_IDX;
1389
1390
1391         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1392         if (error < 0) {
1393                 syslog(LOG_ERR, "bind failed; error:%d", error);
1394                 close(fd);
1395                 exit(EXIT_FAILURE);
1396         }
1397         sock_opt = addr.nl_groups;
1398         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
1399         /*
1400          * Register ourselves with the kernel.
1401          */
1402         message = (struct cn_msg *)kvp_send_buffer;
1403         message->id.idx = CN_KVP_IDX;
1404         message->id.val = CN_KVP_VAL;
1405
1406         hv_msg = (struct hv_kvp_msg *)message->data;
1407         hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1408         message->ack = 0;
1409         message->len = sizeof(struct hv_kvp_msg);
1410
1411         len = netlink_send(fd, message);
1412         if (len < 0) {
1413                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
1414                 close(fd);
1415                 exit(EXIT_FAILURE);
1416         }
1417
1418         pfd.fd = fd;
1419
1420         while (1) {
1421                 struct sockaddr *addr_p = (struct sockaddr *) &addr;
1422                 socklen_t addr_l = sizeof(addr);
1423                 pfd.events = POLLIN;
1424                 pfd.revents = 0;
1425                 poll(&pfd, 1, -1);
1426
1427                 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
1428                                 addr_p, &addr_l);
1429
1430                 if (len < 0 || addr.nl_pid) {
1431                         syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1432                                         addr.nl_pid, errno, strerror(errno));
1433                         close(fd);
1434                         return -1;
1435                 }
1436
1437                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1438                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1439                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1440
1441                 /*
1442                  * We will use the KVP header information to pass back
1443                  * the error from this daemon. So, first copy the state
1444                  * and set the error code to success.
1445                  */
1446                 op = hv_msg->kvp_hdr.operation;
1447                 pool = hv_msg->kvp_hdr.pool;
1448                 hv_msg->error = HV_S_OK;
1449
1450                 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1451                         /*
1452                          * Driver is registering with us; stash away the version
1453                          * information.
1454                          */
1455                         in_hand_shake = 0;
1456                         p = (char *)hv_msg->body.kvp_register.version;
1457                         lic_version = malloc(strlen(p) + 1);
1458                         if (lic_version) {
1459                                 strcpy(lic_version, p);
1460                                 syslog(LOG_INFO, "KVP LIC Version: %s",
1461                                         lic_version);
1462                         } else {
1463                                 syslog(LOG_ERR, "malloc failed");
1464                         }
1465                         continue;
1466                 }
1467
1468                 switch (op) {
1469                 case KVP_OP_GET_IP_INFO:
1470                         kvp_ip_val = &hv_msg->body.kvp_ip_val;
1471                         if_name =
1472                         kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1473
1474                         if (if_name == NULL) {
1475                                 /*
1476                                  * We could not map the mac address to an
1477                                  * interface name; return error.
1478                                  */
1479                                 hv_msg->error = HV_E_FAIL;
1480                                 break;
1481                         }
1482                         error = kvp_get_ip_info(
1483                                                 0, if_name, KVP_OP_GET_IP_INFO,
1484                                                 kvp_ip_val,
1485                                                 (MAX_IP_ADDR_SIZE * 2));
1486
1487                         if (error)
1488                                 hv_msg->error = error;
1489
1490                         free(if_name);
1491                         break;
1492
1493                 case KVP_OP_SET_IP_INFO:
1494                         kvp_ip_val = &hv_msg->body.kvp_ip_val;
1495                         if_name = kvp_get_if_name(
1496                                         (char *)kvp_ip_val->adapter_id);
1497                         if (if_name == NULL) {
1498                                 /*
1499                                  * We could not map the guid to an
1500                                  * interface name; return error.
1501                                  */
1502                                 hv_msg->error = HV_GUID_NOTFOUND;
1503                                 break;
1504                         }
1505                         error = kvp_set_ip_info(if_name, kvp_ip_val);
1506                         if (error)
1507                                 hv_msg->error = error;
1508
1509                         free(if_name);
1510                         break;
1511
1512                 case KVP_OP_SET:
1513                         if (kvp_key_add_or_modify(pool,
1514                                         hv_msg->body.kvp_set.data.key,
1515                                         hv_msg->body.kvp_set.data.key_size,
1516                                         hv_msg->body.kvp_set.data.value,
1517                                         hv_msg->body.kvp_set.data.value_size))
1518                                         hv_msg->error = HV_S_CONT;
1519                         break;
1520
1521                 case KVP_OP_GET:
1522                         if (kvp_get_value(pool,
1523                                         hv_msg->body.kvp_set.data.key,
1524                                         hv_msg->body.kvp_set.data.key_size,
1525                                         hv_msg->body.kvp_set.data.value,
1526                                         hv_msg->body.kvp_set.data.value_size))
1527                                         hv_msg->error = HV_S_CONT;
1528                         break;
1529
1530                 case KVP_OP_DELETE:
1531                         if (kvp_key_delete(pool,
1532                                         hv_msg->body.kvp_delete.key,
1533                                         hv_msg->body.kvp_delete.key_size))
1534                                         hv_msg->error = HV_S_CONT;
1535                         break;
1536
1537                 default:
1538                         break;
1539                 }
1540
1541                 if (op != KVP_OP_ENUMERATE)
1542                         goto kvp_done;
1543
1544                 /*
1545                  * If the pool is KVP_POOL_AUTO, dynamically generate
1546                  * both the key and the value; if not read from the
1547                  * appropriate pool.
1548                  */
1549                 if (pool != KVP_POOL_AUTO) {
1550                         if (kvp_pool_enumerate(pool,
1551                                         hv_msg->body.kvp_enum_data.index,
1552                                         hv_msg->body.kvp_enum_data.data.key,
1553                                         HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1554                                         hv_msg->body.kvp_enum_data.data.value,
1555                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1556                                         hv_msg->error = HV_S_CONT;
1557                         goto kvp_done;
1558                 }
1559
1560                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1561                 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1562                 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1563
1564                 switch (hv_msg->body.kvp_enum_data.index) {
1565                 case FullyQualifiedDomainName:
1566                         kvp_get_domain_name(key_value,
1567                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1568                         strcpy(key_name, "FullyQualifiedDomainName");
1569                         break;
1570                 case IntegrationServicesVersion:
1571                         strcpy(key_name, "IntegrationServicesVersion");
1572                         strcpy(key_value, lic_version);
1573                         break;
1574                 case NetworkAddressIPv4:
1575                         kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1576                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1577                         strcpy(key_name, "NetworkAddressIPv4");
1578                         break;
1579                 case NetworkAddressIPv6:
1580                         kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1581                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1582                         strcpy(key_name, "NetworkAddressIPv6");
1583                         break;
1584                 case OSBuildNumber:
1585                         strcpy(key_value, os_build);
1586                         strcpy(key_name, "OSBuildNumber");
1587                         break;
1588                 case OSName:
1589                         strcpy(key_value, os_name);
1590                         strcpy(key_name, "OSName");
1591                         break;
1592                 case OSMajorVersion:
1593                         strcpy(key_value, os_major);
1594                         strcpy(key_name, "OSMajorVersion");
1595                         break;
1596                 case OSMinorVersion:
1597                         strcpy(key_value, os_minor);
1598                         strcpy(key_name, "OSMinorVersion");
1599                         break;
1600                 case OSVersion:
1601                         strcpy(key_value, os_build);
1602                         strcpy(key_name, "OSVersion");
1603                         break;
1604                 case ProcessorArchitecture:
1605                         strcpy(key_value, processor_arch);
1606                         strcpy(key_name, "ProcessorArchitecture");
1607                         break;
1608                 default:
1609                         hv_msg->error = HV_S_CONT;
1610                         break;
1611                 }
1612                 /*
1613                  * Send the value back to the kernel. The response is
1614                  * already in the receive buffer. Update the cn_msg header to
1615                  * reflect the key value that has been added to the message
1616                  */
1617 kvp_done:
1618
1619                 incoming_cn_msg->id.idx = CN_KVP_IDX;
1620                 incoming_cn_msg->id.val = CN_KVP_VAL;
1621                 incoming_cn_msg->ack = 0;
1622                 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1623
1624                 len = netlink_send(fd, incoming_cn_msg);
1625                 if (len < 0) {
1626                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
1627                         exit(EXIT_FAILURE);
1628                 }
1629         }
1630
1631 }