iPXE
dhcpopts.c File Reference

DHCP options. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ipxe/dhcp.h>
#include <ipxe/dhcpopts.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 FILE_SECBOOT (PERMITTED)
static char * dhcp_tag_name (unsigned int tag)
 Obtain printable version of a DHCP option tag.
static struct dhcp_option * dhcp_option (struct dhcp_options *options, unsigned int offset)
 Get pointer to DHCP option.
static int dhcp_option_offset (struct dhcp_options *options, struct dhcp_option *option)
 Get offset of a DHCP option.
static unsigned int dhcp_option_len (struct dhcp_option *option, size_t remaining)
 Calculate length of any DHCP option.
static int find_dhcp_option_with_encap (struct dhcp_options *options, unsigned int tag, int *encap_offset)
 Find DHCP option within DHCP options block, and its encapsulator (if any).
int dhcpopt_no_realloc (struct dhcp_options *options, size_t len)
 Refuse to reallocate DHCP option block.
static int resize_dhcp_option (struct dhcp_options *options, int offset, int encap_offset, size_t old_len, size_t new_len)
 Resize a DHCP option.
static int set_dhcp_option (struct dhcp_options *options, unsigned int tag, const void *data, size_t len)
 Set value of DHCP option.
int dhcpopt_applies (unsigned int tag)
 Check applicability of DHCP option setting.
int dhcpopt_store (struct dhcp_options *options, unsigned int tag, const void *data, size_t len)
 Store value of DHCP option setting.
int dhcpopt_fetch (struct dhcp_options *options, unsigned int tag, void *data, size_t len)
 Fetch value of DHCP option setting.
void dhcpopt_update_used_len (struct dhcp_options *options)
 Recalculate length of DHCP options block.
void dhcpopt_init (struct dhcp_options *options, void *data, size_t alloc_len, int(*realloc)(struct dhcp_options *options, size_t len))
 Initialise prepopulated block of DHCP options.

Detailed Description

DHCP options.

Definition in file dhcpopts.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED )

◆ dhcp_tag_name()

char * dhcp_tag_name ( unsigned int tag)
inlinestatic

Obtain printable version of a DHCP option tag.

Parameters
tagDHCP option tag
Return values
nameString representation of the tag

Definition at line 48 of file dhcpopts.c.

48 {
49 static char name[8];
50
51 if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
52 snprintf ( name, sizeof ( name ), "%d.%d",
55 } else {
56 snprintf ( name, sizeof ( name ), "%d", tag );
57 }
58 return name;
59}
const char * name
Definition ath9k_hw.c:1986
uint64_t tag
Identity tag.
Definition edd.h:1
#define DHCP_ENCAPSULATOR(encap_opt)
Extract encapsulating option block tag from encapsulated tag value.
Definition dhcp.h:44
#define DHCP_IS_ENCAP_OPT(opt)
Option is encapsulated.
Definition dhcp.h:48
#define DHCP_ENCAPSULATED(encap_opt)
Extract encapsulated option tag from encapsulated tag value.
Definition dhcp.h:46
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383

References DHCP_ENCAPSULATED, DHCP_ENCAPSULATOR, DHCP_IS_ENCAP_OPT, name, snprintf(), and tag.

Referenced by find_dhcp_option_with_encap(), and set_dhcp_option().

◆ dhcp_option()

struct dhcp_option * dhcp_option ( struct dhcp_options * options,
unsigned int offset )
inlinestatic

Get pointer to DHCP option.

Parameters
optionsDHCP options block
offsetOffset within options block
Return values
optionDHCP option

Definition at line 69 of file dhcpopts.c.

69 {
70 return ( ( struct dhcp_option * ) ( options->data + offset ) );
71}
static int options
Definition 3c515.c:286
uint16_t offset
Offset to command line.
Definition bzimage.h:3
A DHCP option.
Definition dhcp.h:582

References offset, and options.

Referenced by dhcpopt_fetch(), dhcpopt_update_used_len(), find_dhcp_option_with_encap(), resize_dhcp_option(), and set_dhcp_option().

◆ dhcp_option_offset()

int dhcp_option_offset ( struct dhcp_options * options,
struct dhcp_option * option )
inlinestatic

Get offset of a DHCP option.

Parameters
optionsDHCP options block
optionDHCP option
Return values
offsetOffset within options block

Definition at line 81 of file dhcpopts.c.

