]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/hv/hv_kvp_daemon.c
Tools: hv: Gather DHCP information
[karo-tx-linux.git] / tools / hv / hv_kvp_daemon.c
1 /*
2  * An implementation of key value pair (KVP) functionality for Linux.
3  *
4  *
5  * Copyright (C) 2010, Novell, Inc.
6  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published
10  * by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15  * NON INFRINGEMENT.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/poll.h>
28 #include <sys/utsname.h>
29 #include <linux/types.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
39 #include <ifaddrs.h>
40 #include <netdb.h>
41 #include <syslog.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44
45 /*
46  * KVP protocol: The user mode component first registers with the
47  * the kernel component. Subsequently, the kernel component requests, data
48  * for the specified keys. In response to this message the user mode component
49  * fills in the value corresponding to the specified key. We overload the
50  * sequence field in the cn_msg header to define our KVP message types.
51  *
52  * We use this infrastructure for also supporting queries from user mode
53  * application for state that may be maintained in the KVP kernel component.
54  *
55  */
56
57
58 enum key_index {
59         FullyQualifiedDomainName = 0,
60         IntegrationServicesVersion, /*This key is serviced in the kernel*/
61         NetworkAddressIPv4,
62         NetworkAddressIPv6,
63         OSBuildNumber,
64         OSName,
65         OSMajorVersion,
66         OSMinorVersion,
67         OSVersion,
68         ProcessorArchitecture
69 };
70
71 static char kvp_send_buffer[4096];
72 static char kvp_recv_buffer[4096 * 2];
73 static struct sockaddr_nl addr;
74 static int in_hand_shake = 1;
75
76 static char *os_name = "";
77 static char *os_major = "";
78 static char *os_minor = "";
79 static char *processor_arch;
80 static char *os_build;
81 static char *lic_version = "Unknown version";
82 static struct utsname uts_buf;
83
84
85 #define MAX_FILE_NAME 100
86 #define ENTRIES_PER_BLOCK 50
87
88 struct kvp_record {
89         char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
90         char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
91 };
92
93 struct kvp_file_state {
94         int fd;
95         int num_blocks;
96         struct kvp_record *records;
97         int num_records;
98         char fname[MAX_FILE_NAME];
99 };
100
101 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
102
103 static void kvp_acquire_lock(int pool)
104 {
105         struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
106         fl.l_pid = getpid();
107
108         if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
109                 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
110                 exit(-1);
111         }
112 }
113
114 static void kvp_release_lock(int pool)
115 {
116         struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
117         fl.l_pid = getpid();
118
119         if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
120                 perror("fcntl");
121                 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
122                 exit(-1);
123         }
124 }
125
126 static void kvp_update_file(int pool)
127 {
128         FILE *filep;
129         size_t bytes_written;
130
131         /*
132          * We are going to write our in-memory registry out to
133          * disk; acquire the lock first.
134          */
135         kvp_acquire_lock(pool);
136
137         filep = fopen(kvp_file_info[pool].fname, "w");
138         if (!filep) {
139                 kvp_release_lock(pool);
140                 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
141                 exit(-1);
142         }
143
144         bytes_written = fwrite(kvp_file_info[pool].records,
145                                 sizeof(struct kvp_record),
146                                 kvp_file_info[pool].num_records, filep);
147
148         fflush(filep);
149         kvp_release_lock(pool);
150 }
151
152 static void kvp_update_mem_state(int pool)
153 {
154         FILE *filep;
155         size_t records_read = 0;
156         struct kvp_record *record = kvp_file_info[pool].records;
157         struct kvp_record *readp;
158         int num_blocks = kvp_file_info[pool].num_blocks;
159         int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
160
161         kvp_acquire_lock(pool);
162
163         filep = fopen(kvp_file_info[pool].fname, "r");
164         if (!filep) {
165                 kvp_release_lock(pool);
166                 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
167                 exit(-1);
168         }
169         while (!feof(filep)) {
170                 readp = &record[records_read];
171                 records_read += fread(readp, sizeof(struct kvp_record),
172                                         ENTRIES_PER_BLOCK * num_blocks,
173                                         filep);
174
175                 if (!feof(filep)) {
176                         /*
177                          * We have more data to read.
178                          */
179                         num_blocks++;
180                         record = realloc(record, alloc_unit * num_blocks);
181
182                         if (record == NULL) {
183                                 syslog(LOG_ERR, "malloc failed");
184                                 exit(-1);
185                         }
186                         continue;
187                 }
188                 break;
189         }
190
191         kvp_file_info[pool].num_blocks = num_blocks;
192         kvp_file_info[pool].records = record;
193         kvp_file_info[pool].num_records = records_read;
194
195         kvp_release_lock(pool);
196 }
197 static int kvp_file_init(void)
198 {
199         int  fd;
200         FILE *filep;
201         size_t records_read;
202         char *fname;
203         struct kvp_record *record;
204         struct kvp_record *readp;
205         int num_blocks;
206         int i;
207         int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
208
209         if (access("/var/opt/hyperv", F_OK)) {
210                 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
211                         syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
212                         exit(-1);
213                 }
214         }
215
216         for (i = 0; i < KVP_POOL_COUNT; i++) {
217                 fname = kvp_file_info[i].fname;
218                 records_read = 0;
219                 num_blocks = 1;
220                 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
221                 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
222
223                 if (fd == -1)
224                         return 1;
225
226
227                 filep = fopen(fname, "r");
228                 if (!filep)
229                         return 1;
230
231                 record = malloc(alloc_unit * num_blocks);
232                 if (record == NULL) {
233                         fclose(filep);
234                         return 1;
235                 }
236                 while (!feof(filep)) {
237                         readp = &record[records_read];
238                         records_read += fread(readp, sizeof(struct kvp_record),
239                                         ENTRIES_PER_BLOCK,
240                                         filep);
241
242                         if (!feof(filep)) {
243                                 /*
244                                  * We have more data to read.
245                                  */
246                                 num_blocks++;
247                                 record = realloc(record, alloc_unit *
248                                                 num_blocks);
249                                 if (record == NULL) {
250                                         fclose(filep);
251                                         return 1;
252                                 }
253                                 continue;
254                         }
255                         break;
256                 }
257                 kvp_file_info[i].fd = fd;
258                 kvp_file_info[i].num_blocks = num_blocks;
259                 kvp_file_info[i].records = record;
260                 kvp_file_info[i].num_records = records_read;
261                 fclose(filep);
262
263         }
264
265         return 0;
266 }
267
268 static int kvp_key_delete(int pool, __u8 *key, int key_size)
269 {
270         int i;
271         int j, k;
272         int num_records;
273         struct kvp_record *record;
274
275         /*
276          * First update the in-memory state.
277          */
278         kvp_update_mem_state(pool);
279
280         num_records = kvp_file_info[pool].num_records;
281         record = kvp_file_info[pool].records;
282
283         for (i = 0; i < num_records; i++) {
284                 if (memcmp(key, record[i].key, key_size))
285                         continue;
286                 /*
287                  * Found a match; just move the remaining
288                  * entries up.
289                  */
290                 if (i == num_records) {
291                         kvp_file_info[pool].num_records--;
292                         kvp_update_file(pool);
293                         return 0;
294                 }
295
296                 j = i;
297                 k = j + 1;
298                 for (; k < num_records; k++) {
299                         strcpy(record[j].key, record[k].key);
300                         strcpy(record[j].value, record[k].value);
301                         j++;
302                 }
303
304                 kvp_file_info[pool].num_records--;
305                 kvp_update_file(pool);
306                 return 0;
307         }
308         return 1;
309 }
310
311 static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
312                         int value_size)
313 {
314         int i;
315         int num_records;
316         struct kvp_record *record;
317         int num_blocks;
318
319         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
320                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
321                 return 1;
322
323         /*
324          * First update the in-memory state.
325          */
326         kvp_update_mem_state(pool);
327
328         num_records = kvp_file_info[pool].num_records;
329         record = kvp_file_info[pool].records;
330         num_blocks = kvp_file_info[pool].num_blocks;
331
332         for (i = 0; i < num_records; i++) {
333                 if (memcmp(key, record[i].key, key_size))
334                         continue;
335                 /*
336                  * Found a match; just update the value -
337                  * this is the modify case.
338                  */
339                 memcpy(record[i].value, value, value_size);
340                 kvp_update_file(pool);
341                 return 0;
342         }
343
344         /*
345          * Need to add a new entry;
346          */
347         if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
348                 /* Need to allocate a larger array for reg entries. */
349                 record = realloc(record, sizeof(struct kvp_record) *
350                          ENTRIES_PER_BLOCK * (num_blocks + 1));
351
352                 if (record == NULL)
353                         return 1;
354                 kvp_file_info[pool].num_blocks++;
355
356         }
357         memcpy(record[i].value, value, value_size);
358         memcpy(record[i].key, key, key_size);
359         kvp_file_info[pool].records = record;
360         kvp_file_info[pool].num_records++;
361         kvp_update_file(pool);
362         return 0;
363 }
364
365 static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
366                         int value_size)
367 {
368         int i;
369         int num_records;
370         struct kvp_record *record;
371
372         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
373                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
374                 return 1;
375
376         /*
377          * First update the in-memory state.
378          */
379         kvp_update_mem_state(pool);
380
381         num_records = kvp_file_info[pool].num_records;
382         record = kvp_file_info[pool].records;
383
384         for (i = 0; i < num_records; i++) {
385                 if (memcmp(key, record[i].key, key_size))
386                         continue;
387                 /*
388                  * Found a match; just copy the value out.
389                  */
390                 memcpy(value, record[i].value, value_size);
391                 return 0;
392         }
393
394         return 1;
395 }
396
397 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
398                                 __u8 *value, int value_size)
399 {
400         struct kvp_record *record;
401
402         /*
403          * First update our in-memory database.
404          */
405         kvp_update_mem_state(pool);
406         record = kvp_file_info[pool].records;
407
408         if (index >= kvp_file_info[pool].num_records) {
409                 return 1;
410         }
411
412         memcpy(key, record[index].key, key_size);
413         memcpy(value, record[index].value, value_size);
414         return 0;
415 }
416
417
418 void kvp_get_os_info(void)
419 {
420         FILE    *file;
421         char    *p, buf[512];
422
423         uname(&uts_buf);
424         os_build = uts_buf.release;
425         processor_arch = uts_buf.machine;
426
427         /*
428          * The current windows host (win7) expects the build
429          * string to be of the form: x.y.z
430          * Strip additional information we may have.
431          */
432         p = strchr(os_build, '-');
433         if (p)
434                 *p = '\0';
435
436         file = fopen("/etc/SuSE-release", "r");
437         if (file != NULL)
438                 goto kvp_osinfo_found;
439         file  = fopen("/etc/redhat-release", "r");
440         if (file != NULL)
441                 goto kvp_osinfo_found;
442         /*
443          * Add code for other supported platforms.
444          */
445
446         /*
447          * We don't have information about the os.
448          */
449         os_name = uts_buf.sysname;
450         return;
451
452 kvp_osinfo_found:
453         /* up to three lines */
454         p = fgets(buf, sizeof(buf), file);
455         if (p) {
456                 p = strchr(buf, '\n');
457                 if (p)
458                         *p = '\0';
459                 p = strdup(buf);
460                 if (!p)
461                         goto done;
462                 os_name = p;
463
464                 /* second line */
465                 p = fgets(buf, sizeof(buf), file);
466                 if (p) {
467                         p = strchr(buf, '\n');
468                         if (p)
469                                 *p = '\0';
470                         p = strdup(buf);
471                         if (!p)
472                                 goto done;
473                         os_major = p;
474
475                         /* third line */
476                         p = fgets(buf, sizeof(buf), file);
477                         if (p)  {
478                                 p = strchr(buf, '\n');
479                                 if (p)
480                                         *p = '\0';
481                                 p = strdup(buf);
482                                 if (p)
483                                         os_minor = p;
484                         }
485                 }
486         }
487
488 done:
489         fclose(file);
490         return;
491 }
492
493 static void kvp_process_ipconfig_file(char *cmd,
494                                         char *config_buf, int len,
495                                         int element_size, int offset)
496 {
497         char buf[256];
498         char *p;
499         char *x;
500         FILE *file;
501
502         /*
503          * First execute the command.
504          */
505         file = popen(cmd, "r");
506         if (file == NULL)
507                 return;
508
509         if (offset == 0)
510                 memset(config_buf, 0, len);
511         while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
512                 if ((len - strlen(config_buf)) < (element_size + 1))
513                         break;
514
515                 x = strchr(p, '\n');
516                 *x = '\0';
517                 strcat(config_buf, p);
518                 strcat(config_buf, ";");
519         }
520         pclose(file);
521 }
522
523 static void kvp_get_ipconfig_info(char *if_name,
524                                  struct hv_kvp_ipaddr_value *buffer)
525 {
526         char cmd[512];
527         char dhcp_info[128];
528         char *p;
529         FILE *file;
530
531         /*
532          * Get the address of default gateway (ipv4).
533          */
534         sprintf(cmd, "%s %s", "ip route show dev", if_name);
535         strcat(cmd, " | awk '/default/ {print $3 }'");
536
537         /*
538          * Execute the command to gather gateway info.
539          */
540         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
541                                 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
542
543         /*
544          * Get the address of default gateway (ipv6).
545          */
546         sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
547         strcat(cmd, " | awk '/default/ {print $3 }'");
548
549         /*
550          * Execute the command to gather gateway info (ipv6).
551          */
552         kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
553                                 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
554
555
556         /*
557          * Gather the DNS  state.
558          * Since there is no standard way to get this information
559          * across various distributions of interest; we just invoke
560          * an external script that needs to be ported across distros
561          * of interest.
562          *
563          * Following is the expected format of the information from the script:
564          *
565          * ipaddr1 (nameserver1)
566          * ipaddr2 (nameserver2)
567          * .
568          * .
569          */
570
571         sprintf(cmd, "%s",  "hv_get_dns_info");
572
573         /*
574          * Execute the command to gather DNS info.
575          */
576         kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
577                                 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
578
579         /*
580          * Gather the DHCP state.
581          * We will gather this state by invoking an external script.
582          * The parameter to the script is the interface name.
583          * Here is the expected output:
584          *
585          * Enabled: DHCP enabled.
586          */
587
588         sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
589
590         file = popen(cmd, "r");
591         if (file == NULL)
592                 return;
593
594         p = fgets(dhcp_info, sizeof(dhcp_info), file);
595         if (p == NULL) {
596                 pclose(file);
597                 return;
598         }
599
600         if (!strncmp(p, "Enabled", 7))
601                 buffer->dhcp_enabled = 1;
602         else
603                 buffer->dhcp_enabled = 0;
604
605         pclose(file);
606 }
607
608
609 static unsigned int hweight32(unsigned int *w)
610 {
611         unsigned int res = *w - ((*w >> 1) & 0x55555555);
612         res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
613         res = (res + (res >> 4)) & 0x0F0F0F0F;
614         res = res + (res >> 8);
615         return (res + (res >> 16)) & 0x000000FF;
616 }
617
618 static int kvp_process_ip_address(void *addrp,
619                                 int family, char *buffer,
620                                 int length,  int *offset)
621 {
622         struct sockaddr_in *addr;
623         struct sockaddr_in6 *addr6;
624         int addr_length;
625         char tmp[50];
626         const char *str;
627
628         if (family == AF_INET) {
629                 addr = (struct sockaddr_in *)addrp;
630                 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
631                 addr_length = INET_ADDRSTRLEN;
632         } else {
633                 addr6 = (struct sockaddr_in6 *)addrp;
634                 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
635                 addr_length = INET6_ADDRSTRLEN;
636         }
637
638         if ((length - *offset) < addr_length + 1)
639                 return 1;
640         if (str == NULL) {
641                 strcpy(buffer, "inet_ntop failed\n");
642                 return 1;
643         }
644         if (*offset == 0)
645                 strcpy(buffer, tmp);
646         else
647                 strcat(buffer, tmp);
648         strcat(buffer, ";");
649
650         *offset += strlen(str) + 1;
651         return 0;
652 }
653
654 static int
655 kvp_get_ip_address(int family, char *if_name, int op,
656                  void  *out_buffer, int length)
657 {
658         struct ifaddrs *ifap;
659         struct ifaddrs *curp;
660         int offset = 0;
661         int sn_offset = 0;
662         int error = 0;
663         char *buffer;
664         struct hv_kvp_ipaddr_value *ip_buffer;
665         char cidr_mask[5]; /* /xyz */
666         int weight;
667         int i;
668         unsigned int *w;
669         char *sn_str;
670         struct sockaddr_in6 *addr6;
671
672         if (op == KVP_OP_ENUMERATE) {
673                 buffer = out_buffer;
674         } else {
675                 ip_buffer = out_buffer;
676                 buffer = (char *)ip_buffer->ip_addr;
677                 ip_buffer->addr_family = 0;
678         }
679         /*
680          * On entry into this function, the buffer is capable of holding the
681          * maximum key value.
682          */
683
684         if (getifaddrs(&ifap)) {
685                 strcpy(buffer, "getifaddrs failed\n");
686                 return 1;
687         }
688
689         curp = ifap;
690         while (curp != NULL) {
691                 if (curp->ifa_addr == NULL) {
692                         curp = curp->ifa_next;
693                         continue;
694                 }
695
696                 if ((if_name != NULL) &&
697                         (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
698                         /*
699                          * We want info about a specific interface;
700                          * just continue.
701                          */
702                         curp = curp->ifa_next;
703                         continue;
704                 }
705
706                 /*
707                  * We only support two address families: AF_INET and AF_INET6.
708                  * If a family value of 0 is specified, we collect both
709                  * supported address families; if not we gather info on
710                  * the specified address family.
711                  */
712                 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
713                         curp = curp->ifa_next;
714                         continue;
715                 }
716                 if ((curp->ifa_addr->sa_family != AF_INET) &&
717                         (curp->ifa_addr->sa_family != AF_INET6)) {
718                         curp = curp->ifa_next;
719                         continue;
720                 }
721
722                 if (op == KVP_OP_GET_IP_INFO) {
723                         /*
724                          * Gather info other than the IP address.
725                          * IP address info will be gathered later.
726                          */
727                         if (curp->ifa_addr->sa_family == AF_INET) {
728                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
729                                 /*
730                                  * Get subnet info.
731                                  */
732                                 error = kvp_process_ip_address(
733                                                              curp->ifa_netmask,
734                                                              AF_INET,
735                                                              (char *)
736                                                              ip_buffer->sub_net,
737                                                              length,
738                                                              &sn_offset);
739                                 if (error)
740                                         goto gather_ipaddr;
741                         } else {
742                                 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
743
744                                 /*
745                                  * Get subnet info in CIDR format.
746                                  */
747                                 weight = 0;
748                                 sn_str = (char *)ip_buffer->sub_net;
749                                 addr6 = (struct sockaddr_in6 *)
750                                         curp->ifa_netmask;
751                                 w = addr6->sin6_addr.s6_addr32;
752
753                                 for (i = 0; i < 4; i++)
754                                         weight += hweight32(&w[i]);
755
756                                 sprintf(cidr_mask, "/%d", weight);
757                                 if ((length - sn_offset) <
758                                         (strlen(cidr_mask) + 1))
759                                         goto gather_ipaddr;
760
761                                 if (sn_offset == 0)
762                                         strcpy(sn_str, cidr_mask);
763                                 else
764                                         strcat(sn_str, cidr_mask);
765                                 strcat((char *)ip_buffer->sub_net, ";");
766                                 sn_offset += strlen(sn_str) + 1;
767                         }
768
769                         /*
770                          * Collect other ip related configuration info.
771                          */
772
773                         kvp_get_ipconfig_info(if_name, ip_buffer);
774                 }
775
776 gather_ipaddr:
777                 error = kvp_process_ip_address(curp->ifa_addr,
778                                                 curp->ifa_addr->sa_family,
779                                                 buffer,
780                                                 length, &offset);
781                 if (error)
782                         goto getaddr_done;
783
784                 curp = curp->ifa_next;
785         }
786
787 getaddr_done:
788         freeifaddrs(ifap);
789         return error;
790 }
791
792
793 static int
794 kvp_get_domain_name(char *buffer, int length)
795 {
796         struct addrinfo hints, *info ;
797         int error = 0;
798
799         gethostname(buffer, length);
800         memset(&hints, 0, sizeof(hints));
801         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
802         hints.ai_socktype = SOCK_STREAM;
803         hints.ai_flags = AI_CANONNAME;
804
805         error = getaddrinfo(buffer, NULL, &hints, &info);
806         if (error != 0) {
807                 strcpy(buffer, "getaddrinfo failed\n");
808                 return error;
809         }
810         strcpy(buffer, info->ai_canonname);
811         freeaddrinfo(info);
812         return error;
813 }
814
815 static int
816 netlink_send(int fd, struct cn_msg *msg)
817 {
818         struct nlmsghdr *nlh;
819         unsigned int size;
820         struct msghdr message;
821         char buffer[64];
822         struct iovec iov[2];
823
824         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
825
826         nlh = (struct nlmsghdr *)buffer;
827         nlh->nlmsg_seq = 0;
828         nlh->nlmsg_pid = getpid();
829         nlh->nlmsg_type = NLMSG_DONE;
830         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
831         nlh->nlmsg_flags = 0;
832
833         iov[0].iov_base = nlh;
834         iov[0].iov_len = sizeof(*nlh);
835
836         iov[1].iov_base = msg;
837         iov[1].iov_len = size;
838
839         memset(&message, 0, sizeof(message));
840         message.msg_name = &addr;
841         message.msg_namelen = sizeof(addr);
842         message.msg_iov = iov;
843         message.msg_iovlen = 2;
844
845         return sendmsg(fd, &message, 0);
846 }
847
848 int main(void)
849 {
850         int fd, len, sock_opt;
851         int error;
852         struct cn_msg *message;
853         struct pollfd pfd;
854         struct nlmsghdr *incoming_msg;
855         struct cn_msg   *incoming_cn_msg;
856         struct hv_kvp_msg *hv_msg;
857         char    *p;
858         char    *key_value;
859         char    *key_name;
860         int     op;
861         int     pool;
862
863         daemon(1, 0);
864         openlog("KVP", 0, LOG_USER);
865         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
866         /*
867          * Retrieve OS release information.
868          */
869         kvp_get_os_info();
870
871         if (kvp_file_init()) {
872                 syslog(LOG_ERR, "Failed to initialize the pools");
873                 exit(-1);
874         }
875
876         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
877         if (fd < 0) {
878                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
879                 exit(-1);
880         }
881         addr.nl_family = AF_NETLINK;
882         addr.nl_pad = 0;
883         addr.nl_pid = 0;
884         addr.nl_groups = CN_KVP_IDX;
885
886
887         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
888         if (error < 0) {
889                 syslog(LOG_ERR, "bind failed; error:%d", error);
890                 close(fd);
891                 exit(-1);
892         }
893         sock_opt = addr.nl_groups;
894         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
895         /*
896          * Register ourselves with the kernel.
897          */
898         message = (struct cn_msg *)kvp_send_buffer;
899         message->id.idx = CN_KVP_IDX;
900         message->id.val = CN_KVP_VAL;
901
902         hv_msg = (struct hv_kvp_msg *)message->data;
903         hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
904         message->ack = 0;
905         message->len = sizeof(struct hv_kvp_msg);
906
907         len = netlink_send(fd, message);
908         if (len < 0) {
909                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
910                 close(fd);
911                 exit(-1);
912         }
913
914         pfd.fd = fd;
915
916         while (1) {
917                 struct sockaddr *addr_p = (struct sockaddr *) &addr;
918                 socklen_t addr_l = sizeof(addr);
919                 pfd.events = POLLIN;
920                 pfd.revents = 0;
921                 poll(&pfd, 1, -1);
922
923                 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
924                                 addr_p, &addr_l);
925
926                 if (len < 0 || addr.nl_pid) {
927                         syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
928                                         addr.nl_pid, errno, strerror(errno));
929                         close(fd);
930                         return -1;
931                 }
932
933                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
934                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
935                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
936
937                 /*
938                  * We will use the KVP header information to pass back
939                  * the error from this daemon. So, first copy the state
940                  * and set the error code to success.
941                  */
942                 op = hv_msg->kvp_hdr.operation;
943                 pool = hv_msg->kvp_hdr.pool;
944                 hv_msg->error = HV_S_OK;
945
946                 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
947                         /*
948                          * Driver is registering with us; stash away the version
949                          * information.
950                          */
951                         in_hand_shake = 0;
952                         p = (char *)hv_msg->body.kvp_register.version;
953                         lic_version = malloc(strlen(p) + 1);
954                         if (lic_version) {
955                                 strcpy(lic_version, p);
956                                 syslog(LOG_INFO, "KVP LIC Version: %s",
957                                         lic_version);
958                         } else {
959                                 syslog(LOG_ERR, "malloc failed");
960                         }
961                         continue;
962                 }
963
964                 switch (op) {
965                 case KVP_OP_SET:
966                         if (kvp_key_add_or_modify(pool,
967                                         hv_msg->body.kvp_set.data.key,
968                                         hv_msg->body.kvp_set.data.key_size,
969                                         hv_msg->body.kvp_set.data.value,
970                                         hv_msg->body.kvp_set.data.value_size))
971                                         hv_msg->error = HV_S_CONT;
972                         break;
973
974                 case KVP_OP_GET:
975                         if (kvp_get_value(pool,
976                                         hv_msg->body.kvp_set.data.key,
977                                         hv_msg->body.kvp_set.data.key_size,
978                                         hv_msg->body.kvp_set.data.value,
979                                         hv_msg->body.kvp_set.data.value_size))
980                                         hv_msg->error = HV_S_CONT;
981                         break;
982
983                 case KVP_OP_DELETE:
984                         if (kvp_key_delete(pool,
985                                         hv_msg->body.kvp_delete.key,
986                                         hv_msg->body.kvp_delete.key_size))
987                                         hv_msg->error = HV_S_CONT;
988                         break;
989
990                 default:
991                         break;
992                 }
993
994                 if (op != KVP_OP_ENUMERATE)
995                         goto kvp_done;
996
997                 /*
998                  * If the pool is KVP_POOL_AUTO, dynamically generate
999                  * both the key and the value; if not read from the
1000                  * appropriate pool.
1001                  */
1002                 if (pool != KVP_POOL_AUTO) {
1003                         if (kvp_pool_enumerate(pool,
1004                                         hv_msg->body.kvp_enum_data.index,
1005                                         hv_msg->body.kvp_enum_data.data.key,
1006                                         HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1007                                         hv_msg->body.kvp_enum_data.data.value,
1008                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1009                                         hv_msg->error = HV_S_CONT;
1010                         goto kvp_done;
1011                 }
1012
1013                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1014                 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1015                 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1016
1017                 switch (hv_msg->body.kvp_enum_data.index) {
1018                 case FullyQualifiedDomainName:
1019                         kvp_get_domain_name(key_value,
1020                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1021                         strcpy(key_name, "FullyQualifiedDomainName");
1022                         break;
1023                 case IntegrationServicesVersion:
1024                         strcpy(key_name, "IntegrationServicesVersion");
1025                         strcpy(key_value, lic_version);
1026                         break;
1027                 case NetworkAddressIPv4:
1028                         kvp_get_ip_address(AF_INET, NULL, KVP_OP_ENUMERATE,
1029                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1030                         strcpy(key_name, "NetworkAddressIPv4");
1031                         break;
1032                 case NetworkAddressIPv6:
1033                         kvp_get_ip_address(AF_INET6, NULL, KVP_OP_ENUMERATE,
1034                                 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1035                         strcpy(key_name, "NetworkAddressIPv6");
1036                         break;
1037                 case OSBuildNumber:
1038                         strcpy(key_value, os_build);
1039                         strcpy(key_name, "OSBuildNumber");
1040                         break;
1041                 case OSName:
1042                         strcpy(key_value, os_name);
1043                         strcpy(key_name, "OSName");
1044                         break;
1045                 case OSMajorVersion:
1046                         strcpy(key_value, os_major);
1047                         strcpy(key_name, "OSMajorVersion");
1048                         break;
1049                 case OSMinorVersion:
1050                         strcpy(key_value, os_minor);
1051                         strcpy(key_name, "OSMinorVersion");
1052                         break;
1053                 case OSVersion:
1054                         strcpy(key_value, os_build);
1055                         strcpy(key_name, "OSVersion");
1056                         break;
1057                 case ProcessorArchitecture:
1058                         strcpy(key_value, processor_arch);
1059                         strcpy(key_name, "ProcessorArchitecture");
1060                         break;
1061                 default:
1062                         hv_msg->error = HV_S_CONT;
1063                         break;
1064                 }
1065                 /*
1066                  * Send the value back to the kernel. The response is
1067                  * already in the receive buffer. Update the cn_msg header to
1068                  * reflect the key value that has been added to the message
1069                  */
1070 kvp_done:
1071
1072                 incoming_cn_msg->id.idx = CN_KVP_IDX;
1073                 incoming_cn_msg->id.val = CN_KVP_VAL;
1074                 incoming_cn_msg->ack = 0;
1075                 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1076
1077                 len = netlink_send(fd, incoming_cn_msg);
1078                 if (len < 0) {
1079                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
1080                         exit(-1);
1081                 }
1082         }
1083
1084 }