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.

nvo.c 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (C) 2006 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <stdint.h>
  19. #include <string.h>
  20. #include <gpxe/dhcp.h>
  21. #include <gpxe/nvs.h>
  22. #include <gpxe/nvo.h>
  23. /** @file
  24. *
  25. * Non-volatile stored options
  26. *
  27. */
  28. #warning "Temporary hack"
  29. struct nvo_block *ugly_nvo_hack = NULL;
  30. /**
  31. * Calculate checksum over non-volatile stored options
  32. *
  33. * @v nvo Non-volatile options block
  34. * @ret sum Checksum
  35. */
  36. static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
  37. uint8_t *data = nvo->options->data;
  38. uint8_t sum = 0;
  39. unsigned int i;
  40. for ( i = 0 ; i < nvo->total_len ; i++ ) {
  41. sum += *(data++);
  42. }
  43. return sum;
  44. }
  45. /**
  46. * Load non-volatile stored options from non-volatile storage device
  47. *
  48. * @v nvo Non-volatile options block
  49. * @ret rc Return status code
  50. */
  51. static int nvo_load ( struct nvo_block *nvo ) {
  52. void *data = nvo->options->data;
  53. struct nvo_fragment *fragment;
  54. int rc;
  55. /* Read data a fragment at a time */
  56. for ( fragment = nvo->fragments ; fragment->len ; fragment++ ) {
  57. if ( ( rc = nvs_read ( nvo->nvs, fragment->address,
  58. data, fragment->len ) ) != 0 ) {
  59. DBG ( "NVO %p could not read %zd bytes at %#04x\n",
  60. nvo, fragment->len, fragment->address );
  61. return rc;
  62. }
  63. data += fragment->len;
  64. }
  65. DBG ( "NVO %p loaded from non-volatile storage\n", nvo );
  66. return 0;
  67. }
  68. /**
  69. * Save non-volatile stored options back to non-volatile storage device
  70. *
  71. * @v nvo Non-volatile options block
  72. * @ret rc Return status code
  73. */
  74. int nvo_save ( struct nvo_block *nvo ) {
  75. void *data = nvo->options->data;
  76. uint8_t *checksum = ( data + nvo->total_len - 1 );
  77. struct nvo_fragment *fragment;
  78. int rc;
  79. /* Recalculate checksum */
  80. *checksum -= nvo_checksum ( nvo );
  81. /* Write data a fragment at a time */
  82. for ( fragment = nvo->fragments ; fragment->len ; fragment++ ) {
  83. if ( ( rc = nvs_write ( nvo->nvs, fragment->address,
  84. data, fragment->len ) ) != 0 ) {
  85. DBG ( "NVO %p could not write %zd bytes at %#04x\n",
  86. nvo, fragment->len, fragment->address );
  87. return rc;
  88. }
  89. data += fragment->len;
  90. }
  91. DBG ( "NVO %p saved to non-volatile storage\n", nvo );
  92. return 0;
  93. }
  94. /**
  95. * Parse stored options
  96. *
  97. * @v nvo Non-volatile options block
  98. *
  99. * Verifies that the options data is valid, and configures the DHCP
  100. * options block. If the data is not valid, it is replaced with an
  101. * empty options block.
  102. */
  103. static void nvo_init_dhcp ( struct nvo_block *nvo ) {
  104. struct dhcp_option_block *options = nvo->options;
  105. struct dhcp_option *option;
  106. /* Steal one byte for the checksum */
  107. options->max_len = ( nvo->total_len - 1 );
  108. /* Verify checksum over whole block */
  109. if ( nvo_checksum ( nvo ) != 0 ) {
  110. DBG ( "NVO %p has bad checksum %02x; assuming empty\n",
  111. nvo, nvo_checksum ( nvo ) );
  112. goto empty;
  113. }
  114. /* Check that we don't just have a block full of zeroes */
  115. option = options->data;
  116. if ( option->tag == DHCP_PAD ) {
  117. DBG ( "NVO %p has bad start; assuming empty\n", nvo );
  118. goto empty;
  119. }
  120. /* Search for the DHCP_END tag */
  121. options->len = options->max_len;
  122. option = find_dhcp_option ( options, DHCP_END );
  123. if ( ! option ) {
  124. DBG ( "NVO %p has no end tag; assuming empty\n", nvo );
  125. goto empty;
  126. }
  127. /* Set correct length of DHCP options */
  128. options->len = ( ( void * ) option - options->data + 1 );
  129. DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n",
  130. nvo, options->len, options->max_len );
  131. return;
  132. empty:
  133. /* No options found; initialise an empty options block */
  134. option = options->data;
  135. option->tag = DHCP_END;
  136. options->len = 1;
  137. return;
  138. }
  139. /**
  140. * Register non-volatile stored options
  141. *
  142. * @v nvo Non-volatile options block
  143. * @ret rc Return status code
  144. */
  145. int nvo_register ( struct nvo_block *nvo ) {
  146. struct nvo_fragment *fragment = nvo->fragments;
  147. int rc;
  148. /* Calculate total length of all fragments */
  149. nvo->total_len = 0;
  150. for ( fragment = nvo->fragments ; fragment->len ; fragment++ ) {
  151. nvo->total_len += fragment->len;
  152. }
  153. /* Allocate memory for options and read in from NVS */
  154. nvo->options = alloc_dhcp_options ( nvo->total_len );
  155. if ( ! nvo->options ) {
  156. DBG ( "NVO %p could not allocate %zd bytes\n",
  157. nvo, nvo->total_len );
  158. rc = -ENOMEM;
  159. goto err;
  160. }
  161. if ( ( rc = nvo_load ( nvo ) ) != 0 )
  162. goto err;
  163. /* Verify and register options */
  164. nvo_init_dhcp ( nvo );
  165. register_dhcp_options ( nvo->options );
  166. ugly_nvo_hack = nvo;
  167. DBG ( "NVO %p registered\n", nvo );
  168. return 0;
  169. err:
  170. free_dhcp_options ( nvo->options );
  171. nvo->options = NULL;
  172. return rc;
  173. }
  174. /**
  175. * Unregister non-volatile stored options
  176. *
  177. * @v nvo Non-volatile options block
  178. */
  179. void nvo_unregister ( struct nvo_block *nvo ) {
  180. if ( nvo->options ) {
  181. unregister_dhcp_options ( nvo->options );
  182. free_dhcp_options ( nvo->options );
  183. nvo->options = NULL;
  184. }
  185. DBG ( "NVO %p unregistered\n", nvo );
  186. ugly_nvo_hack = NULL;
  187. }