Browse Source

[dhcp] Allow use of custom reallocation functions for DHCP option blocks

Allow functions other than realloc() to be used to reallocate DHCP
option block data, and specify the reallocation function at the time
of calling dhcpopt_init().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
17b6a3c506
4 changed files with 74 additions and 62 deletions
  1. 2
    1
      src/core/nvo.c
  2. 11
    4
      src/include/ipxe/dhcpopts.h
  3. 59
    56
      src/net/dhcpopts.c
  4. 2
    1
      src/net/dhcppkt.c

+ 2
- 1
src/core/nvo.c View File

133
 		memset ( nvo->data, 0, nvo->total_len );
133
 		memset ( nvo->data, 0, nvo->total_len );
134
 	}
134
 	}
135
 
135
 
136
-	dhcpopt_init ( &nvo->dhcpopts, options_data, options_len );
136
+	dhcpopt_init ( &nvo->dhcpopts, options_data, options_len,
137
+		       dhcpopt_no_realloc );
137
 }
138
 }
138
 
139
 
139
 /**
140
 /**

+ 11
- 4
src/include/ipxe/dhcpopts.h View File

19
 	size_t used_len;
19
 	size_t used_len;
20
 	/** Option block allocated length */
20
 	/** Option block allocated length */
21
 	size_t alloc_len;
21
 	size_t alloc_len;
22
+	/** Reallocate option block raw data
23
+	 *
24
+	 * @v options		DHCP option block
25
+	 * @v len		New length
26
+	 * @ret rc		Return status code
27
+	 */
28
+	int ( * realloc ) ( struct dhcp_options *options, size_t len );
22
 };
29
 };
23
 
30
 
24
 extern int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
31
 extern int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
25
 			   const void *data, size_t len );
32
 			   const void *data, size_t len );
26
-extern int dhcpopt_extensible_store ( struct dhcp_options *options,
27
-				      unsigned int tag,
28
-				      const void *data, size_t len );
29
 extern int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
33
 extern int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
30
 			   void *data, size_t len );
34
 			   void *data, size_t len );
31
 extern void dhcpopt_init ( struct dhcp_options *options,
35
 extern void dhcpopt_init ( struct dhcp_options *options,
32
-			   void *data, size_t alloc_len );
36
+			   void *data, size_t alloc_len,
37
+			   int ( * realloc ) ( struct dhcp_options *options,
38
+					       size_t len ) );
39
+extern int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len );
33
 
40
 
34
 #endif /* _IPXE_DHCPOPTS_H */
41
 #endif /* _IPXE_DHCPOPTS_H */

+ 59
- 56
src/net/dhcpopts.c View File

169
 	return -ENOENT;
169
 	return -ENOENT;
170
 }
170
 }
171
 
171
 
172
+/**
173
+ * Refuse to reallocate DHCP option block
174
+ *
175
+ * @v options		DHCP option block
176
+ * @v len		New length
177
+ * @ret rc		Return status code
178
+ */
179
+int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len ) {
180
+	return ( ( len <= options->alloc_len ) ? 0 : -ENOSPC );
181
+}
182
+
172
 /**
183
 /**
173
  * Resize a DHCP option
184
  * Resize a DHCP option
174
  *
185
  *
177
  * @v encap_offset	Offset of encapsulating offset (or -ve for none)
188
  * @v encap_offset	Offset of encapsulating offset (or -ve for none)
178
  * @v old_len		Old length (including header)
189
  * @v old_len		Old length (including header)
179
  * @v new_len		New length (including header)
190
  * @v new_len		New length (including header)
180
- * @v can_realloc	Can reallocate options data if necessary
181
  * @ret rc		Return status code
191
  * @ret rc		Return status code
182
  */
192
  */
