|
@@ -130,6 +130,9 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
|
130
|
130
|
return xid;
|
131
|
131
|
}
|
132
|
132
|
|
|
133
|
+/** Settings block name used for ProxyDHCP responses */
|
|
134
|
+#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
|
|
135
|
+
|
133
|
136
|
/**
|
134
|
137
|
* Create a DHCP packet
|
135
|
138
|
*
|
|
@@ -145,10 +148,10 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
|
145
|
148
|
* dhcp_packet structure that can be passed to
|
146
|
149
|
* set_dhcp_packet_option() or copy_dhcp_packet_options().
|
147
|
150
|
*/
|
148
|
|
-static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
|
149
|
|
- struct net_device *netdev, uint8_t msgtype,
|
150
|
|
- struct dhcp_options *options,
|
151
|
|
- void *data, size_t max_len ) {
|
|
151
|
+int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
|
|
152
|
+ struct net_device *netdev, uint8_t msgtype,
|
|
153
|
+ struct dhcp_options *options,
|
|
154
|
+ void *data, size_t max_len ) {
|
152
|
155
|
struct dhcphdr *dhcphdr = data;
|
153
|
156
|
size_t options_len;
|
154
|
157
|
unsigned int hlen;
|
|
@@ -160,10 +163,6 @@ static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
|
160
|
163
|
return -ENOSPC;
|
161
|
164
|
|
162
|
165
|
/* Initialise DHCP packet content */
|
163
|
|
-
|
164
|
|
- /* FIXME: wrong place to fix this. */
|
165
|
|
- memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
|
166
|
|
-
|
167
|
166
|
memset ( dhcphdr, 0, max_len );
|
168
|
167
|
dhcphdr->xid = dhcp_xid ( netdev );
|
169
|
168
|
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
|
|
@@ -182,6 +181,7 @@ static int create_dhcp_packet ( struct dhcp_packet *dhcppkt,
|
182
|
181
|
memcpy ( dhcphdr->options, options->data, options_len );
|
183
|
182
|
|
184
|
183
|
/* Initialise DHCP packet structure and settings interface */
|
|
184
|
+ memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
|
185
|
185
|
dhcppkt_init ( dhcppkt, NULL, data, max_len );
|
186
|
186
|
|
187
|
187
|
/* Set DHCP_MESSAGE_TYPE option */
|
|
@@ -221,29 +221,30 @@ struct dhcp_client_uuid {
|
221
|
221
|
#define DHCP_CLIENT_UUID_TYPE 0
|
222
|
222
|
|
223
|
223
|
/**
|
224
|
|
- * Create DHCP request
|
|
224
|
+ * Create DHCP request packet
|
225
|
225
|
*
|
226
|
226
|
* @v dhcppkt DHCP packet structure to fill in
|
227
|
227
|
* @v netdev Network device
|
228
|
|
- * @v msgtype DHCP message type
|
229
|
|
- * @v offer_settings Settings received in DHCPOFFER, or NULL
|
|
228
|
+ * @v dhcpoffer DHCPOFFER packet received from server
|
230
|
229
|
* @v data Buffer for DHCP packet
|
231
|
230
|
* @v max_len Size of DHCP packet buffer
|
232
|
231
|
* @ret rc Return status code
|
233
|
232
|
*/
|
234
|
|
-int create_dhcp_request ( struct dhcp_packet *dhcppkt,
|
235
|
|
- struct net_device *netdev, int msgtype,
|
236
|
|
- struct settings *offer_settings,
|
237
|
|
- void *data, size_t max_len ) {
|
|
233
|
+static int create_dhcp_request ( struct dhcp_packet *dhcppkt,
|
|
234
|
+ struct net_device *netdev,
|
|
235
|
+ struct dhcp_packet *dhcpoffer,
|
|
236
|
+ void *data, size_t max_len ) {
|
238
|
237
|
struct device_description *desc = &netdev->dev->desc;
|
239
|
238
|
struct dhcp_netdev_desc dhcp_desc;
|
240
|
239
|
struct dhcp_client_id client_id;
|
241
|
240
|
struct dhcp_client_uuid client_uuid;
|
|
241
|
+ unsigned int msgtype;
|
242
|
242
|
size_t dhcp_features_len;
|
243
|
243
|
size_t ll_addr_len;
|
244
|
244
|
int rc;
|
245
|
245
|
|
246
|
246
|
/* Create DHCP packet */
|
|
247
|
+ msgtype = ( dhcpoffer ? DHCPREQUEST : DHCPDISCOVER );
|
247
|
248
|
if ( ( rc = create_dhcp_packet ( dhcppkt, netdev, msgtype,
|
248
|
249
|
&dhcp_request_options, data,
|
249
|
250
|
max_len ) ) != 0 ) {
|
|
@@ -253,10 +254,10 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
|
253
|
254
|
}
|
254
|
255
|
|
255
|
256
|
/* Copy any required options from previous server repsonse */
|
256
|
|
- if ( offer_settings ) {
|
|
257
|
+ if ( dhcpoffer ) {
|
257
|
258
|
if ( ( rc = copy_setting ( &dhcppkt->settings,
|
258
|
259
|
DHCP_SERVER_IDENTIFIER,
|
259
|
|
- offer_settings,
|
|
260
|
+ &dhcpoffer->settings,
|
260
|
261
|
DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
|
261
|
262
|
DBG ( "DHCP could not set server identifier "
|
262
|
263
|
"option: %s\n", strerror ( rc ) );
|
|
@@ -264,7 +265,7 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
|
264
|
265
|
}
|
265
|
266
|
if ( ( rc = copy_setting ( &dhcppkt->settings,
|
266
|
267
|
DHCP_REQUESTED_ADDRESS,
|
267
|
|
- offer_settings,
|
|
268
|
+ &dhcpoffer->settings,
|
268
|
269
|
DHCP_EB_YIADDR ) ) != 0 ) {
|
269
|
270
|
DBG ( "DHCP could not set requested address "
|
270
|
271
|
"option: %s\n", strerror ( rc ) );
|
|
@@ -322,27 +323,87 @@ int create_dhcp_request ( struct dhcp_packet *dhcppkt,
|
322
|
323
|
}
|
323
|
324
|
|
324
|
325
|
/**
|
325
|
|
- * Create DHCP response
|
|
326
|
+ * Create DHCPDISCOVER packet
|
|
327
|
+ *
|
|
328
|
+ * @v netdev Network device
|
|
329
|
+ * @v data Buffer for DHCP packet
|
|
330
|
+ * @v max_len Size of DHCP packet buffer
|
|
331
|
+ * @ret rc Return status code
|
|
332
|
+ *
|
|
333
|
+ * Used by external code.
|
|
334
|
+ */
|
|
335
|
+int create_dhcpdiscover ( struct net_device *netdev,
|
|
336
|
+ void *data, size_t max_len ) {
|
|
337
|
+ struct dhcp_packet dhcppkt;
|
|
338
|
+
|
|
339
|
+ return create_dhcp_request ( &dhcppkt, netdev, NULL, data, max_len );
|
|
340
|
+}
|
|
341
|
+
|
|
342
|
+/**
|
|
343
|
+ * Create DHCPACK packet
|
|
344
|
+ *
|
|
345
|
+ * @v netdev Network device
|
|
346
|
+ * @v data Buffer for DHCP packet
|
|
347
|
+ * @v max_len Size of DHCP packet buffer
|
|
348
|
+ * @ret rc Return status code
|
|
349
|
+ *
|
|
350
|
+ * Used by external code.
|
|
351
|
+ */
|
|
352
|
+int create_dhcpack ( struct net_device *netdev,
|
|
353
|
+ void *data, size_t max_len ) {
|
|
354
|
+ struct dhcp_packet dhcppkt;
|
|
355
|
+ int rc;
|
|
356
|
+
|
|
357
|
+ /* Create base DHCPACK packet */
|
|
358
|
+ if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
|
|
359
|
+ data, max_len ) ) != 0 )
|
|
360
|
+ return rc;
|
|
361
|
+
|
|
362
|
+ /* Merge in globally-scoped settings, then netdev-specific
|
|
363
|
+ * settings. Do it in this order so that netdev-specific
|
|
364
|
+ * settings take precedence regardless of stated priorities.
|
|
365
|
+ */
|
|
366
|
+ if ( ( rc = copy_settings ( &dhcppkt.settings, NULL ) ) != 0 )
|
|
367
|
+ return rc;
|
|
368
|
+ if ( ( rc = copy_settings ( &dhcppkt.settings,
|
|
369
|
+ netdev_settings ( netdev ) ) ) != 0 )
|
|
370
|
+ return rc;
|
|
371
|
+
|
|
372
|
+ return 0;
|
|
373
|
+}
|
|
374
|
+
|
|
375
|
+/**
|
|
376
|
+ * Create ProxyDHCPACK packet
|
326
|
377
|
*
|
327
|
|
- * @v dhcppkt DHCP packet structure to fill in
|
328
|
378
|
* @v netdev Network device
|
329
|
|
- * @v msgtype DHCP message type
|
330
|
|
- * @v settings Settings to include, or NULL
|
331
|
379
|
* @v data Buffer for DHCP packet
|
332
|
380
|
* @v max_len Size of DHCP packet buffer
|
333
|
381
|
* @ret rc Return status code
|
|
382
|
+ *
|
|
383
|
+ * Used by external code.
|
334
|
384
|
*/
|
335
|
|
-int create_dhcp_response ( struct dhcp_packet *dhcppkt,
|
336
|
|
- struct net_device *netdev, int msgtype,
|
337
|
|
- struct settings *settings,
|
338
|
|
- void *data, size_t max_len ) {
|
|
385
|
+int create_proxydhcpack ( struct net_device *netdev,
|
|
386
|
+ void *data, size_t max_len ) {
|
|
387
|
+ struct dhcp_packet dhcppkt;
|
|
388
|
+ struct settings *settings;
|
339
|
389
|
int rc;
|
340
|
390
|
|
341
|
|
- /* Create packet and copy in options */
|
342
|
|
- if ( ( rc = create_dhcp_packet ( dhcppkt, netdev, msgtype, NULL,
|
|
391
|
+ /* Identify ProxyDHCP settings */
|
|
392
|
+ settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
|
|
393
|
+
|
|
394
|
+ /* No ProxyDHCP settings => return empty block */
|
|
395
|
+ if ( ! settings ) {
|
|
396
|
+ memset ( data, 0, max_len );
|
|
397
|
+ return 0;
|
|
398
|
+ }
|
|
399
|
+
|
|
400
|
+ /* Create base DHCPACK packet */
|
|
401
|
+ if ( ( rc = create_dhcp_packet ( &dhcppkt, netdev, DHCPACK, NULL,
|
343
|
402
|
data, max_len ) ) != 0 )
|
344
|
403
|
return rc;
|
345
|
|
- if ( ( rc = copy_settings ( &dhcppkt->settings, settings ) ) != 0 )
|
|
404
|
+
|
|
405
|
+ /* Merge in ProxyDHCP options */
|
|
406
|
+ if ( ( rc = copy_settings ( &dhcppkt.settings, settings ) ) != 0 )
|
346
|
407
|
return rc;
|
347
|
408
|
|
348
|
409
|
return 0;
|
|
@@ -356,10 +417,10 @@ int create_dhcp_response ( struct dhcp_packet *dhcppkt,
|
356
|
417
|
|
357
|
418
|
/** A DHCP packet contained in an I/O buffer */
|
358
|
419
|
struct dhcp_iobuf_packet {
|
359
|
|
- /** Reference counter */
|
360
|
|
- struct refcnt refcnt;
|
361
|
420
|
/** DHCP packet */
|
362
|
421
|
struct dhcp_packet dhcppkt;
|
|
422
|
+ /** Reference counter */
|
|
423
|
+ struct refcnt refcnt;
|
363
|
424
|
/** Containing I/O buffer */
|
364
|
425
|
struct io_buffer *iobuf;
|
365
|
426
|
};
|
|
@@ -480,18 +541,28 @@ static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
|
480
|
541
|
* @ret rc Return status code
|
481
|
542
|
*/
|
482
|
543
|
static int dhcp_register_settings ( struct dhcp_session *dhcp ) {
|
|
544
|
+ struct settings *old_settings;
|
483
|
545
|
struct settings *settings;
|
484
|
546
|
struct settings *parent;
|
485
|
547
|
int rc;
|
486
|
548
|
|
|
549
|
+ /* Register ProxyDHCP settings, if present */
|
487
|
550
|
if ( dhcp->proxy_response ) {
|
488
|
551
|
settings = &dhcp->proxy_response->dhcppkt.settings;
|
|
552
|
+ settings->name = PROXYDHCP_SETTINGS_NAME;
|
|
553
|
+ old_settings = find_settings ( settings->name );
|
|
554
|
+ if ( old_settings )
|
|
555
|
+ unregister_settings ( old_settings );
|
489
|
556
|
if ( ( rc = register_settings ( settings, NULL ) ) != 0 )
|
490
|
557
|
return rc;
|
491
|
558
|
}
|
492
|
559
|
|
493
|
|
- settings = &dhcp->response->dhcppkt.settings;
|
|
560
|
+ /* Register DHCP settings */
|
494
|
561
|
parent = netdev_settings ( dhcp->netdev );
|
|
562
|
+ settings = &dhcp->response->dhcppkt.settings;
|
|
563
|
+ old_settings = find_child_settings ( parent, settings->name );
|
|
564
|
+ if ( old_settings )
|
|
565
|
+ unregister_settings ( old_settings );
|
495
|
566
|
if ( ( rc = register_settings ( settings, parent ) ) != 0 )
|
496
|
567
|
return rc;
|
497
|
568
|
|
|
@@ -514,8 +585,8 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
|
514
|
585
|
struct xfer_metadata meta = {
|
515
|
586
|
.netdev = dhcp->netdev,
|
516
|
587
|
};
|
517
|
|
- struct settings *offer_settings = NULL;
|
518
|
588
|
struct io_buffer *iobuf;
|
|
589
|
+ struct dhcp_packet *dhcpoffer;
|
519
|
590
|
struct dhcp_packet dhcppkt;
|
520
|
591
|
int rc;
|
521
|
592
|
|
|
@@ -536,10 +607,9 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
|
536
|
607
|
return -ENOMEM;
|
537
|
608
|
|
538
|
609
|
/* Create DHCP packet in temporary buffer */
|
539
|
|
- if ( dhcp->response )
|
540
|
|
- offer_settings = &dhcp->response->dhcppkt.settings;
|
541
|
|
- if ( ( rc = create_dhcp_request ( &dhcppkt, dhcp->netdev, dhcp->state,
|
542
|
|
- offer_settings, iobuf->data,
|
|
610
|
+ dhcpoffer = ( dhcp->response ? &dhcp->response->dhcppkt : NULL );
|
|
611
|
+ if ( ( rc = create_dhcp_request ( &dhcppkt, dhcp->netdev,
|
|
612
|
+ dhcpoffer, iobuf->data,
|
543
|
613
|
iob_tailroom ( iobuf ) ) ) != 0 ) {
|
544
|
614
|
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
|
545
|
615
|
dhcp, strerror ( rc ) );
|