hv_kvp_daemon.c 11 KB

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