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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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  */
56 static 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  */
69 static 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 */
109 };
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  */
118 static 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  */
129 static struct dhcp_packet_field *
130 find_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  */
150 static 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  */
165 int 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  */
196 int 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 */
281  .store = dhcppkt_settings_store,
282  .fetch = dhcppkt_settings_fetch,
283 };
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  */
301 void 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 dhcppkt_applies(struct dhcp_packet *dhcppkt __unused, unsigned int tag)
Check applicability of DHCP setting.
Definition: dhcppkt.c:150
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
unsigned short uint16_t
Definition: stdint.h:11
A DHCP packet.
Definition: dhcppkt.h:21
Dynamic Host Configuration Protocol.
struct refcnt refcnt
Reference counter.
Definition: dhcppkt.h:23
__be32 in[4]
Definition: CIB_PRM.h:35
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
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:65
Error codes.
__SIZE_TYPE__ size_t
Definition: stdint.h:6
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
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
uint8_t options[0]
DHCP options.
Definition: dhcp.h:684
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:25
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
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
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
#define DHCP_PACKET_FIELD(_tag, _field, _used_len)
Declare a dedicated field within a DHCP packet.
Definition: dhcppkt.c:96
struct dhcp_options options
DHCP options.
Definition: dhcppkt.h:27
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
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
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static void * dhcp_packet_field(struct dhcphdr *dhcphdr, struct dhcp_packet_field *field)
Get address of a DHCP packet field.
Definition: dhcppkt.c:118
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
static int options
Definition: 3c515.c:286
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
ring len
Length.
Definition: dwmac.h:231
IP address structure.
Definition: in.h:42
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
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
Settings block operations.
Definition: settings.h:86
A settings block.
Definition: settings.h:133
size_t strnlen(const char *src, size_t max)
Get length of string.
Definition: string.c:256
DHCP options.
A setting.
Definition: settings.h:24
struct settings settings
Settings interface.
Definition: dhcppkt.h:29
int dhcpopt_no_realloc(struct dhcp_options *options, size_t len)
Refuse to reallocate DHCP option block.
Definition: dhcpopts.c:185
A DHCP header.
Definition: dhcp.h:616
Network device management.
void dhcppkt_init(struct dhcp_packet *dhcppkt, struct dhcphdr *data, size_t len)
Initialise DHCP packet.
Definition: dhcppkt.c:301
#define ENOSPC
No space left on device.
Definition: errno.h:550
struct dhcphdr * dhcphdr
The DHCP packet contents.
Definition: dhcppkt.h:25
static struct settings_operations dhcppkt_settings_operations
DHCP settings operations.
Definition: dhcppkt.c:279
#define DHCP_EB_SIADDR
"Server" IP address
Definition: dhcp.h:382
#define DHCP_EB_YIADDR
"Your" IP address
Definition: dhcp.h:374
uint8_t data[48]
Additional event data.
Definition: ena.h:22
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
#define DHCP_BOOTFILE_NAME
Bootfile name.
Definition: dhcp.h:265
DHCP packets.
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
size_t(* used_len)(const void *data, size_t len)
Calculate used length of field.
Definition: dhcppkt.c:87
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
uint16_t offset
Offset within DHCP packet.
Definition: dhcppkt.c:78
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
A dedicated field within a DHCP packet.
Definition: dhcppkt.c:74
unsigned int tag
Settings tag number.
Definition: dhcppkt.c:76
#define DHCP_TFTP_SERVER_NAME
TFTP server name.
Definition: dhcp.h:258
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
uint64_t tag
Identity tag.
Definition: edd.h:31
uint16_t len
Length of field.
Definition: dhcppkt.c:80
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
int dhcpopt_applies(unsigned int tag)
Check applicability of DHCP option setting.
Definition: dhcpopts.c:360
String functions.
FILE_SECBOOT(PERMITTED)
void * memset(void *dest, int character, size_t len) __nonnull