tools/hv: Parse /etc/os-release
[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 <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         os_name = uts_buf.sysname;
458         processor_arch = uts_buf.machine;
459
460         /*
461          * The current windows host (win7) expects the build
462          * string to be of the form: x.y.z
463          * Strip additional information we may have.
464          */
465         p = strchr(os_build, '-');
466         if (p)
467                 *p = '\0';
468
469         /*
470          * Parse the /etc/os-release file if present:
471          * http://www.freedesktop.org/software/systemd/man/os-release.html
472          */
473         file = fopen("/etc/os-release", "r");
474         if (file != NULL) {
475                 while (fgets(buf, sizeof(buf), file)) {
476                         char *value, *q;
477
478                         /* Ignore comments */
479                         if (buf[0] == '#')
480                                 continue;
481
482                         /* Split into name=value */
483                         p = strchr(buf, '=');
484                         if (!p)
485                                 continue;
486                         *p++ = 0;
487
488                         /* Remove quotes and newline; un-escape */
489                         value = p;
490                         q = p;
491                         while (*p) {
492                                 if (*p == '\\') {
493                                         ++p;
494                                         if (!*p)
495                                                 break;
496                                         *q++ = *p++;
497                                 } else if (*p == '\'' || *p == '"' ||
498                                            *p == '\n') {
499                                         ++p;
500                                 } else {
501                                         *q++ = *p++;
502                                 }
503                         }
504                         *q = 0;
505
506                         if (!strcmp(buf, "NAME")) {
507                                 p = strdup(value);
508                                 if (!p)
509                                         break;
510                                 os_name = p;
511                         } else if (!strcmp(buf, "VERSION_ID")) {
512                                 p = strdup(value);
513                                 if (!p)
514                                         break;
515                                 os_major = p;
516                         }
517                 }
518                 fclose(file);
519                 return;
520         }
521
522         /* Fallback for older RH/SUSE releases */
523         file = fopen("/etc/SuSE-release", "r");
524         if (file != NULL)
525                 goto kvp_osinfo_found;
526         file  = fopen("/etc/redhat-release", "r");
527         if (file != NULL)
528                 goto kvp_osinfo_found;
529
530         /*
531          * We don't have information about the os.
532          */
533         return;
534
535 kvp_osinfo_found:
536         /* up to three lines */
537         p = fgets(buf, sizeof(buf), file);
538         if (p) {
539                 p = strchr(buf, '\n');
540                 if (p)
541                         *p = '\0';
542                 p = strdup(buf);
543                 if (!p)
544                         goto done;
545                 os_name = p;
546
547                 /* second line */
548                 p = fgets(buf, sizeof(buf), file);
549                 if (p) {
550                         p = strchr(buf, '\n');
551                         if (p)
552                                 *p = '\0';
553                         p = strdup(buf);
554                         if (!p)
555                                 goto done;
556                         os_major = p;
557
558                         /* third line */
559                         p = fgets(buf, sizeof(buf), file);
560                         if (p)  {
561                                 p = strchr(buf, '\n');
562                                 if (p)
563                                         *p = '\0';
564                                 p = strdup(buf);
565                                 if (p)
566                                         os_minor = p;
567                         }
568                 }
569         }
570
571 done:
572         fclose(file);
573         return;
574 }
575
576
577
578 /*
579  * Retrieve an interface name corresponding to the specified guid.
580  * If there is a match, the function returns a pointer
581  * to the interface name and if not, a NULL is returned.
582  * If a match is found, the caller is responsible for
583  * freeing the memory.
584  */
585
586 static char *kvp_get_if_name(char *guid)
587 {
588         DIR *dir;
589         struct dirent *entry;
590         FILE    *file;
591         char    *p, *q, *x;
592         char    *if_name = NULL;
593         char    buf[256];
594         char *kvp_net_dir = "/sys/class/net/";
595         char dev_id[256];
596
597         dir = opendir(kvp_net_dir);
598         if (dir == NULL)
599                 return NULL;
600
601         snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
602         q = dev_id + strlen(kvp_net_dir);
603
604         while ((entry = readdir(dir)) != NULL) {
605                 /*
606                  * Set the state for the next pass.
607                  */
608                 *q = '\0';
609                 strcat(dev_id, entry->d_name);
610                 strcat(dev_id, "/device/device_id");
611
612                 file = fopen(dev_id, "r");
613                 if (file == NULL)
614                         continue;
615
616                 p = fgets(buf, sizeof(buf), file);
617                 if (p) {
618                         x = strchr(p, '\n');
619                         if (x)
620                                 *x = '\0';
621
622                         if (!strcmp(p, guid)) {
623                                 /*
624                                  * Found the guid match; return the interface
625                                  * name. The caller will free the memory.
626                                  */
627                                 if_name = strdup(entry->d_name);
628                                 fclose(file);
629                                 break;
630                         }
631                 }
632                 fclose(file);
633         }
634
635         closedir(dir);
636         return if_name;
637 }
638
639 /*
640  * Retrieve the MAC address given the interface name.
641  */
642
643 static char *kvp_if_name_to_mac(char *if_name)
644 {
645         FILE    *file;
646         char    *p, *x;
647         char    buf[256];
648         char addr_file[256];
649         int i;
650         char *mac_addr = NULL;
651
652         snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
653                 if_name, "/address");
654
655         file = fopen(addr_file, "r");
656         if (file == NULL)
657                 return NULL;
658
659         p = fgets(buf, sizeof(buf), file);
660         if (p) {
661                 x = strchr(p, '\n');
662                 if (x)
663                         *x = '\0';
664                 for (i = 0; i < strlen(p); i++)
665                         p[i] = toupper(p[i]);
666                 mac_addr = strdup(p);
667         }
668
669         fclose(file);
670         return mac_addr;
671 }
672
673
674 /*
675  * Retrieve the interface name given tha MAC address.
676  */
677
678 static char *kvp_mac_to_if_name(char *mac)
679 {
680         DIR *dir;
681         struct dirent *entry;
682         FILE    *file;
683         char    *p, *q, *x;
684         char    *if_name = NULL;
685         char    buf[256];
686         char *kvp_net_dir = "/sys/class/net/";
687         char dev_id[256];
688         int i;
689
690         dir = opendir(kvp_net_dir);
691         if (dir == NULL)
692                 return NULL;
693
694         snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
695         q = dev_id + strlen(kvp_net_dir);
696
697         while ((entry = readdir(dir)) != NULL) {
698                 /*
699                  * Set the state for the next pass.
700                  */
701                 *q = '\0';
702
703                 strcat(dev_id, entry->d_name);
704                 strcat(dev_id, "/address");
705
706                 file = fopen(dev_id, "r");
707                 if (file == NULL)
708                         continue;
709
710                 p = fgets(buf, sizeof(buf), file);
711                 if (p) {
712                         x = strchr(p, '\n');
713                         if (x)
714                                 *x = '\0';
715
716                         for (i = 0; i < strlen(p); i++)
717                                 p[i] = toupper(p[i]);
718
719                         if (!strcmp(p, mac)) {
720                                 /*
721                                  * Found the MAC match; return the interface
722                                  * name. The caller will free the memory.
723                                  */
724                                 if_name = strdup(entry->d_name);
725                                 fclose(file);
726                                 break;
727                         }
728                 }
729                 fclose(file);
730         }
731
732         closedir(dir);
733         return if_name;
734 }
735
736
737 static void kvp_process_ipconfig_file(char *cmd,
738                                         char *config_buf, int len,
739                                         int element_size, int offset)
740 {
741         char buf[256];
742         char *p;
743         char *x;
744         FILE *file;
745
746         /*
747          * First execute the command.
748          */
749         file = popen(cmd, "r");
750         if (file == NULL)
751                 return;
752
753         if (offset == 0)
754                 memset(config_buf, 0, len);
755         while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
756                 if ((len - strlen(config_buf)) < (element_size + 1))
757                         break;
758
759                 x = strchr(p, '\n');
760                 *x = '\0';
761                 strcat(config_buf, p);
762                 strcat(config_buf, ";");
763         }
764         pclose(file);
765 }
766
767 static void kvp_get_ipconfig_info(char *if_name,
768                                  struct hv_kvp_ipaddr_value *buffer)
769 {
770         char cmd[512];
771         char dhcp_info[128];
772         char *p;
773         FILE *file;
774
775         /*
776          * Get the address of default gateway (ipv4).
777          */
778         sprintf(cmd, "%s %s", "ip route show dev", if_name);
779         strcat(cmd, " | awk '/default/ {print $3 }'");
780
781         /*
782          * Execute the command to gather gateway info.
783          */
784         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
785                                 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
786
787         /*
788          * Get the address of default gateway (ipv6).
789          */
790         sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
791         strcat(cmd, " | awk '/default/ {print $3 }'");
792
793         /*
794          * Execute the command to gather gateway info (ipv6).
795          */
796         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
797                                 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
798
799
800         /*
801          * Gather the DNS  state.
802          * Since there is no standard way to get this information
803          * across various distributions of interest; we just invoke
804          * an external script that needs to be ported across distros
805          * of interest.
806          *
807          * Following is the expected format of the information from the script:
808          *
809          * ipaddr1 (nameserver1)
810          * ipaddr2 (nameserver2)
811          * .
812          * .
813          */
814
815         sprintf(cmd, "%s",  "hv_get_dns_info");
816
817         /*
818          * Execute the command to gather DNS info.
819          */
820         kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
821                                 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
822
823         /*
824          * Gather the DHCP state.
825          * We will gather this state by invoking an external script.
826          * The parameter to the script is the interface name.
827          * Here is the expected output:
828          *
829          * Enabled: DHCP enabled.
830          */
831
832         sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
833
834         file = popen(cmd, "r");
835         if (file == NULL)
836                 return;
837
838         p = fgets(dhcp_info, sizeof(dhcp_info), file);
839         if (p == NULL) {
840                 pclose(file);
841                 return;
842         }
843
844         if (!strncmp(p, "Enabled", 7))
845                 buffer->dhcp_enabled = 1;
846         else
847                 buffer->dhcp_enabled = 0;
848
849         pclose(file);
850 }
851
852
853 static unsigned int hweight32(unsigned int *w)
854 {
855         unsigned int res = *w - ((*w >> 1) & 0x55555555);
856         res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
857         res = (res + (res >> 4)) & 0x0F0F0F0F;
858         res = res + (res >> 8);
859         return (res + (res >> 16)) & 0x000000FF;
860 }
861
862 static int kvp_process_ip_address(void *addrp,
863                                 int family, char *buffer,
864                                 int length,  int *offset)
865 {
866         struct sockaddr_in *addr;
867         struct sockaddr_in6 *addr6;
868         int addr_length;
869         char tmp[50];
870         const char *str;
871
872         if (family == AF_INET) {
873                 addr = (struct sockaddr_in *)addrp;
874                 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
875                 addr_length = INET_ADDRSTRLEN;
876         } else {
877                 addr6 = (struct sockaddr_in6 *)addrp;
878                 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
879                 addr_length = INET6_ADDRSTRLEN;
880         }
881
882         if ((length - *offset) < addr_length + 1)
883                 return HV_E_FAIL;
884         if (str == NULL) {
885                 strcpy(buffer, "inet_ntop failed\n");
886                 return HV_E_FAIL;
887         }
888         if (*offset == 0)
889                 strcpy(buffer, tmp);
890         else
891                 strcat(buffer, tmp);
892         strcat(buffer, ";");
893
894         *offset += strlen(str) + 1;
895         return 0;
896 }
897
898 static int
899 kvp_get_ip_info(int family, char *if_name, int op,
900                  void  *out_buffer, int length)
901 {
902         struct ifaddrs *ifap;
903         struct ifaddrs *curp;
904         int offset = 0;
905         int sn_offset = 0;
906         int error = 0;
907         char *buffer;
908         struct hv_kvp_ipaddr_value *ip_buffer;
909         char cidr_mask[5]; /* /xyz */
910         int weight;
911         int i;
912         unsigned int *w;
913         char *sn_str;
914         struct sockaddr_in6 *addr6;
915
916         if (op == KVP_OP_ENUMERATE) {
917                 buffer = out_buffer;
918         } else {
919                 ip_buffer = out_buffer;
920                 buffer = (char *)ip_buffer->ip_addr;
921                 ip_buffer->addr_family = 0;
922         }
923         /*
924          * On entry into this function, the buffer is capable of holding the
925          * maximum key value.
926          */
927
928         if (getifaddrs(&ifap)) {
929                 strcpy(buffer, "getifaddrs failed\n");
930                 return HV_E_FAIL;
931         }
932
933         curp = ifap;
934         while (curp != NULL) {
935                 if (curp->ifa_addr == NULL) {
936                         curp = curp->ifa_next;
937                         continue;
938                 }
939
940                 if ((if_name != NULL) &&
941                         (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
942                         /*
943                          * We want info about a specific interface;
944                          * just continue.
945                          */
946                         curp = curp->ifa_next;
947                         continue;
948                 }
949
950                 /*
951                  * We only support two address families: AF_INET and AF_INET6.
952                  * If a family value of 0 is specified, we collect both
953                  * supported address families; if not we gather info on
954                  * the specified address family.
955                  */
956                 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
957                         curp = curp->ifa_next;
958                         continue;
959                 }
960                 if ((curp->ifa_addr->sa_family != AF_INET) &&
961                         (curp->ifa_addr->sa_family != AF_INET6)) {
962                         curp = curp->ifa_next;
963                         continue;
964                 }
965
966                 if (op == KVP_OP_GET_IP_INFO) {
967                         /*
968                          * Gather info other than the IP address.
969                          * IP address info will be gathered later.
970                          */
971                         if (curp->ifa_addr->sa_family == AF_INET) {
972                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
973                                 /*
974                                  * Get subnet info.
975                                  */
976                                 error = kvp_process_ip_address(
977                                                              curp->ifa_netmask,
978                                                              AF_INET,
979                                                              (char *)
980                                                              ip_buffer->sub_net,
981                                                              length,
982                                                              &sn_offset);
983                                 if (error)
984                                         goto gather_ipaddr;
985                         } else {
986                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
987
988                                 /*
989                                  * Get subnet info in CIDR format.
990                                  */
991                                 weight = 0;
992                                 sn_str = (char *)ip_buffer->sub_net;
993                                 addr6 = (struct sockaddr_in6 *)
994                                         curp->ifa_netmask;
995                                 w = addr6->sin6_addr.s6_addr32;
996
997                                 for (i = 0; i < 4; i++)
998                                         weight += hweight32(&w[i]);
999
1000                                 sprintf(cidr_mask, "/%d", weight);
1001                                 if ((length - sn_offset) <
1002                                         (strlen(cidr_mask) + 1))
1003                                         goto gather_ipaddr;
1004
1005                                 if (sn_offset == 0)
1006                                         strcpy(sn_str, cidr_mask);
1007                                 else
1008                                         strcat(sn_str, cidr_mask);
1009                                 strcat((char *)ip_buffer->sub_net, ";");
1010                                 sn_offset += strlen(sn_str) + 1;
1011                         }
1012
1013                         /*
1014                          * Collect other ip related configuration info.
1015                          */
1016
1017                         kvp_get_ipconfig_info(if_name, ip_buffer);
1018                 }
1019
1020 gather_ipaddr:
1021                 error = kvp_process_ip_address(curp->ifa_addr,
1022                                                 curp->ifa_addr->sa_family,
1023                                                 buffer,
1024                                                 length, &offset);
1025                 if (error)
1026                         goto getaddr_done;
1027
1028                 curp = curp->ifa_next;
1029         }
1030
1031 getaddr_done:
1032         freeifaddrs(ifap);
1033         return error;
1034 }
1035
1036
1037 static int expand_ipv6(char *addr, int type)
1038 {
1039         int ret;
1040         struct in6_addr v6_addr;
1041
1042         ret = inet_pton(AF_INET6, addr, &v6_addr);
1043
1044         if (ret != 1) {
1045                 if (type == NETMASK)
1046                         return 1;
1047                 return 0;
1048         }
1049
1050         sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1051                 "%02x%02x:%02x%02x:%02x%02x",
1052                 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1053                 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1054                 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1055                 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1056                 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1057                 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1058                 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1059                 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1060
1061         return 1;
1062
1063 }
1064
1065 static int is_ipv4(char *addr)
1066 {
1067         int ret;
1068         struct in_addr ipv4_addr;
1069
1070         ret = inet_pton(AF_INET, addr, &ipv4_addr);
1071
1072         if (ret == 1)
1073                 return 1;
1074         return 0;
1075 }
1076
1077 static int parse_ip_val_buffer(char *in_buf, int *offset,
1078                                 char *out_buf, int out_len)
1079 {
1080         char *x;
1081         char *start;
1082
1083         /*
1084          * in_buf has sequence of characters that are seperated by
1085          * the character ';'. The last sequence does not have the
1086          * terminating ";" character.
1087          */
1088         start = in_buf + *offset;
1089
1090         x = strchr(start, ';');
1091         if (x)
1092                 *x = 0;
1093         else
1094                 x = start + strlen(start);
1095
1096         if (strlen(start) != 0) {
1097                 int i = 0;
1098                 /*
1099                  * Get rid of leading spaces.
1100                  */
1101                 while (start[i] == ' ')
1102                         i++;
1103
1104                 if ((x - start) <= out_len) {
1105                         strcpy(out_buf, (start + i));
1106                         *offset += (x - start) + 1;
1107                         return 1;
1108                 }
1109         }
1110         return 0;
1111 }
1112
1113 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1114 {
1115         int ret;
1116
1117         ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1118
1119         if (ret < 0)
1120                 return HV_E_FAIL;
1121
1122         return 0;
1123 }
1124
1125
1126 static int process_ip_string(FILE *f, char *ip_string, int type)
1127 {
1128         int error = 0;
1129         char addr[INET6_ADDRSTRLEN];
1130         int i = 0;
1131         int j = 0;
1132         char str[256];
1133         char sub_str[10];
1134         int offset = 0;
1135
1136         memset(addr, 0, sizeof(addr));
1137
1138         while (parse_ip_val_buffer(ip_string, &offset, addr,
1139                                         (MAX_IP_ADDR_SIZE * 2))) {
1140
1141                 sub_str[0] = 0;
1142                 if (is_ipv4(addr)) {
1143                         switch (type) {
1144                         case IPADDR:
1145                                 snprintf(str, sizeof(str), "%s", "IPADDR");
1146                                 break;
1147                         case NETMASK:
1148                                 snprintf(str, sizeof(str), "%s", "NETMASK");
1149                                 break;
1150                         case GATEWAY:
1151                                 snprintf(str, sizeof(str), "%s", "GATEWAY");
1152                                 break;
1153                         case DNS:
1154                                 snprintf(str, sizeof(str), "%s", "DNS");
1155                                 break;
1156                         }
1157                         if (i != 0) {
1158                                 if (type != DNS) {
1159                                         snprintf(sub_str, sizeof(sub_str),
1160                                                 "_%d", i++);
1161                                 } else {
1162                                         snprintf(sub_str, sizeof(sub_str),
1163                                                 "%d", ++i);
1164                                 }
1165                         } else if (type == DNS) {
1166                                 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1167                         }
1168
1169
1170                 } else if (expand_ipv6(addr, type)) {
1171                         switch (type) {
1172                         case IPADDR:
1173                                 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1174                                 break;
1175                         case NETMASK:
1176                                 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1177                                 break;
1178                         case GATEWAY:
1179                                 snprintf(str, sizeof(str), "%s",
1180                                         "IPV6_DEFAULTGW");
1181                                 break;
1182                         case DNS:
1183                                 snprintf(str, sizeof(str), "%s",  "DNS");
1184                                 break;
1185                         }
1186                         if ((j != 0) || (type == DNS)) {
1187                                 if (type != DNS) {
1188                                         snprintf(sub_str, sizeof(sub_str),
1189                                                 "_%d", j++);
1190                                 } else {
1191                                         snprintf(sub_str, sizeof(sub_str),
1192                                                 "%d", ++i);
1193                                 }
1194                         } else if (type == DNS) {
1195                                 snprintf(sub_str, sizeof(sub_str),
1196                                         "%d", ++i);
1197                         }
1198                 } else {
1199                         return  HV_INVALIDARG;
1200                 }
1201
1202                 error = kvp_write_file(f, str, sub_str, addr);
1203                 if (error)
1204                         return error;
1205                 memset(addr, 0, sizeof(addr));
1206         }
1207
1208         return 0;
1209 }
1210
1211 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1212 {
1213         int error = 0;
1214         char if_file[128];
1215         FILE *file;
1216         char cmd[512];
1217         char *mac_addr;
1218
1219         /*
1220          * Set the configuration for the specified interface with
1221          * the information provided. Since there is no standard
1222          * way to configure an interface, we will have an external
1223          * script that does the job of configuring the interface and
1224          * flushing the configuration.
1225          *
1226          * The parameters passed to this external script are:
1227          * 1. A configuration file that has the specified configuration.
1228          *
1229          * We will embed the name of the interface in the configuration
1230          * file: ifcfg-ethx (where ethx is the interface name).
1231          *
1232          * The information provided here may be more than what is needed
1233          * in a given distro to configure the interface and so are free
1234          * ignore information that may not be relevant.
1235          *
1236          * Here is the format of the ip configuration file:
1237          *
1238          * HWADDR=macaddr
1239          * IF_NAME=interface name
1240          * DHCP=yes (This is optional; if yes, DHCP is configured)
1241          *
1242          * IPADDR=ipaddr1
1243          * IPADDR_1=ipaddr2
1244          * IPADDR_x=ipaddry (where y = x + 1)
1245          *
1246          * NETMASK=netmask1
1247          * NETMASK_x=netmasky (where y = x + 1)
1248          *
1249          * GATEWAY=ipaddr1
1250          * GATEWAY_x=ipaddry (where y = x + 1)
1251          *
1252          * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1253          *
1254          * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1255          * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1256          * IPV6NETMASK.
1257          *
1258          * The host can specify multiple ipv4 and ipv6 addresses to be
1259          * configured for the interface. Furthermore, the configuration
1260          * needs to be persistent. A subsequent GET call on the interface
1261          * is expected to return the configuration that is set via the SET
1262          * call.
1263          */
1264
1265         snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1266                 "hyperv/ifcfg-", if_name);
1267
1268         file = fopen(if_file, "w");
1269
1270         if (file == NULL) {
1271                 syslog(LOG_ERR, "Failed to open config file");
1272                 return HV_E_FAIL;
1273         }
1274
1275         /*
1276          * First write out the MAC address.
1277          */
1278
1279         mac_addr = kvp_if_name_to_mac(if_name);
1280         if (mac_addr == NULL) {
1281                 error = HV_E_FAIL;
1282                 goto setval_error;
1283         }
1284
1285         error = kvp_write_file(file, "HWADDR", "", mac_addr);
1286         if (error)
1287                 goto setval_error;
1288
1289         error = kvp_write_file(file, "IF_NAME", "", if_name);
1290         if (error)
1291                 goto setval_error;
1292
1293         if (new_val->dhcp_enabled) {
1294                 error = kvp_write_file(file, "DHCP", "", "yes");
1295                 if (error)
1296                         goto setval_error;
1297
1298                 /*
1299                  * We are done!.
1300                  */
1301                 goto setval_done;
1302         }
1303
1304         /*
1305          * Write the configuration for ipaddress, netmask, gateway and
1306          * name servers.
1307          */
1308
1309         error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1310         if (error)
1311                 goto setval_error;
1312
1313         error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1314         if (error)
1315                 goto setval_error;
1316
1317         error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1318         if (error)
1319                 goto setval_error;
1320
1321         error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1322         if (error)
1323                 goto setval_error;
1324
1325 setval_done:
1326         free(mac_addr);
1327         fclose(file);
1328
1329         /*
1330          * Now that we have populated the configuration file,
1331          * invoke the external script to do its magic.
1332          */
1333
1334         snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1335         system(cmd);
1336         return 0;
1337
1338 setval_error:
1339         syslog(LOG_ERR, "Failed to write config file");
1340         free(mac_addr);
1341         fclose(file);
1342         return error;
1343 }
1344
1345
1346 static int
1347 kvp_get_domain_name(char *buffer, int length)
1348 {
1349         struct addrinfo hints, *info ;
1350         int error = 0;
1351
1352         gethostname(buffer, length);
1353         memset(&hints, 0, sizeof(hints));
1354         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1355         hints.ai_socktype = SOCK_STREAM;
1356         hints.ai_flags = AI_CANONNAME;
1357
1358         error = getaddrinfo(buffer, NULL, &hints, &info);
1359         if (error != 0) {
1360                 strcpy(buffer, "getaddrinfo failed\n");
1361                 return error;
1362         }
1363         strcpy(buffer, info->ai_canonname);
1364         freeaddrinfo(info);
1365         return error;
1366 }
1367
1368 static int
1369 netlink_send(int fd, struct cn_msg *msg)
1370 {
1371         struct nlmsghdr *nlh;
1372         unsigned int size;
1373         struct msghdr message;
1374         char buffer[64];
1375         struct iovec iov[2];
1376
1377         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
1378
1379         nlh = (struct nlmsghdr *)buffer;
1380         nlh->nlmsg_seq = 0;
1381         nlh->nlmsg_pid = getpid();
1382         nlh->nlmsg_type = NLMSG_DONE;
1383         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
1384         nlh->nlmsg_flags = 0;
1385
1386         iov[0].iov_base = nlh;
1387         iov[0].iov_len = sizeof(*nlh);
1388
1389         iov[1].iov_base = msg;
1390         iov[1].iov_len = size;
1391
1392         memset(&message, 0, sizeof(message));
1393         message.msg_name = &addr;
1394         message.msg_namelen = sizeof(addr);
1395         message.msg_iov = iov;
1396         message.msg_iovlen = 2;
1397
1398         return sendmsg(fd, &message, 0);
1399 }
1400
1401 int main(void)
1402 {
1403         int fd, len, sock_opt;
1404         int error;
1405         struct cn_msg *message;
1406         struct pollfd pfd;
1407         struct nlmsghdr *incoming_msg;
1408         struct cn_msg   *incoming_cn_msg;
1409         struct hv_kvp_msg *hv_msg;
1410         char    *p;
1411         char    *key_value;
1412         char    *key_name;
1413         int     op;
1414         int     pool;
1415         char    *if_name;
1416         struct hv_kvp_ipaddr_value *kvp_ip_val;
1417
1418         daemon(1, 0);
1419         openlog("KVP", 0, LOG_USER);
1420         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1421         /*
1422          * Retrieve OS release information.
1423          */
1424         kvp_get_os_info();
1425
1426         if (kvp_file_init()) {
1427                 syslog(LOG_ERR, "Failed to initialize the pools");
1428                 exit(EXIT_FAILURE);
1429         }
1430
1431         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1432         if (fd < 0) {
1433                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
1434                 exit(EXIT_FAILURE);
1435         }
1436         addr.nl_family = AF_NETLINK;
1437         addr.nl_pad = 0;
1438         addr.nl_pid = 0;
1439         addr.nl_groups = CN_KVP_IDX;
1440
1441
1442         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1443         if (error < 0) {
1444                 syslog(LOG_ERR, "bind failed; error:%d", error);
1445                 close(fd);
1446                 exit(EXIT_FAILURE);
1447         }
1448         sock_opt = addr.nl_groups;
1449         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
1450         /*
1451          * Register ourselves with the kernel.
1452          */
1453         message = (struct cn_msg *)kvp_send_buffer;
1454         message->id.idx = CN_KVP_IDX;
1455         message->id.val = CN_KVP_VAL;
1456
1457         hv_msg = (struct hv_kvp_msg *)message->data;
1458         hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1459         message->ack = 0;
1460         message->len = sizeof(struct hv_kvp_msg);
1461
1462         len = netlink_send(fd, message);
1463         if (len < 0) {
1464                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
1465                 close(fd);
1466                 exit(EXIT_FAILURE);
1467         }
1468
1469         pfd.fd = fd;
1470
1471         while (1) {
1472                 struct sockaddr *addr_p = (struct sockaddr *) &addr;
1473                 socklen_t addr_l = sizeof(addr);
1474                 pfd.events = POLLIN;
1475                 pfd.revents = 0;
1476                 poll(&pfd, 1, -1);
1477
1478                 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
1479                                 addr_p, &addr_l);
1480
1481                 if (len < 0 || addr.nl_pid) {
1482                         syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1483                                         addr.nl_pid, errno, strerror(errno));
1484                         close(fd);
1485                         return -1;
1486                 }
1487
1488                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1489                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1490                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1491
1492                 /*
1493                  * We will use the KVP header information to pass back
1494                  * the error from this daemon. So, first copy the state
1495                  * and set the error code to success.
1496                  */
1497                 op = hv_msg->kvp_hdr.operation;
1498                 pool = hv_msg->kvp_hdr.pool;
1499                 hv_msg->error = HV_S_OK;
1500
1501                 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1502                         /*
1503                          * Driver is registering with us; stash away the version
1504                          * information.
1505                          */
1506                         in_hand_shake = 0;
1507                         p = (char *)hv_msg->body.kvp_register.version;
1508                         lic_version = malloc(strlen(p) + 1);
1509                         if (lic_version) {
1510                                 strcpy(lic_version, p);
1511                                 syslog(LOG_INFO, "KVP LIC Version: %s",
1512                                         lic_version);
1513                         } else {
1514                                 syslog(LOG_ERR, "malloc failed");
1515                         }
1516                         continue;
1517                 }
1518
1519                 switch (op) {
1520                 case KVP_OP_GET_IP_INFO:
1521                         kvp_ip_val = &hv_msg->body.kvp_ip_val;
1522                         if_name =
1523                         kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1524
1525                         if (if_name == NULL) {
1526                                 /*
1527                                  * We could not map the mac address to an
1528                                  * interface name; return error.
1529                                  */
1530                                 hv_msg->error = HV_E_FAIL;
1531                                 break;
1532                         }
1533                         error = kvp_get_ip_info(
1534                                                 0, if_name, KVP_OP_GET_IP_INFO,
1535                                                 kvp_ip_val,
1536                                                 (MAX_IP_ADDR_SIZE * 2));
1537
1538                         if (error)
1539                                 hv_msg->error = error;
1540
1541                         free(if_name);
1542                         break;
1543
1544                 case KVP_OP_SET_IP_INFO:
1545                         kvp_ip_val = &hv_msg->body.kvp_ip_val;
1546                         if_name = kvp_get_if_name(
1547                                         (char *)kvp_ip_val->adapter_id);
1548                         if (if_name == NULL) {
1549                                 /*
1550                                  * We could not map the guid to an
1551                                  * interface name; return error.
1552                                  */
1553                                 hv_msg->error = HV_GUID_NOTFOUND;
1554                                 break;
1555                         }
1556                         error = kvp_set_ip_info(if_name, kvp_ip_val);
1557                         if (error)
1558                                 hv_msg->error = error;
1559
1560                         free(if_name);
1561                         break;
1562
1563                 case KVP_OP_SET:
1564                         if (kvp_key_add_or_modify(pool,
1565                                         hv_msg->body.kvp_set.data.key,
1566                                         hv_msg->body.kvp_set.data.key_size,
1567                                         hv_msg->body.kvp_set.data.value,
1568                                         hv_msg->body.kvp_set.data.value_size))
1569                                         hv_msg->error = HV_S_CONT;
1570                         break;
1571
1572                 case KVP_OP_GET:
1573                         if (kvp_get_value(pool,
1574                                         hv_msg->body.kvp_set.data.key,
1575                                         hv_msg->body.kvp_set.data.key_size,
1576                                         hv_msg->body.kvp_set.data.value,
1577                                         hv_msg->body.kvp_set.data.value_size))
1578                                         hv_msg->error = HV_S_CONT;
1579                         break;
1580
1581                 case KVP_OP_DELETE:
1582                         if (kvp_key_delete(pool,
1583                                         hv_msg->body.kvp_delete.key,
1584                                         hv_msg->body.kvp_delete.key_size))
1585                                         hv_msg->error = HV_S_CONT;
1586                         break;
1587
1588                 default:
1589                         break;
1590                 }
1591
1592                 if (op != KVP_OP_ENUMERATE)
1593                         goto kvp_done;
1594
1595                 /*
1596                  * If the pool is KVP_POOL_AUTO, dynamically generate
1597                  * both the key and the value; if not read from the
1598                  * appropriate pool.
1599                  */
1600                 if (pool != KVP_POOL_AUTO) {
1601                         if (kvp_pool_enumerate(pool,
1602                                         hv_msg->body.kvp_enum_data.index,
1603                                         hv_msg->body.kvp_enum_data.data.key,
1604                                         HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1605                                         hv_msg->body.kvp_enum_data.data.value,
1606                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1607                                         hv_msg->error = HV_S_CONT;
1608                         goto kvp_done;
1609                 }
1610
1611                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1612                 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1613                 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1614
1615                 switch (hv_msg->body.kvp_enum_data.index) {
1616                 case FullyQualifiedDomainName:
1617                         kvp_get_domain_name(key_value,
1618                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1619                         strcpy(key_name, "FullyQualifiedDomainName");
1620                         break;
1621                 case IntegrationServicesVersion:
1622                         strcpy(key_name, "IntegrationServicesVersion");
1623                         strcpy(key_value, lic_version);
1624                         break;
1625                 case NetworkAddressIPv4:
1626                         kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1627                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1628                         strcpy(key_name, "NetworkAddressIPv4");
1629                         break;
1630                 case NetworkAddressIPv6:
1631                         kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1632                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1633                         strcpy(key_name, "NetworkAddressIPv6");
1634                         break;
1635                 case OSBuildNumber:
1636                         strcpy(key_value, os_build);
1637                         strcpy(key_name, "OSBuildNumber");
1638                         break;
1639                 case OSName:
1640                         strcpy(key_value, os_name);
1641                         strcpy(key_name, "OSName");
1642                         break;
1643                 case OSMajorVersion:
1644                         strcpy(key_value, os_major);
1645                         strcpy(key_name, "OSMajorVersion");
1646                         break;
1647                 case OSMinorVersion:
1648                         strcpy(key_value, os_minor);
1649                         strcpy(key_name, "OSMinorVersion");
1650                         break;
1651                 case OSVersion:
1652                         strcpy(key_value, os_build);
1653                         strcpy(key_name, "OSVersion");
1654                         break;
1655                 case ProcessorArchitecture:
1656                         strcpy(key_value, processor_arch);
1657                         strcpy(key_name, "ProcessorArchitecture");
1658                         break;
1659                 default:
1660                         hv_msg->error = HV_S_CONT;
1661                         break;
1662                 }
1663                 /*
1664                  * Send the value back to the kernel. The response is
1665                  * already in the receive buffer. Update the cn_msg header to
1666                  * reflect the key value that has been added to the message
1667                  */
1668 kvp_done:
1669
1670                 incoming_cn_msg->id.idx = CN_KVP_IDX;
1671                 incoming_cn_msg->id.val = CN_KVP_VAL;
1672                 incoming_cn_msg->ack = 0;
1673                 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1674
1675                 len = netlink_send(fd, incoming_cn_msg);
1676                 if (len < 0) {
1677                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
1678                         exit(EXIT_FAILURE);
1679                 }
1680         }
1681
1682 }