hv_kvp_daemon.c 19 KB

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