Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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 <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <strings.h>
  23. #include <byteswap.h>
  24. #include <errno.h>
  25. #include <assert.h>
  26. #include <gpxe/in.h>
  27. #include <gpxe/vsprintf.h>
  28. #include <gpxe/settings.h>
  29. /** @file
  30. *
  31. * Configuration settings
  32. *
  33. */
  34. /** Registered configuration setting types */
  35. static struct config_setting_type config_setting_types[0]
  36. __table_start ( struct config_setting_type, config_setting_types );
  37. static struct config_setting_type config_setting_types_end[0]
  38. __table_end ( struct config_setting_type, config_setting_types );
  39. /** Registered configuration settings */
  40. static struct config_setting config_settings[0]
  41. __table_start ( struct config_setting, config_settings );
  42. static struct config_setting config_settings_end[0]
  43. __table_end ( struct config_setting, config_settings );
  44. struct config_setting_type config_setting_type_hex __config_setting_type;
  45. /**
  46. * Find configuration setting type
  47. *
  48. * @v name Name
  49. * @ret type Configuration setting type, or NULL
  50. */
  51. static struct config_setting_type *
  52. find_config_setting_type ( const char *name ) {
  53. struct config_setting_type *type;
  54. for ( type = config_setting_types ; type < config_setting_types_end ;
  55. type++ ) {
  56. if ( strcasecmp ( name, type->name ) == 0 )
  57. return type;
  58. }
  59. return NULL;
  60. }
  61. /**
  62. * Find configuration setting
  63. *
  64. * @v name Name
  65. * @ret setting Configuration setting, or NULL
  66. */
  67. static struct config_setting * find_config_setting ( const char *name ) {
  68. struct config_setting *setting;
  69. for ( setting = config_settings ; setting < config_settings_end ;
  70. setting++ ) {
  71. if ( strcasecmp ( name, setting->name ) == 0 )
  72. return setting;
  73. }
  74. return NULL;
  75. }
  76. /**
  77. * Find or build configuration setting
  78. *
  79. * @v name Name
  80. * @v setting Buffer to fill in with setting
  81. * @ret rc Return status code
  82. *
  83. * Find setting if it exists. If it doesn't exist, but the name is of
  84. * the form "<num>:<type>" (e.g. "12:string"), then construct a
  85. * setting for that tag and data type, and return it. The constructed
  86. * setting will be placed in the buffer.
  87. */
  88. static int find_or_build_config_setting ( const char *name,
  89. struct config_setting *setting ) {
  90. struct config_setting *known_setting;
  91. char tmp_name[ strlen ( name ) + 1 ];
  92. char *qualifier;
  93. char *tmp;
  94. /* Set defaults */
  95. memset ( setting, 0, sizeof ( *setting ) );
  96. setting->name = name;
  97. setting->type = &config_setting_type_hex;
  98. /* Strip qualifier, if present */
  99. memcpy ( tmp_name, name, sizeof ( tmp_name ) );
  100. if ( ( qualifier = strchr ( tmp_name, ':' ) ) != NULL )
  101. *(qualifier++) = 0;
  102. /* If we recognise the name of the setting, use it */
  103. if ( ( known_setting = find_config_setting ( tmp_name ) ) != NULL ) {
  104. memcpy ( setting, known_setting, sizeof ( *setting ) );
  105. } else {
  106. /* Otherwise, try to interpret as a numerical setting */
  107. for ( tmp = tmp_name ; 1 ; tmp++ ) {
  108. setting->tag = ( ( setting->tag << 8 ) |
  109. strtoul ( tmp, &tmp, 0 ) );
  110. if ( *tmp != '.' )
  111. break;
  112. }
  113. if ( *tmp != 0 )
  114. return -EINVAL;
  115. }
  116. /* Apply qualifier, if present */
  117. if ( qualifier ) {
  118. setting->type = find_config_setting_type ( qualifier );
  119. if ( ! setting->type )
  120. return -EINVAL;
  121. }
  122. return 0;
  123. }
  124. /**
  125. * Show value of named setting
  126. *
  127. * @v context Configuration context
  128. * @v name Configuration setting name
  129. * @v buf Buffer to contain value
  130. * @v len Length of buffer
  131. * @ret len Length of formatted value, or negative error
  132. */
  133. int show_named_setting ( struct config_context *context, const char *name,
  134. char *buf, size_t len ) {
  135. struct config_setting setting;
  136. int rc;
  137. if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 )
  138. return rc;
  139. return show_setting ( context, &setting, buf, len );
  140. }
  141. /**
  142. * Set value of named setting
  143. *
  144. * @v context Configuration context
  145. * @v name Configuration setting name
  146. * @v value Setting value (as a string)
  147. * @ret rc Return status code
  148. */
  149. int set_named_setting ( struct config_context *context, const char *name,
  150. const char *value ) {
  151. struct config_setting setting;
  152. int rc;
  153. if ( ( rc = find_or_build_config_setting ( name, &setting ) ) != 0 )
  154. return rc;
  155. return set_setting ( context, &setting, value );
  156. }
  157. /**
  158. * Set value of setting
  159. *
  160. * @v context Configuration context
  161. * @v setting Configuration setting
  162. * @v value Setting value (as a string), or NULL
  163. * @ret rc Return status code
  164. */
  165. int set_setting ( struct config_context *context,
  166. struct config_setting *setting,
  167. const char *value ) {
  168. if ( ( ! value ) || ( ! *value ) ) {
  169. /* Save putting deletion logic in each individual handler */
  170. return clear_setting ( context, setting );
  171. }
  172. return setting->type->set ( context, setting, value );
  173. }
  174. /**
  175. * Show value of string setting
  176. *
  177. * @v context Configuration context
  178. * @v setting Configuration setting
  179. * @v buf Buffer to contain value
  180. * @v len Length of buffer
  181. * @ret len Length of formatted value, or negative error
  182. */
  183. static int show_string ( struct config_context *context,
  184. struct config_setting *setting,
  185. char *buf, size_t len ) {
  186. struct dhcp_option *option;
  187. option = find_dhcp_option ( context->options, setting->tag );
  188. if ( ! option )
  189. return -ENODATA;
  190. return dhcp_snprintf ( buf, len, option );
  191. }
  192. /**
  193. * Set value of string setting
  194. *
  195. * @v context Configuration context
  196. * @v setting Configuration setting
  197. * @v value Setting value (as a string)
  198. * @ret rc Return status code
  199. */
  200. static int set_string ( struct config_context *context,
  201. struct config_setting *setting,
  202. const char *value ) {
  203. struct dhcp_option *option;
  204. option = set_dhcp_option ( context->options, setting->tag,
  205. value, strlen ( value ) );
  206. if ( ! option )
  207. return -ENOSPC;
  208. return 0;
  209. }
  210. /** A string configuration setting */
  211. struct config_setting_type config_setting_type_string __config_setting_type = {
  212. .name = "string",
  213. .description = "Text string",
  214. .show = show_string,
  215. .set = set_string,
  216. };
  217. /**
  218. * Show value of IPv4 setting
  219. *
  220. * @v context Configuration context
  221. * @v setting Configuration setting
  222. * @v buf Buffer to contain value
  223. * @v len Length of buffer
  224. * @ret len Length of formatted value, or negative error
  225. */
  226. static int show_ipv4 ( struct config_context *context,
  227. struct config_setting *setting,
  228. char *buf, size_t len ) {
  229. struct dhcp_option *option;
  230. struct in_addr ipv4;
  231. option = find_dhcp_option ( context->options, setting->tag );
  232. if ( ! option )
  233. return -ENODATA;
  234. dhcp_ipv4_option ( option, &ipv4 );
  235. return snprintf ( buf, len, inet_ntoa ( ipv4 ) );
  236. }
  237. /**
  238. * Set value of IPV4 setting
  239. *
  240. * @v context Configuration context
  241. * @v setting Configuration setting
  242. * @v value Setting value (as a string)
  243. * @ret rc Return status code
  244. */
  245. static int set_ipv4 ( struct config_context *context,
  246. struct config_setting *setting,
  247. const char *value ) {
  248. struct dhcp_option *option;
  249. struct in_addr ipv4;
  250. if ( inet_aton ( value, &ipv4 ) == 0 )
  251. return -EINVAL;
  252. option = set_dhcp_option ( context->options, setting->tag,
  253. &ipv4, sizeof ( ipv4 ) );
  254. if ( ! option )
  255. return -ENOSPC;
  256. return 0;
  257. }
  258. /** An IPv4 configuration setting */
  259. struct config_setting_type config_setting_type_ipv4 __config_setting_type = {
  260. .name = "ipv4",
  261. .description = "IPv4 address",
  262. .show = show_ipv4,
  263. .set = set_ipv4,
  264. };
  265. /**
  266. * Show value of integer setting
  267. *
  268. * @v context Configuration context
  269. * @v setting Configuration setting
  270. * @v buf Buffer to contain value
  271. * @v len Length of buffer
  272. * @ret len Length of formatted value, or negative error
  273. */
  274. static int show_int ( struct config_context *context,
  275. struct config_setting *setting,
  276. char *buf, size_t len ) {
  277. struct dhcp_option *option;
  278. long num;
  279. option = find_dhcp_option ( context->options, setting->tag );
  280. if ( ! option )
  281. return -ENODATA;
  282. num = dhcp_num_option ( option );
  283. return snprintf ( buf, len, "%ld", num );
  284. }
  285. /**
  286. * Set value of integer setting
  287. *
  288. * @v context Configuration context
  289. * @v setting Configuration setting
  290. * @v value Setting value (as a string)
  291. * @v size Size of integer (in bytes)
  292. * @ret rc Return status code
  293. */
  294. static int set_int ( struct config_context *context,
  295. struct config_setting *setting,
  296. const char *value, unsigned int size ) {
  297. struct dhcp_option *option;
  298. union {
  299. uint32_t num;
  300. uint8_t bytes[4];
  301. } u;
  302. char *endp;
  303. /* Parse number */
  304. if ( ! *value )
  305. return -EINVAL;
  306. u.num = htonl ( strtoul ( value, &endp, 0 ) );
  307. if ( *endp )
  308. return -EINVAL;
  309. /* Set option */
  310. option = set_dhcp_option ( context->options, setting->tag,
  311. &u.bytes[ sizeof ( u ) - size ], size );
  312. if ( ! option )
  313. return -ENOSPC;
  314. return 0;
  315. }
  316. /**
  317. * Set value of 8-bit integer setting
  318. *
  319. * @v context Configuration context
  320. * @v setting Configuration setting
  321. * @v value Setting value (as a string)
  322. * @v size Size of integer (in bytes)
  323. * @ret rc Return status code
  324. */
  325. static int set_int8 ( struct config_context *context,
  326. struct config_setting *setting,
  327. const char *value ) {
  328. return set_int ( context, setting, value, 1 );
  329. }
  330. /**
  331. * Set value of 16-bit integer setting
  332. *
  333. * @v context Configuration context
  334. * @v setting Configuration setting
  335. * @v value Setting value (as a string)
  336. * @v size Size of integer (in bytes)
  337. * @ret rc Return status code
  338. */
  339. static int set_int16 ( struct config_context *context,
  340. struct config_setting *setting,
  341. const char *value ) {
  342. return set_int ( context, setting, value, 2 );
  343. }
  344. /**
  345. * Set value of 32-bit integer setting
  346. *
  347. * @v context Configuration context
  348. * @v setting Configuration setting
  349. * @v value Setting value (as a string)
  350. * @v size Size of integer (in bytes)
  351. * @ret rc Return status code
  352. */
  353. static int set_int32 ( struct config_context *context,
  354. struct config_setting *setting,
  355. const char *value ) {
  356. return set_int ( context, setting, value, 4 );
  357. }
  358. /** An 8-bit integer configuration setting */
  359. struct config_setting_type config_setting_type_int8 __config_setting_type = {
  360. .name = "int8",
  361. .description = "8-bit integer",
  362. .show = show_int,
  363. .set = set_int8,
  364. };
  365. /** A 16-bit integer configuration setting */
  366. struct config_setting_type config_setting_type_int16 __config_setting_type = {
  367. .name = "int16",
  368. .description = "16-bit integer",
  369. .show = show_int,
  370. .set = set_int16,
  371. };
  372. /** A 32-bit integer configuration setting */
  373. struct config_setting_type config_setting_type_int32 __config_setting_type = {
  374. .name = "int32",
  375. .description = "32-bit integer",
  376. .show = show_int,
  377. .set = set_int32,
  378. };
  379. /**
  380. * Set value of hex-string setting
  381. *
  382. * @v context Configuration context
  383. * @v setting Configuration setting
  384. * @v value Setting value (as a string)
  385. * @ret rc Return status code
  386. */
  387. static int set_hex ( struct config_context *context,
  388. struct config_setting *setting,
  389. const char *value ) {
  390. struct dhcp_option *option;
  391. char *ptr = ( char * ) value;
  392. uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
  393. unsigned int len = 0;
  394. while ( 1 ) {
  395. bytes[len++] = strtoul ( ptr, &ptr, 16 );
  396. switch ( *ptr ) {
  397. case '\0' :
  398. option = set_dhcp_option ( context->options,
  399. setting->tag, bytes, len );
  400. if ( ! option )
  401. return -ENOSPC;
  402. return 0;
  403. case ':' :
  404. ptr++;
  405. break;
  406. default :
  407. return -EINVAL;
  408. }
  409. }
  410. }
  411. /**
  412. * Show value of hex-string setting
  413. *
  414. * @v context Configuration context
  415. * @v setting Configuration setting
  416. * @v buf Buffer to contain value
  417. * @v len Length of buffer
  418. * @ret len Length of formatted value, or negative error
  419. */
  420. static int show_hex ( struct config_context *context,
  421. struct config_setting *setting,
  422. char *buf, size_t len ) {
  423. struct dhcp_option *option;
  424. int used = 0;
  425. int i;
  426. option = find_dhcp_option ( context->options, setting->tag );
  427. if ( ! option )
  428. return -ENODATA;
  429. for ( i = 0 ; i < option->len ; i++ ) {
  430. used += ssnprintf ( ( buf + used ), ( len - used ),
  431. "%s%02x", ( used ? ":" : "" ),
  432. option->data.bytes[i] );
  433. }
  434. return used;
  435. }
  436. /** A hex-string configuration setting */
  437. struct config_setting_type config_setting_type_hex __config_setting_type = {
  438. .name = "hex",
  439. .description = "Hex string",
  440. .show = show_hex,
  441. .set = set_hex,
  442. };
  443. /** Some basic setting definitions */
  444. struct config_setting basic_config_settings[] __config_setting = {
  445. {
  446. .name = "ip",
  447. .description = "IP address of this machine (e.g. 192.168.0.1)",
  448. .tag = DHCP_EB_YIADDR,
  449. .type = &config_setting_type_ipv4,
  450. },
  451. {
  452. .name = "hostname",
  453. .description = "Host name of this machine",
  454. .tag = DHCP_HOST_NAME,
  455. .type = &config_setting_type_string,
  456. },
  457. {
  458. .name = "username",
  459. .description = "User name for authentication to servers",
  460. .tag = DHCP_EB_USERNAME,
  461. .type = &config_setting_type_string,
  462. },
  463. {
  464. .name = "password",
  465. .description = "Password for authentication to servers",
  466. .tag = DHCP_EB_PASSWORD,
  467. .type = &config_setting_type_string,
  468. },
  469. {
  470. .name = "root-path",
  471. .description = "NFS/iSCSI root path",
  472. .tag = DHCP_ROOT_PATH,
  473. .type = &config_setting_type_string,
  474. },
  475. {
  476. .name = "priority",
  477. .description = "Priority of these options",
  478. .tag = DHCP_EB_PRIORITY,
  479. .type = &config_setting_type_int8,
  480. },
  481. {
  482. .name = "initiator-iqn",
  483. .description = "iSCSI qualified name of this machine",
  484. .tag = DHCP_ISCSI_INITIATOR_IQN,
  485. .type = &config_setting_type_string,
  486. }
  487. };