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)
 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)
static

Calculate length of any DHCP option.

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

Definition at line 92 of file dhcpopts.c.

92 {
93 if ( ( option->tag == DHCP_END ) || ( option->tag == DHCP_PAD ) ) {
94 return 1;
95 } else {
96 return ( option->len + DHCP_OPTION_HEADER_LEN );
97 }
98}
#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 120 of file dhcpopts.c.

122 {
123 unsigned int original_tag __attribute__ (( unused )) = tag;
124 struct dhcp_option *option;
125 int offset = 0;
126 ssize_t remaining = options->used_len;
127 unsigned int option_len;
128
129 /* Sanity check */
130 if ( tag == DHCP_PAD )
131 return -ENOENT;
132
133 /* Search for option */
134 while ( remaining ) {
135 /* Calculate length of this option. Abort processing
136 * if the length is malformed (i.e. takes us beyond
137 * the end of the data block).
138 */
140 option_len = dhcp_option_len ( option );
141 remaining -= option_len;
142 if ( remaining < 0 )
143 break;
144 /* Check for explicit end marker */
145 if ( option->tag == DHCP_END ) {
146 if ( tag == DHCP_END )
147 /* Special case where the caller is interested
148 * in whether we have this marker or not.
149 */
150 return offset;
151 else
152 break;
153 }
154 /* Check for matching tag */
155 if ( option->tag == tag ) {
156 DBGC ( options, "DHCPOPT %p found %s (length %d)\n",
157 options, dhcp_tag_name ( original_tag ),
158 option_len );
159 return offset;
160 }
161 /* Check for start of matching encapsulation block */
162 if ( DHCP_IS_ENCAP_OPT ( tag ) &&
163 ( option->tag == DHCP_ENCAPSULATOR ( tag ) ) ) {
164 if ( encap_offset )
165 *encap_offset = offset;
166 /* Continue search within encapsulated option block */
168 remaining = option_len;
170 continue;
171 }
172 offset += option_len;
173 }
174
175 return -ENOENT;
176}
signed long ssize_t
Definition stdint.h:7
static unsigned int dhcp_option_len(struct dhcp_option *option)
Calculate length of any DHCP option.
Definition dhcpopts.c:92
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:505
#define ENOENT
No such file or directory.
Definition errno.h:515
#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 185 of file dhcpopts.c.

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

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 199 of file dhcpopts.c.

201 {
202 struct dhcp_option *encapsulator;
203 struct dhcp_option *option;
204 ssize_t delta = ( new_len - old_len );
205 size_t old_alloc_len;
206 size_t new_used_len;
207 size_t new_encapsulator_len;
208 void *source;
209 void *dest;
210 int rc;
211
212 /* Check for sufficient space */
213 if ( new_len > DHCP_MAX_LEN ) {
214 DBGC ( options, "DHCPOPT %p overlength option\n", options );
215 return -ENOSPC;
216 }
217 new_used_len = ( options->used_len + delta );
218
219 /* Expand options block, if necessary */
220 if ( new_used_len > options->alloc_len ) {
221 /* Reallocate options block */
222 old_alloc_len = options->alloc_len;
223 if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
224 DBGC ( options, "DHCPOPT %p could not reallocate to "
225 "%zd bytes\n", options, new_used_len );
226 return rc;
227 }
228 /* Clear newly allocated space */
229 memset ( ( options->data + old_alloc_len ), 0,
230 ( options->alloc_len - old_alloc_len ) );
231 }
232
233 /* Update encapsulator, if applicable */
234 if ( encap_offset >= 0 ) {
235 encapsulator = dhcp_option ( options, encap_offset );
236 new_encapsulator_len = ( encapsulator->len + delta );
237 if ( new_encapsulator_len > DHCP_MAX_LEN ) {
238 DBGC ( options, "DHCPOPT %p overlength encapsulator\n",
239 options );
240 return -ENOSPC;
241 }
242 encapsulator->len = new_encapsulator_len;
243 }
244
245 /* Update used length */
246 options->used_len = new_used_len;
247
248 /* Move remainder of option data */
250 source = ( ( ( void * ) option ) + old_len );
251 dest = ( ( ( void * ) option ) + new_len );
252 memmove ( dest, source, ( new_used_len - offset - new_len ) );
253
254 /* Shrink options block, if applicable */
255 if ( new_used_len < options->alloc_len ) {
256 if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
257 DBGC ( options, "DHCPOPT %p could not reallocate to "
258 "%zd bytes\n", options, new_used_len );
259 return rc;
260 }
261 }
262
263 return 0;
264}
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 283 of file dhcpopts.c.

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

360 {
361
362 return ( tag && ( tag <= DHCP_ENCAP_OPT ( DHCP_MAX_OPTION,
363 DHCP_MAX_OPTION ) ) );
364}
#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 375 of file dhcpopts.c.

376 {
377 int offset;
378
380 if ( offset < 0 )
381 return offset;
382 return 0;
383}

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 394 of file dhcpopts.c.

395 {
396 int offset;
397 struct dhcp_option *option;
398 size_t option_len;
399
401 if ( offset < 0 )
402 return offset;
403
405 option_len = option->len;
406 if ( len > option_len )
407 len = option_len;
408 memcpy ( data, option->data, len );
409
410 return option_len;
411}

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 421 of file dhcpopts.c.

421 {
422 struct dhcp_option *option;
423 int offset = 0;
424 ssize_t remaining = options->alloc_len;
425 unsigned int option_len;
426
427 /* Find last non-pad option */
428 options->used_len = 0;
429 while ( remaining ) {
431 option_len = dhcp_option_len ( option );
432 remaining -= option_len;
433 if ( remaining < 0 )
434 break;
435 offset += option_len;
436 if ( option->tag != DHCP_PAD )
437 options->used_len = offset;
438 }
439}

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 452 of file dhcpopts.c.

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

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

Referenced by dhcppkt_init(), and nvo_init().