iPXE
dhcppkt.c
Go to the documentation of this file.
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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdint.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <errno.h>
31#include <string.h>
32#include <ipxe/netdevice.h>
33#include <ipxe/dhcp.h>
34#include <ipxe/dhcpopts.h>
35#include <ipxe/dhcppkt.h>
36
37/** @file
38 *
39 * DHCP packets
40 *
41 */
42
43/****************************************************************************
44 *
45 * DHCP packet raw interface
46 *
47 */
48
49/**
50 * Calculate used length of an IPv4 field within a DHCP packet
51 *
52 * @v data Field data
53 * @v len Length of field
54 * @ret used Used length of field
55 */
56static size_t used_len_ipv4 ( const void *data, size_t len __unused ) {
57 const struct in_addr *in = data;
58
59 return ( in->s_addr ? sizeof ( *in ) : 0 );
60}
61
62/**
63 * Calculate used length of a string field within a DHCP packet
64 *
65 * @v data Field data
66 * @v len Length of field
67 * @ret used Used length of field
68 */
69static size_t used_len_string ( const void *data, size_t len ) {
70 return strnlen ( data, len );
71}
72
73/** A dedicated field within a DHCP packet */
75 /** Settings tag number */
76 unsigned int tag;
77 /** Offset within DHCP packet */
79 /** Length of field */
81 /** Calculate used length of field
82 *
83 * @v data Field data
84 * @v len Length of field
85 * @ret used Used length of field
86 */
87 size_t ( * used_len ) ( const void *data, size_t len );
88};
89
90/** Declare a dedicated field within a DHCP packet
91 *
92 * @v _tag Settings tag number
93 * @v _field Field name
94 * @v _used_len Function to calculate used length of field
95 */
96#define DHCP_PACKET_FIELD( _tag, _field, _used_len ) { \
97 .tag = (_tag), \
98 .offset = offsetof ( struct dhcphdr, _field ), \
99 .len = sizeof ( ( ( struct dhcphdr * ) 0 )->_field ), \
100 .used_len = _used_len, \
101 }
102
103/** Dedicated fields within a DHCP packet */
110
111/**
112 * Get address of a DHCP packet field
113 *
114 * @v dhcphdr DHCP packet header
115 * @v field DHCP packet field
116 * @ret data Packet field data
117 */
118static inline void * dhcp_packet_field ( struct dhcphdr *dhcphdr,
119 struct dhcp_packet_field *field ) {
120 return ( ( ( void * ) dhcphdr ) + field->offset );
121}
122
123/**
124 * Find DHCP packet field corresponding to settings tag number
125 *
126 * @v tag Settings tag number
127 * @ret field DHCP packet field, or NULL
128 */
129static struct dhcp_packet_field *
130find_dhcp_packet_field ( unsigned int tag ) {
131 struct dhcp_packet_field *field;
132 unsigned int i;
133
134 for ( i = 0 ; i < ( sizeof ( dhcp_packet_fields ) /
135 sizeof ( dhcp_packet_fields[0] ) ) ; i++ ) {
136 field = &dhcp_packet_fields[i];
137 if ( field->tag == tag )
138 return field;
139 }
140 return NULL;
141}
142
143/**
144 * Check applicability of DHCP setting
145 *
146 * @v dhcppkt DHCP packet
147 * @v tag Setting tag number
148 * @ret applies Setting applies within this settings block
149 */
150static int dhcppkt_applies ( struct dhcp_packet *dhcppkt __unused,
151 unsigned int tag ) {
152
153 return dhcpopt_applies ( tag );
154}
155
156/**
157 * Store value of DHCP packet setting
158 *
159 * @v dhcppkt DHCP packet
160 * @v tag Setting tag number
161 * @v data Setting data, or NULL to clear setting
162 * @v len Length of setting data
163 * @ret rc Return status code
164 */
165int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
166 const void *data, size_t len ) {
167 struct dhcp_packet_field *field;
168 void *field_data;
169
170 /* If this is a special field, fill it in */
171 if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
172 if ( len > field->len )
173 return -ENOSPC;
174 field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
175 memset ( field_data, 0, field->len );
176 memcpy ( dhcp_packet_field ( dhcppkt->dhcphdr, field ),
177 data, len );
178 /* Erase any equivalent option from the options block */
179 dhcpopt_store ( &dhcppkt->options, tag, NULL, 0 );
180 return 0;
181 }
182
183 /* Otherwise, use the generic options block */
184 return dhcpopt_store ( &dhcppkt->options, tag, data, len );
185}
186
187/**
188 * Fetch value of DHCP packet setting
189 *
190 * @v dhcppkt DHCP packet
191 * @v tag Setting tag number
192 * @v data Buffer to fill with setting data
193 * @v len Length of buffer
194 * @ret len Length of setting data, or negative error
195 */
196int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
197 void *data, size_t len ) {
198 struct dhcp_packet_field *field;
199 void *field_data;
200 size_t field_len = 0;
201
202 /* Identify special field, if any */
203 if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
204 field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
205 field_len = field->used_len ( field_data, field->len );
206 }
207
208 /* Return special field, if it exists and is populated */
209 if ( field_len ) {
210 if ( len > field_len )
211 len = field_len;
212 memcpy ( data, field_data, len );
213 return field_len;
214 }
215
216 /* Otherwise, use the generic options block */
217 return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
218}
219
220/****************************************************************************
221 *
222 * DHCP packet settings interface
223 *
224 */
225
226/**
227 * Check applicability of DHCP setting
228 *
229 * @v settings Settings block
230 * @v setting Setting
231 * @ret applies Setting applies within this settings block
232 */
234 const struct setting *setting ) {
235 struct dhcp_packet *dhcppkt =
237
238 return ( ( setting->scope == NULL ) &&
239 dhcppkt_applies ( dhcppkt, setting->tag ) );
240}
241
242/**
243 * Store value of DHCP setting
244 *
245 * @v settings Settings block
246 * @v setting Setting to store
247 * @v data Setting data, or NULL to clear setting
248 * @v len Length of setting data
249 * @ret rc Return status code
250 */
252 const struct setting *setting,
253 const void *data, size_t len ) {
254 struct dhcp_packet *dhcppkt =
256
257 return dhcppkt_store ( dhcppkt, setting->tag, data, len );
258}
259
260/**
261 * Fetch value of DHCP setting
262 *
263 * @v settings Settings block, or NULL to search all blocks
264 * @v setting Setting to fetch
265 * @v data Buffer to fill with setting data
266 * @v len Length of buffer
267 * @ret len Length of setting data, or negative error
268 */
270 struct setting *setting,
271 void *data, size_t len ) {
272 struct dhcp_packet *dhcppkt =
274
275 return dhcppkt_fetch ( dhcppkt, setting->tag, data, len );
276}
277
278/** DHCP settings operations */
284
285/****************************************************************************
286 *
287 * Constructor
288 *
289 */
290
291/**
292 * Initialise DHCP packet
293 *
294 * @v dhcppkt DHCP packet structure to fill in
295 * @v data DHCP packet raw data
296 * @v max_len Length of raw data buffer
297 *
298 * Initialise a DHCP packet structure from a data buffer containing a
299 * DHCP packet.
300 */
301void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
302 size_t len ) {
303 ref_init ( &dhcppkt->refcnt, NULL );
304 dhcppkt->dhcphdr = data;
305 dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
306 ( len - offsetof ( struct dhcphdr, options ) ),
309 &dhcppkt->refcnt, NULL );
310}
static int options
Definition 3c515.c:286
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
__be32 in[4]
Definition CIB_PRM.h:7
unsigned short uint16_t
Definition stdint.h:11
__SIZE_TYPE__ size_t
Definition stdint.h:6
int dhcpopt_no_realloc(struct dhcp_options *options, size_t len)
Refuse to reallocate DHCP option block.
Definition dhcpopts.c:185
int dhcpopt_applies(unsigned int tag)
Check applicability of DHCP option setting.
Definition dhcpopts.c:360
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.
Definition dhcpopts.c:452
int dhcpopt_fetch(struct dhcp_options *options, unsigned int tag, void *data, size_t len)
Fetch value of DHCP option setting.
Definition dhcpopts.c:394
int dhcpopt_store(struct dhcp_options *options, unsigned int tag, const void *data, size_t len)
Store value of DHCP option setting.
Definition dhcpopts.c:375
DHCP options.
static struct settings_operations dhcppkt_settings_operations
DHCP settings operations.
Definition dhcppkt.c:279
static int dhcppkt_applies(struct dhcp_packet *dhcppkt __unused, unsigned int tag)
Check applicability of DHCP setting.
Definition dhcppkt.c:150
static int dhcppkt_settings_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of DHCP setting.
Definition dhcppkt.c:269
static struct dhcp_packet_field * find_dhcp_packet_field(unsigned int tag)
Find DHCP packet field corresponding to settings tag number.
Definition dhcppkt.c:130
void dhcppkt_init(struct dhcp_packet *dhcppkt, struct dhcphdr *data, size_t len)
Initialise DHCP packet.
Definition dhcppkt.c:301
int dhcppkt_store(struct dhcp_packet *dhcppkt, unsigned int tag, const void *data, size_t len)
Store value of DHCP packet setting.
Definition dhcppkt.c:165
int dhcppkt_fetch(struct dhcp_packet *dhcppkt, unsigned int tag, void *data, size_t len)
Fetch value of DHCP packet setting.
Definition dhcppkt.c:196
static size_t used_len_string(const void *data, size_t len)
Calculate used length of a string field within a DHCP packet.
Definition dhcppkt.c:69
static size_t used_len_ipv4(const void *data, size_t len __unused)
Calculate used length of an IPv4 field within a DHCP packet.
Definition dhcppkt.c:56
static int dhcppkt_settings_applies(struct settings *settings, const struct setting *setting)
Check applicability of DHCP setting.
Definition dhcppkt.c:233
static struct dhcp_packet_field dhcp_packet_fields[]
Dedicated fields within a DHCP packet.
Definition dhcppkt.c:104
#define DHCP_PACKET_FIELD(_tag, _field, _used_len)
Declare a dedicated field within a DHCP packet.
Definition dhcppkt.c:96
static int dhcppkt_settings_store(struct settings *settings, const struct setting *setting, const void *data, size_t len)
Store value of DHCP setting.
Definition dhcppkt.c:251
static void * dhcp_packet_field(struct dhcphdr *dhcphdr, struct dhcp_packet_field *field)
Get address of a DHCP packet field.
Definition dhcppkt.c:118
DHCP packets.
ring len
Length.
Definition dwmac.h:226
uint64_t tag
Identity tag.
Definition edd.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DHCP_EB_SIADDR
"Server" IP address
Definition dhcp.h:382
#define DHCP_EB_YIADDR
"Your" IP address
Definition dhcp.h:374
#define DHCP_BOOTFILE_NAME
Bootfile name.
Definition dhcp.h:265
#define DHCP_TFTP_SERVER_NAME
TFTP server name.
Definition dhcp.h:258
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOSPC
No space left on device.
Definition errno.h:550
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Dynamic Host Configuration Protocol.
static void settings_init(struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, const struct settings_scope *default_scope)
Initialise a settings block.
Definition settings.h:503
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
Network device management.
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
size_t strnlen(const char *src, size_t max)
Get length of string.
Definition string.c:256
A dedicated field within a DHCP packet.
Definition dhcppkt.c:74
size_t(* used_len)(const void *data, size_t len)
Calculate used length of field.
Definition dhcppkt.c:87
uint16_t len
Length of field.
Definition dhcppkt.c:80
uint16_t offset
Offset within DHCP packet.
Definition dhcppkt.c:78
unsigned int tag
Settings tag number.
Definition dhcppkt.c:76
A DHCP packet.
Definition dhcppkt.h:21
struct refcnt refcnt
Reference counter.
Definition dhcppkt.h:23
struct settings settings
Settings interface.
Definition dhcppkt.h:29
struct dhcphdr * dhcphdr
The DHCP packet contents.
Definition dhcppkt.h:25
struct dhcp_options options
DHCP options.
Definition dhcppkt.h:27
A DHCP header.
Definition dhcp.h:616
uint8_t options[0]
DHCP options.
Definition dhcp.h:684
IP address structure.
Definition in.h:42
A setting.
Definition settings.h:24
const struct settings_scope * scope
Setting scope (or NULL)
Definition settings.h:50
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
Settings block operations.
Definition settings.h:86
A settings block.
Definition settings.h:133