You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dhcp.c 45KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  1. /*
  2. * Copyright (C) 2006 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #include <assert.h>
  25. #include <byteswap.h>
  26. #include <ipxe/if_ether.h>
  27. #include <ipxe/netdevice.h>
  28. #include <ipxe/device.h>
  29. #include <ipxe/xfer.h>
  30. #include <ipxe/open.h>
  31. #include <ipxe/job.h>
  32. #include <ipxe/retry.h>
  33. #include <ipxe/tcpip.h>
  34. #include <ipxe/ip.h>
  35. #include <ipxe/uuid.h>
  36. #include <ipxe/timer.h>
  37. #include <ipxe/settings.h>
  38. #include <ipxe/dhcp.h>
  39. #include <ipxe/dhcpopts.h>
  40. #include <ipxe/dhcppkt.h>
  41. #include <ipxe/features.h>
  42. /** @file
  43. *
  44. * Dynamic Host Configuration Protocol
  45. *
  46. */
  47. struct dhcp_session;
  48. static int dhcp_tx ( struct dhcp_session *dhcp );
  49. /**
  50. * DHCP operation types
  51. *
  52. * This table maps from DHCP message types (i.e. values of the @c
  53. * DHCP_MESSAGE_TYPE option) to values of the "op" field within a DHCP
  54. * packet.
  55. */
  56. static const uint8_t dhcp_op[] = {
  57. [DHCPDISCOVER] = BOOTP_REQUEST,
  58. [DHCPOFFER] = BOOTP_REPLY,
  59. [DHCPREQUEST] = BOOTP_REQUEST,
  60. [DHCPDECLINE] = BOOTP_REQUEST,
  61. [DHCPACK] = BOOTP_REPLY,
  62. [DHCPNAK] = BOOTP_REPLY,
  63. [DHCPRELEASE] = BOOTP_REQUEST,
  64. [DHCPINFORM] = BOOTP_REQUEST,
  65. };
  66. /** Raw option data for options common to all DHCP requests */
  67. static uint8_t dhcp_request_options_data[] = {
  68. DHCP_MESSAGE_TYPE, DHCP_BYTE ( 0 ),
  69. DHCP_MAX_MESSAGE_SIZE,
  70. DHCP_WORD ( ETH_MAX_MTU - 20 /* IP header */ - 8 /* UDP header */ ),
  71. DHCP_CLIENT_ARCHITECTURE, DHCP_WORD ( 0 ),
  72. DHCP_CLIENT_NDI, DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ ),
  73. DHCP_VENDOR_CLASS_ID,
  74. DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',
  75. 'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':',
  76. 'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' ),
  77. DHCP_USER_CLASS_ID,
  78. DHCP_STRING ( 'g', 'P', 'X', 'E' ),
  79. DHCP_PARAMETER_REQUEST_LIST,
  80. DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
  81. DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
  82. DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
  83. DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
  84. DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
  85. DHCP_END
  86. };
  87. /** Version number feature */
  88. FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
  89. /** DHCP server address setting */
  90. struct setting dhcp_server_setting __setting = {
  91. .name = "dhcp-server",
  92. .description = "DHCP server address",
  93. .tag = DHCP_SERVER_IDENTIFIER,
  94. .type = &setting_type_ipv4,
  95. };
  96. /** DHCP user class setting */
  97. struct setting user_class_setting __setting = {
  98. .name = "user-class",
  99. .description = "User class identifier",
  100. .tag = DHCP_USER_CLASS_ID,
  101. .type = &setting_type_string,
  102. };
  103. /** Use cached network settings */
  104. struct setting use_cached_setting __setting = {
  105. .name = "use-cached",
  106. .description = "Use cached network settings",
  107. .tag = DHCP_EB_USE_CACHED,
  108. .type = &setting_type_uint8,
  109. };
  110. /**
  111. * Name a DHCP packet type
  112. *
  113. * @v msgtype DHCP message type
  114. * @ret string DHCP mesasge type name
  115. */
  116. static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
  117. switch ( msgtype ) {
  118. case DHCPNONE: return "BOOTP"; /* Non-DHCP packet */
  119. case DHCPDISCOVER: return "DHCPDISCOVER";
  120. case DHCPOFFER: return "DHCPOFFER";
  121. case DHCPREQUEST: return "DHCPREQUEST";
  122. case DHCPDECLINE: return "DHCPDECLINE";
  123. case DHCPACK: return "DHCPACK";
  124. case DHCPNAK: return "DHCPNAK";
  125. case DHCPRELEASE: return "DHCPRELEASE";
  126. case DHCPINFORM: return "DHCPINFORM";
  127. default: return "DHCP<invalid>";
  128. }
  129. }
  130. /**
  131. * Calculate DHCP transaction ID for a network device
  132. *
  133. * @v netdev Network device
  134. * @ret xid DHCP XID
  135. *
  136. * Extract the least significant bits of the hardware address for use
  137. * as the transaction ID.
  138. */
  139. static uint32_t dhcp_xid ( struct net_device *netdev ) {
  140. uint32_t xid;
  141. memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
  142. - sizeof ( xid ) ), sizeof ( xid ) );
  143. return xid;
  144. }
  145. /****************************************************************************
  146. *
  147. * DHCP session
  148. *
  149. */
  150. struct dhcp_session;
  151. /** DHCP session state operations */
  152. struct dhcp_session_state {
  153. /** State name */
  154. const char *name;
  155. /**
  156. * Construct transmitted packet
  157. *
  158. * @v dhcp DHCP session
  159. * @v dhcppkt DHCP packet
  160. * @v peer Destination address
  161. */
  162. int ( * tx ) ( struct dhcp_session *dhcp,
  163. struct dhcp_packet *dhcppkt,
  164. struct sockaddr_in *peer );
  165. /** Handle received packet
  166. *
  167. * @v dhcp DHCP session
  168. * @v dhcppkt DHCP packet
  169. * @v peer DHCP server address
  170. * @v msgtype DHCP message type
  171. * @v server_id DHCP server ID
  172. */
  173. void ( * rx ) ( struct dhcp_session *dhcp,
  174. struct dhcp_packet *dhcppkt,
  175. struct sockaddr_in *peer,
  176. uint8_t msgtype, struct in_addr server_id );
  177. /** Handle timer expiry
  178. *
  179. * @v dhcp DHCP session
  180. */
  181. void ( * expired ) ( struct dhcp_session *dhcp );
  182. /** Transmitted message type */
  183. uint8_t tx_msgtype;
  184. /** Apply minimum timeout */
  185. uint8_t apply_min_timeout;
  186. };
  187. static struct dhcp_session_state dhcp_state_discover;
  188. static struct dhcp_session_state dhcp_state_request;
  189. static struct dhcp_session_state dhcp_state_proxy;
  190. static struct dhcp_session_state dhcp_state_pxebs;
  191. /** DHCP offer is valid for IP lease */
  192. #define DHCP_OFFER_IP 1
  193. /** DHCP offer is valid for PXE options */
  194. #define DHCP_OFFER_PXE 2
  195. /** A DHCP offer */
  196. struct dhcp_offer {
  197. /** IP address of server granting offer */
  198. struct in_addr server;
  199. /** IP address being offered, or 0.0.0.0 for a pure proxy */
  200. struct in_addr ip;
  201. /** DHCP packet containing PXE options; NULL if missing or proxied */
  202. struct dhcp_packet *pxe;
  203. /** Valid uses for this offer, a combination of DHCP_OFFER bits */
  204. uint8_t valid;
  205. /** Priority of this offer */
  206. int8_t priority;
  207. /** Whether to ignore PXE DHCP extensions */
  208. uint8_t no_pxedhcp;
  209. };
  210. /** Maximum number of DHCP offers to queue */
  211. #define DHCP_MAX_OFFERS 6
  212. /** A DHCP session */
  213. struct dhcp_session {
  214. /** Reference counter */
  215. struct refcnt refcnt;
  216. /** Job control interface */
  217. struct job_interface job;
  218. /** Data transfer interface */
  219. struct xfer_interface xfer;
  220. /** Network device being configured */
  221. struct net_device *netdev;
  222. /** Local socket address */
  223. struct sockaddr_in local;
  224. /** State of the session */
  225. struct dhcp_session_state *state;
  226. /** PXE Boot Server type */
  227. uint16_t pxe_type;
  228. /** List of PXE Boot Servers to attempt */
  229. struct in_addr *pxe_attempt;
  230. /** List of PXE Boot Servers to accept */
  231. struct in_addr *pxe_accept;
  232. /** Retransmission timer */
  233. struct retry_timer timer;
  234. /** Start time of the current state (in ticks) */
  235. unsigned long start;
  236. /** DHCP offer just requested */
  237. struct dhcp_offer *current_offer;
  238. /** List of DHCP offers received */
  239. struct dhcp_offer offers[DHCP_MAX_OFFERS];
  240. };
  241. /**
  242. * Free DHCP session
  243. *
  244. * @v refcnt Reference counter
  245. */
  246. static void dhcp_free ( struct refcnt *refcnt ) {
  247. struct dhcp_session *dhcp =
  248. container_of ( refcnt, struct dhcp_session, refcnt );
  249. int i;
  250. for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
  251. if ( dhcp->offers[i].pxe )
  252. dhcppkt_put ( dhcp->offers[i].pxe );
  253. }
  254. netdev_put ( dhcp->netdev );
  255. free ( dhcp );
  256. }
  257. /**
  258. * Mark DHCP session as complete
  259. *
  260. * @v dhcp DHCP session
  261. * @v rc Return status code
  262. */
  263. static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
  264. /* Block futher incoming messages */
  265. job_nullify ( &dhcp->job );
  266. xfer_nullify ( &dhcp->xfer );
  267. /* Stop retry timer */
  268. stop_timer ( &dhcp->timer );
  269. /* Free resources and close interfaces */
  270. xfer_close ( &dhcp->xfer, rc );
  271. job_done ( &dhcp->job, rc );
  272. }
  273. /**
  274. * Transition to new DHCP session state
  275. *
  276. * @v dhcp DHCP session
  277. * @v state New session state
  278. */
  279. static void dhcp_set_state ( struct dhcp_session *dhcp,
  280. struct dhcp_session_state *state ) {
  281. DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
  282. dhcp->state = state;
  283. dhcp->start = currticks();
  284. stop_timer ( &dhcp->timer );
  285. dhcp->timer.min_timeout =
  286. ( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 );
  287. dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
  288. start_timer_nodelay ( &dhcp->timer );
  289. }
  290. /**
  291. * Determine next DHCP offer to try
  292. *
  293. * @v dhcp DHCP session
  294. * @v type DHCP offer type
  295. * @ret offer Next DHCP offer to try
  296. *
  297. * Offers are ranked by priority, then by completeness (combined
  298. * IP+PXE are tried before @a type alone), then by order of receipt.
  299. */
  300. static struct dhcp_offer * dhcp_next_offer ( struct dhcp_session *dhcp,
  301. uint8_t type ) {
  302. struct dhcp_offer *offer;
  303. struct dhcp_offer *best = NULL;
  304. for ( offer = dhcp->offers ; offer < dhcp->offers + DHCP_MAX_OFFERS ;
  305. offer++ ) {
  306. if ( ( offer->valid & type ) &&
  307. ( ( best == NULL ) ||
  308. ( offer->priority > best->priority ) ||
  309. ( ( offer->priority == best->priority ) &&
  310. ( offer->valid & ~best->valid ) ) ) )
  311. best = offer;
  312. }
  313. return best;
  314. }
  315. /****************************************************************************
  316. *
  317. * DHCP state machine
  318. *
  319. */
  320. /**
  321. * Construct transmitted packet for DHCP discovery
  322. *
  323. * @v dhcp DHCP session
  324. * @v dhcppkt DHCP packet
  325. * @v peer Destination address
  326. */
  327. static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
  328. struct dhcp_packet *dhcppkt __unused,
  329. struct sockaddr_in *peer ) {
  330. DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
  331. /* Set server address */
  332. peer->sin_addr.s_addr = INADDR_BROADCAST;
  333. peer->sin_port = htons ( BOOTPS_PORT );
  334. return 0;
  335. }
  336. /**
  337. * Handle received DHCPOFFER during any state
  338. *
  339. * @v dhcp DHCP session
  340. * @v dhcppkt DHCP packet
  341. * @v peer DHCP server address
  342. * @v msgtype DHCP message type
  343. * @v server_id DHCP server ID
  344. */
  345. static void dhcp_rx_offer ( struct dhcp_session *dhcp,
  346. struct dhcp_packet *dhcppkt,
  347. struct sockaddr_in *peer, uint8_t msgtype,
  348. struct in_addr server_id ) {
  349. char vci[9]; /* "PXEClient" */
  350. int vci_len;
  351. int has_pxeclient;
  352. int pxeopts_len;
  353. int has_pxeopts;
  354. uint8_t discovery_control = 0;
  355. struct dhcp_offer *offer;
  356. int i;
  357. DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
  358. dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
  359. ntohs ( peer->sin_port ) );
  360. if ( server_id.s_addr != peer->sin_addr.s_addr )
  361. DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
  362. /* Identify offered IP address */
  363. if ( dhcppkt->dhcphdr->yiaddr.s_addr )
  364. DBGC ( dhcp, " for %s", inet_ntoa ( dhcppkt->dhcphdr->yiaddr ));
  365. /* Enqueue an offer to be filled in */
  366. for ( i = 0 ; i < DHCP_MAX_OFFERS ; i++ ) {
  367. if ( dhcp->offers[i].server.s_addr == server_id.s_addr ) {
  368. DBGC ( dhcp, " dup\n" );
  369. return;
  370. }
  371. if ( ! dhcp->offers[i].valid )
  372. break;
  373. }
  374. if ( i == DHCP_MAX_OFFERS ) {
  375. DBGC ( dhcp, " dropped\n" );
  376. return;
  377. }
  378. offer = &dhcp->offers[i];
  379. offer->server = server_id;
  380. offer->ip = dhcppkt->dhcphdr->yiaddr;
  381. /* Identify "PXEClient" vendor class */
  382. vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
  383. vci, sizeof ( vci ) );
  384. has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
  385. ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
  386. /*
  387. * Identify presence of PXE-specific options
  388. *
  389. * The Intel firmware appears to check for:
  390. * - PXE_DISCOVERY_CONTROL exists and has bit 3 set, or
  391. * - both PXE_BOOT_MENU and PXE_BOOT_MENU_PROMPT exist
  392. *
  393. * If DISCOVERY_CONTROL bit 3 is set, the firmware treats this
  394. * packet like a "normal" non-PXE DHCP packet with respect to
  395. * boot filename, except that it can come from ProxyDHCP. This
  396. * is the scheme that dnsmasq uses in the simple case.
  397. *
  398. * Otherwise, if one of the boot menu / boot menu prompt
  399. * options exists but not both, the firmware signals an
  400. * error. If neither exists, the packet is not considered to
  401. * contain DHCP options.
  402. *
  403. * In an effort to preserve semantics but be more flexible, we
  404. * check only for bit 3 of DISCOVERY_CONTROL or the presence
  405. * of BOOT_MENU. We don't care (yet) about the menu prompt.
  406. */
  407. pxeopts_len = dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 );
  408. dhcppkt_fetch ( dhcppkt, DHCP_PXE_DISCOVERY_CONTROL,
  409. &discovery_control, sizeof ( discovery_control ) );
  410. has_pxeopts = ( ( pxeopts_len >= 0 ) ||
  411. ( discovery_control & PXEBS_SKIP ) );
  412. if ( has_pxeclient )
  413. DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
  414. if ( has_pxeclient && has_pxeopts ) {
  415. /* Save reference to packet for future use */
  416. if ( offer->pxe )
  417. dhcppkt_put ( offer->pxe );
  418. offer->pxe = dhcppkt_get ( dhcppkt );
  419. }
  420. /* Identify priority */
  421. dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &offer->priority,
  422. sizeof ( offer->priority ) );
  423. if ( offer->priority )
  424. DBGC ( dhcp, " pri %d", offer->priority );
  425. /* Identify ignore-PXE flag */
  426. dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &offer->no_pxedhcp,
  427. sizeof ( offer->no_pxedhcp ) );
  428. if ( offer->no_pxedhcp )
  429. DBGC ( dhcp, " nopxe" );
  430. DBGC ( dhcp, "\n" );
  431. /* Determine roles this offer can fill */
  432. if ( offer->ip.s_addr &&
  433. ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
  434. ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) )
  435. offer->valid |= DHCP_OFFER_IP;
  436. if ( has_pxeclient && ( msgtype == DHCPOFFER ) )
  437. offer->valid |= DHCP_OFFER_PXE;
  438. }
  439. /**
  440. * Handle received packet during DHCP discovery
  441. *
  442. * @v dhcp DHCP session
  443. * @v dhcppkt DHCP packet
  444. * @v peer DHCP server address
  445. * @v msgtype DHCP message type
  446. * @v server_id DHCP server ID
  447. */
  448. static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
  449. struct dhcp_packet *dhcppkt,
  450. struct sockaddr_in *peer, uint8_t msgtype,
  451. struct in_addr server_id ) {
  452. unsigned long elapsed;
  453. struct dhcp_offer *ip_offer;
  454. dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
  455. /* We can exit the discovery state when we have a valid
  456. * DHCPOFFER, and either:
  457. *
  458. * o The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or
  459. * o We have a valid ProxyDHCPOFFER, or
  460. * o We have allowed sufficient time for ProxyDHCPOFFERs.
  461. */
  462. /* If we don't yet have a DHCPOFFER, do nothing */
  463. ip_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
  464. if ( ! ip_offer )
  465. return;
  466. /* If we can't yet transition to DHCPREQUEST, do nothing */
  467. elapsed = ( currticks() - dhcp->start );
  468. if ( ! ( ip_offer->no_pxedhcp ||
  469. dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ||
  470. ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
  471. return;
  472. /* Transition to DHCPREQUEST */
  473. dhcp_set_state ( dhcp, &dhcp_state_request );
  474. }
  475. /**
  476. * Handle timer expiry during DHCP discovery
  477. *
  478. * @v dhcp DHCP session
  479. */
  480. static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
  481. unsigned long elapsed = ( currticks() - dhcp->start );
  482. /* Give up waiting for ProxyDHCP before we reach the failure point */
  483. if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) &&
  484. ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
  485. dhcp_set_state ( dhcp, &dhcp_state_request );
  486. return;
  487. }
  488. /* Otherwise, retransmit current packet */
  489. dhcp_tx ( dhcp );
  490. }
  491. /** DHCP discovery state operations */
  492. static struct dhcp_session_state dhcp_state_discover = {
  493. .name = "discovery",
  494. .tx = dhcp_discovery_tx,
  495. .rx = dhcp_discovery_rx,
  496. .expired = dhcp_discovery_expired,
  497. .tx_msgtype = DHCPDISCOVER,
  498. .apply_min_timeout = 1,
  499. };
  500. /**
  501. * Construct transmitted packet for DHCP request
  502. *
  503. * @v dhcp DHCP session
  504. * @v dhcppkt DHCP packet
  505. * @v peer Destination address
  506. */
  507. static int dhcp_request_tx ( struct dhcp_session *dhcp,
  508. struct dhcp_packet *dhcppkt,
  509. struct sockaddr_in *peer ) {
  510. int rc;
  511. struct dhcp_offer *offer;
  512. offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_IP );
  513. DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
  514. dhcp, inet_ntoa ( offer->server ), BOOTPS_PORT );
  515. DBGC ( dhcp, " for %s\n", inet_ntoa ( offer->ip ) );
  516. /* Set server ID */
  517. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
  518. &offer->server,
  519. sizeof ( offer->server ) ) ) != 0 )
  520. return rc;
  521. /* Set requested IP address */
  522. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
  523. &offer->ip, sizeof ( offer->ip ) ) ) != 0 )
  524. return rc;
  525. /* Set server address */
  526. peer->sin_addr.s_addr = INADDR_BROADCAST;
  527. peer->sin_port = htons ( BOOTPS_PORT );
  528. return 0;
  529. }
  530. /**
  531. * Handle received packet during DHCP request
  532. *
  533. * @v dhcp DHCP session
  534. * @v dhcppkt DHCP packet
  535. * @v peer DHCP server address
  536. * @v msgtype DHCP message type
  537. * @v server_id DHCP server ID
  538. */
  539. static void dhcp_request_rx ( struct dhcp_session *dhcp,
  540. struct dhcp_packet *dhcppkt,
  541. struct sockaddr_in *peer, uint8_t msgtype,
  542. struct in_addr server_id ) {
  543. struct in_addr ip;
  544. struct settings *parent;
  545. int rc;
  546. struct dhcp_offer *pxe_offer;
  547. if ( msgtype == DHCPOFFER ) {
  548. dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
  549. if ( dhcp_next_offer ( dhcp, DHCP_OFFER_IP ) !=
  550. dhcp->current_offer ) {
  551. /* Restart due to higher-priority offer received */
  552. DBGC ( dhcp, "DHCP %p re-requesting\n", dhcp );
  553. dhcp_set_state ( dhcp, &dhcp_state_request );
  554. }
  555. return;
  556. }
  557. DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
  558. dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
  559. ntohs ( peer->sin_port ) );
  560. if ( server_id.s_addr != peer->sin_addr.s_addr )
  561. DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
  562. /* Identify leased IP address */
  563. ip = dhcppkt->dhcphdr->yiaddr;
  564. if ( ip.s_addr )
  565. DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
  566. DBGC ( dhcp, "\n" );
  567. /* Filter out unacceptable responses */
  568. if ( peer->sin_port != htons ( BOOTPS_PORT ) )
  569. return;
  570. if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
  571. return;
  572. if ( server_id.s_addr != dhcp->current_offer->server.s_addr )
  573. return;
  574. /* Record assigned address */
  575. dhcp->local.sin_addr = ip;
  576. /* Register settings */
  577. parent = netdev_settings ( dhcp->netdev );
  578. if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
  579. DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
  580. dhcp, strerror ( rc ) );
  581. dhcp_finished ( dhcp, rc );
  582. return;
  583. }
  584. /* Locate best source of PXE settings */
  585. pxe_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
  586. if ( ( ! pxe_offer ) || /* No PXE available */
  587. /* IP offer instructs us to ignore PXE */
  588. dhcp->current_offer->no_pxedhcp ||
  589. /* PXE settings already registered with IP offer */
  590. ( ( dhcp->current_offer == pxe_offer ) && ( pxe_offer->pxe ) ) ) {
  591. /* Terminate DHCP */
  592. dhcp_finished ( dhcp, 0 );
  593. } else if ( pxe_offer->pxe ) {
  594. /* Register PXE settings and terminate DHCP */
  595. pxe_offer->pxe->settings.name = PROXYDHCP_SETTINGS_NAME;
  596. if ( ( rc = register_settings ( &pxe_offer->pxe->settings,
  597. NULL ) ) != 0 ) {
  598. DBGC ( dhcp, "DHCP %p could not register settings: "
  599. "%s\n", dhcp, strerror ( rc ) );
  600. }
  601. dhcp_finished ( dhcp, rc );
  602. } else {
  603. /* Start ProxyDHCP */
  604. dhcp_set_state ( dhcp, &dhcp_state_proxy );
  605. }
  606. }
  607. /**
  608. * Handle timer expiry during DHCP discovery
  609. *
  610. * @v dhcp DHCP session
  611. */
  612. static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
  613. /* Retransmit current packet */
  614. dhcp_tx ( dhcp );
  615. }
  616. /** DHCP request state operations */
  617. static struct dhcp_session_state dhcp_state_request = {
  618. .name = "request",
  619. .tx = dhcp_request_tx,
  620. .rx = dhcp_request_rx,
  621. .expired = dhcp_request_expired,
  622. .tx_msgtype = DHCPREQUEST,
  623. .apply_min_timeout = 0,
  624. };
  625. /**
  626. * Construct transmitted packet for ProxyDHCP request
  627. *
  628. * @v dhcp DHCP session
  629. * @v dhcppkt DHCP packet
  630. * @v peer Destination address
  631. */
  632. static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
  633. struct dhcp_packet *dhcppkt,
  634. struct sockaddr_in *peer ) {
  635. int rc;
  636. struct dhcp_offer *offer;
  637. offer = dhcp->current_offer = dhcp_next_offer ( dhcp, DHCP_OFFER_PXE );
  638. DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
  639. inet_ntoa ( offer->server ), PXE_PORT );
  640. /* Set server ID */
  641. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
  642. &offer->server,
  643. sizeof ( offer->server ) ) ) != 0 )
  644. return rc;
  645. /* Set server address */
  646. peer->sin_addr = offer->server;
  647. peer->sin_port = htons ( PXE_PORT );
  648. return 0;
  649. }
  650. /**
  651. * Handle received packet during ProxyDHCP request
  652. *
  653. * @v dhcp DHCP session
  654. * @v dhcppkt DHCP packet
  655. * @v peer DHCP server address
  656. * @v msgtype DHCP message type
  657. * @v server_id DHCP server ID
  658. */
  659. static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
  660. struct dhcp_packet *dhcppkt,
  661. struct sockaddr_in *peer, uint8_t msgtype,
  662. struct in_addr server_id ) {
  663. int rc;
  664. /* Enqueue last-minute DHCPOFFERs for use in case of failure */
  665. if ( peer->sin_port == htons ( BOOTPS_PORT ) &&
  666. msgtype == DHCPOFFER ) {
  667. dhcp_rx_offer ( dhcp, dhcppkt, peer, msgtype, server_id );
  668. return;
  669. }
  670. DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
  671. dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
  672. ntohs ( peer->sin_port ) );
  673. if ( server_id.s_addr != peer->sin_addr.s_addr )
  674. DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
  675. DBGC ( dhcp, "\n" );
  676. /* Filter out unacceptable responses */
  677. if ( peer->sin_port != htons ( PXE_PORT ) )
  678. return;
  679. if ( msgtype != DHCPACK && msgtype != DHCPOFFER )
  680. return;
  681. if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
  682. ( server_id.s_addr != dhcp->current_offer->server.s_addr ) )
  683. return;
  684. /* Register settings */
  685. dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
  686. if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
  687. DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
  688. dhcp, strerror ( rc ) );
  689. dhcp_finished ( dhcp, rc );
  690. return;
  691. }
  692. /* Terminate DHCP */
  693. dhcp_finished ( dhcp, 0 );
  694. }
  695. /**
  696. * Handle timer expiry during ProxyDHCP request
  697. *
  698. * @v dhcp DHCP session
  699. */
  700. static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
  701. unsigned long elapsed = ( currticks() - dhcp->start );
  702. /* Give up waiting for ProxyDHCP before we reach the failure point */
  703. if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
  704. /* Mark failed offer as unsuitable for ProxyDHCP */
  705. dhcp->current_offer->valid &= ~DHCP_OFFER_PXE;
  706. /* Prefer not to use only half of a PXE+IP offer if we
  707. * have other offers available
  708. */
  709. dhcp->current_offer->priority = -1;
  710. /* If we have any other PXE offers we can try, go back
  711. * to DHCPREQUEST (since they might not be proxied
  712. * offers, or might be coupled to a new IP address).
  713. * We should probably DHCPRELEASE our old IP, but the
  714. * standard does not require it.
  715. */
  716. if ( dhcp_next_offer ( dhcp, DHCP_OFFER_PXE ) ) {
  717. dhcp->local.sin_addr.s_addr = 0;
  718. dhcp_set_state ( dhcp, &dhcp_state_request );
  719. return;
  720. }
  721. /* No possibilities left; finish without PXE options */
  722. dhcp_finished ( dhcp, 0 );
  723. return;
  724. }
  725. /* Retransmit current packet */
  726. dhcp_tx ( dhcp );
  727. }
  728. /** ProxyDHCP request state operations */
  729. static struct dhcp_session_state dhcp_state_proxy = {
  730. .name = "ProxyDHCP",
  731. .tx = dhcp_proxy_tx,
  732. .rx = dhcp_proxy_rx,
  733. .expired = dhcp_proxy_expired,
  734. .tx_msgtype = DHCPREQUEST,
  735. .apply_min_timeout = 0,
  736. };
  737. /**
  738. * Construct transmitted packet for PXE Boot Server Discovery
  739. *
  740. * @v dhcp DHCP session
  741. * @v dhcppkt DHCP packet
  742. * @v peer Destination address
  743. */
  744. static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
  745. struct dhcp_packet *dhcppkt,
  746. struct sockaddr_in *peer ) {
  747. struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
  748. int rc;
  749. /* Set server address */
  750. peer->sin_addr = *(dhcp->pxe_attempt);
  751. peer->sin_port = ( ( peer->sin_addr.s_addr == INADDR_BROADCAST ) ?
  752. htons ( BOOTPS_PORT ) : htons ( PXE_PORT ) );
  753. DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
  754. dhcp, inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
  755. le16_to_cpu ( dhcp->pxe_type ) );
  756. /* Set boot menu item */
  757. menu_item.type = dhcp->pxe_type;
  758. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
  759. &menu_item, sizeof ( menu_item ) ) ) != 0 )
  760. return rc;
  761. return 0;
  762. }
  763. /**
  764. * Check to see if PXE Boot Server address is acceptable
  765. *
  766. * @v dhcp DHCP session
  767. * @v bs Boot Server address
  768. * @ret accept Boot Server is acceptable
  769. */
  770. static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
  771. struct in_addr bs ) {
  772. struct in_addr *accept;
  773. /* Accept if we have no acceptance filter */
  774. if ( ! dhcp->pxe_accept )
  775. return 1;
  776. /* Scan through acceptance list */
  777. for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
  778. if ( accept->s_addr == bs.s_addr )
  779. return 1;
  780. }
  781. DBGC ( dhcp, "DHCP %p rejecting server %s\n",
  782. dhcp, inet_ntoa ( bs ) );
  783. return 0;
  784. }
  785. /**
  786. * Handle received packet during PXE Boot Server Discovery
  787. *
  788. * @v dhcp DHCP session
  789. * @v dhcppkt DHCP packet
  790. * @v peer DHCP server address
  791. * @v msgtype DHCP message type
  792. * @v server_id DHCP server ID
  793. */
  794. static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
  795. struct dhcp_packet *dhcppkt,
  796. struct sockaddr_in *peer, uint8_t msgtype,
  797. struct in_addr server_id ) {
  798. struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
  799. int rc;
  800. DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
  801. dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
  802. ntohs ( peer->sin_port ) );
  803. if ( server_id.s_addr != peer->sin_addr.s_addr )
  804. DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
  805. /* Identify boot menu item */
  806. dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
  807. &menu_item, sizeof ( menu_item ) );
  808. if ( menu_item.type )
  809. DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
  810. DBGC ( dhcp, "\n" );
  811. /* Filter out unacceptable responses */
  812. if ( ( peer->sin_port != htons ( BOOTPS_PORT ) ) &&
  813. ( peer->sin_port != htons ( PXE_PORT ) ) )
  814. return;
  815. if ( msgtype != DHCPACK )
  816. return;
  817. if ( menu_item.type != dhcp->pxe_type )
  818. return;
  819. if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
  820. server_id : peer->sin_addr ) ) )
  821. return;
  822. /* Register settings */
  823. dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
  824. if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
  825. DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
  826. dhcp, strerror ( rc ) );
  827. dhcp_finished ( dhcp, rc );
  828. return;
  829. }
  830. /* Terminate DHCP */
  831. dhcp_finished ( dhcp, 0 );
  832. }
  833. /**
  834. * Handle timer expiry during PXE Boot Server Discovery
  835. *
  836. * @v dhcp DHCP session
  837. */
  838. static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
  839. unsigned long elapsed = ( currticks() - dhcp->start );
  840. /* Give up waiting before we reach the failure point, and fail
  841. * over to the next server in the attempt list
  842. */
  843. if ( elapsed > PXEBS_MAX_TIMEOUT ) {
  844. dhcp->pxe_attempt++;
  845. if ( dhcp->pxe_attempt->s_addr ) {
  846. dhcp_set_state ( dhcp, &dhcp_state_pxebs );
  847. return;
  848. } else {
  849. dhcp_finished ( dhcp, -ETIMEDOUT );
  850. return;
  851. }
  852. }
  853. /* Retransmit current packet */
  854. dhcp_tx ( dhcp );
  855. }
  856. /** PXE Boot Server Discovery state operations */
  857. static struct dhcp_session_state dhcp_state_pxebs = {
  858. .name = "PXEBS",
  859. .tx = dhcp_pxebs_tx,
  860. .rx = dhcp_pxebs_rx,
  861. .expired = dhcp_pxebs_expired,
  862. .tx_msgtype = DHCPREQUEST,
  863. .apply_min_timeout = 1,
  864. };
  865. /****************************************************************************
  866. *
  867. * Packet construction
  868. *
  869. */
  870. /**
  871. * Construct DHCP client hardware address field and broadcast flag
  872. *
  873. * @v netdev Network device
  874. * @v hlen DHCP hardware address length to fill in
  875. * @v flags DHCP flags to fill in
  876. * @ret chaddr DHCP client hardware address
  877. */
  878. void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
  879. uint16_t *flags ) {
  880. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  881. typeof ( ( ( struct dhcphdr * ) NULL )->chaddr ) chaddr;
  882. /* If the link-layer address cannot fit into the chaddr field
  883. * (as is the case for IPoIB) then try using the hardware
  884. * address instead. If we do this, set the broadcast flag,
  885. * since chaddr then does not represent a valid link-layer
  886. * address for the return path.
  887. *
  888. * If even the hardware address is too large, use an empty
  889. * chaddr field and set the broadcast flag.
  890. *
  891. * This goes against RFC4390, but RFC4390 mandates that we use
  892. * a DHCP client identifier that conforms with RFC4361, which
  893. * we cannot do without either persistent (NIC-independent)
  894. * storage, or by eliminating the hardware address completely
  895. * from the DHCP packet, which seems unfriendly to users.
  896. */
  897. if ( ( *hlen = ll_protocol->ll_addr_len ) <= sizeof ( chaddr ) ) {
  898. return netdev->ll_addr;
  899. }
  900. *flags = htons ( BOOTP_FL_BROADCAST );
  901. if ( ( *hlen = ll_protocol->hw_addr_len ) <= sizeof ( chaddr ) ) {
  902. return netdev->hw_addr;
  903. } else {
  904. *hlen = 0;
  905. return NULL;
  906. }
  907. }
  908. /**
  909. * Create a DHCP packet
  910. *
  911. * @v dhcppkt DHCP packet structure to fill in
  912. * @v netdev Network device
  913. * @v msgtype DHCP message type
  914. * @v options Initial options to include (or NULL)
  915. * @v options_len Length of initial options
  916. * @v data Buffer for DHCP packet
  917. * @v max_len Size of DHCP packet buffer
  918. * @ret rc Return status code
  919. *
  920. * Creates a DHCP packet in the specified buffer, and initialise a
  921. * DHCP packet structure.
  922. */
  923. int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
  924. struct net_device *netdev, uint8_t msgtype,
  925. const void *options, size_t options_len,
  926. void *data, size_t max_len ) {
  927. struct dhcphdr *dhcphdr = data;
  928. void *chaddr;
  929. int rc;
  930. /* Sanity check */
  931. if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
  932. return -ENOSPC;
  933. /* Initialise DHCP packet content */
  934. memset ( dhcphdr, 0, max_len );
  935. dhcphdr->xid = dhcp_xid ( netdev );
  936. dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
  937. dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
  938. dhcphdr->op = dhcp_op[msgtype];
  939. chaddr = dhcp_chaddr ( netdev, &dhcphdr->hlen, &dhcphdr->flags );
  940. memcpy ( dhcphdr->chaddr, chaddr, dhcphdr->hlen );
  941. memcpy ( dhcphdr->options, options, options_len );
  942. /* Initialise DHCP packet structure */
  943. memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
  944. dhcppkt_init ( dhcppkt, data, max_len );
  945. /* Set DHCP_MESSAGE_TYPE option */
  946. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
  947. &msgtype, sizeof ( msgtype ) ) ) != 0 )
  948. return rc;
  949. return 0;
  950. }
  951. /**
  952. * Create DHCP request packet
  953. *
  954. * @v dhcppkt DHCP packet structure to fill in
  955. * @v netdev Network device
  956. * @v msgtype DHCP message type
  957. * @v ciaddr Client IP address
  958. * @v data Buffer for DHCP packet
  959. * @v max_len Size of DHCP packet buffer
  960. * @ret rc Return status code
  961. *
  962. * Creates a DHCP request packet in the specified buffer, and
  963. * initialise a DHCP packet structure.
  964. */
  965. int dhcp_create_request ( struct dhcp_packet *dhcppkt,
  966. struct net_device *netdev, unsigned int msgtype,
  967. struct in_addr ciaddr, void *data, size_t max_len ) {
  968. struct dhcp_netdev_desc dhcp_desc;
  969. struct dhcp_client_id client_id;
  970. struct dhcp_client_uuid client_uuid;
  971. uint8_t *dhcp_features;
  972. size_t dhcp_features_len;
  973. size_t ll_addr_len;
  974. ssize_t len;
  975. int rc;
  976. /* Create DHCP packet */
  977. if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
  978. dhcp_request_options_data,
  979. sizeof ( dhcp_request_options_data ),
  980. data, max_len ) ) != 0 ) {
  981. DBG ( "DHCP could not create DHCP packet: %s\n",
  982. strerror ( rc ) );
  983. return rc;
  984. }
  985. /* Set client IP address */
  986. dhcppkt->dhcphdr->ciaddr = ciaddr;
  987. /* Add options to identify the feature list */
  988. dhcp_features = table_start ( DHCP_FEATURES );
  989. dhcp_features_len = table_num_entries ( DHCP_FEATURES );
  990. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
  991. dhcp_features_len ) ) != 0 ) {
  992. DBG ( "DHCP could not set features list option: %s\n",
  993. strerror ( rc ) );
  994. return rc;
  995. }
  996. /* Add options to identify the network device */
  997. fetch_setting ( &netdev->settings.settings, &busid_setting, &dhcp_desc,
  998. sizeof ( dhcp_desc ) );
  999. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
  1000. sizeof ( dhcp_desc ) ) ) != 0 ) {
  1001. DBG ( "DHCP could not set bus ID option: %s\n",
  1002. strerror ( rc ) );
  1003. return rc;
  1004. }
  1005. /* Add DHCP client identifier. Required for Infiniband, and
  1006. * doesn't hurt other link layers.
  1007. */
  1008. client_id.ll_proto = ntohs ( netdev->ll_protocol->ll_proto );
  1009. ll_addr_len = netdev->ll_protocol->ll_addr_len;
  1010. assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
  1011. memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
  1012. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
  1013. ( ll_addr_len + 1 ) ) ) != 0 ) {
  1014. DBG ( "DHCP could not set client ID: %s\n",
  1015. strerror ( rc ) );
  1016. return rc;
  1017. }
  1018. /* Add client UUID, if we have one. Required for PXE. */
  1019. client_uuid.type = DHCP_CLIENT_UUID_TYPE;
  1020. if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
  1021. &client_uuid.uuid ) ) >= 0 ) {
  1022. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
  1023. &client_uuid,
  1024. sizeof ( client_uuid ) ) ) != 0 ) {
  1025. DBG ( "DHCP could not set client UUID: %s\n",
  1026. strerror ( rc ) );
  1027. return rc;
  1028. }
  1029. }
  1030. /* Add user class, if we have one. */
  1031. if ( ( len = fetch_setting_len ( NULL, &user_class_setting ) ) >= 0 ) {
  1032. char user_class[len];
  1033. fetch_setting ( NULL, &user_class_setting, user_class,
  1034. sizeof ( user_class ) );
  1035. if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID,
  1036. &user_class,
  1037. sizeof ( user_class ) ) ) != 0 ) {
  1038. DBG ( "DHCP could not set user class: %s\n",
  1039. strerror ( rc ) );
  1040. return rc;
  1041. }
  1042. }
  1043. return 0;
  1044. }
  1045. /****************************************************************************
  1046. *
  1047. * Data transfer interface
  1048. *
  1049. */
  1050. /**
  1051. * Transmit DHCP request
  1052. *
  1053. * @v dhcp DHCP session
  1054. * @ret rc Return status code
  1055. */
  1056. static int dhcp_tx ( struct dhcp_session *dhcp ) {
  1057. static struct sockaddr_in peer = {
  1058. .sin_family = AF_INET,
  1059. };
  1060. struct xfer_metadata meta = {
  1061. .netdev = dhcp->netdev,
  1062. .src = ( struct sockaddr * ) &dhcp->local,
  1063. .dest = ( struct sockaddr * ) &peer,
  1064. };
  1065. struct io_buffer *iobuf;
  1066. uint8_t msgtype = dhcp->state->tx_msgtype;
  1067. struct dhcp_packet dhcppkt;
  1068. int rc;
  1069. /* Start retry timer. Do this first so that failures to
  1070. * transmit will be retried.
  1071. */
  1072. start_timer ( &dhcp->timer );
  1073. /* Allocate buffer for packet */
  1074. iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
  1075. if ( ! iobuf )
  1076. return -ENOMEM;
  1077. /* Create basic DHCP packet in temporary buffer */
  1078. if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
  1079. dhcp->local.sin_addr, iobuf->data,
  1080. iob_tailroom ( iobuf ) ) ) != 0 ) {
  1081. DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
  1082. dhcp, strerror ( rc ) );
  1083. goto done;
  1084. }
  1085. /* Fill in packet based on current state */
  1086. if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
  1087. DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
  1088. dhcp, strerror ( rc ) );
  1089. goto done;
  1090. }
  1091. /* Transmit the packet */
  1092. iob_put ( iobuf, dhcppkt.len );
  1093. if ( ( rc = xfer_deliver_iob_meta ( &dhcp->xfer, iob_disown ( iobuf ),
  1094. &meta ) ) != 0 ) {
  1095. DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
  1096. dhcp, strerror ( rc ) );
  1097. goto done;
  1098. }
  1099. done:
  1100. free_iob ( iobuf );
  1101. return rc;
  1102. }
  1103. /**
  1104. * Receive new data
  1105. *
  1106. * @v xfer Data transfer interface
  1107. * @v iobuf I/O buffer
  1108. * @v meta Transfer metadata
  1109. * @ret rc Return status code
  1110. */
  1111. static int dhcp_deliver_iob ( struct xfer_interface *xfer,
  1112. struct io_buffer *iobuf,
  1113. struct xfer_metadata *meta ) {
  1114. struct dhcp_session *dhcp =
  1115. container_of ( xfer, struct dhcp_session, xfer );
  1116. struct sockaddr_in *peer;
  1117. size_t data_len;
  1118. struct dhcp_packet *dhcppkt;
  1119. struct dhcphdr *dhcphdr;
  1120. uint8_t msgtype = 0;
  1121. struct in_addr server_id = { 0 };
  1122. int rc = 0;
  1123. /* Sanity checks */
  1124. if ( ! meta->src ) {
  1125. DBGC ( dhcp, "DHCP %p received packet without source port\n",
  1126. dhcp );
  1127. rc = -EINVAL;
  1128. goto err_no_src;
  1129. }
  1130. peer = ( struct sockaddr_in * ) meta->src;
  1131. /* Create a DHCP packet containing the I/O buffer contents.
  1132. * Whilst we could just use the original buffer in situ, that
  1133. * would waste the unused space in the packet buffer, and also
  1134. * waste a relatively scarce fully-aligned I/O buffer.
  1135. */
  1136. data_len = iob_len ( iobuf );
  1137. dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
  1138. if ( ! dhcppkt ) {
  1139. rc = -ENOMEM;
  1140. goto err_alloc_dhcppkt;
  1141. }
  1142. dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
  1143. memcpy ( dhcphdr, iobuf->data, data_len );
  1144. dhcppkt_init ( dhcppkt, dhcphdr, data_len );
  1145. /* Identify message type */
  1146. dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
  1147. sizeof ( msgtype ) );
  1148. /* Identify server ID */
  1149. dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
  1150. &server_id, sizeof ( server_id ) );
  1151. /* Check for matching transaction ID */
  1152. if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
  1153. DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
  1154. "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
  1155. inet_ntoa ( peer->sin_addr ),
  1156. ntohs ( peer->sin_port ) );
  1157. rc = -EINVAL;
  1158. goto err_xid;
  1159. };
  1160. /* Handle packet based on current state */
  1161. dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
  1162. err_xid:
  1163. dhcppkt_put ( dhcppkt );
  1164. err_alloc_dhcppkt:
  1165. err_no_src:
  1166. free_iob ( iobuf );
  1167. return rc;
  1168. }
  1169. /** DHCP data transfer interface operations */
  1170. static struct xfer_interface_operations dhcp_xfer_operations = {
  1171. .close = ignore_xfer_close,
  1172. .vredirect = xfer_vreopen,
  1173. .window = unlimited_xfer_window,
  1174. .alloc_iob = default_xfer_alloc_iob,
  1175. .deliver_iob = dhcp_deliver_iob,
  1176. .deliver_raw = xfer_deliver_as_iob,
  1177. };
  1178. /**
  1179. * Handle DHCP retry timer expiry
  1180. *
  1181. * @v timer DHCP retry timer
  1182. * @v fail Failure indicator
  1183. */
  1184. static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
  1185. struct dhcp_session *dhcp =
  1186. container_of ( timer, struct dhcp_session, timer );
  1187. /* If we have failed, terminate DHCP */
  1188. if ( fail ) {
  1189. dhcp_finished ( dhcp, -ETIMEDOUT );
  1190. return;
  1191. }
  1192. /* Handle timer expiry based on current state */
  1193. dhcp->state->expired ( dhcp );
  1194. }
  1195. /****************************************************************************
  1196. *
  1197. * Job control interface
  1198. *
  1199. */
  1200. /**
  1201. * Handle kill() event received via job control interface
  1202. *
  1203. * @v job DHCP job control interface
  1204. */
  1205. static void dhcp_job_kill ( struct job_interface *job ) {
  1206. struct dhcp_session *dhcp =
  1207. container_of ( job, struct dhcp_session, job );
  1208. /* Terminate DHCP session */
  1209. dhcp_finished ( dhcp, -ECANCELED );
  1210. }
  1211. /** DHCP job control interface operations */
  1212. static struct job_interface_operations dhcp_job_operations = {
  1213. .done = ignore_job_done,
  1214. .kill = dhcp_job_kill,
  1215. .progress = ignore_job_progress,
  1216. };
  1217. /****************************************************************************
  1218. *
  1219. * Instantiators
  1220. *
  1221. */
  1222. /**
  1223. * DHCP peer address for socket opening
  1224. *
  1225. * This is a dummy address; the only useful portion is the socket
  1226. * family (so that we get a UDP connection). The DHCP client will set
  1227. * the IP address and source port explicitly on each transmission.
  1228. */
  1229. static struct sockaddr dhcp_peer = {
  1230. .sa_family = AF_INET,
  1231. };
  1232. /**
  1233. * Get cached DHCPACK where none exists
  1234. */
  1235. __weak void get_cached_dhcpack ( void ) {}
  1236. /**
  1237. * Start DHCP state machine on a network device
  1238. *
  1239. * @v job Job control interface
  1240. * @v netdev Network device
  1241. * @ret rc Return status code, or positive if cached
  1242. *
  1243. * Starts DHCP on the specified network device. If successful, the
  1244. * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as
  1245. * option sources.
  1246. *
  1247. * On a return of 0, a background job has been started to perform the
  1248. * DHCP request. Any nonzero return means the job has not been
  1249. * started; a positive return value indicates the success condition of
  1250. * having fetched the appropriate data from cached information.
  1251. */
  1252. int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
  1253. struct dhcp_session *dhcp;
  1254. int rc;
  1255. /* Check for cached DHCP information */
  1256. get_cached_dhcpack();
  1257. if ( fetch_uintz_setting ( NULL, &use_cached_setting ) ) {
  1258. DBG ( "DHCP using cached network settings\n" );
  1259. return 1;
  1260. }
  1261. /* Allocate and initialise structure */
  1262. dhcp = zalloc ( sizeof ( *dhcp ) );
  1263. if ( ! dhcp )
  1264. return -ENOMEM;
  1265. dhcp->refcnt.free = dhcp_free;
  1266. job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
  1267. xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
  1268. dhcp->netdev = netdev_get ( netdev );
  1269. dhcp->local.sin_family = AF_INET;
  1270. dhcp->local.sin_port = htons ( BOOTPC_PORT );
  1271. dhcp->timer.expired = dhcp_timer_expired;
  1272. /* Instantiate child objects and attach to our interfaces */
  1273. if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
  1274. ( struct sockaddr * ) &dhcp->local ) ) != 0 )
  1275. goto err;
  1276. /* Enter DHCPDISCOVER state */
  1277. dhcp_set_state ( dhcp, &dhcp_state_discover );
  1278. /* Attach parent interface, mortalise self, and return */
  1279. job_plug_plug ( &dhcp->job, job );
  1280. ref_put ( &dhcp->refcnt );
  1281. return 0;
  1282. err:
  1283. dhcp_finished ( dhcp, rc );
  1284. ref_put ( &dhcp->refcnt );
  1285. return rc;
  1286. }
  1287. /**
  1288. * Retrieve list of PXE boot servers for a given server type
  1289. *
  1290. * @v dhcp DHCP session
  1291. * @v raw DHCP PXE boot server list
  1292. * @v raw_len Length of DHCP PXE boot server list
  1293. * @v ip IP address list to fill in
  1294. *
  1295. * The caller must ensure that the IP address list has sufficient
  1296. * space.
  1297. */
  1298. static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
  1299. size_t raw_len, struct in_addr *ip ) {
  1300. struct dhcp_pxe_boot_server *server = raw;
  1301. size_t server_len;
  1302. unsigned int i;
  1303. while ( raw_len ) {
  1304. if ( raw_len < sizeof ( *server ) ) {
  1305. DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
  1306. dhcp );
  1307. break;
  1308. }
  1309. server_len = offsetof ( typeof ( *server ),
  1310. ip[ server->num_ip ] );
  1311. if ( raw_len < server_len ) {
  1312. DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
  1313. dhcp );
  1314. break;
  1315. }
  1316. if ( server->type == dhcp->pxe_type ) {
  1317. for ( i = 0 ; i < server->num_ip ; i++ )
  1318. *(ip++) = server->ip[i];
  1319. }
  1320. server = ( ( ( void * ) server ) + server_len );
  1321. raw_len -= server_len;
  1322. }
  1323. }
  1324. /**
  1325. * Start PXE Boot Server Discovery on a network device
  1326. *
  1327. * @v job Job control interface
  1328. * @v netdev Network device
  1329. * @v pxe_type PXE server type
  1330. * @ret rc Return status code
  1331. *
  1332. * Starts PXE Boot Server Discovery on the specified network device.
  1333. * If successful, the Boot Server ACK will be registered as an option
  1334. * source.
  1335. */
  1336. int start_pxebs ( struct job_interface *job, struct net_device *netdev,
  1337. unsigned int pxe_type ) {
  1338. struct setting pxe_discovery_control_setting =
  1339. { .tag = DHCP_PXE_DISCOVERY_CONTROL };
  1340. struct setting pxe_boot_servers_setting =
  1341. { .tag = DHCP_PXE_BOOT_SERVERS };
  1342. struct setting pxe_boot_server_mcast_setting =
  1343. { .tag = DHCP_PXE_BOOT_SERVER_MCAST };
  1344. ssize_t pxebs_list_len;
  1345. struct dhcp_session *dhcp;
  1346. struct in_addr *ip;
  1347. unsigned int pxe_discovery_control;
  1348. int rc;
  1349. /* Get upper bound for PXE boot server IP address list */
  1350. pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
  1351. if ( pxebs_list_len < 0 )
  1352. pxebs_list_len = 0;
  1353. /* Allocate and initialise structure */
  1354. dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
  1355. sizeof ( *ip ) /* bcast */ + pxebs_list_len +
  1356. sizeof ( *ip ) /* terminator */ );
  1357. if ( ! dhcp )
  1358. return -ENOMEM;
  1359. dhcp->refcnt.free = dhcp_free;
  1360. job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
  1361. xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
  1362. dhcp->netdev = netdev_get ( netdev );
  1363. dhcp->local.sin_family = AF_INET;
  1364. fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
  1365. &dhcp->local.sin_addr );
  1366. dhcp->local.sin_port = htons ( BOOTPC_PORT );
  1367. dhcp->pxe_type = cpu_to_le16 ( pxe_type );
  1368. dhcp->timer.expired = dhcp_timer_expired;
  1369. /* Construct PXE boot server IP address lists */
  1370. pxe_discovery_control =
  1371. fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
  1372. ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
  1373. dhcp->pxe_attempt = ip;
  1374. if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
  1375. fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
  1376. if ( ip->s_addr )
  1377. ip++;
  1378. }
  1379. if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
  1380. (ip++)->s_addr = INADDR_BROADCAST;
  1381. if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
  1382. dhcp->pxe_accept = ip;
  1383. if ( pxebs_list_len ) {
  1384. uint8_t buf[pxebs_list_len];
  1385. fetch_setting ( NULL, &pxe_boot_servers_setting,
  1386. buf, sizeof ( buf ) );
  1387. pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
  1388. }
  1389. if ( ! dhcp->pxe_attempt->s_addr ) {
  1390. DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
  1391. dhcp, pxe_type );
  1392. rc = -EINVAL;
  1393. goto err;
  1394. }
  1395. /* Dump out PXE server lists */
  1396. DBGC ( dhcp, "DHCP %p attempting", dhcp );
  1397. for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
  1398. DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
  1399. DBGC ( dhcp, "\n" );
  1400. if ( dhcp->pxe_accept ) {
  1401. DBGC ( dhcp, "DHCP %p accepting", dhcp );
  1402. for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
  1403. DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
  1404. DBGC ( dhcp, "\n" );
  1405. }
  1406. /* Instantiate child objects and attach to our interfaces */
  1407. if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
  1408. ( struct sockaddr * ) &dhcp->local ) ) != 0 )
  1409. goto err;
  1410. /* Enter PXEBS state */
  1411. dhcp_set_state ( dhcp, &dhcp_state_pxebs );
  1412. /* Attach parent interface, mortalise self, and return */
  1413. job_plug_plug ( &dhcp->job, job );
  1414. ref_put ( &dhcp->refcnt );
  1415. return 0;
  1416. err:
  1417. dhcp_finished ( dhcp, rc );
  1418. ref_put ( &dhcp->refcnt );
  1419. return rc;
  1420. }