You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

guestinfo.c 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. /** @file
  21. *
  22. * VMware GuestInfo settings
  23. *
  24. */
  25. #include <stdint.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <ipxe/init.h>
  31. #include <ipxe/settings.h>
  32. #include <ipxe/netdevice.h>
  33. #include <ipxe/guestrpc.h>
  34. /** GuestInfo GuestRPC channel */
  35. static int guestinfo_channel;
  36. /**
  37. * Fetch value of typed GuestInfo setting
  38. *
  39. * @v settings Settings block
  40. * @v setting Setting to fetch
  41. * @v type Setting type to attempt (or NULL for default)
  42. * @v data Buffer to fill with setting data
  43. * @v len Length of buffer
  44. * @ret found Setting found in GuestInfo
  45. * @ret len Length of setting data, or negative error
  46. */
  47. static int guestinfo_fetch_type ( struct settings *settings,
  48. struct setting *setting,
  49. struct setting_type *type,
  50. void *data, size_t len, int *found ) {
  51. const char *parent_name = settings->parent->name;
  52. char command[ 24 /* "info-get guestinfo.ipxe." */ +
  53. strlen ( parent_name ) + 1 /* "." */ +
  54. strlen ( setting->name ) + 1 /* "." */ +
  55. ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
  56. struct setting *named_setting;
  57. char *info;
  58. int info_len;
  59. int check_len;
  60. int ret;
  61. /* Construct info-get command */
  62. snprintf ( command, sizeof ( command ),
  63. "info-get guestinfo.ipxe.%s%s%s%s%s",
  64. parent_name, ( parent_name[0] ? "." : "" ), setting->name,
  65. ( type ? "." : "" ), ( type ? type->name : "" ) );
  66. /* Check for existence and obtain length of GuestInfo value */
  67. info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
  68. if ( info_len < 0 ) {
  69. ret = info_len;
  70. goto err_get_info_len;
  71. }
  72. /* Mark as found */
  73. *found = 1;
  74. /* Determine default type if necessary */
  75. if ( ! type ) {
  76. named_setting = find_setting ( setting->name );
  77. type = ( named_setting ?
  78. named_setting->type : &setting_type_string );
  79. }
  80. assert ( type != NULL );
  81. /* Allocate temporary block to hold GuestInfo value */
  82. info = zalloc ( info_len + 1 /* NUL */ );
  83. if ( ! info ) {
  84. DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n",
  85. settings, info_len );
  86. ret = -ENOMEM;
  87. goto err_alloc;
  88. }
  89. info[info_len] = '\0';
  90. /* Fetch GuestInfo value */
  91. check_len = guestrpc_command ( guestinfo_channel, command,
  92. info, info_len );
  93. if ( check_len < 0 ) {
  94. ret = check_len;
  95. goto err_get_info;
  96. }
  97. if ( check_len != info_len ) {
  98. DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
  99. "got %d)\n", settings, info_len, check_len );
  100. ret = -EIO;
  101. goto err_get_info;
  102. }
  103. DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
  104. settings, &command[9] /* Skip "info-get " */, info );
  105. /* Parse GuestInfo value according to type */
  106. ret = type->parse ( info, data, len );
  107. if ( ret < 0 ) {
  108. DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
  109. "%s\n", settings, info, type->name, strerror ( ret ) );
  110. goto err_parse;
  111. }
  112. err_parse:
  113. err_get_info:
  114. free ( info );
  115. err_alloc:
  116. err_get_info_len:
  117. return ret;
  118. }
  119. /**
  120. * Fetch value of GuestInfo setting
  121. *
  122. * @v settings Settings block
  123. * @v setting Setting to fetch
  124. * @v data Buffer to fill with setting data
  125. * @v len Length of buffer
  126. * @ret len Length of setting data, or negative error
  127. */
  128. static int guestinfo_fetch ( struct settings *settings,
  129. struct setting *setting,
  130. void *data, size_t len ) {
  131. struct setting_type *type;
  132. int found = 0;
  133. int ret;
  134. /* Try default type first */
  135. ret = guestinfo_fetch_type ( settings, setting, NULL,
  136. data, len, &found );
  137. if ( found )
  138. return ret;
  139. /* Otherwise, try all possible types */
  140. for_each_table_entry ( type, SETTING_TYPES ) {
  141. ret = guestinfo_fetch_type ( settings, setting, type,
  142. data, len, &found );
  143. if ( found )
  144. return ret;
  145. }
  146. /* Not found */
  147. return -ENOENT;
  148. }
  149. /** GuestInfo settings operations */
  150. static struct settings_operations guestinfo_settings_operations = {
  151. .fetch = guestinfo_fetch,
  152. };
  153. /** GuestInfo settings */
  154. static struct settings guestinfo_settings = {
  155. .refcnt = NULL,
  156. .siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
  157. .children = LIST_HEAD_INIT ( guestinfo_settings.children ),
  158. .op = &guestinfo_settings_operations,
  159. };
  160. /** Initialise GuestInfo settings */
  161. static void guestinfo_init ( void ) {
  162. int rc;
  163. /* Open GuestRPC channel */
  164. guestinfo_channel = guestrpc_open();
  165. if ( guestinfo_channel < 0 ) {
  166. rc = guestinfo_channel;
  167. DBG ( "GuestInfo could not open channel: %s\n",
  168. strerror ( rc ) );
  169. return;
  170. }
  171. /* Register root GuestInfo settings */
  172. if ( ( rc = register_settings ( &guestinfo_settings, NULL,
  173. "vmware" ) ) != 0 ) {
  174. DBG ( "GuestInfo could not register settings: %s\n",
  175. strerror ( rc ) );
  176. return;
  177. }
  178. }
  179. /** GuestInfo settings initialiser */
  180. struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
  181. .initialise = guestinfo_init,
  182. };
  183. /**
  184. * Create per-netdevice GuestInfo settings
  185. *
  186. * @v netdev Network device
  187. * @ret rc Return status code
  188. */
  189. static int guestinfo_net_probe ( struct net_device *netdev ) {
  190. struct settings *settings;
  191. int rc;
  192. /* Do nothing unless we have a GuestInfo channel available */
  193. if ( guestinfo_channel < 0 )
  194. return 0;
  195. /* Allocate and initialise settings block */
  196. settings = zalloc ( sizeof ( *settings ) );
  197. if ( ! settings ) {
  198. rc = -ENOMEM;
  199. goto err_alloc;
  200. }
  201. settings_init ( settings, &guestinfo_settings_operations, NULL, 0 );
  202. /* Register settings */
  203. if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
  204. "vmware" ) ) != 0 ) {
  205. DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
  206. settings, netdev->name, strerror ( rc ) );
  207. goto err_register;
  208. }
  209. DBGC ( settings, "GuestInfo %p registered for %s\n",
  210. settings, netdev->name );
  211. return 0;
  212. err_register:
  213. free ( settings );
  214. err_alloc:
  215. return rc;
  216. }
  217. /**
  218. * Handle network device or link state change
  219. *
  220. * @v netdev Network device
  221. */
  222. static void guestinfo_net_notify ( struct net_device *netdev __unused ) {
  223. /* Nothing to do */
  224. }
  225. /**
  226. * Remove per-netdevice GuestInfo settings
  227. *
  228. * @v netdev Network device
  229. */
  230. static void guestinfo_net_remove ( struct net_device *netdev ) {
  231. struct settings *parent = netdev_settings ( netdev );
  232. struct settings *settings;
  233. list_for_each_entry ( settings, &parent->children, siblings ) {
  234. if ( settings->op == &guestinfo_settings_operations ) {
  235. DBGC ( settings, "GuestInfo %p unregistered for %s\n",
  236. settings, netdev->name );
  237. unregister_settings ( settings );
  238. free ( settings );
  239. return;
  240. }
  241. }
  242. }
  243. /** GuestInfo per-netdevice driver */
  244. struct net_driver guestinfo_net_driver __net_driver = {
  245. .name = "GuestInfo",
  246. .probe = guestinfo_net_probe,
  247. .notify = guestinfo_net_notify,
  248. .remove = guestinfo_net_remove,
  249. };