82 {
83 return ( ( ( void * ) option ) - options->data );
84}
A long option, as used for getopt_long().
Definition getopt.h:25

References options.

◆ dhcp_option_len()

unsigned int dhcp_option_len ( struct dhcp_option * option,
size_t remaining )
static

Calculate length of any DHCP option.

Parameters
optionDHCP option
remainingRemaining space
Return values
lenLength (including tag and length field)

Definition at line 93 of file dhcpopts.c.

94 {
95 if ( ( option->tag == DHCP_END ) || ( option->tag == DHCP_PAD ) ||
96 ( remaining < DHCP_OPTION_HEADER_LEN ) ) {
97 return 1;
98 } else {
99 return ( option->len + DHCP_OPTION_HEADER_LEN );
100 }
101}
#define DHCP_PAD
Padding.
Definition dhcp.h:60
#define DHCP_END
End of options.
Definition dhcp.h:549
#define DHCP_OPTION_HEADER_LEN
Length of a DHCP option header.
Definition dhcp.h:607

References DHCP_END, DHCP_OPTION_HEADER_LEN, and DHCP_PAD.

Referenced by dhcpopt_update_used_len(), find_dhcp_option_with_encap(), and set_dhcp_option().

◆ find_dhcp_option_with_encap()

int find_dhcp_option_with_encap ( struct dhcp_options * options,
unsigned int tag,
int * encap_offset )
static

Find DHCP option within DHCP options block, and its encapsulator (if any).

Parameters
optionsDHCP options block
tagDHCP option tag to search for
Return values
encap_offsetOffset of encapsulating DHCP option
offsetOffset of DHCP option, or negative error

Searches for the DHCP option matching the specified tag within the DHCP option block. Encapsulated options may be searched for by using DHCP_ENCAP_OPT() to construct the tag value.

If the option is encapsulated, and encap_offset is non-NULL, it will be filled in with the offset of the encapsulating option.

This routine is designed to be paranoid. It does not assume that the option data is well-formatted, and so must guard against flaws such as options missing a DHCP_END terminator, or options whose length would take them beyond the end of the data block.

Definition at line 123 of file dhcpopts.c.

125 {
126 unsigned int original_tag __attribute__ (( unused )) = tag;
127 struct dhcp_option *option;
128 int offset = 0;
129 ssize_t remaining = options->used_len;
130 unsigned int option_len;
131
132 /* Sanity check */
133 if ( tag == DHCP_PAD )
134 return -ENOENT;
135
136 /* Search for option */
137 while ( remaining ) {
138 /* Calculate length of this option. Abort processing
139 * if the length is malformed (i.e. takes us beyond
140 * the end of the data block).
141 */
143 option_len = dhcp_option_len ( option, remaining );
144 remaining -= option_len;
145 if ( remaining < 0 )
146 break;
147 /* Check for explicit end marker */
148 if ( option->tag == DHCP_END ) {
149 if ( tag == DHCP_END )
150 /* Special case where the caller is interested
151 * in whether we have this marker or not.
152 */
153 return offset;
154 else
155 break;
156 }
157 /* Check for matching tag */
158 if ( option->tag == tag ) {
159 DBGC ( options, "DHCPOPT %p found %s (length %d)\n",
160 options, dhcp_tag_name ( original_tag ),
161 option_len );
162 return offset;
163 }
164 /* Check for start of matching encapsulation block */
165 if ( DHCP_IS_ENCAP_OPT ( tag ) &&
166 ( option->tag == DHCP_ENCAPSULATOR ( tag ) ) &&
167 ( option_len >= DHCP_OPTION_HEADER_LEN ) ) {
168 if ( encap_offset )
169 *encap_offset = offset;
170 /* Continue search within encapsulated option block */
172 remaining = ( option_len - DHCP_OPTION_HEADER_LEN );
174 continue;
175 }
176 offset += option_len;
177 }
178
179 return -ENOENT;
180}
signed long ssize_t
Definition stdint.h:7
static unsigned int dhcp_option_len(struct dhcp_option *option, size_t remaining)
Calculate length of any DHCP option.
Definition dhcpopts.c:93
static char * dhcp_tag_name(unsigned int tag)
Obtain printable version of a DHCP option tag.
Definition dhcpopts.c:48
static struct dhcp_option * dhcp_option(struct dhcp_options *options, unsigned int offset)
Get pointer to DHCP option.
Definition dhcpopts.c:69
#define DBGC(...)
Definition compiler.h:530
#define ENOENT
No such file or directory.
Definition errno.h:558
#define __attribute__(x)
Definition compiler.h:10
uint8_t unused
Unused.
Definition librm.h:5

