]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/hv/tools/hv_kvp_daemon.c
Merge branches 'dma-debug/next', 'amd-iommu/command-cleanups', 'amd-iommu/ats' and...
[karo-tx-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 = "";
106 static char *os_major = "";
107 static char *os_minor = "";
108 static char *processor_arch;
109 static char *os_build;
110 static char *lic_version;
111 static struct utsname uts_buf;
112
113 void kvp_get_os_info(void)
114 {
115         FILE    *file;
116         char    *p, buf[512];
117
118         uname(&uts_buf);
119         os_build = uts_buf.release;
120         processor_arch= uts_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         os_name = uts_buf.sysname;
136         return;
137
138 kvp_osinfo_found:
139         /* up to three lines */
140         p = fgets(buf, sizeof(buf), file);
141         if (p) {
142                 p = strchr(buf, '\n');
143                 if (p)
144                         *p = '\0';
145                 p = strdup(buf);
146                 if (!p)
147                         goto done;
148                 os_name = p;
149
150                 /* second line */
151                 p = fgets(buf, sizeof(buf), file);
152                 if (p) {
153                         p = strchr(buf, '\n');
154                         if (p)
155                                 *p = '\0';
156                         p = strdup(buf);
157                         if (!p)
158                                 goto done;
159                         os_major = p;
160
161                         /* third line */
162                         p = fgets(buf, sizeof(buf), file);
163                         if (p)  {
164                                 p = strchr(buf, '\n');
165                                 if (p)
166                                         *p = '\0';
167                                 p = strdup(buf);
168                                 if (p)
169                                         os_minor = p;
170                         }
171                 }
172         }
173
174 done:
175         fclose(file);
176         return;
177 }
178
179 static int
180 kvp_get_ip_address(int family, char *buffer, int length)
181 {
182         struct ifaddrs *ifap;
183         struct ifaddrs *curp;
184         int ipv4_len = strlen("255.255.255.255") + 1;
185         int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
186         int offset = 0;
187         const char *str;
188         char tmp[50];
189         int error = 0;
190
191         /*
192          * On entry into this function, the buffer is capable of holding the
193          * maximum key value (2048 bytes).
194          */
195
196         if (getifaddrs(&ifap)) {
197                 strcpy(buffer, "getifaddrs failed\n");
198                 return 1;
199         }
200
201         curp = ifap;
202         while (curp != NULL) {
203                 if ((curp->ifa_addr != NULL) &&
204                    (curp->ifa_addr->sa_family == family)) {
205                         if (family == AF_INET) {
206                                 struct sockaddr_in *addr =
207                                 (struct sockaddr_in *) curp->ifa_addr;
208
209                                 str = inet_ntop(family, &addr->sin_addr,
210                                                 tmp, 50);
211                                 if (str == NULL) {
212                                         strcpy(buffer, "inet_ntop failed\n");
213                                         error = 1;
214                                         goto getaddr_done;
215                                 }
216                                 if (offset == 0)
217                                         strcpy(buffer, tmp);
218                                 else
219                                         strcat(buffer, tmp);
220                                 strcat(buffer, ";");
221
222                                 offset += strlen(str) + 1;
223                                 if ((length - offset) < (ipv4_len + 1))
224                                         goto getaddr_done;
225
226                         } else {
227
228                         /*
229                          * We only support AF_INET and AF_INET6
230                          * and the list of addresses is separated by a ";".
231                          */
232                                 struct sockaddr_in6 *addr =
233                                 (struct sockaddr_in6 *) curp->ifa_addr;
234
235                                 str = inet_ntop(family,
236                                         &addr->sin6_addr.s6_addr,
237                                         tmp, 50);
238                                 if (str == NULL) {
239                                         strcpy(buffer, "inet_ntop failed\n");
240                                         error = 1;
241                                         goto getaddr_done;
242                                 }
243                                 if (offset == 0)
244                                         strcpy(buffer, tmp);
245                                 else
246                                         strcat(buffer, tmp);
247                                 strcat(buffer, ";");
248                                 offset += strlen(str) + 1;
249                                 if ((length - offset) < (ipv6_len + 1))
250                                         goto getaddr_done;
251
252                         }
253
254                 }
255                 curp = curp->ifa_next;
256         }
257
258 getaddr_done:
259         freeifaddrs(ifap);
260         return error;
261 }
262
263
264 static int
265 kvp_get_domain_name(char *buffer, int length)
266 {
267         struct addrinfo hints, *info ;
268         gethostname(buffer, length);
269         int error = 0;
270
271         memset(&hints, 0, sizeof(hints));
272         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
273         hints.ai_socktype = SOCK_STREAM;
274         hints.ai_flags = AI_CANONNAME;
275
276         error = getaddrinfo(buffer, "http", &hints, &info);
277         if (error != 0) {
278                 strcpy(buffer, "getaddrinfo failed\n");
279                 error = 1;
280                 goto get_domain_done;
281         }
282         strcpy(buffer, info->ai_canonname);
283 get_domain_done:
284         freeaddrinfo(info);
285         return error;
286 }
287
288 static int
289 netlink_send(int fd, struct cn_msg *msg)
290 {
291         struct nlmsghdr *nlh;
292         unsigned int size;
293         struct msghdr message;
294         char buffer[64];
295         struct iovec iov[2];
296
297         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
298
299         nlh = (struct nlmsghdr *)buffer;
300         nlh->nlmsg_seq = 0;
301         nlh->nlmsg_pid = getpid();
302         nlh->nlmsg_type = NLMSG_DONE;
303         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
304         nlh->nlmsg_flags = 0;
305
306         iov[0].iov_base = nlh;
307         iov[0].iov_len = sizeof(*nlh);
308
309         iov[1].iov_base = msg;
310         iov[1].iov_len = size;
311
312         memset(&message, 0, sizeof(message));
313         message.msg_name = &addr;
314         message.msg_namelen = sizeof(addr);
315         message.msg_iov = iov;
316         message.msg_iovlen = 2;
317
318         return sendmsg(fd, &message, 0);
319 }
320
321 int main(void)
322 {
323         int fd, len, sock_opt;
324         int error;
325         struct cn_msg *message;
326         struct pollfd pfd;
327         struct nlmsghdr *incoming_msg;
328         struct cn_msg   *incoming_cn_msg;
329         struct hv_ku_msg *hv_msg;
330         char    *p;
331         char    *key_value;
332         char    *key_name;
333
334         daemon(1, 0);
335         openlog("KVP", 0, LOG_USER);
336         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
337         /*
338          * Retrieve OS release information.
339          */
340         kvp_get_os_info();
341
342         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
343         if (fd < 0) {
344                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
345                 exit(-1);
346         }
347         addr.nl_family = AF_NETLINK;
348         addr.nl_pad = 0;
349         addr.nl_pid = 0;
350         addr.nl_groups = CN_KVP_IDX;
351
352
353         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
354         if (error < 0) {
355                 syslog(LOG_ERR, "bind failed; error:%d", error);
356                 close(fd);
357                 exit(-1);
358         }
359         sock_opt = addr.nl_groups;
360         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
361         /*
362          * Register ourselves with the kernel.
363          */
364         message = (struct cn_msg *)kvp_send_buffer;
365         message->id.idx = CN_KVP_IDX;
366         message->id.val = CN_KVP_VAL;
367         message->seq = KVP_REGISTER;
368         message->ack = 0;
369         message->len = 0;
370
371         len = netlink_send(fd, message);
372         if (len < 0) {
373                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
374                 close(fd);
375                 exit(-1);
376         }
377
378         pfd.fd = fd;
379
380         while (1) {
381                 pfd.events = POLLIN;
382                 pfd.revents = 0;
383                 poll(&pfd, 1, -1);
384
385                 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
386
387                 if (len < 0) {
388                         syslog(LOG_ERR, "recv failed; error:%d", len);
389                         close(fd);
390                         return -1;
391                 }
392
393                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
394                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
395
396                 switch (incoming_cn_msg->seq) {
397                 case KVP_REGISTER:
398                         /*
399                          * Driver is registering with us; stash away the version
400                          * information.
401                          */
402                         p = (char *)incoming_cn_msg->data;
403                         lic_version = malloc(strlen(p) + 1);
404                         if (lic_version) {
405                                 strcpy(lic_version, p);
406                                 syslog(LOG_INFO, "KVP LIC Version: %s",
407                                         lic_version);
408                         } else {
409                                 syslog(LOG_ERR, "malloc failed");
410                         }
411                         continue;
412
413                 case KVP_KERNEL_GET:
414                         break;
415                 default:
416                         continue;
417                 }
418
419                 hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
420                 key_name = (char *)hv_msg->kvp_key;
421                 key_value = (char *)hv_msg->kvp_value;
422
423                 switch (hv_msg->kvp_index) {
424                 case FullyQualifiedDomainName:
425                         kvp_get_domain_name(key_value,
426                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
427                         strcpy(key_name, "FullyQualifiedDomainName");
428                         break;
429                 case IntegrationServicesVersion:
430                         strcpy(key_name, "IntegrationServicesVersion");
431                         strcpy(key_value, lic_version);
432                         break;
433                 case NetworkAddressIPv4:
434                         kvp_get_ip_address(AF_INET, key_value,
435                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
436                         strcpy(key_name, "NetworkAddressIPv4");
437                         break;
438                 case NetworkAddressIPv6:
439                         kvp_get_ip_address(AF_INET6, key_value,
440                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
441                         strcpy(key_name, "NetworkAddressIPv6");
442                         break;
443                 case OSBuildNumber:
444                         strcpy(key_value, os_build);
445                         strcpy(key_name, "OSBuildNumber");
446                         break;
447                 case OSName:
448                         strcpy(key_value, os_name);
449                         strcpy(key_name, "OSName");
450                         break;
451                 case OSMajorVersion:
452                         strcpy(key_value, os_major);
453                         strcpy(key_name, "OSMajorVersion");
454                         break;
455                 case OSMinorVersion:
456                         strcpy(key_value, os_minor);
457                         strcpy(key_name, "OSMinorVersion");
458                         break;
459                 case OSVersion:
460                         strcpy(key_value, os_build);
461                         strcpy(key_name, "OSVersion");
462                         break;
463                 case ProcessorArchitecture:
464                         strcpy(key_value, processor_arch);
465                         strcpy(key_name, "ProcessorArchitecture");
466                         break;
467                 default:
468                         strcpy(key_value, "Unknown Key");
469                         /*
470                          * We use a null key name to terminate enumeration.
471                          */
472                         strcpy(key_name, "");
473                         break;
474                 }
475                 /*
476                  * Send the value back to the kernel. The response is
477                  * already in the receive buffer. Update the cn_msg header to
478                  * reflect the key value that has been added to the message
479                  */
480
481                 incoming_cn_msg->id.idx = CN_KVP_IDX;
482                 incoming_cn_msg->id.val = CN_KVP_VAL;
483                 incoming_cn_msg->seq = KVP_USER_SET;
484                 incoming_cn_msg->ack = 0;
485                 incoming_cn_msg->len = sizeof(struct hv_ku_msg);
486
487                 len = netlink_send(fd, incoming_cn_msg);
488                 if (len < 0) {
489                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
490                         exit(-1);
491                 }
492         }
493
494 }