183
 static int resize_dhcp_option ( struct dhcp_options *options,
193
 static int resize_dhcp_option ( struct dhcp_options *options,
184
 				int offset, int encap_offset,
194
 				int offset, int encap_offset,
185
-				size_t old_len, size_t new_len,
186
-				int can_realloc ) {
195
+				size_t old_len, size_t new_len ) {
187
 	struct dhcp_option *encapsulator;
196
 	struct dhcp_option *encapsulator;
188
 	struct dhcp_option *option;
197
 	struct dhcp_option *option;
189
 	ssize_t delta = ( new_len - old_len );
198
 	ssize_t delta = ( new_len - old_len );
190
-	size_t new_options_len;
199
+	size_t old_alloc_len;
200
+	size_t new_used_len;
191
 	size_t new_encapsulator_len;
201
 	size_t new_encapsulator_len;
192
-	void *new_data;
193
 	void *source;
202
 	void *source;
194
 	void *dest;
203
 	void *dest;
195
 	void *end;
204
 	void *end;
205
+	int rc;
196
 
206
 
197
-	/* Check for sufficient space, and update length fields */
207
+	/* Check for sufficient space */
198
 	if ( new_len > DHCP_MAX_LEN ) {
208
 	if ( new_len > DHCP_MAX_LEN ) {
199
 		DBGC ( options, "DHCPOPT %p overlength option\n", options );
209
 		DBGC ( options, "DHCPOPT %p overlength option\n", options );
200
 		return -ENOSPC;
210
 		return -ENOSPC;
201
 	}
211
 	}
202
-	new_options_len = ( options->used_len + delta );
203
-	if ( new_options_len > options->alloc_len ) {
204
-		/* Reallocate options block if allowed to do so. */
205
-		if ( can_realloc ) {
206
-			new_data = realloc ( options->data, new_options_len );
207
-			if ( ! new_data ) {
208
-				DBGC ( options, "DHCPOPT %p could not "
209
-				       "reallocate to %zd bytes\n", options,
210
-				       new_options_len );
211
-				return -ENOMEM;
212
-			}
213
-			options->data = new_data;
214
-			options->alloc_len = new_options_len;
215
-		} else {
216
-			DBGC ( options, "DHCPOPT %p out of space\n", options );
217
-			return -ENOMEM;
212
+	new_used_len = ( options->used_len + delta );
213
+
214
+	/* Expand options block, if necessary */
215
+	if ( new_used_len > options->alloc_len ) {
216
+		/* Reallocate options block */
217
+		old_alloc_len = options->alloc_len;
218
+		if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
219
+			DBGC ( options, "DHCPOPT %p could not reallocate to "
220
+			       "%zd bytes\n", options, new_used_len );
221
+			return rc;
218
 		}
222
 		}
223
+		/* Clear newly allocated space */
224
+		memset ( ( options->data + old_alloc_len ), 0,
225
+			 ( options->alloc_len - old_alloc_len ) );
219
 	}
226
 	}
227
+
228
+	/* Update encapsulator, if applicable */
220
 	if ( encap_offset >= 0 ) {
229
 	if ( encap_offset >= 0 ) {
221
 		encapsulator = dhcp_option ( options, encap_offset );
230
 		encapsulator = dhcp_option ( options, encap_offset );
222
 		new_encapsulator_len = ( encapsulator->len + delta );
231
 		new_encapsulator_len = ( encapsulator->len + delta );
227
 		}
236
 		}
228
 		encapsulator->len = new_encapsulator_len;
237
 		encapsulator->len = new_encapsulator_len;
229
 	}
238
 	}
230
-	options->used_len = new_options_len;
239
+
240
+	/* Update used length */
241
+	options->used_len = new_used_len;
231
 
242
 
232
 	/* Move remainder of option data */
243
 	/* Move remainder of option data */
233
 	option = dhcp_option ( options, offset );
244
 	option = dhcp_option ( options, offset );
236
 	end = ( options->data + options->alloc_len );
247
 	end = ( options->data + options->alloc_len );
237
 	memmove ( dest, source, ( end - dest ) );
248
 	memmove ( dest, source, ( end - dest ) );
238
 
249
 
250
+	/* Shrink options block, if applicable */
251
+	if ( new_used_len < options->alloc_len ) {
252
+		if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
253
+			DBGC ( options, "DHCPOPT %p could not reallocate to "
254
+			       "%zd bytes\n", options, new_used_len );
255
+			return rc;
256
+		}
257
+	}
258
+
239
 	return 0;
259
 	return 0;
240
 }
260
 }
241
 
261
 
246
  * @v tag		DHCP option tag
266
  * @v tag		DHCP option tag
247
  * @v data		New value for DHCP option
267
  * @v data		New value for DHCP option
248
  * @v len		Length of value, in bytes
268
  * @v len		Length of value, in bytes
249
- * @v can_realloc	Can reallocate options data if necessary
250
  * @ret offset		Offset of DHCP option, or negative error
269
  * @ret offset		Offset of DHCP option, or negative error
251
  *
270
  *
252
  * Sets the value of a DHCP option within the options block.  The
271
  * Sets the value of a DHCP option within the options block.  The
258
  * be left with its original value.
277
  * be left with its original value.
259
  */
278
  */
260
 static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
279
 static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
