hv_kvp_daemon.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  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. #include <sys/stat.h>
  41. #include <fcntl.h>
  42. /*
  43. * KVP protocol: The user mode component first registers with the
  44. * the kernel component. Subsequently, the kernel component requests, data
  45. * for the specified keys. In response to this message the user mode component
  46. * fills in the value corresponding to the specified key. We overload the
  47. * sequence field in the cn_msg header to define our KVP message types.
  48. *
  49. * We use this infrastructure for also supporting queries from user mode
  50. * application for state that may be maintained in the KVP kernel component.
  51. *
  52. */
  53. enum key_index {
  54. FullyQualifiedDomainName = 0,
  55. IntegrationServicesVersion, /*This key is serviced in the kernel*/
  56. NetworkAddressIPv4,
  57. NetworkAddressIPv6,
  58. OSBuildNumber,
  59. OSName,
  60. OSMajorVersion,
  61. OSMinorVersion,
  62. OSVersion,
  63. ProcessorArchitecture
  64. };
  65. static char kvp_send_buffer[4096];
  66. static char kvp_recv_buffer[4096];
  67. static struct sockaddr_nl addr;
  68. static char *os_name = "";
  69. static char *os_major = "";
  70. static char *os_minor = "";
  71. static char *processor_arch;
  72. static char *os_build;
  73. static char *lic_version;
  74. static struct utsname uts_buf;
  75. #define MAX_FILE_NAME 100
  76. #define ENTRIES_PER_BLOCK 50
  77. struct kvp_record {
  78. __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
  79. __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
  80. };
  81. struct kvp_file_state {
  82. int fd;
  83. int num_blocks;
  84. struct kvp_record *records;
  85. int num_records;
  86. __u8 fname[MAX_FILE_NAME];
  87. };
  88. static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
  89. static void kvp_acquire_lock(int pool)
  90. {
  91. struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
  92. fl.l_pid = getpid();
  93. if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
  94. syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
  95. exit(EXIT_FAILURE);
  96. }
  97. }
  98. static void kvp_release_lock(int pool)
  99. {
  100. struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
  101. fl.l_pid = getpid();
  102. if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
  103. perror("fcntl");
  104. syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
  105. exit(EXIT_FAILURE);
  106. }
  107. }
  108. static void kvp_update_file(int pool)
  109. {
  110. FILE *filep;
  111. size_t bytes_written;
  112. /*
  113. * We are going to write our in-memory registry out to
  114. * disk; acquire the lock first.
  115. */
  116. kvp_acquire_lock(pool);
  117. filep = fopen(kvp_file_info[pool].fname, "w");
  118. if (!filep) {
  119. kvp_release_lock(pool);
  120. syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
  121. exit(EXIT_FAILURE);
  122. }
  123. bytes_written = fwrite(kvp_file_info[pool].records,
  124. sizeof(struct kvp_record),
  125. kvp_file_info[pool].num_records, filep);
  126. if (ferror(filep) || fclose(filep)) {
  127. kvp_release_lock(pool);
  128. syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
  129. exit(EXIT_FAILURE);
  130. }
  131. kvp_release_lock(pool);
  132. }
  133. static void kvp_update_mem_state(int pool)
  134. {
  135. FILE *filep;
  136. size_t records_read = 0;
  137. struct kvp_record *record = kvp_file_info[pool].records;
  138. struct kvp_record *readp;
  139. int num_blocks = kvp_file_info[pool].num_blocks;
  140. int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
  141. kvp_acquire_lock(pool);
  142. filep = fopen(kvp_file_info[pool].fname, "r");
  143. if (!filep) {
  144. kvp_release_lock(pool);
  145. syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
  146. exit(EXIT_FAILURE);
  147. }
  148. for (;;) {
  149. readp = &record[records_read];
  150. records_read += fread(readp, sizeof(struct kvp_record),
  151. ENTRIES_PER_BLOCK * num_blocks,
  152. filep);
  153. if (ferror(filep)) {
  154. syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
  155. exit(EXIT_FAILURE);
  156. }
  157. if (!feof(filep)) {
  158. /*
  159. * We have more data to read.
  160. */
  161. num_blocks++;
  162. record = realloc(record, alloc_unit * num_blocks);
  163. if (record == NULL) {
  164. syslog(LOG_ERR, "malloc failed");
  165. exit(EXIT_FAILURE);
  166. }
  167. continue;
  168. }
  169. break;
  170. }
  171. kvp_file_info[pool].num_blocks = num_blocks;
  172. kvp_file_info[pool].records = record;
  173. kvp_file_info[pool].num_records = records_read;
  174. fclose(filep);
  175. kvp_release_lock(pool);
  176. }
  177. static int kvp_file_init(void)
  178. {
  179. int ret, fd;
  180. FILE *filep;
  181. size_t records_read;
  182. __u8 *fname;
  183. struct kvp_record *record;
  184. struct kvp_record *readp;
  185. int num_blocks;
  186. int i;
  187. int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
  188. if (access("/var/opt/hyperv", F_OK)) {
  189. if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
  190. syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
  191. exit(EXIT_FAILURE);
  192. }
  193. }
  194. for (i = 0; i < KVP_POOL_COUNT; i++) {
  195. fname = kvp_file_info[i].fname;
  196. records_read = 0;
  197. num_blocks = 1;
  198. sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
  199. fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
  200. if (fd == -1)
  201. return 1;
  202. filep = fopen(fname, "r");
  203. if (!filep)
  204. return 1;
  205. record = malloc(alloc_unit * num_blocks);
  206. if (record == NULL) {
  207. fclose(filep);
  208. return 1;
  209. }
  210. for (;;) {
  211. readp = &record[records_read];
  212. records_read += fread(readp, sizeof(struct kvp_record),
  213. ENTRIES_PER_BLOCK,
  214. filep);
  215. if (ferror(filep)) {
  216. syslog(LOG_ERR, "Failed to read file, pool: %d",
  217. i);
  218. exit(EXIT_FAILURE);
  219. }
  220. if (!feof(filep)) {
  221. /*
  222. * We have more data to read.
  223. */
  224. num_blocks++;
  225. record = realloc(record, alloc_unit *
  226. num_blocks);
  227. if (record == NULL) {
  228. fclose(filep);
  229. return 1;
  230. }
  231. continue;
  232. }
  233. break;
  234. }
  235. kvp_file_info[i].fd = fd;
  236. kvp_file_info[i].num_blocks = num_blocks;
  237. kvp_file_info[i].records = record;
  238. kvp_file_info[i].num_records = records_read;
  239. fclose(filep);
  240. }
  241. return 0;
  242. }
  243. static int kvp_key_delete(int pool, __u8 *key, int key_size)
  244. {
  245. int i;
  246. int j, k;
  247. int num_records;
  248. struct kvp_record *record;
  249. /*
  250. * First update the in-memory state.
  251. */
  252. kvp_update_mem_state(pool);
  253. num_records = kvp_file_info[pool].num_records;
  254. record = kvp_file_info[pool].records;
  255. for (i = 0; i < num_records; i++) {
  256. if (memcmp(key, record[i].key, key_size))
  257. continue;
  258. /*
  259. * Found a match; just move the remaining
  260. * entries up.
  261. */
  262. if (i == num_records) {
  263. kvp_file_info[pool].num_records--;
  264. kvp_update_file(pool);
  265. return 0;
  266. }
  267. j = i;
  268. k = j + 1;
  269. for (; k < num_records; k++) {
  270. strcpy(record[j].key, record[k].key);
  271. strcpy(record[j].value, record[k].value);
  272. j++;
  273. }
  274. kvp_file_info[pool].num_records--;
  275. kvp_update_file(pool);
  276. return 0;
  277. }
  278. return 1;
  279. }
  280. static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
  281. int value_size)
  282. {
  283. int i;
  284. int j, k;
  285. int num_records;
  286. struct kvp_record *record;
  287. int num_blocks;
  288. if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
  289. (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
  290. return 1;
  291. /*
  292. * First update the in-memory state.
  293. */
  294. kvp_update_mem_state(pool);
  295. num_records = kvp_file_info[pool].num_records;
  296. record = kvp_file_info[pool].records;
  297. num_blocks = kvp_file_info[pool].num_blocks;
  298. for (i = 0; i < num_records; i++) {
  299. if (memcmp(key, record[i].key, key_size))
  300. continue;
  301. /*
  302. * Found a match; just update the value -
  303. * this is the modify case.
  304. */
  305. memcpy(record[i].value, value, value_size);
  306. kvp_update_file(pool);
  307. return 0;
  308. }
  309. /*
  310. * Need to add a new entry;
  311. */
  312. if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
  313. /* Need to allocate a larger array for reg entries. */
  314. record = realloc(record, sizeof(struct kvp_record) *
  315. ENTRIES_PER_BLOCK * (num_blocks + 1));
  316. if (record == NULL)
  317. return 1;
  318. kvp_file_info[pool].num_blocks++;
  319. }
  320. memcpy(record[i].value, value, value_size);
  321. memcpy(record[i].key, key, key_size);
  322. kvp_file_info[pool].records = record;
  323. kvp_file_info[pool].num_records++;
  324. kvp_update_file(pool);
  325. return 0;
  326. }
  327. static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
  328. int value_size)
  329. {
  330. int i;
  331. int num_records;
  332. struct kvp_record *record;
  333. if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
  334. (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
  335. return 1;
  336. /*
  337. * First update the in-memory state.
  338. */
  339. kvp_update_mem_state(pool);
  340. num_records = kvp_file_info[pool].num_records;
  341. record = kvp_file_info[pool].records;
  342. for (i = 0; i < num_records; i++) {
  343. if (memcmp(key, record[i].key, key_size))
  344. continue;
  345. /*
  346. * Found a match; just copy the value out.
  347. */
  348. memcpy(value, record[i].value, value_size);
  349. return 0;
  350. }
  351. return 1;
  352. }
  353. static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
  354. __u8 *value, int value_size)
  355. {
  356. struct kvp_record *record;
  357. /*
  358. * First update our in-memory database.
  359. */
  360. kvp_update_mem_state(pool);
  361. record = kvp_file_info[pool].records;
  362. if (index >= kvp_file_info[pool].num_records) {
  363. /*
  364. * This is an invalid index; terminate enumeration;
  365. * - a NULL value will do the trick.
  366. */
  367. strcpy(value, "");
  368. return;
  369. }
  370. memcpy(key, record[index].key, key_size);
  371. memcpy(value, record[index].value, value_size);
  372. }
  373. void kvp_get_os_info(void)
  374. {
  375. FILE *file;
  376. char *p, buf[512];
  377. uname(&uts_buf);
  378. os_build = uts_buf.release;
  379. processor_arch = uts_buf.machine;
  380. /*
  381. * The current windows host (win7) expects the build
  382. * string to be of the form: x.y.z
  383. * Strip additional information we may have.
  384. */
  385. p = strchr(os_build, '-');
  386. if (p)
  387. *p = '\0';
  388. file = fopen("/etc/SuSE-release", "r");
  389. if (file != NULL)
  390. goto kvp_osinfo_found;
  391. file = fopen("/etc/redhat-release", "r");
  392. if (file != NULL)
  393. goto kvp_osinfo_found;
  394. /*
  395. * Add code for other supported platforms.
  396. */
  397. /*
  398. * We don't have information about the os.
  399. */
  400. os_name = uts_buf.sysname;
  401. return;
  402. kvp_osinfo_found:
  403. /* up to three lines */
  404. p = fgets(buf, sizeof(buf), file);
  405. if (p) {
  406. p = strchr(buf, '\n');
  407. if (p)
  408. *p = '\0';
  409. p = strdup(buf);
  410. if (!p)
  411. goto done;
  412. os_name = p;
  413. /* second line */
  414. p = fgets(buf, sizeof(buf), file);
  415. if (p) {
  416. p = strchr(buf, '\n');
  417. if (p)
  418. *p = '\0';
  419. p = strdup(buf);
  420. if (!p)
  421. goto done;
  422. os_major = p;
  423. /* third line */
  424. p = fgets(buf, sizeof(buf), file);
  425. if (p) {
  426. p = strchr(buf, '\n');
  427. if (p)
  428. *p = '\0';
  429. p = strdup(buf);
  430. if (p)
  431. os_minor = p;
  432. }
  433. }
  434. }
  435. done:
  436. fclose(file);
  437. return;
  438. }
  439. static int
  440. kvp_get_ip_address(int family, char *buffer, int length)
  441. {
  442. struct ifaddrs *ifap;
  443. struct ifaddrs *curp;
  444. int ipv4_len = strlen("255.255.255.255") + 1;
  445. int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
  446. int offset = 0;
  447. const char *str;
  448. char tmp[50];
  449. int error = 0;
  450. /*
  451. * On entry into this function, the buffer is capable of holding the
  452. * maximum key value (2048 bytes).
  453. */
  454. if (getifaddrs(&ifap)) {
  455. strcpy(buffer, "getifaddrs failed\n");
  456. return 1;
  457. }
  458. curp = ifap;
  459. while (curp != NULL) {
  460. if ((curp->ifa_addr != NULL) &&
  461. (curp->ifa_addr->sa_family == family)) {
  462. if (family == AF_INET) {
  463. struct sockaddr_in *addr =
  464. (struct sockaddr_in *) curp->ifa_addr;
  465. str = inet_ntop(family, &addr->sin_addr,
  466. tmp, 50);
  467. if (str == NULL) {
  468. strcpy(buffer, "inet_ntop failed\n");
  469. error = 1;
  470. goto getaddr_done;
  471. }
  472. if (offset == 0)
  473. strcpy(buffer, tmp);
  474. else
  475. strcat(buffer, tmp);
  476. strcat(buffer, ";");
  477. offset += strlen(str) + 1;
  478. if ((length - offset) < (ipv4_len + 1))
  479. goto getaddr_done;
  480. } else {
  481. /*
  482. * We only support AF_INET and AF_INET6
  483. * and the list of addresses is separated by a ";".
  484. */
  485. struct sockaddr_in6 *addr =
  486. (struct sockaddr_in6 *) curp->ifa_addr;
  487. str = inet_ntop(family,
  488. &addr->sin6_addr.s6_addr,
  489. tmp, 50);
  490. if (str == NULL) {
  491. strcpy(buffer, "inet_ntop failed\n");
  492. error = 1;
  493. goto getaddr_done;
  494. }
  495. if (offset == 0)
  496. strcpy(buffer, tmp);
  497. else
  498. strcat(buffer, tmp);
  499. strcat(buffer, ";");
  500. offset += strlen(str) + 1;
  501. if ((length - offset) < (ipv6_len + 1))
  502. goto getaddr_done;
  503. }
  504. }
  505. curp = curp->ifa_next;
  506. }
  507. getaddr_done:
  508. freeifaddrs(ifap);
  509. return error;
  510. }
  511. static int
  512. kvp_get_domain_name(char *buffer, int length)
  513. {
  514. struct addrinfo hints, *info ;
  515. int error = 0;
  516. gethostname(buffer, length);
  517. memset(&hints, 0, sizeof(hints));
  518. hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
  519. hints.ai_socktype = SOCK_STREAM;
  520. hints.ai_flags = AI_CANONNAME;
  521. error = getaddrinfo(buffer, NULL, &hints, &info);
  522. if (error != 0) {
  523. strcpy(buffer, "getaddrinfo failed\n");
  524. return error;
  525. }
  526. strcpy(buffer, info->ai_canonname);
  527. freeaddrinfo(info);
  528. return error;
  529. }
  530. static int
  531. netlink_send(int fd, struct cn_msg *msg)
  532. {
  533. struct nlmsghdr *nlh;
  534. unsigned int size;
  535. struct msghdr message;
  536. char buffer[64];
  537. struct iovec iov[2];
  538. size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
  539. nlh = (struct nlmsghdr *)buffer;
  540. nlh->nlmsg_seq = 0;
  541. nlh->nlmsg_pid = getpid();
  542. nlh->nlmsg_type = NLMSG_DONE;
  543. nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
  544. nlh->nlmsg_flags = 0;
  545. iov[0].iov_base = nlh;
  546. iov[0].iov_len = sizeof(*nlh);
  547. iov[1].iov_base = msg;
  548. iov[1].iov_len = size;
  549. memset(&message, 0, sizeof(message));
  550. message.msg_name = &addr;
  551. message.msg_namelen = sizeof(addr);
  552. message.msg_iov = iov;
  553. message.msg_iovlen = 2;
  554. return sendmsg(fd, &message, 0);
  555. }
  556. int main(void)
  557. {
  558. int fd, len, sock_opt;
  559. int error;
  560. struct cn_msg *message;
  561. struct pollfd pfd;
  562. struct nlmsghdr *incoming_msg;
  563. struct cn_msg *incoming_cn_msg;
  564. struct hv_kvp_msg *hv_msg;
  565. char *p;
  566. char *key_value;
  567. char *key_name;
  568. daemon(1, 0);
  569. openlog("KVP", 0, LOG_USER);
  570. syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
  571. /*
  572. * Retrieve OS release information.
  573. */
  574. kvp_get_os_info();
  575. if (kvp_file_init()) {
  576. syslog(LOG_ERR, "Failed to initialize the pools");
  577. exit(EXIT_FAILURE);
  578. }
  579. fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
  580. if (fd < 0) {
  581. syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
  582. exit(EXIT_FAILURE);
  583. }
  584. addr.nl_family = AF_NETLINK;
  585. addr.nl_pad = 0;
  586. addr.nl_pid = 0;
  587. addr.nl_groups = CN_KVP_IDX;
  588. error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
  589. if (error < 0) {
  590. syslog(LOG_ERR, "bind failed; error:%d", error);
  591. close(fd);
  592. exit(EXIT_FAILURE);
  593. }
  594. sock_opt = addr.nl_groups;
  595. setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
  596. /*
  597. * Register ourselves with the kernel.
  598. */
  599. message = (struct cn_msg *)kvp_send_buffer;
  600. message->id.idx = CN_KVP_IDX;
  601. message->id.val = CN_KVP_VAL;
  602. hv_msg = (struct hv_kvp_msg *)message->data;
  603. hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
  604. message->ack = 0;
  605. message->len = sizeof(struct hv_kvp_msg);
  606. len = netlink_send(fd, message);
  607. if (len < 0) {
  608. syslog(LOG_ERR, "netlink_send failed; error:%d", len);
  609. close(fd);
  610. exit(EXIT_FAILURE);
  611. }
  612. pfd.fd = fd;
  613. while (1) {
  614. struct sockaddr *addr_p = (struct sockaddr *) &addr;
  615. socklen_t addr_l = sizeof(addr);
  616. pfd.events = POLLIN;
  617. pfd.revents = 0;
  618. poll(&pfd, 1, -1);
  619. len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
  620. addr_p, &addr_l);
  621. if (len < 0) {
  622. syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
  623. addr.nl_pid, errno, strerror(errno));
  624. close(fd);
  625. return -1;
  626. }
  627. if (addr.nl_pid) {
  628. syslog(LOG_WARNING, "Received packet from untrusted pid:%u",
  629. addr.nl_pid);
  630. continue;
  631. }
  632. incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
  633. incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
  634. hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
  635. switch (hv_msg->kvp_hdr.operation) {
  636. case KVP_OP_REGISTER:
  637. /*
  638. * Driver is registering with us; stash away the version
  639. * information.
  640. */
  641. p = (char *)hv_msg->body.kvp_register.version;
  642. lic_version = malloc(strlen(p) + 1);
  643. if (lic_version) {
  644. strcpy(lic_version, p);
  645. syslog(LOG_INFO, "KVP LIC Version: %s",
  646. lic_version);
  647. } else {
  648. syslog(LOG_ERR, "malloc failed");
  649. }
  650. continue;
  651. /*
  652. * The current protocol with the kernel component uses a
  653. * NULL key name to pass an error condition.
  654. * For the SET, GET and DELETE operations,
  655. * use the existing protocol to pass back error.
  656. */
  657. case KVP_OP_SET:
  658. if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
  659. hv_msg->body.kvp_set.data.key,
  660. hv_msg->body.kvp_set.data.key_size,
  661. hv_msg->body.kvp_set.data.value,
  662. hv_msg->body.kvp_set.data.value_size))
  663. strcpy(hv_msg->body.kvp_set.data.key, "");
  664. break;
  665. case KVP_OP_GET:
  666. if (kvp_get_value(hv_msg->kvp_hdr.pool,
  667. hv_msg->body.kvp_set.data.key,
  668. hv_msg->body.kvp_set.data.key_size,
  669. hv_msg->body.kvp_set.data.value,
  670. hv_msg->body.kvp_set.data.value_size))
  671. strcpy(hv_msg->body.kvp_set.data.key, "");
  672. break;
  673. case KVP_OP_DELETE:
  674. if (kvp_key_delete(hv_msg->kvp_hdr.pool,
  675. hv_msg->body.kvp_delete.key,
  676. hv_msg->body.kvp_delete.key_size))
  677. strcpy(hv_msg->body.kvp_delete.key, "");
  678. break;
  679. default:
  680. break;
  681. }
  682. if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
  683. goto kvp_done;
  684. /*
  685. * If the pool is KVP_POOL_AUTO, dynamically generate
  686. * both the key and the value; if not read from the
  687. * appropriate pool.
  688. */
  689. if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
  690. kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
  691. hv_msg->body.kvp_enum_data.index,
  692. hv_msg->body.kvp_enum_data.data.key,
  693. HV_KVP_EXCHANGE_MAX_KEY_SIZE,
  694. hv_msg->body.kvp_enum_data.data.value,
  695. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  696. goto kvp_done;
  697. }
  698. hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
  699. key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
  700. key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
  701. switch (hv_msg->body.kvp_enum_data.index) {
  702. case FullyQualifiedDomainName:
  703. kvp_get_domain_name(key_value,
  704. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  705. strcpy(key_name, "FullyQualifiedDomainName");
  706. break;
  707. case IntegrationServicesVersion:
  708. strcpy(key_name, "IntegrationServicesVersion");
  709. strcpy(key_value, lic_version);
  710. break;
  711. case NetworkAddressIPv4:
  712. kvp_get_ip_address(AF_INET, key_value,
  713. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  714. strcpy(key_name, "NetworkAddressIPv4");
  715. break;
  716. case NetworkAddressIPv6:
  717. kvp_get_ip_address(AF_INET6, key_value,
  718. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  719. strcpy(key_name, "NetworkAddressIPv6");
  720. break;
  721. case OSBuildNumber:
  722. strcpy(key_value, os_build);
  723. strcpy(key_name, "OSBuildNumber");
  724. break;
  725. case OSName:
  726. strcpy(key_value, os_name);
  727. strcpy(key_name, "OSName");
  728. break;
  729. case OSMajorVersion:
  730. strcpy(key_value, os_major);
  731. strcpy(key_name, "OSMajorVersion");
  732. break;
  733. case OSMinorVersion:
  734. strcpy(key_value, os_minor);
  735. strcpy(key_name, "OSMinorVersion");
  736. break;
  737. case OSVersion:
  738. strcpy(key_value, os_build);
  739. strcpy(key_name, "OSVersion");
  740. break;
  741. case ProcessorArchitecture:
  742. strcpy(key_value, processor_arch);
  743. strcpy(key_name, "ProcessorArchitecture");
  744. break;
  745. default:
  746. strcpy(key_value, "Unknown Key");
  747. /*
  748. * We use a null key name to terminate enumeration.
  749. */
  750. strcpy(key_name, "");
  751. break;
  752. }
  753. /*
  754. * Send the value back to the kernel. The response is
  755. * already in the receive buffer. Update the cn_msg header to
  756. * reflect the key value that has been added to the message
  757. */
  758. kvp_done:
  759. incoming_cn_msg->id.idx = CN_KVP_IDX;
  760. incoming_cn_msg->id.val = CN_KVP_VAL;
  761. incoming_cn_msg->ack = 0;
  762. incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
  763. len = netlink_send(fd, incoming_cn_msg);
  764. if (len < 0) {
  765. syslog(LOG_ERR, "net_link send failed; error:%d", len);
  766. exit(EXIT_FAILURE);
  767. }
  768. }
  769. }