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