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