f5a2dd6946117d0dfbcf7d13cb6eb4b484f3d2dc
[cascardo/linux.git] / drivers / staging / hv / tools / 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/netlink.h>
38 #include <sys/socket.h>
39 #include <ifaddrs.h>
40 #include <netdb.h>
41 #include <syslog.h>
42
43 /*
44  * KYS: TODO. Need to register these in the kernel.
45  *
46  * The following definitions are shared with the in-kernel component; do not
47  * change any of this without making the corresponding changes in
48  * the KVP kernel component.
49  */
50 #define CN_KVP_IDX              0x9     /* MSFT KVP functionality */
51 #define CN_KVP_VAL              0x1 /* This supports queries from the kernel */
52 #define CN_KVP_USER_VAL         0x2 /* This supports queries from the user  */
53
54 /*
55  * KVP protocol: The user mode component first registers with the
56  * the kernel component. Subsequently, the kernel component requests, data
57  * for the specified keys. In response to this message the user mode component
58  * fills in the value corresponding to the specified key. We overload the
59  * sequence field in the cn_msg header to define our KVP message types.
60  *
61  * We use this infrastructure for also supporting queries from user mode
62  * application for state that may be maintained in the KVP kernel component.
63  *
64  * XXXKYS: Have a shared header file between the user and kernel (TODO)
65  */
66
67 enum kvp_op {
68         KVP_REGISTER = 0, /* Register the user mode component*/
69         KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
70         KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
71         KVP_USER_GET, /*User is requesting the value for the specified key*/
72         KVP_USER_SET /*User is providing the value for the specified key*/
73 };
74
75 #define HV_KVP_EXCHANGE_MAX_KEY_SIZE    512
76 #define HV_KVP_EXCHANGE_MAX_VALUE_SIZE  2048
77
78 struct hv_ku_msg {
79         __u32   kvp_index;
80         __u8  kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
81         __u8  kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key  value */
82 };
83
84 enum key_index {
85         FullyQualifiedDomainName = 0,
86         IntegrationServicesVersion, /*This key is serviced in the kernel*/
87         NetworkAddressIPv4,
88         NetworkAddressIPv6,
89         OSBuildNumber,
90         OSName,
91         OSMajorVersion,
92         OSMinorVersion,
93         OSVersion,
94         ProcessorArchitecture
95 };
96
97 /*
98  * End of shared definitions.
99  */
100
101 static char kvp_send_buffer[4096];
102 static char kvp_recv_buffer[4096];
103 static struct sockaddr_nl addr;
104
105 static char os_name[100];
106 static char os_major[50];
107 static char os_minor[50];
108 static char processor_arch[50];
109 static char os_build[100];
110 static char *lic_version;
111
112 void kvp_get_os_info(void)
113 {
114         FILE    *file;
115         char    *eol;
116         struct utsname buf;
117
118         uname(&buf);
119         strcpy(os_build, buf.release);
120         strcpy(processor_arch, buf.machine);
121
122         file = fopen("/etc/SuSE-release", "r");
123         if (file != NULL)
124                 goto kvp_osinfo_found;
125         file  = fopen("/etc/redhat-release", "r");
126         if (file != NULL)
127                 goto kvp_osinfo_found;
128         /*
129          * Add code for other supported platforms.
130          */
131
132         /*
133          * We don't have information about the os.
134          */
135         strcpy(os_name, "Linux");
136         strcpy(os_major, "0");
137         strcpy(os_minor, "0");
138         return;
139
140 kvp_osinfo_found:
141         fgets(os_name, 99, file);
142         eol = index(os_name, '\n');
143         *eol = '\0';
144         fgets(os_major, 49, file);
145         eol = index(os_major, '\n');
146         *eol = '\0';
147         fgets(os_minor, 49, file);
148         eol = index(os_minor, '\n');
149         *eol = '\0';
150         fclose(file);
151         return;
152 }
153
154 static int
155 kvp_get_ip_address(int family, char *buffer, int length)
156 {
157         struct ifaddrs *ifap;
158         struct ifaddrs *curp;
159         int ipv4_len = strlen("255.255.255.255") + 1;
160         int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
161         int offset = 0;
162         const char *str;
163         char tmp[50];
164         int error = 0;
165
166         /*
167          * On entry into this function, the buffer is capable of holding the
168          * maximum key value (2048 bytes).
169          */
170
171         if (getifaddrs(&ifap)) {
172                 strcpy(buffer, "getifaddrs failed\n");
173                 return 1;
174         }
175
176         curp = ifap;
177         while (curp != NULL) {
178                 if ((curp->ifa_addr != NULL) &&
179                    (curp->ifa_addr->sa_family == family)) {
180                         if (family == AF_INET) {
181                                 struct sockaddr_in *addr =
182                                 (struct sockaddr_in *) curp->ifa_addr;
183
184                                 str = inet_ntop(family, &addr->sin_addr,
185                                                 tmp, 50);
186                                 if (str == NULL) {
187                                         strcpy(buffer, "inet_ntop failed\n");
188                                         error = 1;
189                                         goto getaddr_done;
190                                 }
191                                 if (offset == 0)
192                                         strcpy(buffer, tmp);
193                                 else
194                                         strcat(buffer, tmp);
195                                 strcat(buffer, ";");
196
197                                 offset += strlen(str) + 1;
198                                 if ((length - offset) < (ipv4_len + 1))
199                                         goto getaddr_done;
200
201                         } else {
202
203                         /*
204                          * We only support AF_INET and AF_INET6
205                          * and the list of addresses is seperated by a ";".
206                          */
207                                 struct sockaddr_in6 *addr =
208                                 (struct sockaddr_in6 *) curp->ifa_addr;
209
210                                 str = inet_ntop(family,
211                                         &addr->sin6_addr.s6_addr,
212                                         tmp, 50);
213                                 if (str == NULL) {
214                                         strcpy(buffer, "inet_ntop failed\n");
215                                         error = 1;
216                                         goto getaddr_done;
217                                 }
218                                 if (offset == 0)
219                                         strcpy(buffer, tmp);
220                                 else
221                                         strcat(buffer, tmp);
222                                 strcat(buffer, ";");
223                                 offset += strlen(str) + 1;
224                                 if ((length - offset) < (ipv6_len + 1))
225                                         goto getaddr_done;
226
227                         }
228
229                 }
230                 curp = curp->ifa_next;
231         }
232
233 getaddr_done:
234         freeifaddrs(ifap);
235         return error;
236 }
237
238
239 static int
240 kvp_get_domain_name(char *buffer, int length)
241 {
242         struct addrinfo hints, *info ;
243         gethostname(buffer, length);
244         int error = 0;
245
246         memset(&hints, 0, sizeof(hints));
247         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
248         hints.ai_socktype = SOCK_STREAM;
249         hints.ai_flags = AI_CANONNAME;
250
251         error = getaddrinfo(buffer, "http", &hints, &info);
252         if (error != 0) {
253                 strcpy(buffer, "getaddrinfo failed\n");
254                 error = 1;
255                 goto get_domain_done;
256         }
257         strcpy(buffer, info->ai_canonname);
258 get_domain_done:
259         freeaddrinfo(info);
260         return error;
261 }
262
263 static int
264 netlink_send(int fd, struct cn_msg *msg)
265 {
266         struct nlmsghdr *nlh;
267         unsigned int size;
268         struct msghdr message;
269         char buffer[64];
270         struct iovec iov[2];
271
272         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
273
274         nlh = (struct nlmsghdr *)buffer;
275         nlh->nlmsg_seq = 0;
276         nlh->nlmsg_pid = getpid();
277         nlh->nlmsg_type = NLMSG_DONE;
278         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
279         nlh->nlmsg_flags = 0;
280
281         iov[0].iov_base = nlh;
282         iov[0].iov_len = sizeof(*nlh);
283
284         iov[1].iov_base = msg;
285         iov[1].iov_len = size;
286
287         memset(&message, 0, sizeof(message));
288         message.msg_name = &addr;
289         message.msg_namelen = sizeof(addr);
290         message.msg_iov = iov;
291         message.msg_iovlen = 2;
292
293         return sendmsg(fd, &message, 0);
294 }
295
296 main(void)
297 {
298         int fd, len, sock_opt;
299         int error;
300         struct cn_msg *message;
301         struct pollfd pfd;
302         struct nlmsghdr *incoming_msg;
303         struct cn_msg   *incoming_cn_msg;
304         char    *key_value;
305         char    *key_name;
306         int      key_index;
307
308         daemon(1, 0);
309         openlog("KVP", 0, LOG_USER);
310         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
311         /*
312          * Retrieve OS release information.
313          */
314         kvp_get_os_info();
315
316         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
317         if (fd < 0) {
318                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
319                 exit(-1);
320         }
321         addr.nl_family = AF_NETLINK;
322         addr.nl_pad = 0;
323         addr.nl_pid = 0;
324         addr.nl_groups = CN_KVP_IDX;
325
326
327         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
328         if (error < 0) {
329                 syslog(LOG_ERR, "bind failed; error:%d", error);
330                 close(fd);
331                 exit(-1);
332         }
333         sock_opt = addr.nl_groups;
334         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
335         /*
336          * Register ourselves with the kernel.
337          */
338         message = (struct cn_msg *)kvp_send_buffer;
339         message->id.idx = CN_KVP_IDX;
340         message->id.val = CN_KVP_VAL;
341         message->seq = KVP_REGISTER;
342         message->ack = 0;
343         message->len = 0;
344
345         len = netlink_send(fd, message);
346         if (len < 0) {
347                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
348                 close(fd);
349                 exit(-1);
350         }
351
352         pfd.fd = fd;
353
354         while (1) {
355                 pfd.events = POLLIN;
356                 pfd.revents = 0;
357                 poll(&pfd, 1, -1);
358
359                 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
360
361                 if (len < 0) {
362                         syslog(LOG_ERR, "recv failed; error:%d", len);
363                         close(fd);
364                         return -1;
365                 }
366
367                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
368                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
369
370                 switch (incoming_cn_msg->seq) {
371                 case KVP_REGISTER:
372                         /*
373                          * Driver is registering with us; stash away the version
374                          * information.
375                          */
376                         lic_version = malloc(strlen(incoming_cn_msg->data) + 1);
377                         if (lic_version) {
378                                 strcpy(lic_version, incoming_cn_msg->data);
379                                 syslog(LOG_INFO, "KVP LIC Version: %s",
380                                         lic_version);
381                         } else {
382                                 syslog(LOG_ERR, "malloc failed");
383                         }
384                         continue;
385
386                 case KVP_KERNEL_GET:
387                         break;
388                 default:
389                         continue;
390                 }
391
392                 key_index =
393                 ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_index;
394                 key_name =
395                 ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_key;
396                 key_value =
397                 ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_value;
398
399                 switch (key_index) {
400                 case FullyQualifiedDomainName:
401                         kvp_get_domain_name(key_value,
402                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
403                         strcpy(key_name, "FullyQualifiedDomainName");
404                         break;
405                 case IntegrationServicesVersion:
406                         strcpy(key_name, "IntegrationServicesVersion");
407                         strcpy(key_value, lic_version);
408                         break;
409                 case NetworkAddressIPv4:
410                         kvp_get_ip_address(AF_INET, key_value,
411                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
412                         strcpy(key_name, "NetworkAddressIPv4");
413                         break;
414                 case NetworkAddressIPv6:
415                         kvp_get_ip_address(AF_INET6, key_value,
416                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
417                         strcpy(key_name, "NetworkAddressIPv6");
418                         break;
419                 case OSBuildNumber:
420                         strcpy(key_value, os_build);
421                         strcpy(key_name, "OSBuildNumber");
422                         break;
423                 case OSName:
424                         strcpy(key_value, os_name);
425                         strcpy(key_name, "OSName");
426                         break;
427                 case OSMajorVersion:
428                         strcpy(key_value, os_major);
429                         strcpy(key_name, "OSMajorVersion");
430                         break;
431                 case OSMinorVersion:
432                         strcpy(key_value, os_minor);
433                         strcpy(key_name, "OSMinorVersion");
434                         break;
435                 case OSVersion:
436                         strcpy(key_value, os_build);
437                         strcpy(key_name, "OSVersion");
438                         break;
439                 case ProcessorArchitecture:
440                         strcpy(key_value, processor_arch);
441                         strcpy(key_name, "ProcessorArchitecture");
442                         break;
443                 default:
444                         strcpy(key_value, "Unknown Key");
445                         /*
446                          * We use a null key name to terminate enumeration.
447                          */
448                         strcpy(key_name, "");
449                         break;
450                 }
451                 /*
452                  * Send the value back to the kernel. The response is
453                  * already in the receive buffer. Update the cn_msg header to
454                  * reflect the key value that has been added to the message
455                  */
456
457                 incoming_cn_msg->id.idx = CN_KVP_IDX;
458                 incoming_cn_msg->id.val = CN_KVP_VAL;
459                 incoming_cn_msg->seq = KVP_USER_SET;
460                 incoming_cn_msg->ack = 0;
461                 incoming_cn_msg->len = sizeof(struct hv_ku_msg);
462
463                 len = netlink_send(fd, incoming_cn_msg);
464                 if (len < 0) {
465                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
466                         exit(-1);
467                 }
468         }
469
470 }