|
@@ -118,19 +118,25 @@ static inline unsigned int dhcp_any_option_len ( struct dhcp_option *option ) {
|
118
|
118
|
*
|
119
|
119
|
* @v options DHCP options block
|
120
|
120
|
* @v tag DHCP option tag to search for
|
|
121
|
+ * @ret encapsulator Encapsulating DHCP option
|
121
|
122
|
* @ret option DHCP option, or NULL if not found
|
122
|
123
|
*
|
123
|
124
|
* Searches for the DHCP option matching the specified tag within the
|
124
|
|
- * block of data. Encapsulated options may be searched for by using
|
125
|
|
- * DHCP_ENCAP_OPT() to construct the tag value.
|
|
125
|
+ * DHCP option block. Encapsulated options may be searched for by
|
|
126
|
+ * using DHCP_ENCAP_OPT() to construct the tag value.
|
|
127
|
+ *
|
|
128
|
+ * If the option is encapsulated, and @c encapsulator is non-NULL, it
|
|
129
|
+ * will be filled in with a pointer to the encapsulating option.
|
126
|
130
|
*
|
127
|
131
|
* This routine is designed to be paranoid. It does not assume that
|
128
|
132
|
* the option data is well-formatted, and so must guard against flaws
|
129
|
133
|
* such as options missing a @c DHCP_END terminator, or options whose
|
130
|
134
|
* length would take them beyond the end of the data block.
|
131
|
135
|
*/
|
132
|
|
-struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
|
133
|
|
- unsigned int tag ) {
|
|
136
|
+static struct dhcp_option *
|
|
137
|
+find_dhcp_option_with_encap ( struct dhcp_option_block *options,
|
|
138
|
+ unsigned int tag,
|
|
139
|
+ struct dhcp_option **encapsulator ) {
|
134
|
140
|
unsigned int original_tag __attribute__ (( unused )) = tag;
|
135
|
141
|
struct dhcp_option *option = options->data;
|
136
|
142
|
ssize_t remaining = options->len;
|
|
@@ -157,6 +163,8 @@ struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
|
157
|
163
|
/* Check for start of matching encapsulation block */
|
158
|
164
|
if ( DHCP_IS_ENCAP_OPT ( tag ) &&
|
159
|
165
|
( option->tag == DHCP_ENCAPSULATOR ( tag ) ) ) {
|
|
166
|
+ if ( encapsulator )
|
|
167
|
+ *encapsulator = option;
|
160
|
168
|
/* Continue search within encapsulated option block */
|
161
|
169
|
tag = DHCP_ENCAPSULATED ( tag );
|
162
|
170
|
remaining = option->len;
|
|
@@ -169,30 +177,36 @@ struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
|
169
|
177
|
}
|
170
|
178
|
|
171
|
179
|
/**
|
172
|
|
- * Find DHCP option within all registered DHCP options blocks
|
|
180
|
+ * Find DHCP option within DHCP options block
|
173
|
181
|
*
|
|
182
|
+ * @v options DHCP options block, or NULL
|
174
|
183
|
* @v tag DHCP option tag to search for
|
175
|
184
|
* @ret option DHCP option, or NULL if not found
|
176
|
185
|
*
|
177
|
|
- * Searches within all registered DHCP option blocks for the specified
|
178
|
|
- * tag. Encapsulated options may be searched for by using
|
179
|
|
- * DHCP_ENCAP_OPT() to construct the tag value.
|
|
186
|
+ * Searches for the DHCP option matching the specified tag within the
|
|
187
|
+ * DHCP option block. Encapsulated options may be searched for by
|
|
188
|
+ * using DHCP_ENCAP_OPT() to construct the tag value.
|
180
|
189
|
*
|
181
|
|
- * Where multiple option blocks contain the same DHCP option, the
|
182
|
|
- * option from the highest-priority block will be returned. (Priority
|
183
|
|
- * of an options block is determined by the value of the @c
|
184
|
|
- * DHCP_EB_PRIORITY option within the block, if present; the default
|
185
|
|
- * priority is zero).
|
|
190
|
+ * If @c options is NULL, all registered option blocks will be
|
|
191
|
+ * searched. Where multiple option blocks contain the same DHCP
|
|
192
|
+ * option, the option from the highest-priority block will be
|
|
193
|
+ * returned. (Priority of an options block is determined by the value
|
|
194
|
+ * of the @c DHCP_EB_PRIORITY option within the block, if present; the
|
|
195
|
+ * default priority is zero).
|
186
|
196
|
*/
|
187
|
|
-struct dhcp_option * find_global_dhcp_option ( unsigned int tag ) {
|
188
|
|
- struct dhcp_option_block *options;
|
|
197
|
+struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
|
|
198
|
+ unsigned int tag ) {
|
189
|
199
|
struct dhcp_option *option;
|
190
|
200
|
|
191
|
|
- list_for_each_entry ( options, &option_blocks, list ) {
|
192
|
|
- if ( ( option = find_dhcp_option ( options, tag ) ) )
|
193
|
|
- return option;
|
|
201
|
+ if ( options ) {
|
|
202
|
+ return find_dhcp_option_with_encap ( options, tag, NULL );
|
|
203
|
+ } else {
|
|
204
|
+ list_for_each_entry ( options, &option_blocks, list ) {
|
|
205
|
+ if ( ( option = find_dhcp_option ( options, tag ) ) )
|
|
206
|
+ return option;
|
|
207
|
+ }
|
|
208
|
+ return NULL;
|
194
|
209
|
}
|
195
|
|
- return NULL;
|
196
|
210
|
}
|
197
|
211
|
|
198
|
212
|
/**
|
|
@@ -348,7 +362,7 @@ struct dhcp_option * set_dhcp_option ( struct dhcp_option_block *options,
|
348
|
362
|
size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 );
|
349
|
363
|
|
350
|
364
|
/* Find old instance of this option, if any */
|
351
|
|
- option = find_dhcp_option ( options, tag );
|
|
365
|
+ option = find_dhcp_option_with_encap ( options, tag, &encapsulator );
|
352
|
366
|
if ( option ) {
|
353
|
367
|
old_len = dhcp_option_len ( option );
|
354
|
368
|
DBG ( "Resizing DHCP option %s from length %d to %d\n",
|
|
@@ -361,7 +375,6 @@ struct dhcp_option * set_dhcp_option ( struct dhcp_option_block *options,
|
361
|
375
|
|
362
|
376
|
/* Ensure that encapsulator exists, if required */
|
363
|
377
|
if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
|
364
|
|
- encapsulator = find_dhcp_option ( options, encap_tag );
|
365
|
378
|
if ( ! encapsulator )
|
366
|
379
|
encapsulator = set_dhcp_option ( options, encap_tag,
|
367
|
380
|
empty_encapsulator,
|
|
@@ -393,3 +406,66 @@ struct dhcp_option * set_dhcp_option ( struct dhcp_option_block *options,
|
393
|
406
|
|
394
|
407
|
return option;
|
395
|
408
|
}
|
|
409
|
+
|
|
410
|
+/**
|
|
411
|
+ * Find DHCP option within all registered DHCP options blocks
|
|
412
|
+ *
|
|
413
|
+ * @v tag DHCP option tag to search for
|
|
414
|
+ * @ret option DHCP option, or NULL if not found
|
|
415
|
+ *
|
|
416
|
+ * This function exists merely as a notational shorthand for
|
|
417
|
+ * find_dhcp_option() with @c options set to NULL.
|
|
418
|
+ */
|
|
419
|
+struct dhcp_option * find_global_dhcp_option ( unsigned int tag ) {
|
|
420
|
+ return find_dhcp_option ( NULL, tag );
|
|
421
|
+}
|
|
422
|
+
|
|
423
|
+/**
|
|
424
|
+ * Find DHCP numerical option, and return its value
|
|
425
|
+ *
|
|
426
|
+ * @v options DHCP options block
|
|
427
|
+ * @v tag DHCP option tag to search for
|
|
428
|
+ * @ret value Numerical value of the option, or 0 if not found
|
|
429
|
+ *
|
|
430
|
+ * This function exists merely as a notational shorthand for a call to
|
|
431
|
+ * find_dhcp_option() followed by a call to dhcp_num_option(). It is
|
|
432
|
+ * not possible to distinguish between the cases "option not found"
|
|
433
|
+ * and "option has a value of zero" using this function; if this
|
|
434
|
+ * matters to you then issue the two constituent calls directly and
|
|
435
|
+ * check that find_dhcp_option() returns a non-NULL value.
|
|
436
|
+ */
|
|
437
|
+unsigned long find_dhcp_num_option ( struct dhcp_option_block *options,
|
|
438
|
+ unsigned int tag ) {
|
|
439
|
+ return dhcp_num_option ( find_dhcp_option ( options, tag ) );
|
|
440
|
+}
|
|
441
|
+
|
|
442
|
+/**
|
|
443
|
+ * Find DHCP numerical option, and return its value
|
|
444
|
+ *
|
|
445
|
+ * @v tag DHCP option tag to search for
|
|
446
|
+ * @ret value Numerical value of the option, or 0 if not found
|
|
447
|
+ *
|
|
448
|
+ * This function exists merely as a notational shorthand for a call to
|
|
449
|
+ * find_global_dhcp_option() followed by a call to dhcp_num_option().
|
|
450
|
+ * It is not possible to distinguish between the cases "option not
|
|
451
|
+ * found" and "option has a value of zero" using this function; if
|
|
452
|
+ * this matters to you then issue the two constituent calls directly
|
|
453
|
+ * and check that find_global_dhcp_option() returns a non-NULL value.
|
|
454
|
+ */
|
|
455
|
+unsigned long find_global_dhcp_num_option ( unsigned int tag ) {
|
|
456
|
+ return dhcp_num_option ( find_global_dhcp_option ( tag ) );
|
|
457
|
+}
|
|
458
|
+
|
|
459
|
+/**
|
|
460
|
+ * Delete DHCP option
|
|
461
|
+ *
|
|
462
|
+ * @v options DHCP options block
|
|
463
|
+ * @v tag DHCP option tag
|
|
464
|
+ *
|
|
465
|
+ * This function exists merely as a notational shorthand for a call to
|
|
466
|
+ * set_dhcp_option() with @c len set to zero.
|
|
467
|
+ */
|
|
468
|
+void delete_dhcp_option ( struct dhcp_option_block *options,
|
|
469
|
+ unsigned int tag ) {
|
|
470
|
+ set_dhcp_option ( options, tag, NULL, 0 );
|
|
471
|
+}
|