References __attribute__, DBGC, DHCP_ENCAPSULATED, DHCP_ENCAPSULATOR, DHCP_END, DHCP_IS_ENCAP_OPT, dhcp_option(), DHCP_OPTION_HEADER_LEN, dhcp_option_len(), DHCP_PAD, dhcp_tag_name(), ENOENT, offset, options, tag, and unused.

Referenced by dhcpopt_fetch(), and set_dhcp_option().

◆ dhcpopt_no_realloc()

int dhcpopt_no_realloc ( struct dhcp_options * options,
size_t len )

Refuse to reallocate DHCP option block.

Parameters
optionsDHCP option block
lenNew length
Return values
rcReturn status code

Definition at line 189 of file dhcpopts.c.

189 {
190 return ( ( len <= options->alloc_len ) ? 0 : -ENOSPC );
191}
ring len
Length.
Definition dwmac.h:226
#define ENOSPC
No space left on device.
Definition errno.h:593

References ENOSPC, len, and options.

Referenced by dhcppkt_init(), and nvo_realloc_dhcpopt().

◆ resize_dhcp_option()

int resize_dhcp_option ( struct dhcp_options * options,
int offset,
int encap_offset,
size_t old_len,
size_t new_len )
static

Resize a DHCP option.

Parameters
optionsDHCP option block
offsetOffset of option to resize
encap_offsetOffset of encapsulating offset (or -ve for none)
old_lenOld length (including header)
new_lenNew length (including header)
Return values
rcReturn status code

Definition at line 203 of file dhcpopts.c.

205 {
206 struct dhcp_option *encapsulator;
207 struct dhcp_option *option;
208 ssize_t delta = ( new_len - old_len );
209 size_t old_alloc_len;
210 size_t new_used_len;
211 size_t new_encapsulator_len;
212 void *source;
213 void *dest;
214 int rc;
215
216 /* Check for sufficient space */
217 if ( new_len > DHCP_MAX_LEN ) {
218 DBGC ( options, "DHCPOPT %p overlength option\n", options );
219 return -ENOSPC;
220 }
221 new_used_len = ( options->used_len + delta );
222
223 /* Expand options block, if necessary */
224 if ( new_used_len > options->alloc_len ) {
225 /* Reallocate options block */
226 old_alloc_len = options->alloc_len;
227 if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
228 DBGC ( options, "DHCPOPT %p could not reallocate to "
229 "%zd bytes\n", options, new_used_len );
230 return rc;
231 }
232 /* Clear newly allocated space */
233 memset ( ( options->data + old_alloc_len ), 0,
234 ( options->alloc_len - old_alloc_len ) );
235 }
236
237 /* Update encapsulator, if applicable */
238 if ( encap_offset >= 0 ) {
239 encapsulator = dhcp_option ( options, encap_offset );
240 new_encapsulator_len = ( encapsulator->len + delta );
241 if ( new_encapsulator_len > DHCP_MAX_LEN ) {
242 DBGC ( options, "DHCPOPT %p overlength encapsulator\n",
243 options );
244 return -ENOSPC;
245 }
246 encapsulator->len = new_encapsulator_len;
247 }
248
249 /* Update used length */
250 options->used_len = new_used_len;
251
252 /* Move remainder of option data */
254 source = ( ( ( void * ) option ) + old_len );
255 dest = ( ( ( void * ) option ) + new_len );
256 memmove ( dest, source, ( new_used_len - offset - new_len ) );
257
258 /* Shrink options block, if applicable */
259 if ( new_used_len < options->alloc_len ) {
260 if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
261 DBGC ( options, "DHCPOPT %p could not reallocate to "
262 "%zd bytes\n", options, new_used_len );
263 return rc;
264 }
265 }
266
267 return 0;
268}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" retur dest)
Definition string.h:151
#define DHCP_MAX_LEN
Maximum length for a single DHCP option.
Definition dhcp.h:610
void * memset(void *dest, int character, size_t len) __nonnull
void * memmove(void *dest, const void *src, size_t len) __nonnull
uint8_t len
Length.
Definition dhcp.h:596

References DBGC, dest, DHCP_MAX_LEN, dhcp_option(), ENOSPC, dhcp_option::len, memmove(), memset(), offset, options, and rc.

