iPXE
cachedhcp.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 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 <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <ipxe/dhcppkt.h>
31 #include <ipxe/init.h>
32 #include <ipxe/netdevice.h>
33 #include <ipxe/vlan.h>
34 #include <ipxe/uaccess.h>
35 #include <ipxe/cachedhcp.h>
36 
37 /** @file
38  *
39  * Cached DHCP packet
40  *
41  */
42 
43 /** A cached DHCP packet */
45  /** Settings block name */
46  const char *name;
47  /** DHCP packet (if any) */
49  /** VLAN tag (if applicable) */
50  unsigned int vlan;
51  /** Flags */
52  unsigned int flags;
53 };
54 
55 /** Cached DHCP packet should be retained */
56 #define CACHEDHCP_RETAIN 0x0001
57 
58 /** Cached DHCP packet has been used */
59 #define CACHEDHCP_USED 0x0002
60 
61 /** Cached DHCPACK */
64  .flags = CACHEDHCP_RETAIN,
65 };
66 
67 /** Cached ProxyDHCPOFFER */
70 };
71 
72 /** Cached PXEBSACK */
75 };
76 
77 /** List of cached DHCP packets */
78 static struct cached_dhcp_packet *cached_packets[] = {
81  &cached_pxebs,
82 };
83 
84 /** Colour for debug messages */
85 #define colour &cached_dhcpack
86 
87 /**
88  * Free cached DHCP packet
89  *
90  * @v cache Cached DHCP packet
91  */
92 static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
93 
94  dhcppkt_put ( cache->dhcppkt );
95  cache->dhcppkt = NULL;
96 }
97 
98 /**
99  * Apply cached DHCP packet settings
100  *
101  * @v cache Cached DHCP packet
102  * @v netdev Network device, or NULL
103  * @ret rc Return status code
104  */
105 static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
106  struct net_device *netdev ) {
107  struct settings *settings = NULL;
108  struct ll_protocol *ll_protocol;
109  const uint8_t *chaddr;
110  uint8_t *hw_addr;
111  uint8_t *ll_addr;
112  size_t ll_addr_len;
113  int rc;
114 
115  /* Do nothing if cache is empty or already in use */
116  if ( ( ! cache->dhcppkt ) || ( cache->flags & CACHEDHCP_USED ) )
117  return 0;
118  chaddr = cache->dhcppkt->dhcphdr->chaddr;
119 
120  /* Handle association with network device, if specified */
121  if ( netdev ) {
122  hw_addr = netdev->hw_addr;
123  ll_addr = netdev->ll_addr;
126 
127  /* If cached packet's MAC address matches the network
128  * device's permanent MAC address, then assume that
129  * the permanent MAC address ought to be the network
130  * device's current link-layer address.
131  *
132  * This situation can arise when the PXE ROM does not
133  * understand the system-specific mechanism for
134  * overriding the MAC address, and so uses the
135  * permanent MAC address instead. We choose to match
136  * this behaviour in order to minimise surprise.
137  */
138  if ( memcmp ( hw_addr, chaddr, ll_addr_len ) == 0 ) {
139  if ( memcmp ( hw_addr, ll_addr, ll_addr_len ) != 0 ) {
140  DBGC ( colour, "CACHEDHCP %s resetting %s MAC "
141  "%s ", cache->name, netdev->name,
142  ll_protocol->ntoa ( ll_addr ) );
143  DBGC ( colour, "-> %s\n",
144  ll_protocol->ntoa ( hw_addr ) );
145  }
146  memcpy ( ll_addr, hw_addr, ll_addr_len );
147  }
148 
149  /* Do nothing unless cached packet's MAC address
150  * matches this network device.
151  */
152  if ( memcmp ( ll_addr, chaddr, ll_addr_len ) != 0 ) {
153  DBGC ( colour, "CACHEDHCP %s %s does not match %s\n",
154  cache->name, ll_protocol->ntoa ( chaddr ),
155  netdev->name );
156  return 0;
157  }
158 
159  /* Do nothing unless cached packet's VLAN tag matches
160  * this network device.
161  */
162  if ( vlan_tag ( netdev ) != cache->vlan ) {
163  DBGC ( colour, "CACHEDHCP %s VLAN %d does not match "
164  "%s\n", cache->name, cache->vlan,
165  netdev->name );
166  return 0;
167  }
168 
169  /* Use network device's settings block */
171  DBGC ( colour, "CACHEDHCP %s is for %s\n",
172  cache->name, netdev->name );
173  }
174 
175  /* Register settings */
176  if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
177  cache->name ) ) != 0 ) {
178  DBGC ( colour, "CACHEDHCP %s could not register settings: %s\n",
179  cache->name, strerror ( rc ) );
180  return rc;
181  }
182 
183  /* Mark as used */
184  cache->flags |= CACHEDHCP_USED;
185 
186  /* Free cached DHCP packet, if applicable */
187  if ( ! ( cache->flags & CACHEDHCP_RETAIN ) )
188  cachedhcp_free ( cache );
189 
190  return 0;
191 }
192 
193 /**
194  * Record cached DHCP packet
195  *
196  * @v cache Cached DHCP packet
197  * @v vlan VLAN tag, if any
198  * @v data DHCPACK packet buffer
199  * @v max_len Maximum possible length
200  * @ret rc Return status code
201  */
202 int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan,
203  const void *data, size_t max_len ) {
204  struct dhcp_packet *dhcppkt;
205  struct dhcp_packet *tmp;
206  struct dhcphdr *dhcphdr;
207  unsigned int i;
208  size_t len;
209 
210  /* Free any existing cached packet */
211  cachedhcp_free ( cache );
212 
213  /* Allocate and populate DHCP packet */
214  dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
215  if ( ! dhcppkt ) {
216  DBGC ( colour, "CACHEDHCP %s could not allocate copy\n",
217  cache->name );
218  return -ENOMEM;
219  }
220  dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
221  memcpy ( dhcphdr, data, max_len );
222  dhcppkt_init ( dhcppkt, dhcphdr, max_len );
223 
224  /* Shrink packet to required length. If reallocation fails,
225  * just continue to use the original packet and waste the
226  * unused space.
227  */
228  len = dhcppkt_len ( dhcppkt );
229  assert ( len <= max_len );
230  tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
231  if ( tmp )
232  dhcppkt = tmp;
233 
234  /* Reinitialise packet at new address */
235  dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
236  dhcppkt_init ( dhcppkt, dhcphdr, len );
237 
238  /* Discard duplicate packets, since some PXE stacks (including
239  * iPXE itself) will report the DHCPACK packet as the PXEBSACK
240  * if no separate PXEBSACK exists.
241  */
242  for ( i = 0 ; i < ( sizeof ( cached_packets ) /
243  sizeof ( cached_packets[0] ) ) ; i++ ) {
244  tmp = cached_packets[i]->dhcppkt;
245  if ( tmp && ( dhcppkt_len ( tmp ) == len ) &&
246  ( memcmp ( tmp->dhcphdr, dhcppkt->dhcphdr, len ) == 0 ) ) {
247  DBGC ( colour, "CACHEDHCP %s duplicates %s\n",
248  cache->name, cached_packets[i]->name );
249  dhcppkt_put ( dhcppkt );
250  return -EEXIST;
251  }
252  }
253 
254  /* Store as cached packet */
255  DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
256  virt_to_phys ( data ), len, max_len );
257  cache->dhcppkt = dhcppkt;
258  cache->vlan = vlan;
259 
260  return 0;
261 }
262 
263 /**
264  * Cached DHCP packet early startup function
265  *
266  */
267 static void cachedhcp_startup_early ( void ) {
268 
269  /* Apply cached ProxyDHCPOFFER, if any */
272 
273  /* Apply cached PXEBSACK, if any */
276 }
277 
278 /**
279  * Cache DHCP packet late startup function
280  *
281  */
282 static void cachedhcp_startup_late ( void ) {
283 
284  /* Clear retention flag */
286 
287  /* Free cached DHCPACK, if used by a network device */
290 
291  /* Report unclaimed DHCPACK, if any. Do not free yet, since
292  * it may still be claimed by a dynamically created device
293  * such as a VLAN device.
294  */
295  if ( cached_dhcpack.dhcppkt ) {
296  DBGC ( colour, "CACHEDHCP %s unclaimed\n",
298  }
299 }
300 
301 /**
302  * Cached DHCP packet shutdown function
303  *
304  * @v booting System is shutting down for OS boot
305  */
306 static void cachedhcp_shutdown ( int booting __unused ) {
307 
308  /* Free cached DHCPACK, if any */
309  if ( cached_dhcpack.dhcppkt ) {
310  DBGC ( colour, "CACHEDHCP %s never claimed\n",
312  }
314 }
315 
316 /** Cached DHCP packet early startup function */
317 struct startup_fn cachedhcp_early_fn __startup_fn ( STARTUP_EARLY ) = {
318  .name = "cachedhcp1",
319  .startup = cachedhcp_startup_early,
320 };
321 
322 /** Cached DHCP packet late startup function */
323 struct startup_fn cachedhcp_late_fn __startup_fn ( STARTUP_LATE ) = {
324  .name = "cachedhcp2",
325  .startup = cachedhcp_startup_late,
326  .shutdown = cachedhcp_shutdown,
327 };
328 
329 /**
330  * Apply cached DHCPACK to network device, if applicable
331  *
332  * @v netdev Network device
333  * @v priv Private data
334  * @ret rc Return status code
335  */
336 static int cachedhcp_probe ( struct net_device *netdev, void *priv __unused ) {
337 
338  /* Apply cached DHCPACK to network device, if applicable */
340 }
341 
342 /** Cached DHCP packet network device driver */
343 struct net_driver cachedhcp_driver __net_driver = {
344  .name = "cachedhcp",
345  .probe = cachedhcp_probe,
346 };
347 
348 /**
349  * Recycle cached DHCPACK
350  *
351  * @v netdev Network device
352  * @v priv Private data
353  */
355  struct cached_dhcp_packet *cache = &cached_dhcpack;
356  struct settings *settings;
357 
358  /* Return DHCPACK to cache, if applicable */
360  cache->name );
361  if ( cache->dhcppkt && ( settings == &cache->dhcppkt->settings ) ) {
362  DBGC ( colour, "CACHEDHCP %s recycled from %s\n",
363  cache->name, netdev->name );
364  assert ( cache->flags & CACHEDHCP_USED );
366  cache->flags &= ~CACHEDHCP_USED;
367  }
368 }
#define colour
Colour for debug messages.
Definition: cachedhcp.c:85
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
A DHCP packet.
Definition: dhcppkt.h:20
uint8_t ll_addr_len
Link-layer address length.
Definition: netdevice.h:198
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition: settings.c:514
unsigned int vlan
VLAN tag (if applicable)
Definition: cachedhcp.c:50
Error codes.
#define EEXIST
File exists.
Definition: errno.h:388
static int cachedhcp_probe(struct net_device *netdev, void *priv __unused)
Apply cached DHCPACK to network device, if applicable.
Definition: cachedhcp.c:336
struct cached_dhcp_packet cached_proxydhcp
Cached ProxyDHCPOFFER.
Definition: cachedhcp.c:68
#define STARTUP_EARLY
Early startup.
Definition: init.h:63
#define DBGC(...)
Definition: compiler.h:505
static void cachedhcp_startup_early(void)
Cached DHCP packet early startup function.
Definition: cachedhcp.c:267
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct net_driver cachedhcp_driver __net_driver
Cached DHCP packet network device driver.
Definition: cachedhcp.c:343
const char * name
Definition: init.h:43
A network upper-layer driver.
Definition: netdevice.h:476
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:586
A link-layer protocol.
Definition: netdevice.h:114
#define STARTUP_LATE
Late startup.
Definition: init.h:65
static struct cached_dhcp_packet * cached_packets[]
List of cached DHCP packets.
Definition: cachedhcp.c:78
struct dhcp_packet * dhcppkt
DHCP packet (if any)
Definition: cachedhcp.c:48
void cachedhcp_recycle(struct net_device *netdev)
Recycle cached DHCPACK.
Definition: cachedhcp.c:354
static void cachedhcp_free(struct cached_dhcp_packet *cache)
Free cached DHCP packet.
Definition: cachedhcp.c:92
unsigned long tmp
Definition: linux_pci.h:64
A startup/shutdown function.
Definition: init.h:42
#define ENOMEM
Not enough space.
Definition: errno.h:534
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * name
Name.
Definition: netdevice.h:478
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define PROXYDHCP_SETTINGS_NAME
Settings block name used for ProxyDHCP responses.
Definition: dhcp.h:713
Access to external ("user") memory.
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static int cachedhcp_apply(struct cached_dhcp_packet *cache, struct net_device *netdev)
Apply cached DHCP packet settings.
Definition: cachedhcp.c:105
#define DHCP_SETTINGS_NAME
Settings block name used for DHCP responses.
Definition: dhcp.h:710
ring len
Length.
Definition: dwmac.h:231
int cachedhcp_record(struct cached_dhcp_packet *cache, unsigned int vlan, const void *data, size_t max_len)
Record cached DHCP packet.
Definition: cachedhcp.c:202
Cached DHCP packet.
static struct net_device * netdev
Definition: gdbudp.c:52
A cached DHCP packet.
Definition: cachedhcp.c:44
struct startup_fn cachedhcp_early_fn __startup_fn(STARTUP_EARLY)
Cached DHCP packet early startup function.
#define PXEBS_SETTINGS_NAME
Setting block name used for BootServerDHCP responses.
Definition: dhcp.h:716
#define CACHEDHCP_RETAIN
Cached DHCP packet should be retained.
Definition: cachedhcp.c:56
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:661
uint8_t chaddr[16]
Client hardware address.
Definition: dhcp.h:661
A network device.
Definition: netdevice.h:352
A settings block.
Definition: settings.h:132
unsigned char uint8_t
Definition: stdint.h:10
static void cachedhcp_shutdown(int booting __unused)
Cached DHCP packet shutdown function.
Definition: cachedhcp.c:306
struct cached_dhcp_packet cached_dhcpack
Cached DHCPACK.
Definition: cachedhcp.c:62
unsigned int flags
Flags.
Definition: cachedhcp.c:52
struct settings settings
Settings interface.
Definition: dhcppkt.h:28
A DHCP header.
Definition: dhcp.h:615
Network device management.
void dhcppkt_init(struct dhcp_packet *dhcppkt, struct dhcphdr *data, size_t len)
Initialise DHCP packet.
Definition: dhcppkt.c:300
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:362
struct dhcphdr * dhcphdr
The DHCP packet contents.
Definition: dhcppkt.h:24
static struct tlan_private * priv
Definition: tlan.c:225
static void dhcppkt_put(struct dhcp_packet *dhcppkt)
Decrement reference count on DHCP packet.
Definition: dhcppkt.h:49
static size_t dhcppkt_len(struct dhcp_packet *dhcppkt)
Get used length of DHCP packet.
Definition: dhcppkt.h:59
const char * name
Settings block name.
Definition: cachedhcp.c:46
uint8_t data[48]
Additional event data.
Definition: ena.h:22
Virtual LANs.
const char *(* ntoa)(const void *ll_addr)
Transcribe link-layer address.
Definition: netdevice.h:163
DHCP packets.
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition: malloc.c:606
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:475
struct cached_dhcp_packet cached_pxebs
Cached PXEBSACK.
Definition: cachedhcp.c:73
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:387
static unsigned int vlan_tag(struct net_device *netdev)
Get the VLAN tag.
Definition: vlan.h:73
struct settings * find_child_settings(struct settings *parent, const char *name)
Find child settings block.
Definition: settings.c:279
#define CACHEDHCP_USED
Cached DHCP packet has been used.
Definition: cachedhcp.c:59
static void cachedhcp_startup_late(void)
Cache DHCP packet late startup function.
Definition: cachedhcp.c:282
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
Definition: netdevice.h:381
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:372