diff options
author | Michael Brown <mcb30@ipxe.org> | 2021-02-17 15:59:52 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2021-02-17 15:59:52 +0000 |
commit | 057674bb1f766db8b4c6593dc238ea68e4f38028 (patch) | |
tree | 5bfd66f170528a5856b0314c0c4cef9a02116a93 /src/core | |
parent | 19d0fab40f07eeea7fe6b9e0d4e8d4b0c2de215f (diff) | |
download | ipxe-057674bb1f766db8b4c6593dc238ea68e4f38028.tar.gz |
[pxe] Split out platform-independent portions of cachedhcp.c
Split out the portions of cachedhcp.c that can be shared between BIOS
and UEFI (both of which can provide a buffer containing a previously
obtained DHCP packet, and neither of which provide a means to
determine the length of this DHCP packet).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/cachedhcp.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c new file mode 100644 index 000000000..0e7da4bf2 --- /dev/null +++ b/src/core/cachedhcp.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <ipxe/dhcppkt.h> +#include <ipxe/init.h> +#include <ipxe/netdevice.h> +#include <ipxe/cachedhcp.h> + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK */ +static struct dhcp_packet *cached_dhcpack; + +/** Colour for debug messages */ +#define colour &cached_dhcpack + +/** + * Record cached DHCPACK + * + * @v data DHCPACK packet buffer + * @v max_len Maximum possible length + * @ret rc Return status code + */ +int cachedhcp_record ( userptr_t data, size_t max_len ) { + struct dhcp_packet *dhcppkt; + struct dhcp_packet *tmp; + struct dhcphdr *dhcphdr; + size_t len; + + /* Allocate and populate DHCP packet */ + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len ); + if ( ! dhcppkt ) { + DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); + return -ENOMEM; + } + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + copy_from_user ( dhcphdr, data, 0, max_len ); + dhcppkt_init ( dhcppkt, dhcphdr, max_len ); + + /* Shrink packet to required length. If reallocation fails, + * just continue to use the original packet and waste the + * unused space. + */ + len = dhcppkt_len ( dhcppkt ); + assert ( len <= max_len ); + tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); + if ( tmp ) + dhcppkt = tmp; + + /* Reinitialise packet at new address */ + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Store as cached DHCPACK, and mark original copy as consumed */ + DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n", + user_to_phys ( data, 0 ), len, max_len ); + cached_dhcpack = dhcppkt; + + return 0; +} + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_startup ( void ) { + + /* If cached DHCP packet was not claimed by any network device + * during startup, then free it. + */ + if ( cached_dhcpack ) { + DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + } +} + +/** Cached DHCPACK startup function */ +struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { + .name = "cachedhcp", + .startup = cachedhcp_startup, +}; + +/** + * Apply cached DHCPACK to network device, if applicable + * + * @v netdev Network device + * @ret rc Return status code + */ +static int cachedhcp_probe ( struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Do nothing unless we have a cached DHCPACK */ + if ( ! cached_dhcpack ) + return 0; + + /* Do nothing unless cached DHCPACK's MAC address matches this + * network device. + */ + if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", + netdev->name ); + return 0; + } + DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); + + /* Register as DHCP settings for this network device */ + if ( ( rc = register_settings ( &cached_dhcpack->settings, + netdev_settings ( netdev ), + DHCP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not register settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Claim cached DHCPACK */ + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + + return 0; +} + +/** Cached DHCP packet network device driver */ +struct net_driver cachedhcp_driver __net_driver = { + .name = "cachedhcp", + .probe = cachedhcp_probe, +}; |