Referenced by set_dhcp_option().

◆ set_dhcp_option()

int set_dhcp_option ( struct dhcp_options * options,
unsigned int tag,
const void * data,
size_t len )
static

Set value of DHCP option.

Parameters
optionsDHCP option block
tagDHCP option tag
dataNew value for DHCP option
lenLength of value, in bytes
Return values
offsetOffset of DHCP option, or negative error

Sets the value of a DHCP option within the options block. The option may or may not already exist. Encapsulators will be created (and deleted) as necessary.

This call may fail due to insufficient space in the options block. If it does fail, and the option existed previously, the option will be left with its original value.

Definition at line 287 of file dhcpopts.c.

288 {
289 static const uint8_t empty_encap[] = { DHCP_END };
290 int offset;
291 int encap_offset = -1;
292 int creation_offset;
293 struct dhcp_option *option;
294 unsigned int encap_tag = DHCP_ENCAPSULATOR ( tag );
295 size_t old_len = 0;
296 size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 );
297 int rc;
298
299 /* Sanity check */
300 if ( tag == DHCP_PAD )
301 return -ENOTTY;
302
303 creation_offset = find_dhcp_option_with_encap ( options, DHCP_END,
304 NULL );
305 if ( creation_offset < 0 )
306 creation_offset = options->used_len;
307 /* Find old instance of this option, if any */
308 offset = find_dhcp_option_with_encap ( options, tag, &encap_offset );
309 if ( offset >= 0 ) {
310 old_len = dhcp_option_len ( dhcp_option ( options, offset ),
311 ( options->used_len - offset ) );
312 DBGC ( options, "DHCPOPT %p resizing %s from %zd to %zd\n",
313 options, dhcp_tag_name ( tag ), old_len, new_len );
314 } else {
315 DBGC ( options, "DHCPOPT %p creating %s (length %zd)\n",
316 options, dhcp_tag_name ( tag ), new_len );
317 }
318
319 /* Ensure that encapsulator exists, if required */
320 if ( encap_tag ) {
321 if ( encap_offset < 0 ) {
322 encap_offset =
323 set_dhcp_option ( options, encap_tag,
324 empty_encap,
325 sizeof ( empty_encap ) );
326 }
327 if ( encap_offset < 0 )
328 return encap_offset;
329 creation_offset = ( encap_offset + DHCP_OPTION_HEADER_LEN );
330 }
331
332 /* Create new option if necessary */
333 if ( offset < 0 )
334 offset = creation_offset;
335
336 /* Resize option to fit new data */
337 if ( ( rc = resize_dhcp_option ( options, offset, encap_offset,
338 old_len, new_len ) ) != 0 )
339 return rc;
340
341 /* Copy new data into option, if applicable */
342 if ( len ) {
344 option->tag = tag;
345 option->len = len;
346 memcpy ( &option->data, data, len );
347 }
348
349 /* Delete encapsulator if there's nothing else left in it */
350 if ( encap_offset >= 0 ) {
351 option = dhcp_option ( options, encap_offset );
352 if ( option->len <= 1 )
353 set_dhcp_option ( options, encap_tag, NULL, 0 );
354 }
355
356 return offset;
357}
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
unsigned char uint8_t
Definition stdint.h:10
static int set_dhcp_option(struct dhcp_options *options, unsigned int tag, const void *data, size_t len)
Set value of DHCP option.
Definition dhcpopts.c:287
static int find_dhcp_option_with_encap(struct dhcp_options *options, unsigned int tag, int *encap_offset)
Find DHCP option within DHCP options block, and its encapsulator (if any).
Definition dhcpopts.c:123
static int resize_dhcp_option(struct dhcp_options *options, int offset, int encap_offset, size_t old_len, size_t new_len)
Resize a DHCP option.
Definition dhcpopts.c:203
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:638
void * memcpy(void *dest, const void *src, size_t len) __nonnull

References data, DBGC, DHCP_ENCAPSULATOR, DHCP_END, dhcp_option(), DHCP_OPTION_HEADER_LEN, dhcp_option_len(), DHCP_PAD, dhcp_tag_name(), ENOTTY, find_dhcp_option_with_encap(), len, memcpy(), NULL, offset, options, rc, resize_dhcp_option(), set_dhcp_option(), and tag.

Referenced by dhcpopt_store(), and set_dhcp_option().

◆ dhcpopt_applies()

int dhcpopt_applies ( unsigned int tag)

