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.

netdev_settings.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Copyright (C) 2008 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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <byteswap.h>
  27. #include <ipxe/dhcp.h>
  28. #include <ipxe/dhcpopts.h>
  29. #include <ipxe/settings.h>
  30. #include <ipxe/device.h>
  31. #include <ipxe/netdevice.h>
  32. #include <ipxe/init.h>
  33. /** @file
  34. *
  35. * Network device configuration settings
  36. *
  37. */
  38. /** Network device predefined settings */
  39. const struct setting mac_setting __setting ( SETTING_NETDEV, mac ) = {
  40. .name = "mac",
  41. .description = "MAC address",
  42. .type = &setting_type_hex,
  43. };
  44. const struct setting bustype_setting __setting ( SETTING_NETDEV, bustype ) = {
  45. .name = "bustype",
  46. .description = "Bus type",
  47. .type = &setting_type_string,
  48. };
  49. const struct setting busloc_setting __setting ( SETTING_NETDEV, busloc ) = {
  50. .name = "busloc",
  51. .description = "Bus location",
  52. .type = &setting_type_uint32,
  53. };
  54. const struct setting busid_setting __setting ( SETTING_NETDEV, busid ) = {
  55. .name = "busid",
  56. .description = "Bus ID",
  57. .type = &setting_type_hex,
  58. };
  59. const struct setting chip_setting __setting ( SETTING_NETDEV, chip ) = {
  60. .name = "chip",
  61. .description = "Chip",
  62. .type = &setting_type_string,
  63. };
  64. const struct setting ifname_setting __setting ( SETTING_NETDEV, ifname ) = {
  65. .name = "ifname",
  66. .description = "Interface name",
  67. .type = &setting_type_string,
  68. };
  69. const struct setting mtu_setting __setting ( SETTING_NETDEV, mtu ) = {
  70. .name = "mtu",
  71. .description = "MTU",
  72. .type = &setting_type_int16,
  73. .tag = DHCP_MTU,
  74. };
  75. /**
  76. * Store MAC address setting
  77. *
  78. * @v netdev Network device
  79. * @v data Setting data, or NULL to clear setting
  80. * @v len Length of setting data
  81. * @ret rc Return status code
  82. */
  83. static int netdev_store_mac ( struct net_device *netdev,
  84. const void *data, size_t len ) {
  85. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  86. /* Record new MAC address */
  87. if ( data ) {
  88. if ( len != netdev->ll_protocol->ll_addr_len )
  89. return -EINVAL;
  90. memcpy ( netdev->ll_addr, data, len );
  91. } else {
  92. /* Reset MAC address if clearing setting */
  93. ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
  94. }
  95. return 0;
  96. }
  97. /**
  98. * Fetch MAC address setting
  99. *
  100. * @v netdev Network device
  101. * @v data Buffer to fill with setting data
  102. * @v len Length of buffer
  103. * @ret len Length of setting data, or negative error
  104. */
  105. static int netdev_fetch_mac ( struct net_device *netdev, void *data,
  106. size_t len ) {
  107. if ( len > netdev->ll_protocol->ll_addr_len )
  108. len = netdev->ll_protocol->ll_addr_len;
  109. memcpy ( data, netdev->ll_addr, len );
  110. return netdev->ll_protocol->ll_addr_len;
  111. }
  112. /**
  113. * Fetch bus type setting
  114. *
  115. * @v netdev Network device
  116. * @v data Buffer to fill with setting data
  117. * @v len Length of buffer
  118. * @ret len Length of setting data, or negative error
  119. */
  120. static int netdev_fetch_bustype ( struct net_device *netdev, void *data,
  121. size_t len ) {
  122. static const char *bustypes[] = {
  123. [BUS_TYPE_PCI] = "PCI",
  124. [BUS_TYPE_ISAPNP] = "ISAPNP",
  125. [BUS_TYPE_EISA] = "EISA",
  126. [BUS_TYPE_MCA] = "MCA",
  127. [BUS_TYPE_ISA] = "ISA",
  128. [BUS_TYPE_TAP] = "TAP",
  129. [BUS_TYPE_EFI] = "EFI",
  130. [BUS_TYPE_XEN] = "XEN",
  131. [BUS_TYPE_HV] = "HV",
  132. [BUS_TYPE_USB] = "USB",
  133. };
  134. struct device_description *desc = &netdev->dev->desc;
  135. const char *bustype;
  136. assert ( desc->bus_type < ( sizeof ( bustypes ) /
  137. sizeof ( bustypes[0] ) ) );
  138. bustype = bustypes[desc->bus_type];
  139. if ( ! bustype )
  140. return -ENOENT;
  141. strncpy ( data, bustype, len );
  142. return strlen ( bustype );
  143. }
  144. /**
  145. * Fetch bus location setting
  146. *
  147. * @v netdev Network device
  148. * @v data Buffer to fill with setting data
  149. * @v len Length of buffer
  150. * @ret len Length of setting data, or negative error
  151. */
  152. static int netdev_fetch_busloc ( struct net_device *netdev, void *data,
  153. size_t len ) {
  154. struct device_description *desc = &netdev->dev->desc;
  155. uint32_t busloc;
  156. busloc = cpu_to_be32 ( desc->location );
  157. if ( len > sizeof ( busloc ) )
  158. len = sizeof ( busloc );
  159. memcpy ( data, &busloc, len );
  160. return sizeof ( busloc );
  161. }
  162. /**
  163. * Fetch bus ID setting
  164. *
  165. * @v netdev Network device
  166. * @v data Buffer to fill with setting data
  167. * @v len Length of buffer
  168. * @ret len Length of setting data, or negative error
  169. */
  170. static int netdev_fetch_busid ( struct net_device *netdev, void *data,
  171. size_t len ) {
  172. struct device_description *desc = &netdev->dev->desc;
  173. struct dhcp_netdev_desc dhcp_desc;
  174. dhcp_desc.type = desc->bus_type;
  175. dhcp_desc.vendor = htons ( desc->vendor );
  176. dhcp_desc.device = htons ( desc->device );
  177. if ( len > sizeof ( dhcp_desc ) )
  178. len = sizeof ( dhcp_desc );
  179. memcpy ( data, &dhcp_desc, len );
  180. return sizeof ( dhcp_desc );
  181. }
  182. /**
  183. * Fetch chip setting
  184. *
  185. * @v netdev Network device
  186. * @v data Buffer to fill with setting data
  187. * @v len Length of buffer
  188. * @ret len Length of setting data, or negative error
  189. */
  190. static int netdev_fetch_chip ( struct net_device *netdev, void *data,
  191. size_t len ) {
  192. const char *chip = netdev->dev->driver_name;
  193. strncpy ( data, chip, len );
  194. return strlen ( chip );
  195. }
  196. /**
  197. * Fetch ifname setting
  198. *
  199. * @v netdev Network device
  200. * @v data Buffer to fill with setting data
  201. * @v len Length of buffer
  202. * @ret len Length of setting data, or negative error
  203. */
  204. static int netdev_fetch_ifname ( struct net_device *netdev, void *data,
  205. size_t len ) {
  206. const char *ifname = netdev->name;
  207. strncpy ( data, ifname, len );
  208. return strlen ( ifname );
  209. }
  210. /** A network device setting operation */
  211. struct netdev_setting_operation {
  212. /** Setting */
  213. const struct setting *setting;
  214. /** Store setting (or NULL if not supported)
  215. *
  216. * @v netdev Network device
  217. * @v data Setting data, or NULL to clear setting
  218. * @v len Length of setting data
  219. * @ret rc Return status code
  220. */
  221. int ( * store ) ( struct net_device *netdev, const void *data,
  222. size_t len );
  223. /** Fetch setting
  224. *
  225. * @v netdev Network device
  226. * @v data Buffer to fill with setting data
  227. * @v len Length of buffer
  228. * @ret len Length of setting data, or negative error
  229. */
  230. int ( * fetch ) ( struct net_device *netdev, void *data, size_t len );
  231. };
  232. /** Network device settings */
  233. static struct netdev_setting_operation netdev_setting_operations[] = {
  234. { &mac_setting, netdev_store_mac, netdev_fetch_mac },
  235. { &bustype_setting, NULL, netdev_fetch_bustype },
  236. { &busloc_setting, NULL, netdev_fetch_busloc },
  237. { &busid_setting, NULL, netdev_fetch_busid },
  238. { &chip_setting, NULL, netdev_fetch_chip },
  239. { &ifname_setting, NULL, netdev_fetch_ifname },
  240. };
  241. /**
  242. * Store value of network device setting
  243. *
  244. * @v settings Settings block
  245. * @v setting Setting to store
  246. * @v data Setting data, or NULL to clear setting
  247. * @v len Length of setting data
  248. * @ret rc Return status code
  249. */
  250. static int netdev_store ( struct settings *settings,
  251. const struct setting *setting,
  252. const void *data, size_t len ) {
  253. struct net_device *netdev = container_of ( settings, struct net_device,
  254. settings.settings );
  255. struct netdev_setting_operation *op;
  256. unsigned int i;
  257. /* Handle network device-specific settings */
  258. for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
  259. sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
  260. op = &netdev_setting_operations[i];
  261. if ( setting_cmp ( setting, op->setting ) == 0 ) {
  262. if ( op->store ) {
  263. return op->store ( netdev, data, len );
  264. } else {
  265. return -ENOTSUP;
  266. }
  267. }
  268. }
  269. return generic_settings_store ( settings, setting, data, len );
  270. }
  271. /**
  272. * Fetch value of network device setting
  273. *
  274. * @v settings Settings block
  275. * @v setting Setting to fetch
  276. * @v data Buffer to fill with setting data
  277. * @v len Length of buffer
  278. * @ret len Length of setting data, or negative error
  279. */
  280. static int netdev_fetch ( struct settings *settings, struct setting *setting,
  281. void *data, size_t len ) {
  282. struct net_device *netdev = container_of ( settings, struct net_device,
  283. settings.settings );
  284. struct netdev_setting_operation *op;
  285. unsigned int i;
  286. /* Handle network device-specific settings */
  287. for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
  288. sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
  289. op = &netdev_setting_operations[i];
  290. if ( setting_cmp ( setting, op->setting ) == 0 )
  291. return op->fetch ( netdev, data, len );
  292. }
  293. return generic_settings_fetch ( settings, setting, data, len );
  294. }
  295. /**
  296. * Clear network device settings
  297. *
  298. * @v settings Settings block
  299. */
  300. static void netdev_clear ( struct settings *settings ) {
  301. generic_settings_clear ( settings );
  302. }
  303. /** Network device configuration settings operations */
  304. struct settings_operations netdev_settings_operations = {
  305. .store = netdev_store,
  306. .fetch = netdev_fetch,
  307. .clear = netdev_clear,
  308. };
  309. /**
  310. * Redirect "netX" settings block
  311. *
  312. * @v settings Settings block
  313. * @ret settings Underlying settings block
  314. */
  315. static struct settings * netdev_redirect ( struct settings *settings ) {
  316. struct net_device *netdev;
  317. /* Redirect to most recently opened network device */
  318. netdev = last_opened_netdev();
  319. if ( netdev ) {
  320. return netdev_settings ( netdev );
  321. } else {
  322. return settings;
  323. }
  324. }
  325. /** "netX" settings operations */
  326. static struct settings_operations netdev_redirect_settings_operations = {
  327. .redirect = netdev_redirect,
  328. };
  329. /** "netX" settings */
  330. static struct settings netdev_redirect_settings = {
  331. .refcnt = NULL,
  332. .siblings = LIST_HEAD_INIT ( netdev_redirect_settings.siblings ),
  333. .children = LIST_HEAD_INIT ( netdev_redirect_settings.children ),
  334. .op = &netdev_redirect_settings_operations,
  335. };
  336. /** Initialise "netX" settings */
  337. static void netdev_redirect_settings_init ( void ) {
  338. int rc;
  339. if ( ( rc = register_settings ( &netdev_redirect_settings, NULL,
  340. "netX" ) ) != 0 ) {
  341. DBG ( "Could not register netX settings: %s\n",
  342. strerror ( rc ) );
  343. return;
  344. }
  345. }
  346. /** "netX" settings initialiser */
  347. struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = {
  348. .initialise = netdev_redirect_settings_init,
  349. };
  350. /**
  351. * Apply network device settings
  352. *
  353. * @ret rc Return status code
  354. */
  355. static int apply_netdev_settings ( void ) {
  356. struct net_device *netdev;
  357. struct settings *settings;
  358. struct ll_protocol *ll_protocol;
  359. size_t max_mtu;
  360. size_t old_mtu;
  361. size_t mtu;
  362. int rc;
  363. /* Process settings for each network device */
  364. for_each_netdev ( netdev ) {
  365. /* Get network device settings */
  366. settings = netdev_settings ( netdev );
  367. /* Get MTU */
  368. mtu = fetch_uintz_setting ( settings, &mtu_setting );
  369. /* Do nothing unless MTU is specified */
  370. if ( ! mtu )
  371. continue;
  372. /* Limit MTU to maximum supported by hardware */
  373. ll_protocol = netdev->ll_protocol;
  374. max_mtu = ( netdev->max_pkt_len - ll_protocol->ll_header_len );
  375. if ( mtu > max_mtu ) {
  376. DBGC ( netdev, "NETDEV %s cannot support MTU %zd (max "
  377. "%zd)\n", netdev->name, mtu, max_mtu );
  378. mtu = max_mtu;
  379. }
  380. /* Update maximum packet length */
  381. old_mtu = netdev->mtu;
  382. netdev->mtu = mtu;
  383. if ( mtu != old_mtu ) {
  384. DBGC ( netdev, "NETDEV %s MTU is %zd\n",
  385. netdev->name, mtu );
  386. }
  387. /* Close and reopen network device if MTU has increased */
  388. if ( netdev_is_open ( netdev ) && ( mtu > old_mtu ) ) {
  389. netdev_close ( netdev );
  390. if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
  391. DBGC ( netdev, "NETDEV %s could not reopen: "
  392. "%s\n", netdev->name, strerror ( rc ) );
  393. return rc;
  394. }
  395. }
  396. }
  397. return 0;
  398. }
  399. /** Network device settings applicator */
  400. struct settings_applicator netdev_applicator __settings_applicator = {
  401. .apply = apply_netdev_settings,
  402. };