00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <ctype.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 #include <byteswap.h>
00028 #include <gpxe/if_ether.h>
00029 #include <gpxe/netdevice.h>
00030 #include <gpxe/device.h>
00031 #include <gpxe/xfer.h>
00032 #include <gpxe/open.h>
00033 #include <gpxe/job.h>
00034 #include <gpxe/retry.h>
00035 #include <gpxe/tcpip.h>
00036 #include <gpxe/ip.h>
00037 #include <gpxe/uuid.h>
00038 #include <gpxe/timer.h>
00039 #include <gpxe/settings.h>
00040 #include <gpxe/dhcp.h>
00041 #include <gpxe/dhcpopts.h>
00042 #include <gpxe/dhcppkt.h>
00043 #include <gpxe/features.h>
00044
00045
00046
00047
00048
00049
00050
00051 struct dhcp_session;
00052 static int dhcp_tx ( struct dhcp_session *dhcp );
00053
00054
00055
00056
00057
00058
00059
00060
00061 static const uint8_t dhcp_op[] = {
00062 [DHCPDISCOVER] = BOOTP_REQUEST,
00063 [DHCPOFFER] = BOOTP_REPLY,
00064 [DHCPREQUEST] = BOOTP_REQUEST,
00065 [DHCPDECLINE] = BOOTP_REQUEST,
00066 [DHCPACK] = BOOTP_REPLY,
00067 [DHCPNAK] = BOOTP_REPLY,
00068 [DHCPRELEASE] = BOOTP_REQUEST,
00069 [DHCPINFORM] = BOOTP_REQUEST,
00070 };
00071
00072
00073 static uint8_t dhcp_request_options_data[] = {
00074 DHCP_MESSAGE_TYPE, DHCP_BYTE ( 0 ),
00075 DHCP_MAX_MESSAGE_SIZE,
00076 DHCP_WORD ( ETH_MAX_MTU - 20 - 8 ),
00077 DHCP_CLIENT_ARCHITECTURE, DHCP_WORD ( 0 ),
00078 DHCP_CLIENT_NDI, DHCP_OPTION ( 1 , 2, 1 ),
00079 DHCP_VENDOR_CLASS_ID,
00080 DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',
00081 'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':',
00082 'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' ),
00083 DHCP_USER_CLASS_ID,
00084 DHCP_STRING ( 'g', 'P', 'X', 'E' ),
00085 DHCP_PARAMETER_REQUEST_LIST,
00086 DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
00087 DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
00088 DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
00089 DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
00090 DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
00091 DHCP_END
00092 };
00093
00094
00095 FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
00096
00097
00098 struct setting dhcp_server_setting __setting = {
00099 .name = "dhcp-server",
00100 .description = "DHCP server address",
00101 .tag = DHCP_SERVER_IDENTIFIER,
00102 .type = &setting_type_ipv4,
00103 };
00104
00105
00106 struct setting user_class_setting __setting = {
00107 .name = "user-class",
00108 .description = "User class identifier",
00109 .tag = DHCP_USER_CLASS_ID,
00110 .type = &setting_type_string,
00111 };
00112
00113
00114 struct setting use_cached_setting __setting = {
00115 .name = "use-cached",
00116 .description = "Use cached network settings",
00117 .tag = DHCP_EB_USE_CACHED,
00118 .type = &setting_type_uint8,
00119 };
00120
00121
00122
00123
00124
00125
00126
00127 static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
00128 switch ( msgtype ) {
00129 case DHCPNONE: return "BOOTP";
00130 case DHCPDISCOVER: return "DHCPDISCOVER";
00131 case DHCPOFFER: return "DHCPOFFER";
00132 case DHCPREQUEST: return "DHCPREQUEST";
00133 case DHCPDECLINE: return "DHCPDECLINE";
00134 case DHCPACK: return "DHCPACK";
00135 case DHCPNAK: return "DHCPNAK";
00136 case DHCPRELEASE: return "DHCPRELEASE";
00137 case DHCPINFORM: return "DHCPINFORM";
00138 default: return "DHCP<invalid>";
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 static uint32_t dhcp_xid ( struct net_device *netdev ) {
00152 uint32_t xid;
00153
00154 memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
00155 - sizeof ( xid ) ), sizeof ( xid ) );
00156 return xid;
00157 }
00158
00159
00160
00161
00162
00163
00164
00165 struct dhcp_session;
00166
00167
00168 struct dhcp_session_state {
00169
00170 const char *name;
00171
00172
00173
00174
00175
00176
00177
00178 int ( * tx ) ( struct dhcp_session *dhcp,
00179 struct dhcp_packet *dhcppkt,
00180 struct sockaddr_in *peer );
00181
00182
00183
00184
00185
00186
00187
00188
00189 void ( * rx ) ( struct dhcp_session *dhcp,
00190 struct dhcp_packet *dhcppkt,
00191 struct sockaddr_in *peer,
00192 uint8_t msgtype, struct in_addr server_id );
00193
00194
00195
00196
00197 void ( * expired ) ( struct dhcp_session *dhcp );
00198
00199 uint8_t tx_msgtype;
00200
00201 uint8_t apply_min_timeout;
00202 };
00203
00204 static struct dhcp_session_state dhcp_state_discover;
00205 static struct dhcp_session_state dhcp_state_request;
00206 static struct dhcp_session_state dhcp_state_proxy;
00207 static struct dhcp_session_state dhcp_state_pxebs;
00208
00209
00210 #define DHCP_OFFER_IP 1
00211
00212
00213 #define DHCP_OFFER_PXE 2
00214
00215
00216 struct dhcp_offer {
00217
00218 struct in_addr server;
00219
00220
00221 struct in_addr ip;
00222
00223
00224 struct dhcp_packet *pxe;
00225
00226
00227 uint8_t valid;
00228
00229
00230 int8_t priority;
00231
00232
00233 uint8_t no_pxedhcp;
00234 };
00235
00236
00237 #define DHCP_MAX_OFFERS 6
00238
00239
00240 struct dhcp_session {
00241
00242 struct refcnt refcnt;
00243
00244 struct job_interface job;
00245
00246 struct xfer_interface xfer;
00247
00248
00249 struct net_device *netdev;
00250
00251 struct sockaddr_in local;
00252
00253 struct dhcp_session_state *state;
00254
00255
00256 uint16_t pxe_type;
00257
00258 struct in_addr *pxe_attempt;
00259
00260 struct in_addr *pxe_accept;
00261
00262
00263 struct retry_timer timer;
00264
00265 unsigned long start;
00266
00267
00268 struct dhcp_offer *current_offer;
00269
00270 struct dhcp_offer offers[DHCP_MAX_OFFERS];
00271 };
00272
00273
00274
00275
00276
00277
00278 static void dhcp_free ( struct refcnt *refcnt ) {
00279 struct dhcp_session *dhcp =
00280 container_of ( refcnt, struct dhcp_session, refcnt );
00281 int i;
00282
00283 for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
00284 if ( dhcp->offers[i].pxe )
00285 dhcppkt_put ( dhcp->offers[i].pxe );
00286 }
00287
00288 netdev_put ( dhcp->netdev );
00289 free ( dhcp );
00290 }
00291
00292
00293
00294
00295
00296
00297
00298 static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
00299
00300
00301 job_nullify ( &dhcp->job );
00302 xfer_nullify ( &dhcp->xfer );
00303
00304
00305 stop_timer ( &dhcp->timer );
00306
00307
00308 xfer_close ( &dhcp->xfer, rc );
00309 job_done ( &dhcp->job, rc );
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 static void dhcp_set_state ( struct dhcp_session *dhcp,
00319 struct dhcp_session_state *state ) {
00320
00321 DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
00322 dhcp->state = state;
00323 dhcp->start = currticks();
00324 stop_timer ( &dhcp->timer );
00325 dhcp->timer.min_timeout =
00326 ( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 );
00327 dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
00328 start_timer_nodelay ( &dhcp->timer );
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 static struct dhcp_offer * dhcp_next_offer ( struct dhcp_session *dhcp,
00342 uint8_t type ) {
00343
00344 struct dhcp_offer *offer;
00345 struct dhcp_offer *best = NULL;
00346
00347 for ( offer = dhcp->offers ; offer < dhcp->offers + DHCP_MAX_OFFERS ;
00348 offer++ ) {
00349 if ( ( offer->valid & type ) &&
00350 ( ( best == NULL ) ||
00351 ( offer->priority > best->priority ) ||
00352 ( ( offer->priority == best->priority ) &&
00353 ( offer->valid & ~best->valid ) ) ) )
00354 best = offer;
00355 }
00356
00357 return best;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
00374 struct dhcp_packet *dhcppkt __unused,
00375 struct sockaddr_in *peer ) {
00376
00377 DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
00378
00379
00380 peer->sin_addr.s_addr = INADDR_BROADCAST;
00381 peer->sin_port = htons ( BOOTPS_PORT );
00382
00383 return 0;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 static void dhcp_rx_offer ( struct dhcp_session *dhcp,
00396 struct dhcp_packet *dhcppkt,
00397 struct sockaddr_in *peer, uint8_t msgtype,
00398 struct in_addr server_id ) {
00399 char vci[9];
00400 int vci_len;
00401 int has_pxeclient;
00402 int pxeopts_len;
00403 int has_pxeopts;
00404 struct dhcp_offer *offer;
00405 int i;
00406
00407 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
00408 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
00409 ntohs ( peer->sin_port ) );
00410 if ( server_id.s_addr != peer->sin_addr.s_addr )
00411 DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
00412
00413
00414 if ( dhcppkt->dhcphdr->yiaddr.s_addr )
00415 DBGC ( dhcp, " for %s", inet_ntoa ( dhcppkt->dhcphdr->yiaddr ));
00416
00417
00418 for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
00419 if ( dhcp->offers[i].server.s_addr == server_id.s_addr ) {
00420 DBGC ( dhcp, " dup\n" );
00421 return;
00422 }
00423
00424 if ( ! dhcp->offers[i].valid )
00425 break;
00426 }
00427 if ( i == DHCP_MAX_OFFERS ) {
00428 DBGC ( dhcp, " dropped\n" );
00429 return;
00430 }
00431
00432 offer = &dhcp->offers[i];
00433 offer->server = server_id;
00434 offer->ip = dhcppkt->dhcphdr->yiaddr;
00435
00436
00437 vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
00438 vci, sizeof ( vci ) );
00439 has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
00440 ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
00441
00442
00443 pxeopts_len = dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 );
00444 has_pxeopts = ( pxeopts_len >= 0 );
00445 if ( has_pxeclient )
00446 DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
00447
00448 if ( has_pxeclient && has_pxeopts ) {
00449
00450 if ( offer->pxe )
00451 dhcppkt_put ( offer->pxe );
00452 offer->pxe = dhcppkt_get ( dhcppkt );
00453 }
00454
00455
00456 dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &offer->priority,
00457 sizeof ( offer->priority ) );
00458 if ( offer->priority )
00459 DBGC ( dhcp, " pri %d", offer->priority );
00460
00461
00462 dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &offer->no_pxedhcp,
00463 sizeof ( offer->no_pxedhcp ) );
00464 if ( offer->no_pxedhcp )
00465 DBGC ( dhcp, " nopxe" );
00466 DBGC ( dhcp, "\n" );
00467
00468
00469 if ( offer->ip.s_addr &&
00470 ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
00471 ( ( msgtype == DHCPOFFER ) || ( ! msgtype ) ) )
00472 offer->valid |= DHCP_OFFER_IP;
00473
00474 if ( has_pxeclient && ( msgtype == DHCPOFFER ) )
00475 offer->valid |= DHCP_OFFER_PXE;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
00488 struct dhcp_packet *dhcppkt,
00489 struct sockaddr_in *peer, uint8_t msgtype,
00490 struct in_addr server_id ) {
00491 unsigned long elapsed;
00492 struct dhcp_offer *ip_offer;
00493
00494 dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 ip_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
00506 if ( ! ip_offer )
00507 return;
00508
00509
00510 elapsed = ( currticks() - dhcp->start );
00511 if ( ! ( ip_offer->no_pxedhcp ||
00512 dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ||
00513 ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
00514 return;
00515
00516
00517 dhcp_set_state ( dhcp, &dhcp_state_request );
00518 }
00519
00520
00521
00522
00523
00524
00525 static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
00526 unsigned long elapsed = ( currticks() - dhcp->start );
00527
00528
00529 if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) &&
00530 ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
00531 dhcp_set_state ( dhcp, &dhcp_state_request );
00532 return;
00533 }
00534
00535
00536 dhcp_tx ( dhcp );
00537 }
00538
00539
00540 static struct dhcp_session_state dhcp_state_discover = {
00541 .name = "discovery",
00542 .tx = dhcp_discovery_tx,
00543 .rx = dhcp_discovery_rx,
00544 .expired = dhcp_discovery_expired,
00545 .tx_msgtype = DHCPDISCOVER,
00546 .apply_min_timeout = 1,
00547 };
00548
00549
00550
00551
00552
00553
00554
00555
00556 static int dhcp_request_tx ( struct dhcp_session *dhcp,
00557 struct dhcp_packet *dhcppkt,
00558 struct sockaddr_in *peer ) {
00559 int rc;
00560 struct dhcp_offer *offer;
00561
00562 offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
00563
00564 DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
00565 dhcp, inet_ntoa ( offer->server ), BOOTPS_PORT );
00566 DBGC ( dhcp, " for %s\n", inet_ntoa ( offer->ip ) );
00567
00568
00569 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
00570 &offer->server,
00571 sizeof ( offer->server ) ) ) != 0 )
00572 return rc;
00573
00574
00575 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
00576 &offer->ip, sizeof ( offer->ip ) ) ) != 0 )
00577 return rc;
00578
00579
00580 peer->sin_addr.s_addr = INADDR_BROADCAST;
00581 peer->sin_port = htons ( BOOTPS_PORT );
00582
00583 return 0;
00584 }
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 static void dhcp_request_rx ( struct dhcp_session *dhcp,
00596 struct dhcp_packet *dhcppkt,
00597 struct sockaddr_in *peer, uint8_t msgtype,
00598 struct in_addr server_id ) {
00599 struct in_addr ip;
00600 struct settings *parent;
00601 int rc;
00602 struct dhcp_offer *pxe_offer;
00603
00604 if ( msgtype == DHCPOFFER ) {
00605 dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
00606 if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) !=
00607 dhcp->current_offer ) {
00608
00609 DBGC ( dhcp, "DHCP %p re-requesting\n", dhcp );
00610 dhcp_set_state ( dhcp, &dhcp_state_request );
00611 }
00612 return;
00613 }
00614
00615 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
00616 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
00617 ntohs ( peer->sin_port ) );
00618 if ( server_id.s_addr != peer->sin_addr.s_addr )
00619 DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
00620
00621
00622 ip = dhcppkt->dhcphdr->yiaddr;
00623 if ( ip.s_addr )
00624 DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
00625 DBGC ( dhcp, "\n" );
00626
00627
00628 if ( peer->sin_port != htons ( BOOTPS_PORT ) )
00629 return;
00630 if ( msgtype && ( msgtype != DHCPACK ) )
00631 return;
00632 if ( server_id.s_addr != dhcp->current_offer->server.s_addr )
00633 return;
00634
00635
00636 dhcp->local.sin_addr = ip;
00637
00638
00639 parent = netdev_settings ( dhcp->netdev );
00640 if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
00641 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
00642 dhcp, strerror ( rc ) );
00643 dhcp_finished ( dhcp, rc );
00644 return;
00645 }
00646
00647
00648 pxe_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
00649
00650 if ( ( ! pxe_offer ) ||
00651
00652 dhcp->current_offer->no_pxedhcp ||
00653
00654 ( ( dhcp->current_offer == pxe_offer ) && ( pxe_offer->pxe ) ) ) {
00655
00656
00657 dhcp_finished ( dhcp, 0 );
00658
00659 } else if ( pxe_offer->pxe ) {
00660
00661 pxe_offer->pxe->settings.name = PROXYDHCP_SETTINGS_NAME;
00662 if ( ( rc = register_settings ( &pxe_offer->pxe->settings,
00663 NULL ) ) != 0 ) {
00664 DBGC ( dhcp, "DHCP %p could not register settings: "
00665 "%s\n", dhcp, strerror ( rc ) );
00666 }
00667 dhcp_finished ( dhcp, rc );
00668 } else {
00669
00670 dhcp_set_state ( dhcp, &dhcp_state_proxy );
00671 }
00672 }
00673
00674
00675
00676
00677
00678
00679 static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
00680
00681
00682 dhcp_tx ( dhcp );
00683 }
00684
00685
00686 static struct dhcp_session_state dhcp_state_request = {
00687 .name = "request",
00688 .tx = dhcp_request_tx,
00689 .rx = dhcp_request_rx,
00690 .expired = dhcp_request_expired,
00691 .tx_msgtype = DHCPREQUEST,
00692 .apply_min_timeout = 0,
00693 };
00694
00695
00696
00697
00698
00699
00700
00701
00702 static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
00703 struct dhcp_packet *dhcppkt,
00704 struct sockaddr_in *peer ) {
00705 int rc;
00706 struct dhcp_offer *offer;
00707
00708 offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
00709
00710 DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
00711 inet_ntoa ( offer->server ), PXE_PORT );
00712
00713
00714 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
00715 &offer->server,
00716 sizeof ( offer->server ) ) ) != 0 )
00717 return rc;
00718
00719
00720 peer->sin_addr = offer->server;
00721 peer->sin_port = htons ( PXE_PORT );
00722
00723 return 0;
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
00736 struct dhcp_packet *dhcppkt,
00737 struct sockaddr_in *peer, uint8_t msgtype,
00738 struct in_addr server_id ) {
00739 int rc;
00740
00741
00742 if ( peer->sin_port == htons ( BOOTPS_PORT ) &&
00743 msgtype == DHCPOFFER ) {
00744 dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
00745 return;
00746 }
00747
00748 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
00749 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
00750 ntohs ( peer->sin_port ) );
00751 if ( server_id.s_addr != peer->sin_addr.s_addr )
00752 DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
00753 DBGC ( dhcp, "\n" );
00754
00755
00756 if ( peer->sin_port != htons ( PXE_PORT ) )
00757 return;
00758 if ( msgtype != DHCPACK && msgtype != DHCPOFFER )
00759 return;
00760 if ( server_id.s_addr &&
00761 ( server_id.s_addr != dhcp->current_offer->server.s_addr ) )
00762 return;
00763
00764
00765 dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
00766 if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
00767 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
00768 dhcp, strerror ( rc ) );
00769 dhcp_finished ( dhcp, rc );
00770 return;
00771 }
00772
00773
00774 dhcp_finished ( dhcp, 0 );
00775 }
00776
00777
00778
00779
00780
00781
00782 static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
00783 unsigned long elapsed = ( currticks() - dhcp->start );
00784
00785
00786 if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
00787
00788
00789 dhcp->current_offer->valid &= ~DHCP_OFFER_PXE;
00790
00791
00792
00793
00794 dhcp->current_offer->priority = -1;
00795
00796
00797
00798
00799
00800
00801
00802 if ( dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ) {
00803 dhcp->local.sin_addr.s_addr = 0;
00804 dhcp_set_state ( dhcp, &dhcp_state_request );
00805 return;
00806 }
00807
00808
00809 dhcp_finished ( dhcp, 0 );
00810 return;
00811 }
00812
00813
00814 dhcp_tx ( dhcp );
00815 }
00816
00817
00818 static struct dhcp_session_state dhcp_state_proxy = {
00819 .name = "ProxyDHCP",
00820 .tx = dhcp_proxy_tx,
00821 .rx = dhcp_proxy_rx,
00822 .expired = dhcp_proxy_expired,
00823 .tx_msgtype = DHCPREQUEST,
00824 .apply_min_timeout = 0,
00825 };
00826
00827
00828
00829
00830
00831
00832
00833
00834 static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
00835 struct dhcp_packet *dhcppkt,
00836 struct sockaddr_in *peer ) {
00837 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
00838 int rc;
00839
00840
00841 peer->sin_addr = *(dhcp->pxe_attempt);
00842 peer->sin_port = ( ( peer->sin_addr.s_addr == INADDR_BROADCAST ) ?
00843 htons ( BOOTPS_PORT ) : htons ( PXE_PORT ) );
00844
00845 DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
00846 dhcp, inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
00847 le16_to_cpu ( dhcp->pxe_type ) );
00848
00849
00850 menu_item.type = dhcp->pxe_type;
00851 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
00852 &menu_item, sizeof ( menu_item ) ) ) != 0 )
00853 return rc;
00854
00855 return 0;
00856 }
00857
00858
00859
00860
00861
00862
00863
00864
00865 static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
00866 struct in_addr bs ) {
00867 struct in_addr *accept;
00868
00869
00870 if ( ! dhcp->pxe_accept )
00871 return 1;
00872
00873
00874 for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
00875 if ( accept->s_addr == bs.s_addr )
00876 return 1;
00877 }
00878
00879 DBGC ( dhcp, "DHCP %p rejecting server %s\n",
00880 dhcp, inet_ntoa ( bs ) );
00881 return 0;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893 static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
00894 struct dhcp_packet *dhcppkt,
00895 struct sockaddr_in *peer, uint8_t msgtype,
00896 struct in_addr server_id ) {
00897 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
00898 int rc;
00899
00900 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
00901 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
00902 ntohs ( peer->sin_port ) );
00903 if ( server_id.s_addr != peer->sin_addr.s_addr )
00904 DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
00905
00906
00907 dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
00908 &menu_item, sizeof ( menu_item ) );
00909 if ( menu_item.type )
00910 DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
00911 DBGC ( dhcp, "\n" );
00912
00913
00914 if ( ( peer->sin_port != htons ( BOOTPS_PORT ) ) &&
00915 ( peer->sin_port != htons ( PXE_PORT ) ) )
00916 return;
00917 if ( msgtype != DHCPACK )
00918 return;
00919 if ( menu_item.type != dhcp->pxe_type )
00920 return;
00921 if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
00922 server_id : peer->sin_addr ) ) )
00923 return;
00924
00925
00926 dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
00927 if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
00928 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
00929 dhcp, strerror ( rc ) );
00930 dhcp_finished ( dhcp, rc );
00931 return;
00932 }
00933
00934
00935 dhcp_finished ( dhcp, 0 );
00936 }
00937
00938
00939
00940
00941
00942
00943 static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
00944 unsigned long elapsed = ( currticks() - dhcp->start );
00945
00946
00947
00948
00949 if ( elapsed > PXEBS_MAX_TIMEOUT ) {
00950 dhcp->pxe_attempt++;
00951 if ( dhcp->pxe_attempt->s_addr ) {
00952 dhcp_set_state ( dhcp, &dhcp_state_pxebs );
00953 return;
00954 } else {
00955 dhcp_finished ( dhcp, -ETIMEDOUT );
00956 return;
00957 }
00958 }
00959
00960
00961 dhcp_tx ( dhcp );
00962 }
00963
00964
00965 static struct dhcp_session_state dhcp_state_pxebs = {
00966 .name = "PXEBS",
00967 .tx = dhcp_pxebs_tx,
00968 .rx = dhcp_pxebs_rx,
00969 .expired = dhcp_pxebs_expired,
00970 .tx_msgtype = DHCPREQUEST,
00971 .apply_min_timeout = 1,
00972 };
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988 void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
00989 uint16_t *flags ) {
00990 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00991 typeof ( ( ( struct dhcphdr * ) NULL )->chaddr ) chaddr;
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008 if ( ( *hlen = ll_protocol->ll_addr_len ) <= sizeof ( chaddr ) ) {
01009 return netdev->ll_addr;
01010 }
01011 *flags = htons ( BOOTP_FL_BROADCAST );
01012 if ( ( *hlen = ll_protocol->hw_addr_len ) <= sizeof ( chaddr ) ) {
01013 return netdev->hw_addr;
01014 } else {
01015 *hlen = 0;
01016 return NULL;
01017 }
01018 }
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035 int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
01036 struct net_device *netdev, uint8_t msgtype,
01037 const void *options, size_t options_len,
01038 void *data, size_t max_len ) {
01039 struct dhcphdr *dhcphdr = data;
01040 void *chaddr;
01041 int rc;
01042
01043
01044 if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
01045 return -ENOSPC;
01046
01047
01048 memset ( dhcphdr, 0, max_len );
01049 dhcphdr->xid = dhcp_xid ( netdev );
01050 dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
01051 dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
01052 dhcphdr->op = dhcp_op[msgtype];
01053 chaddr = dhcp_chaddr ( netdev, &dhcphdr->hlen, &dhcphdr->flags );
01054 memcpy ( dhcphdr->chaddr, chaddr, dhcphdr->hlen );
01055 memcpy ( dhcphdr->options, options, options_len );
01056
01057
01058 memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
01059 dhcppkt_init ( dhcppkt, data, max_len );
01060
01061
01062 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
01063 &msgtype, sizeof ( msgtype ) ) ) != 0 )
01064 return rc;
01065
01066 return 0;
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 int dhcp_create_request ( struct dhcp_packet *dhcppkt,
01084 struct net_device *netdev, unsigned int msgtype,
01085 struct in_addr ciaddr, void *data, size_t max_len ) {
01086 struct dhcp_netdev_desc dhcp_desc;
01087 struct dhcp_client_id client_id;
01088 struct dhcp_client_uuid client_uuid;
01089 uint8_t *dhcp_features;
01090 size_t dhcp_features_len;
01091 size_t ll_addr_len;
01092 ssize_t len;
01093 int rc;
01094
01095
01096 if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
01097 dhcp_request_options_data,
01098 sizeof ( dhcp_request_options_data ),
01099 data, max_len ) ) != 0 ) {
01100 DBG ( "DHCP could not create DHCP packet: %s\n",
01101 strerror ( rc ) );
01102 return rc;
01103 }
01104
01105
01106 dhcppkt->dhcphdr->ciaddr = ciaddr;
01107
01108
01109 dhcp_features = table_start ( DHCP_FEATURES );
01110 dhcp_features_len = table_num_entries ( DHCP_FEATURES );
01111 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
01112 dhcp_features_len ) ) != 0 ) {
01113 DBG ( "DHCP could not set features list option: %s\n",
01114 strerror ( rc ) );
01115 return rc;
01116 }
01117
01118
01119 fetch_setting ( &netdev->settings.settings, &busid_setting, &dhcp_desc,
01120 sizeof ( dhcp_desc ) );
01121 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
01122 sizeof ( dhcp_desc ) ) ) != 0 ) {
01123 DBG ( "DHCP could not set bus ID option: %s\n",
01124 strerror ( rc ) );
01125 return rc;
01126 }
01127
01128
01129
01130
01131 client_id.ll_proto = ntohs ( netdev->ll_protocol->ll_proto );
01132 ll_addr_len = netdev->ll_protocol->ll_addr_len;
01133 assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
01134 memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
01135 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
01136 ( ll_addr_len + 1 ) ) ) != 0 ) {
01137 DBG ( "DHCP could not set client ID: %s\n",
01138 strerror ( rc ) );
01139 return rc;
01140 }
01141
01142
01143 client_uuid.type = DHCP_CLIENT_UUID_TYPE;
01144 if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
01145 &client_uuid.uuid ) ) >= 0 ) {
01146 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
01147 &client_uuid,
01148 sizeof ( client_uuid ) ) ) != 0 ) {
01149 DBG ( "DHCP could not set client UUID: %s\n",
01150 strerror ( rc ) );
01151 return rc;
01152 }
01153 }
01154
01155
01156 if ( ( len = fetch_setting_len ( NULL, &user_class_setting ) ) >= 0 ) {
01157 char user_class[len];
01158 fetch_setting ( NULL, &user_class_setting, user_class,
01159 sizeof ( user_class ) );
01160 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID,
01161 &user_class,
01162 sizeof ( user_class ) ) ) != 0 ) {
01163 DBG ( "DHCP could not set user class: %s\n",
01164 strerror ( rc ) );
01165 return rc;
01166 }
01167 }
01168
01169 return 0;
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184 static int dhcp_tx ( struct dhcp_session *dhcp ) {
01185 static struct sockaddr_in peer = {
01186 .sin_family = AF_INET,
01187 };
01188 struct xfer_metadata meta = {
01189 .netdev = dhcp->netdev,
01190 .src = ( struct sockaddr * ) &dhcp->local,
01191 .dest = ( struct sockaddr * ) &peer,
01192 };
01193 struct io_buffer *iobuf;
01194 uint8_t msgtype = dhcp->state->tx_msgtype;
01195 struct dhcp_packet dhcppkt;
01196 int rc;
01197
01198
01199
01200
01201 start_timer ( &dhcp->timer );
01202
01203
01204 iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
01205 if ( ! iobuf )
01206 return -ENOMEM;
01207
01208
01209 if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
01210 dhcp->local.sin_addr, iobuf->data,
01211 iob_tailroom ( iobuf ) ) ) != 0 ) {
01212 DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
01213 dhcp, strerror ( rc ) );
01214 goto done;
01215 }
01216
01217
01218 if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
01219 DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
01220 dhcp, strerror ( rc ) );
01221 goto done;
01222 }
01223
01224
01225 iob_put ( iobuf, dhcppkt.len );
01226 if ( ( rc = xfer_deliver_iob_meta ( &dhcp->xfer, iob_disown ( iobuf ),
01227 &meta ) ) != 0 ) {
01228 DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
01229 dhcp, strerror ( rc ) );
01230 goto done;
01231 }
01232
01233 done:
01234 free_iob ( iobuf );
01235 return rc;
01236 }
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246 static int dhcp_deliver_iob ( struct xfer_interface *xfer,
01247 struct io_buffer *iobuf,
01248 struct xfer_metadata *meta ) {
01249 struct dhcp_session *dhcp =
01250 container_of ( xfer, struct dhcp_session, xfer );
01251 struct sockaddr_in *peer;
01252 size_t data_len;
01253 struct dhcp_packet *dhcppkt;
01254 struct dhcphdr *dhcphdr;
01255 uint8_t msgtype = 0;
01256 struct in_addr server_id = { 0 };
01257 int rc = 0;
01258
01259
01260 if ( ! meta->src ) {
01261 DBGC ( dhcp, "DHCP %p received packet without source port\n",
01262 dhcp );
01263 rc = -EINVAL;
01264 goto err_no_src;
01265 }
01266 peer = ( struct sockaddr_in * ) meta->src;
01267
01268
01269
01270
01271
01272
01273 data_len = iob_len ( iobuf );
01274 dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
01275 if ( ! dhcppkt ) {
01276 rc = -ENOMEM;
01277 goto err_alloc_dhcppkt;
01278 }
01279 dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
01280 memcpy ( dhcphdr, iobuf->data, data_len );
01281 dhcppkt_init ( dhcppkt, dhcphdr, data_len );
01282
01283
01284 dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
01285 sizeof ( msgtype ) );
01286
01287
01288 dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
01289 &server_id, sizeof ( server_id ) );
01290
01291
01292 if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
01293 DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
01294 "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
01295 inet_ntoa ( peer->sin_addr ),
01296 ntohs ( peer->sin_port ) );
01297 rc = -EINVAL;
01298 goto err_xid;
01299 };
01300
01301
01302 dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
01303
01304 err_xid:
01305 dhcppkt_put ( dhcppkt );
01306 err_alloc_dhcppkt:
01307 err_no_src:
01308 free_iob ( iobuf );
01309 return rc;
01310 }
01311
01312
01313 static struct xfer_interface_operations dhcp_xfer_operations = {
01314 .close = ignore_xfer_close,
01315 .vredirect = xfer_vreopen,
01316 .window = unlimited_xfer_window,
01317 .alloc_iob = default_xfer_alloc_iob,
01318 .deliver_iob = dhcp_deliver_iob,
01319 .deliver_raw = xfer_deliver_as_iob,
01320 };
01321
01322
01323
01324
01325
01326
01327
01328 static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
01329 struct dhcp_session *dhcp =
01330 container_of ( timer, struct dhcp_session, timer );
01331
01332
01333 if ( fail ) {
01334 dhcp_finished ( dhcp, -ETIMEDOUT );
01335 return;
01336 }
01337
01338
01339 dhcp->state->expired ( dhcp );
01340 }
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353 static void dhcp_job_kill ( struct job_interface *job ) {
01354 struct dhcp_session *dhcp =
01355 container_of ( job, struct dhcp_session, job );
01356
01357
01358 dhcp_finished ( dhcp, -ECANCELED );
01359 }
01360
01361
01362 static struct job_interface_operations dhcp_job_operations = {
01363 .done = ignore_job_done,
01364 .kill = dhcp_job_kill,
01365 .progress = ignore_job_progress,
01366 };
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381 static struct sockaddr dhcp_peer = {
01382 .sa_family = AF_INET,
01383 };
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
01402 struct dhcp_session *dhcp;
01403 int rc;
01404
01405
01406 get_cached_dhcpack();
01407 if ( fetch_uintz_setting ( NULL, &use_cached_setting ) ) {
01408 DBG ( "DHCP using cached network settings\n" );
01409 return 1;
01410 }
01411
01412
01413 dhcp = zalloc ( sizeof ( *dhcp ) );
01414 if ( ! dhcp )
01415 return -ENOMEM;
01416 dhcp->refcnt.free = dhcp_free;
01417 job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
01418 xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
01419 dhcp->netdev = netdev_get ( netdev );
01420 dhcp->local.sin_family = AF_INET;
01421 dhcp->local.sin_port = htons ( BOOTPC_PORT );
01422 dhcp->timer.expired = dhcp_timer_expired;
01423
01424
01425 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
01426 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
01427 goto err;
01428
01429
01430 dhcp_set_state ( dhcp, &dhcp_state_discover );
01431
01432
01433 job_plug_plug ( &dhcp->job, job );
01434 ref_put ( &dhcp->refcnt );
01435 return 0;
01436
01437 err:
01438 dhcp_finished ( dhcp, rc );
01439 ref_put ( &dhcp->refcnt );
01440 return rc;
01441 }
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454 static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
01455 size_t raw_len, struct in_addr *ip ) {
01456 struct dhcp_pxe_boot_server *server = raw;
01457 size_t server_len;
01458 unsigned int i;
01459
01460 while ( raw_len ) {
01461 if ( raw_len < sizeof ( *server ) ) {
01462 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
01463 dhcp );
01464 break;
01465 }
01466 server_len = offsetof ( typeof ( *server ),
01467 ip[ server->num_ip ] );
01468 if ( raw_len < server_len ) {
01469 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
01470 dhcp );
01471 break;
01472 }
01473 if ( server->type == dhcp->pxe_type ) {
01474 for ( i = 0 ; i < server->num_ip ; i++ )
01475 *(ip++) = server->ip[i];
01476 }
01477 server = ( ( ( void * ) server ) + server_len );
01478 raw_len -= server_len;
01479 }
01480 }
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494 int start_pxebs ( struct job_interface *job, struct net_device *netdev,
01495 unsigned int pxe_type ) {
01496 struct setting pxe_discovery_control_setting =
01497 { .tag = DHCP_PXE_DISCOVERY_CONTROL };
01498 struct setting pxe_boot_servers_setting =
01499 { .tag = DHCP_PXE_BOOT_SERVERS };
01500 struct setting pxe_boot_server_mcast_setting =
01501 { .tag = DHCP_PXE_BOOT_SERVER_MCAST };
01502 ssize_t pxebs_list_len;
01503 struct dhcp_session *dhcp;
01504 struct in_addr *ip;
01505 unsigned int pxe_discovery_control;
01506 int rc;
01507
01508
01509 pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
01510 if ( pxebs_list_len < 0 )
01511 pxebs_list_len = 0;
01512
01513
01514 dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) +
01515 sizeof ( *ip ) + pxebs_list_len +
01516 sizeof ( *ip ) );
01517 if ( ! dhcp )
01518 return -ENOMEM;
01519 dhcp->refcnt.free = dhcp_free;
01520 job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
01521 xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
01522 dhcp->netdev = netdev_get ( netdev );
01523 dhcp->local.sin_family = AF_INET;
01524 fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
01525 &dhcp->local.sin_addr );
01526 dhcp->local.sin_port = htons ( BOOTPC_PORT );
01527 dhcp->pxe_type = cpu_to_le16 ( pxe_type );
01528 dhcp->timer.expired = dhcp_timer_expired;
01529
01530
01531 pxe_discovery_control =
01532 fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
01533 ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
01534 dhcp->pxe_attempt = ip;
01535 if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
01536 fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
01537 if ( ip->s_addr )
01538 ip++;
01539 }
01540 if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
01541 (ip++)->s_addr = INADDR_BROADCAST;
01542 if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
01543 dhcp->pxe_accept = ip;
01544 if ( pxebs_list_len ) {
01545 uint8_t buf[pxebs_list_len];
01546
01547 fetch_setting ( NULL, &pxe_boot_servers_setting,
01548 buf, sizeof ( buf ) );
01549 pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
01550 }
01551 if ( ! dhcp->pxe_attempt->s_addr ) {
01552 DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
01553 dhcp, pxe_type );
01554 rc = -EINVAL;
01555 goto err;
01556 }
01557
01558
01559 DBGC ( dhcp, "DHCP %p attempting", dhcp );
01560 for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
01561 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
01562 DBGC ( dhcp, "\n" );
01563 if ( dhcp->pxe_accept ) {
01564 DBGC ( dhcp, "DHCP %p accepting", dhcp );
01565 for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
01566 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
01567 DBGC ( dhcp, "\n" );
01568 }
01569
01570
01571 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
01572 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
01573 goto err;
01574
01575
01576 dhcp_set_state ( dhcp, &dhcp_state_pxebs );
01577
01578
01579 job_plug_plug ( &dhcp->job, job );
01580 ref_put ( &dhcp->refcnt );
01581 return 0;
01582
01583 err:
01584 dhcp_finished ( dhcp, rc );
01585 ref_put ( &dhcp->refcnt );
01586 return rc;
01587 }