261
-			     const void *data, size_t len,
262
-			     int can_realloc ) {
263
-	static const uint8_t empty_encapsulator[] = { DHCP_END };
280
+			     const void *data, size_t len ) {
281
+	static const uint8_t empty_encap[] = { DHCP_END };
264
 	int offset;
282
 	int offset;
265
 	int encap_offset = -1;
283
 	int encap_offset = -1;
266
 	int creation_offset;
284
 	int creation_offset;
291
 
309
 
292
 	/* Ensure that encapsulator exists, if required */
310
 	/* Ensure that encapsulator exists, if required */
293
 	if ( encap_tag ) {
311
 	if ( encap_tag ) {
294
-		if ( encap_offset < 0 )
295
-			encap_offset = set_dhcp_option ( options, encap_tag,
296
-							 empty_encapsulator, 1,
297
-							 can_realloc );
312
+		if ( encap_offset < 0 ) {
313
+			encap_offset =
314
+				set_dhcp_option ( options, encap_tag,
315
+						  empty_encap,
316
+						  sizeof ( empty_encap ) );
317
+		}
298
 		if ( encap_offset < 0 )
318
 		if ( encap_offset < 0 )
299
 			return encap_offset;
319
 			return encap_offset;
300
 		creation_offset = ( encap_offset + DHCP_OPTION_HEADER_LEN );
320
 		creation_offset = ( encap_offset + DHCP_OPTION_HEADER_LEN );
306
 
326
 
307
 	/* Resize option to fit new data */
327
 	/* Resize option to fit new data */
308
 	if ( ( rc = resize_dhcp_option ( options, offset, encap_offset,
328
 	if ( ( rc = resize_dhcp_option ( options, offset, encap_offset,
309
-					 old_len, new_len,
310
-					 can_realloc ) ) != 0 )
329
+					 old_len, new_len ) ) != 0 )
311
 		return rc;
330
 		return rc;
312
 
331
 
313
 	/* Copy new data into option, if applicable */
332
 	/* Copy new data into option, if applicable */
322
 	if ( encap_offset >= 0 ) {
341
 	if ( encap_offset >= 0 ) {
323
 		option = dhcp_option ( options, encap_offset );
342
 		option = dhcp_option ( options, encap_offset );
324
 		if ( option->len <= 1 )
343
 		if ( option->len <= 1 )
325
-			set_dhcp_option ( options, encap_tag, NULL, 0, 0 );
344
+			set_dhcp_option ( options, encap_tag, NULL, 0 );
326
 	}
345
 	}
327
 
346
 
328
 	return offset;
347
 	return offset;
341
 		    const void *data, size_t len ) {
360
 		    const void *data, size_t len ) {
342
 	int offset;
361
 	int offset;
343
 
362
 
344
-	offset = set_dhcp_option ( options, tag, data, len, 0 );
345
-	if ( offset < 0 )
346
-		return offset;
347
-	return 0;
348
-}
349
-
350
-/**
351
- * Store value of DHCP option setting, extending options block if necessary
352
- *
353
- * @v options		DHCP option block
354
- * @v tag		Setting tag number
355
- * @v data		Setting data, or NULL to clear setting
356
- * @v len		Length of setting data
357
- * @ret rc		Return status code
358
- */
359
-int dhcpopt_extensible_store ( struct dhcp_options *options, unsigned int tag,
360
-			       const void *data, size_t len ) {
361
-	int offset;
362
-
363
-	offset = set_dhcp_option ( options, tag, data, len, 1 );
363
+	offset = set_dhcp_option ( options, tag, data, len );
364
 	if ( offset < 0 )
364
 	if ( offset < 0 )
365
 		return offset;
365
 		return offset;
366
 	return 0;
366
 	return 0;
428
  * @v options		Uninitialised DHCP option block
428
  * @v options		Uninitialised DHCP option block
429
  * @v data		Memory for DHCP option data
429
  * @v data		Memory for DHCP option data
430
  * @v alloc_len		Length of memory for DHCP option data
430
  * @v alloc_len		Length of memory for DHCP option data
431
+ * @v realloc		DHCP option block reallocator
431
  *
432
  *
432
  * The memory content must already be filled with valid DHCP options.
433
  * The memory content must already be filled with valid DHCP options.
433
  * A zeroed block counts as a block of valid DHCP options.
434
  * A zeroed block counts as a block of valid DHCP options.
434
  */
435
  */
435
-void dhcpopt_init ( struct dhcp_options *options, void *data,
436
-		    size_t alloc_len ) {
436
+void dhcpopt_init ( struct dhcp_options *options, void *data, size_t alloc_len,
437
+		    int ( * realloc ) ( struct dhcp_options *options,
438
+					size_t len ) ) {
437
 
439
 
438
 	/* Fill in fields */
440
 	/* Fill in fields */
439
 	options->data = data;
441
 	options->data = data;
440
 	options->alloc_len = alloc_len;
442
 	options->alloc_len = alloc_len;
443
+	options->realloc = realloc;
441
 
444
 
442
 	/* Update length */
445
 	/* Update length */
443
 	dhcpopt_update_used_len ( options );
446
 	dhcpopt_update_used_len ( options );

+ 2
- 1
src/net/dhcppkt.c View File

267
 	ref_init ( &dhcppkt->refcnt, NULL );
267
 	ref_init ( &dhcppkt->refcnt, NULL );
268
 	dhcppkt->dhcphdr = data;
268
 	dhcppkt->dhcphdr = data;
269
 	dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
269
 	dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
270
-		       ( len - offsetof ( struct dhcphdr, options ) ) );
270
+		       ( len - offsetof ( struct dhcphdr, options ) ),
271
+		       dhcpopt_no_realloc );
271
 	settings_init ( &dhcppkt->settings,
272
 	settings_init ( &dhcppkt->settings,
272
 			&dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
273
 			&dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
273
 }
274
 }

Loading…
Cancel
Save