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