blob: 146fd6147e84be5cde2a66009f331f1b6ee2b805 [file] [log] [blame]
Ky Srinivasancc04acf2010-12-16 18:56:54 -07001/*
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>
K. Y. Srinivasaneab6af72012-02-02 16:56:49 -080037#include <linux/hyperv.h>
Ky Srinivasancc04acf2010-12-16 18:56:54 -070038#include <linux/netlink.h>
Ky Srinivasancc04acf2010-12-16 18:56:54 -070039#include <ifaddrs.h>
40#include <netdb.h>
41#include <syslog.h>
K. Y. Srinivasandb425332012-03-16 08:02:26 -070042#include <sys/stat.h>
43#include <fcntl.h>
Ky Srinivasancc04acf2010-12-16 18:56:54 -070044
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 *
Ky Srinivasancc04acf2010-12-16 18:56:54 -070055 */
56
Ky Srinivasancc04acf2010-12-16 18:56:54 -070057
58enum 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
Ky Srinivasancc04acf2010-12-16 18:56:54 -070071static char kvp_send_buffer[4096];
72static char kvp_recv_buffer[4096];
73static struct sockaddr_nl addr;
74
Olaf Hering7989f7d2011-03-22 10:02:17 +010075static char *os_name = "";
76static char *os_major = "";
77static char *os_minor = "";
78static char *processor_arch;
79static char *os_build;
Ky Srinivasancc04acf2010-12-16 18:56:54 -070080static char *lic_version;
Olaf Hering7989f7d2011-03-22 10:02:17 +010081static struct utsname uts_buf;
Ky Srinivasancc04acf2010-12-16 18:56:54 -070082
K. Y. Srinivasandb425332012-03-16 08:02:26 -070083
84#define MAX_FILE_NAME 100
85#define ENTRIES_PER_BLOCK 50
86
87struct kvp_record {
88 __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89 __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
90};
91
92struct kvp_file_state {
93 int fd;
94 int num_blocks;
95 struct kvp_record *records;
96 int num_records;
97 __u8 fname[MAX_FILE_NAME];
98};
99
100static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
101
102static void kvp_acquire_lock(int pool)
103{
104 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
105 fl.l_pid = getpid();
106
107 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
109 exit(-1);
110 }
111}
112
113static void kvp_release_lock(int pool)
114{
115 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
116 fl.l_pid = getpid();
117
118 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
119 perror("fcntl");
120 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
121 exit(-1);
122 }
123}
124
125static void kvp_update_file(int pool)
126{
127 FILE *filep;
128 size_t bytes_written;
129
130 /*
131 * We are going to write our in-memory registry out to
132 * disk; acquire the lock first.
133 */
134 kvp_acquire_lock(pool);
135
136 filep = fopen(kvp_file_info[pool].fname, "w");
137 if (!filep) {
138 kvp_release_lock(pool);
139 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
140 exit(-1);
141 }
142
143 bytes_written = fwrite(kvp_file_info[pool].records,
144 sizeof(struct kvp_record),
145 kvp_file_info[pool].num_records, filep);
146
147 fflush(filep);
148 kvp_release_lock(pool);
149}
150
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700151static void kvp_update_mem_state(int pool)
152{
153 FILE *filep;
154 size_t records_read = 0;
155 struct kvp_record *record = kvp_file_info[pool].records;
156 struct kvp_record *readp;
157 int num_blocks = kvp_file_info[pool].num_blocks;
158 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
159
160 kvp_acquire_lock(pool);
161
162 filep = fopen(kvp_file_info[pool].fname, "r");
163 if (!filep) {
164 kvp_release_lock(pool);
165 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
166 exit(-1);
167 }
168 while (!feof(filep)) {
169 readp = &record[records_read];
170 records_read += fread(readp, sizeof(struct kvp_record),
171 ENTRIES_PER_BLOCK * num_blocks,
172 filep);
173
174 if (!feof(filep)) {
175 /*
176 * We have more data to read.
177 */
178 num_blocks++;
179 record = realloc(record, alloc_unit * num_blocks);
180
181 if (record == NULL) {
182 syslog(LOG_ERR, "malloc failed");
183 exit(-1);
184 }
185 continue;
186 }
187 break;
188 }
189
190 kvp_file_info[pool].num_blocks = num_blocks;
191 kvp_file_info[pool].records = record;
192 kvp_file_info[pool].num_records = records_read;
193
194 kvp_release_lock(pool);
195}
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700196static int kvp_file_init(void)
197{
198 int ret, fd;
199 FILE *filep;
200 size_t records_read;
201 __u8 *fname;
202 struct kvp_record *record;
203 struct kvp_record *readp;
204 int num_blocks;
205 int i;
206 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
207
208 if (access("/var/opt/hyperv", F_OK)) {
209 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
210 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
211 exit(-1);
212 }
213 }
214
215 for (i = 0; i < KVP_POOL_COUNT; i++) {
216 fname = kvp_file_info[i].fname;
217 records_read = 0;
218 num_blocks = 1;
219 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
220 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
221
222 if (fd == -1)
223 return 1;
224
225
226 filep = fopen(fname, "r");
227 if (!filep)
228 return 1;
229
230 record = malloc(alloc_unit * num_blocks);
231 if (record == NULL) {
232 fclose(filep);
233 return 1;
234 }
235 while (!feof(filep)) {
236 readp = &record[records_read];
237 records_read += fread(readp, sizeof(struct kvp_record),
238 ENTRIES_PER_BLOCK,
239 filep);
240
241 if (!feof(filep)) {
242 /*
243 * We have more data to read.
244 */
245 num_blocks++;
246 record = realloc(record, alloc_unit *
247 num_blocks);
248 if (record == NULL) {
249 fclose(filep);
250 return 1;
251 }
252 continue;
253 }
254 break;
255 }
256 kvp_file_info[i].fd = fd;
257 kvp_file_info[i].num_blocks = num_blocks;
258 kvp_file_info[i].records = record;
259 kvp_file_info[i].num_records = records_read;
260 fclose(filep);
261
262 }
263
264 return 0;
265}
266
267static int kvp_key_delete(int pool, __u8 *key, int key_size)
268{
269 int i;
270 int j, k;
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700271 int num_records;
272 struct kvp_record *record;
273
274 /*
275 * First update the in-memory state.
276 */
277 kvp_update_mem_state(pool);
278
279 num_records = kvp_file_info[pool].num_records;
280 record = kvp_file_info[pool].records;
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700281
282 for (i = 0; i < num_records; i++) {
283 if (memcmp(key, record[i].key, key_size))
284 continue;
285 /*
286 * Found a match; just move the remaining
287 * entries up.
288 */
289 if (i == num_records) {
290 kvp_file_info[pool].num_records--;
291 kvp_update_file(pool);
292 return 0;
293 }
294
295 j = i;
296 k = j + 1;
297 for (; k < num_records; k++) {
298 strcpy(record[j].key, record[k].key);
299 strcpy(record[j].value, record[k].value);
300 j++;
301 }
302
303 kvp_file_info[pool].num_records--;
304 kvp_update_file(pool);
305 return 0;
306 }
307 return 1;
308}
309
310static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
311 int value_size)
312{
313 int i;
314 int j, k;
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700315 int num_records;
316 struct kvp_record *record;
317 int num_blocks;
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700318
319 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
320 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
321 return 1;
322
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700323 /*
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
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700332 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
365static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
366 int value_size)
367{
368 int i;
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700369 int num_records;
370 struct kvp_record *record;
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700371
372 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
373 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
374 return 1;
375
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700376 /*
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
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700384 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
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700397static void 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 /*
410 * This is an invalid index; terminate enumeration;
411 * - a NULL value will do the trick.
412 */
413 strcpy(value, "");
414 return;
415 }
416
417 memcpy(key, record[index].key, key_size);
418 memcpy(value, record[index].value, value_size);
419}
420
421
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700422void kvp_get_os_info(void)
423{
424 FILE *file;
Olaf Hering7989f7d2011-03-22 10:02:17 +0100425 char *p, buf[512];
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700426
Olaf Hering7989f7d2011-03-22 10:02:17 +0100427 uname(&uts_buf);
428 os_build = uts_buf.release;
K. Y. Srinivasan064931d2011-07-19 11:44:20 -0700429 processor_arch = uts_buf.machine;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700430
K. Y. Srinivasane54bbc62011-07-22 10:14:31 -0700431 /*
432 * The current windows host (win7) expects the build
433 * string to be of the form: x.y.z
434 * Strip additional information we may have.
435 */
436 p = strchr(os_build, '-');
437 if (p)
438 *p = '\0';
439
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700440 file = fopen("/etc/SuSE-release", "r");
441 if (file != NULL)
442 goto kvp_osinfo_found;
443 file = fopen("/etc/redhat-release", "r");
444 if (file != NULL)
445 goto kvp_osinfo_found;
446 /*
447 * Add code for other supported platforms.
448 */
449
450 /*
451 * We don't have information about the os.
452 */
Olaf Hering7989f7d2011-03-22 10:02:17 +0100453 os_name = uts_buf.sysname;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700454 return;
455
456kvp_osinfo_found:
Olaf Hering7989f7d2011-03-22 10:02:17 +0100457 /* up to three lines */
458 p = fgets(buf, sizeof(buf), file);
459 if (p) {
460 p = strchr(buf, '\n');
461 if (p)
462 *p = '\0';
463 p = strdup(buf);
464 if (!p)
465 goto done;
466 os_name = p;
467
468 /* second line */
469 p = fgets(buf, sizeof(buf), file);
470 if (p) {
471 p = strchr(buf, '\n');
472 if (p)
473 *p = '\0';
474 p = strdup(buf);
475 if (!p)
476 goto done;
477 os_major = p;
478
479 /* third line */
480 p = fgets(buf, sizeof(buf), file);
481 if (p) {
482 p = strchr(buf, '\n');
483 if (p)
484 *p = '\0';
485 p = strdup(buf);
486 if (p)
487 os_minor = p;
488 }
489 }
490 }
491
492done:
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700493 fclose(file);
494 return;
495}
496
497static int
498kvp_get_ip_address(int family, char *buffer, int length)
499{
500 struct ifaddrs *ifap;
501 struct ifaddrs *curp;
502 int ipv4_len = strlen("255.255.255.255") + 1;
503 int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
504 int offset = 0;
505 const char *str;
506 char tmp[50];
507 int error = 0;
508
509 /*
510 * On entry into this function, the buffer is capable of holding the
511 * maximum key value (2048 bytes).
512 */
513
514 if (getifaddrs(&ifap)) {
515 strcpy(buffer, "getifaddrs failed\n");
516 return 1;
517 }
518
519 curp = ifap;
520 while (curp != NULL) {
521 if ((curp->ifa_addr != NULL) &&
522 (curp->ifa_addr->sa_family == family)) {
523 if (family == AF_INET) {
524 struct sockaddr_in *addr =
525 (struct sockaddr_in *) curp->ifa_addr;
526
527 str = inet_ntop(family, &addr->sin_addr,
528 tmp, 50);
529 if (str == NULL) {
530 strcpy(buffer, "inet_ntop failed\n");
531 error = 1;
532 goto getaddr_done;
533 }
534 if (offset == 0)
535 strcpy(buffer, tmp);
536 else
537 strcat(buffer, tmp);
538 strcat(buffer, ";");
539
540 offset += strlen(str) + 1;
541 if ((length - offset) < (ipv4_len + 1))
542 goto getaddr_done;
543
544 } else {
545
546 /*
547 * We only support AF_INET and AF_INET6
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300548 * and the list of addresses is separated by a ";".
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700549 */
550 struct sockaddr_in6 *addr =
551 (struct sockaddr_in6 *) curp->ifa_addr;
552
553 str = inet_ntop(family,
554 &addr->sin6_addr.s6_addr,
555 tmp, 50);
556 if (str == NULL) {
557 strcpy(buffer, "inet_ntop failed\n");
558 error = 1;
559 goto getaddr_done;
560 }
561 if (offset == 0)
562 strcpy(buffer, tmp);
563 else
564 strcat(buffer, tmp);
565 strcat(buffer, ";");
566 offset += strlen(str) + 1;
567 if ((length - offset) < (ipv6_len + 1))
568 goto getaddr_done;
569
570 }
571
572 }
573 curp = curp->ifa_next;
574 }
575
576getaddr_done:
577 freeifaddrs(ifap);
578 return error;
579}
580
581
582static int
583kvp_get_domain_name(char *buffer, int length)
584{
585 struct addrinfo hints, *info ;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700586 int error = 0;
587
K. Y. Srinivasan5be528c2011-07-26 11:03:10 -0700588 gethostname(buffer, length);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700589 memset(&hints, 0, sizeof(hints));
590 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
591 hints.ai_socktype = SOCK_STREAM;
592 hints.ai_flags = AI_CANONNAME;
593
K. Y. Srinivasan5be528c2011-07-26 11:03:10 -0700594 error = getaddrinfo(buffer, NULL, &hints, &info);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700595 if (error != 0) {
596 strcpy(buffer, "getaddrinfo failed\n");
K. Y. Srinivasan5be528c2011-07-26 11:03:10 -0700597 return error;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700598 }
599 strcpy(buffer, info->ai_canonname);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700600 freeaddrinfo(info);
601 return error;
602}
603
604static int
605netlink_send(int fd, struct cn_msg *msg)
606{
607 struct nlmsghdr *nlh;
608 unsigned int size;
609 struct msghdr message;
610 char buffer[64];
611 struct iovec iov[2];
612
613 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
614
615 nlh = (struct nlmsghdr *)buffer;
616 nlh->nlmsg_seq = 0;
617 nlh->nlmsg_pid = getpid();
618 nlh->nlmsg_type = NLMSG_DONE;
619 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
620 nlh->nlmsg_flags = 0;
621
622 iov[0].iov_base = nlh;
623 iov[0].iov_len = sizeof(*nlh);
624
625 iov[1].iov_base = msg;
626 iov[1].iov_len = size;
627
628 memset(&message, 0, sizeof(message));
629 message.msg_name = &addr;
630 message.msg_namelen = sizeof(addr);
631 message.msg_iov = iov;
632 message.msg_iovlen = 2;
633
634 return sendmsg(fd, &message, 0);
635}
636
Olaf Hering7989f7d2011-03-22 10:02:17 +0100637int main(void)
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700638{
639 int fd, len, sock_opt;
640 int error;
641 struct cn_msg *message;
642 struct pollfd pfd;
643 struct nlmsghdr *incoming_msg;
644 struct cn_msg *incoming_cn_msg;
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800645 struct hv_kvp_msg *hv_msg;
Olaf Hering7989f7d2011-03-22 10:02:17 +0100646 char *p;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700647 char *key_value;
648 char *key_name;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700649
650 daemon(1, 0);
651 openlog("KVP", 0, LOG_USER);
652 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
653 /*
654 * Retrieve OS release information.
655 */
656 kvp_get_os_info();
657
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700658 if (kvp_file_init()) {
659 syslog(LOG_ERR, "Failed to initialize the pools");
660 exit(-1);
661 }
662
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700663 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
664 if (fd < 0) {
665 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
666 exit(-1);
667 }
668 addr.nl_family = AF_NETLINK;
669 addr.nl_pad = 0;
670 addr.nl_pid = 0;
671 addr.nl_groups = CN_KVP_IDX;
672
673
674 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
675 if (error < 0) {
676 syslog(LOG_ERR, "bind failed; error:%d", error);
677 close(fd);
678 exit(-1);
679 }
680 sock_opt = addr.nl_groups;
681 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
682 /*
683 * Register ourselves with the kernel.
684 */
685 message = (struct cn_msg *)kvp_send_buffer;
686 message->id.idx = CN_KVP_IDX;
687 message->id.val = CN_KVP_VAL;
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800688
689 hv_msg = (struct hv_kvp_msg *)message->data;
690 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700691 message->ack = 0;
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800692 message->len = sizeof(struct hv_kvp_msg);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700693
694 len = netlink_send(fd, message);
695 if (len < 0) {
696 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
697 close(fd);
698 exit(-1);
699 }
700
701 pfd.fd = fd;
702
703 while (1) {
704 pfd.events = POLLIN;
705 pfd.revents = 0;
706 poll(&pfd, 1, -1);
707
708 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
709
710 if (len < 0) {
711 syslog(LOG_ERR, "recv failed; error:%d", len);
712 close(fd);
713 return -1;
714 }
715
716 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
717 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800718 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700719
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800720 switch (hv_msg->kvp_hdr.operation) {
721 case KVP_OP_REGISTER:
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700722 /*
723 * Driver is registering with us; stash away the version
724 * information.
725 */
K. Y. Srinivasane485ceac2012-03-10 15:32:08 -0800726 p = (char *)hv_msg->body.kvp_register.version;
Olaf Hering7989f7d2011-03-22 10:02:17 +0100727 lic_version = malloc(strlen(p) + 1);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700728 if (lic_version) {
Olaf Hering7989f7d2011-03-22 10:02:17 +0100729 strcpy(lic_version, p);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700730 syslog(LOG_INFO, "KVP LIC Version: %s",
731 lic_version);
732 } else {
733 syslog(LOG_ERR, "malloc failed");
734 }
735 continue;
736
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700737 /*
738 * The current protocol with the kernel component uses a
739 * NULL key name to pass an error condition.
740 * For the SET, GET and DELETE operations,
741 * use the existing protocol to pass back error.
742 */
743
K. Y. Srinivasanfa3d5b82012-03-16 08:02:25 -0700744 case KVP_OP_SET:
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700745 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
746 hv_msg->body.kvp_set.data.key,
747 hv_msg->body.kvp_set.data.key_size,
748 hv_msg->body.kvp_set.data.value,
749 hv_msg->body.kvp_set.data.value_size))
750 strcpy(hv_msg->body.kvp_set.data.key, "");
751 break;
752
K. Y. Srinivasanfa3d5b82012-03-16 08:02:25 -0700753 case KVP_OP_GET:
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700754 if (kvp_get_value(hv_msg->kvp_hdr.pool,
755 hv_msg->body.kvp_set.data.key,
756 hv_msg->body.kvp_set.data.key_size,
757 hv_msg->body.kvp_set.data.value,
758 hv_msg->body.kvp_set.data.value_size))
759 strcpy(hv_msg->body.kvp_set.data.key, "");
760 break;
761
K. Y. Srinivasanfa3d5b82012-03-16 08:02:25 -0700762 case KVP_OP_DELETE:
K. Y. Srinivasandb425332012-03-16 08:02:26 -0700763 if (kvp_key_delete(hv_msg->kvp_hdr.pool,
764 hv_msg->body.kvp_delete.key,
765 hv_msg->body.kvp_delete.key_size))
766 strcpy(hv_msg->body.kvp_delete.key, "");
767 break;
768
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700769 default:
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800770 break;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700771 }
772
K. Y. Srinivasanfa3d5b82012-03-16 08:02:25 -0700773 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
774 goto kvp_done;
775
K. Y. Srinivasanadc80ae2012-03-16 08:02:27 -0700776 /*
777 * If the pool is KVP_POOL_AUTO, dynamically generate
778 * both the key and the value; if not read from the
779 * appropriate pool.
780 */
781 if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
782 kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
783 hv_msg->body.kvp_enum_data.index,
784 hv_msg->body.kvp_enum_data.data.key,
785 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
786 hv_msg->body.kvp_enum_data.data.value,
787 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
788 goto kvp_done;
789 }
790
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800791 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
792 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
793 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700794
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800795 switch (hv_msg->body.kvp_enum_data.index) {
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700796 case FullyQualifiedDomainName:
797 kvp_get_domain_name(key_value,
798 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
799 strcpy(key_name, "FullyQualifiedDomainName");
800 break;
801 case IntegrationServicesVersion:
802 strcpy(key_name, "IntegrationServicesVersion");
803 strcpy(key_value, lic_version);
804 break;
805 case NetworkAddressIPv4:
806 kvp_get_ip_address(AF_INET, key_value,
807 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
808 strcpy(key_name, "NetworkAddressIPv4");
809 break;
810 case NetworkAddressIPv6:
811 kvp_get_ip_address(AF_INET6, key_value,
812 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
813 strcpy(key_name, "NetworkAddressIPv6");
814 break;
815 case OSBuildNumber:
816 strcpy(key_value, os_build);
817 strcpy(key_name, "OSBuildNumber");
818 break;
819 case OSName:
820 strcpy(key_value, os_name);
821 strcpy(key_name, "OSName");
822 break;
823 case OSMajorVersion:
824 strcpy(key_value, os_major);
825 strcpy(key_name, "OSMajorVersion");
826 break;
827 case OSMinorVersion:
828 strcpy(key_value, os_minor);
829 strcpy(key_name, "OSMinorVersion");
830 break;
831 case OSVersion:
832 strcpy(key_value, os_build);
833 strcpy(key_name, "OSVersion");
834 break;
835 case ProcessorArchitecture:
836 strcpy(key_value, processor_arch);
837 strcpy(key_name, "ProcessorArchitecture");
838 break;
839 default:
840 strcpy(key_value, "Unknown Key");
841 /*
842 * We use a null key name to terminate enumeration.
843 */
844 strcpy(key_name, "");
845 break;
846 }
847 /*
848 * Send the value back to the kernel. The response is
849 * already in the receive buffer. Update the cn_msg header to
850 * reflect the key value that has been added to the message
851 */
K. Y. Srinivasanfa3d5b82012-03-16 08:02:25 -0700852kvp_done:
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700853
854 incoming_cn_msg->id.idx = CN_KVP_IDX;
855 incoming_cn_msg->id.val = CN_KVP_VAL;
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700856 incoming_cn_msg->ack = 0;
K. Y. Srinivasan26403352012-02-02 16:56:50 -0800857 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
Ky Srinivasancc04acf2010-12-16 18:56:54 -0700858
859 len = netlink_send(fd, incoming_cn_msg);
860 if (len < 0) {
861 syslog(LOG_ERR, "net_link send failed; error:%d", len);
862 exit(-1);
863 }
864 }
865
866}