Check applicability of DHCP option setting.

Parameters
tagSetting tag number
Return values
appliesSetting applies to this option block

Definition at line 365 of file dhcpopts.c.

365 {
366
367 return ( tag && ( tag <= DHCP_ENCAP_OPT ( DHCP_MAX_OPTION,
368 DHCP_MAX_OPTION ) ) );
369}
#define DHCP_MAX_OPTION
Maximum normal DHCP option.
Definition dhcp.h:542
#define DHCP_ENCAP_OPT(encapsulator, encapsulated)
Construct a tag value for an encapsulated option.
Definition dhcp.h:41

References DHCP_ENCAP_OPT, DHCP_MAX_OPTION, and tag.

Referenced by dhcppkt_applies(), and nvo_applies().

◆ dhcpopt_store()

int dhcpopt_store ( struct dhcp_options * options,
unsigned int tag,
const void * data,
size_t len )

Store value of DHCP option setting.

Parameters
optionsDHCP option block
tagSetting tag number
dataSetting data, or NULL to clear setting
lenLength of setting data
Return values
rcReturn status code

Definition at line 380 of file dhcpopts.c.

381 {
382 int offset;
383
385 if ( offset < 0 )
386 return offset;
387 return 0;
388}

References data, len, offset, options, set_dhcp_option(), and tag.

Referenced by dhcppkt_store(), and nvo_store().

◆ dhcpopt_fetch()

int dhcpopt_fetch ( struct dhcp_options * options,
unsigned int tag,
void * data,
size_t len )

Fetch value of DHCP option setting.

Parameters
optionsDHCP option block
tagSetting tag number
dataBuffer to fill with setting data
lenLength of buffer
Return values
lenLength of setting data, or negative error

Definition at line 399 of file dhcpopts.c.

400 {
401 int offset;
402 struct dhcp_option *option;
403 size_t option_len;
404
406 if ( offset < 0 )
407 return offset;
408
410 option_len = option->len;
411 if ( len > option_len )
412 len = option_len;
413 memcpy ( data, option->data, len );
414
415 return option_len;
416}

References data, dhcp_option(), find_dhcp_option_with_encap(), len, memcpy(), NULL, offset, options, and tag.

Referenced by dhcppkt_fetch(), and nvo_fetch().

◆ dhcpopt_update_used_len()

void dhcpopt_update_used_len ( struct dhcp_options * options)

Recalculate length of DHCP options block.

Parameters
optionsUninitialised DHCP option block

The "used length" field will be updated based on scanning through the block to find the end of the options.

Definition at line 426 of file dhcpopts.c.

426 {
427 struct dhcp_option *option;
428 int offset = 0;
429 ssize_t remaining = options->alloc_len;
430 unsigned int option_len;
431
432 /* Find last non-pad option */
433 options->used_len = 0;
434 while ( remaining ) {
436 option_len = dhcp_option_len ( option, remaining );
437 remaining -= option_len;
438 if ( remaining < 0 )
439 break;
440 offset += option_len;
441 if ( option->tag != DHCP_PAD )
442 options->used_len = offset;
443 }
444}

References dhcp_option(), dhcp_option_len(), DHCP_PAD, offset, and options.

Referenced by dhcpopt_init(), and nvo_load().

◆ dhcpopt_init()

void dhcpopt_init ( struct dhcp_options * options,
void * data,
size_t alloc_len,
int(* realloc )(struct dhcp_options *options, size_t len) )

Initialise prepopulated block of DHCP options.

Parameters
optionsUninitialised DHCP option block
dataMemory for DHCP option data
alloc_lenLength of memory for DHCP option data
reallocDHCP option block reallocator

The memory content must already be filled with valid DHCP options. A zeroed block counts as a block of valid DHCP options.

Definition at line 457 of file dhcpopts.c.

459 {
460
461 /* Fill in fields */
462 options->data = data;
463 options->alloc_len = alloc_len;
464 options->realloc = realloc;
465
466 /* Update length */
468
469 DBGC ( options, "DHCPOPT %p created (data %p lengths %#zx,%#zx)\n",
470 options, options->data, options->used_len, options->alloc_len );
471}
void dhcpopt_update_used_len(struct dhcp_options *options)
Recalculate length of DHCP options block.
Definition dhcpopts.c:426
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition malloc.c:663

References data, DBGC, dhcpopt_update_used_len(), len, options, and realloc().

Referenced by dhcppkt_init(), and nvo_init().