Forgot to set initial session state. Now works!
[people/xl0/gpxe-arm.git] / src / net / udp / dhcp.c
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
19 #include <string.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <byteswap.h>
24 #include <gpxe/if_ether.h>
25 #include <gpxe/netdevice.h>
26 #include <gpxe/xfer.h>
27 #include <gpxe/open.h>
28 #include <gpxe/job.h>
29 #include <gpxe/retry.h>
30 #include <gpxe/dhcp.h>
31
32 /** @file
33  *
34  * Dynamic Host Configuration Protocol
35  *
36  */
37
38 /** DHCP operation types
39  *
40  * This table maps from DHCP message types (i.e. values of the @c
41  * DHCP_MESSAGE_TYPE option) to values of the "op" field within a DHCP
42  * packet.
43  */
44 static const uint8_t dhcp_op[] = {
45         [DHCPDISCOVER]  = BOOTP_REQUEST,
46         [DHCPOFFER]     = BOOTP_REPLY,
47         [DHCPREQUEST]   = BOOTP_REQUEST,
48         [DHCPDECLINE]   = BOOTP_REQUEST,
49         [DHCPACK]       = BOOTP_REPLY,
50         [DHCPNAK]       = BOOTP_REPLY,
51         [DHCPRELEASE]   = BOOTP_REQUEST,
52         [DHCPINFORM]    = BOOTP_REQUEST,
53 };
54
55 /** Raw option data for options common to all DHCP requests */
56 static uint8_t dhcp_request_options_data[] = {
57         DHCP_MAX_MESSAGE_SIZE, DHCP_WORD ( ETH_MAX_MTU ),
58         DHCP_VENDOR_CLASS_ID,
59         DHCP_STRING (  'E', 't', 'h', 'e', 'r', 'b', 'o', 'o', 't' ),
60         DHCP_PARAMETER_REQUEST_LIST,
61         DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS, DHCP_LOG_SERVERS,
62                       DHCP_HOST_NAME, DHCP_DOMAIN_NAME, DHCP_ROOT_PATH,
63                       DHCP_VENDOR_ENCAP, DHCP_TFTP_SERVER_NAME,
64                       DHCP_BOOTFILE_NAME, DHCP_EB_ENCAP,
65                       DHCP_ISCSI_INITIATOR_IQN ),
66         DHCP_END
67 };
68
69 /**
70  * Name a DHCP packet type
71  *
72  * @v msgtype           DHCP message type
73  * @ret string          DHCP mesasge type name
74  */
75 static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
76         switch ( msgtype ) {
77         case 0:                 return "BOOTP"; /* Non-DHCP packet */
78         case DHCPDISCOVER:      return "DHCPDISCOVER";
79         case DHCPOFFER:         return "DHCPOFFER";
80         case DHCPREQUEST:       return "DHCPREQUEST";
81         case DHCPDECLINE:       return "DHCPDECLINE";
82         case DHCPACK:           return "DHCPACK";
83         case DHCPNAK:           return "DHCPNAK";
84         case DHCPRELEASE:       return "DHCPRELEASE";
85         case DHCPINFORM:        return "DHCPINFORM";
86         default:                return "DHCP<invalid>";
87         }
88 }
89
90 /**
91  * Calculate DHCP transaction ID for a network device
92  *
93  * @v netdev            Network device
94  * @ret xid             DHCP XID
95  *
96  * Extract the least significant bits of the hardware address for use
97  * as the transaction ID.
98  */
99 static uint32_t dhcp_xid ( struct net_device *netdev ) {
100         uint32_t xid;
101
102         memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
103                          - sizeof ( xid ) ), sizeof ( xid ) );
104         return xid;
105 }
106
107 /** Options common to all DHCP requests */
108 struct dhcp_option_block dhcp_request_options = {
109         .data = dhcp_request_options_data,
110         .max_len = sizeof ( dhcp_request_options_data ),
111         .len = sizeof ( dhcp_request_options_data ),
112 };
113
114 /**
115  * Set option within DHCP packet
116  *
117  * @v dhcppkt           DHCP packet
118  * @v tag               DHCP option tag
119  * @v data              New value for DHCP option
120  * @v len               Length of value, in bytes
121  * @ret rc              Return status code
122  *
123  * Sets the option within the first available options block within the
124  * DHCP packet.  Option blocks are tried in the order specified by @c
125  * dhcp_option_block_fill_order.
126  *
127  * The magic options @c DHCP_EB_YIADDR and @c DHCP_EB_SIADDR are
128  * intercepted and inserted into the appropriate fixed fields within
129  * the DHCP packet.  The option @c DHCP_OPTION_OVERLOAD is silently
130  * ignored, since our DHCP packet assembly method relies on always
131  * having option overloading in use.
132  */
133 static int set_dhcp_packet_option ( struct dhcp_packet *dhcppkt,
134                                     unsigned int tag, const void *data,
135                                     size_t len ) {
136         struct dhcphdr *dhcphdr = dhcppkt->dhcphdr;
137         struct dhcp_option_block *options = dhcppkt->options;
138         struct dhcp_option *option = NULL;
139
140         /* Special-case the magic options */
141         switch ( tag ) {
142         case DHCP_OPTION_OVERLOAD:
143                 /* Hard-coded in packets we create; always ignore */
144                 return 0;
145         case DHCP_EB_YIADDR:
146                 memcpy ( &dhcphdr->yiaddr, data, sizeof ( dhcphdr->yiaddr ) );
147                 return 0;
148         case DHCP_EB_SIADDR:
149                 memcpy ( &dhcphdr->siaddr, data, sizeof ( dhcphdr->siaddr ) );
150                 return 0;
151         case DHCP_MESSAGE_TYPE:
152         case DHCP_REQUESTED_ADDRESS:
153         case DHCP_PARAMETER_REQUEST_LIST:
154                 /* These options have to be within the main options
155                  * block.  This doesn't seem to be required by the
156                  * RFCs, but at least ISC dhcpd refuses to recognise
157                  * them otherwise.
158                  */
159                 options = &dhcppkt->options[OPTS_MAIN];
160                 break;
161         default:
162                 /* Continue processing as normal */
163                 break;
164         }
165                 
166         /* Set option in first available options block */
167         for ( ; options < &dhcppkt->options[NUM_OPT_BLOCKS] ; options++ ) {
168                 option = set_dhcp_option ( options, tag, data, len );
169                 if ( option )
170                         break;
171         }
172
173         /* Update DHCP packet length */
174         dhcppkt->len = ( offsetof ( typeof ( *dhcppkt->dhcphdr ), options )
175                          + dhcppkt->options[OPTS_MAIN].len );
176
177         return ( option ? 0 : -ENOSPC );
178 }
179
180 /**
181  * Copy option into DHCP packet
182  *
183  * @v dhcppkt           DHCP packet
184  * @v options           DHCP option block, or NULL
185  * @v tag               DHCP option tag to search for
186  * @v new_tag           DHCP option tag to use for copied option
187  * @ret rc              Return status code
188  *
189  * Copies a single option, if present, from the DHCP options block
190  * into a DHCP packet.  The tag for the option may be changed if
191  * desired; this is required by other parts of the DHCP code.
192  *
193  * @c options may specify a single options block, or be left as NULL
194  * in order to search for the option within all registered options
195  * blocks.
196  */
197 static int copy_dhcp_packet_option ( struct dhcp_packet *dhcppkt,
198                                      struct dhcp_option_block *options,
199                                      unsigned int tag, unsigned int new_tag ) {
200         struct dhcp_option *option;
201         int rc;
202
203         option = find_dhcp_option ( options, tag );
204         if ( option ) {
205                 if ( ( rc = set_dhcp_packet_option ( dhcppkt, new_tag,
206                                                      &option->data,
207                                                      option->len ) ) != 0 )
208                         return rc;
209         }
210         return 0;
211 }
212
213 /**
214  * Copy options into DHCP packet
215  *
216  * @v dhcppkt           DHCP packet
217  * @v options           DHCP option block, or NULL
218  * @v encapsulator      Encapsulating option, or zero
219  * @ret rc              Return status code
220  * 
221  * Copies options with the specified encapsulator from DHCP options
222  * blocks into a DHCP packet.  Most options are copied verbatim.
223  * Recognised encapsulated options fields are handled as such.
224  *
225  * @c options may specify a single options block, or be left as NULL
226  * in order to copy options from all registered options blocks.
227  */
228 static int copy_dhcp_packet_encap_options ( struct dhcp_packet *dhcppkt,
229                                             struct dhcp_option_block *options,
230                                             unsigned int encapsulator ) {
231         unsigned int subtag;
232         unsigned int tag;
233         int rc;
234
235         for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
236                 tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
237                 switch ( tag ) {
238                 case DHCP_EB_ENCAP:
239                 case DHCP_VENDOR_ENCAP:
240                         /* Process encapsulated options field */
241                         if ( ( rc = copy_dhcp_packet_encap_options ( dhcppkt,
242                                                                      options,
243                                                                      tag)) !=0)
244                                 return rc;
245                         break;
246                 default:
247                         /* Copy option to reassembled packet */
248                         if ( ( rc = copy_dhcp_packet_option ( dhcppkt, options,
249                                                               tag, tag ) ) !=0)
250                                 return rc;
251                         break;
252                 };
253         }
254
255         return 0;
256 }
257
258 /**
259  * Copy options into DHCP packet
260  *
261  * @v dhcppkt           DHCP packet
262  * @v options           DHCP option block, or NULL
263  * @ret rc              Return status code
264  * 
265  * Copies options from DHCP options blocks into a DHCP packet.  Most
266  * options are copied verbatim.  Recognised encapsulated options
267  * fields are handled as such.
268  *
269  * @c options may specify a single options block, or be left as NULL
270  * in order to copy options from all registered options blocks.
271  */
272 int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
273                                struct dhcp_option_block *options ) {
274         return copy_dhcp_packet_encap_options ( dhcppkt, options, 0 );
275 }
276
277 /**
278  * Create a DHCP packet
279  *
280  * @v netdev            Network device
281  * @v msgtype           DHCP message type
282  * @v data              Buffer for DHCP packet
283  * @v max_len           Size of DHCP packet buffer
284  * @v dhcppkt           DHCP packet structure to fill in
285  * @ret rc              Return status code
286  *
287  * Creates a DHCP packet in the specified buffer, and fills out a @c
288  * dhcp_packet structure that can be passed to
289  * set_dhcp_packet_option() or copy_dhcp_packet_options().
290  */
291 int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
292                          void *data, size_t max_len,
293                          struct dhcp_packet *dhcppkt ) {
294         struct dhcphdr *dhcphdr = data;
295         static const uint8_t overloading = ( DHCP_OPTION_OVERLOAD_FILE |
296                                              DHCP_OPTION_OVERLOAD_SNAME );
297         int rc;
298
299         /* Sanity check */
300         if ( max_len < sizeof ( *dhcphdr ) )
301                 return -ENOSPC;
302
303         /* Initialise DHCP packet content */
304         memset ( dhcphdr, 0, max_len );
305         dhcphdr->xid = dhcp_xid ( netdev );
306         dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
307         dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
308         dhcphdr->hlen = netdev->ll_protocol->ll_addr_len;
309         memcpy ( dhcphdr->chaddr, netdev->ll_addr, dhcphdr->hlen );
310         dhcphdr->op = dhcp_op[msgtype];
311
312         /* Initialise DHCP packet structure */
313         dhcppkt->dhcphdr = dhcphdr;
314         dhcppkt->max_len = max_len;
315         init_dhcp_options ( &dhcppkt->options[OPTS_MAIN], dhcphdr->options,
316                             ( max_len -
317                               offsetof ( typeof ( *dhcphdr ), options ) ) );
318         init_dhcp_options ( &dhcppkt->options[OPTS_FILE], dhcphdr->file,
319                             sizeof ( dhcphdr->file ) );
320         init_dhcp_options ( &dhcppkt->options[OPTS_SNAME], dhcphdr->sname,
321                             sizeof ( dhcphdr->sname ) );
322         
323         /* Set DHCP_OPTION_OVERLOAD option within the main options block */
324         if ( set_dhcp_option ( &dhcppkt->options[OPTS_MAIN],
325                                DHCP_OPTION_OVERLOAD, &overloading,
326                                sizeof ( overloading ) ) == NULL )
327                 return -ENOSPC;
328
329         /* Set DHCP_MESSAGE_TYPE option */
330         if ( ( rc = set_dhcp_packet_option ( dhcppkt, DHCP_MESSAGE_TYPE,
331                                              &msgtype,
332                                              sizeof ( msgtype ) ) ) != 0 )
333                 return rc;
334
335         return 0;
336 }
337
338 /**
339  * Calculate used length of a field containing DHCP options
340  *
341  * @v data              Field containing DHCP options
342  * @v max_len           Field length
343  * @ret len             Used length (excluding the @c DHCP_END tag)
344  */
345 static size_t dhcp_field_len ( const void *data, size_t max_len ) {
346         struct dhcp_option_block options;
347         struct dhcp_option *end;
348
349         options.data = ( ( void * ) data );
350         options.len = max_len;
351         end = find_dhcp_option ( &options, DHCP_END );
352         return ( end ? ( ( ( void * ) end ) - data ) : 0 );
353 }
354
355 /**
356  * Merge field containing DHCP options or string into DHCP options block
357  *
358  * @v options           DHCP option block
359  * @v data              Field containing DHCP options
360  * @v max_len           Field length
361  * @v tag               DHCP option tag, or 0
362  *
363  * If @c tag is non-zero, the field will be treated as a
364  * NUL-terminated string representing the value of the specified DHCP
365  * option.  If @c tag is zero, the field will be treated as a block of
366  * DHCP options, and simply appended to the existing options in the
367  * option block.
368  *
369  * The caller must ensure that there is enough space in the options
370  * block to perform the merge.
371  */
372 static void merge_dhcp_field ( struct dhcp_option_block *options,
373                                const void *data, size_t max_len,
374                                unsigned int tag ) {
375         size_t len;
376         void *dest;
377         struct dhcp_option *end;
378
379         if ( tag ) {
380                 set_dhcp_option ( options, tag, data, strlen ( data ) );
381         } else {
382                 len = dhcp_field_len ( data, max_len );
383                 dest = ( options->data + options->len - 1 );
384                 memcpy ( dest, data, len );
385                 options->len += len;
386                 end = ( dest + len );
387                 end->tag = DHCP_END;
388         }
389 }
390
391 /**
392  * Parse DHCP packet and construct DHCP options block
393  *
394  * @v dhcphdr           DHCP packet
395  * @v len               Length of DHCP packet
396  * @ret options         DHCP options block, or NULL
397  *
398  * Parses a received DHCP packet and canonicalises its contents into a
399  * single DHCP options block.  The "file" and "sname" fields are
400  * converted into the corresponding DHCP options (@c
401  * DHCP_BOOTFILE_NAME and @c DHCP_TFTP_SERVER_NAME respectively).  If
402  * these fields are used for option overloading, their options are
403  * merged in to the options block.
404  *
405  * The values of the "yiaddr" and "siaddr" fields will be stored
406  * within the options block as the magic options @c DHCP_EB_YIADDR and
407  * @c DHCP_EB_SIADDR.
408  * 
409  * Note that this call allocates new memory for the constructed DHCP
410  * options block; it is the responsibility of the caller to eventually
411  * free this memory.
412  */
413 static struct dhcp_option_block * dhcp_parse ( const struct dhcphdr *dhcphdr,
414                                                size_t len ) {
415         struct dhcp_option_block *options;
416         size_t options_len;
417         unsigned int overloading;
418
419         /* Sanity check */
420         if ( len < sizeof ( *dhcphdr ) )
421                 return NULL;
422
423         /* Calculate size of resulting concatenated option block:
424          *
425          *   The "options" field : length of the field minus the DHCP_END tag.
426          *
427          *   The "file" field : maximum length of the field minus the
428          *   NUL terminator, plus a 2-byte DHCP header or, if used for
429          *   option overloading, the length of the field minus the
430          *   DHCP_END tag.
431          *
432          *   The "sname" field : as for the "file" field.
433          *
434          *   15 bytes for an encapsulated options field to contain the
435          *   value of the "yiaddr" and "siaddr" fields
436          *
437          *   1 byte for a final terminating DHCP_END tag.
438          */
439         options_len = ( ( len - offsetof ( typeof ( *dhcphdr ), options ) ) - 1
440                         + ( sizeof ( dhcphdr->file ) + 1 )
441                         + ( sizeof ( dhcphdr->sname ) + 1 )
442                         + 15 /* yiaddr and siaddr */
443                         + 1 /* DHCP_END tag */ );
444         
445         /* Allocate empty options block of required size */
446         options = alloc_dhcp_options ( options_len );
447         if ( ! options ) {
448                 DBG ( "DHCP could not allocate %d-byte option block\n",
449                       options_len );
450                 return NULL;
451         }
452         
453         /* Merge in "options" field, if this is a DHCP packet */
454         if ( dhcphdr->magic == htonl ( DHCP_MAGIC_COOKIE ) ) {
455                 merge_dhcp_field ( options, dhcphdr->options,
456                                    ( len -
457                                      offsetof ( typeof (*dhcphdr), options ) ),
458                                    0 /* Always contains options */ );
459         }
460
461         /* Identify overloaded fields */
462         overloading = find_dhcp_num_option ( options, DHCP_OPTION_OVERLOAD );
463         
464         /* Merge in "file" and "sname" fields */
465         merge_dhcp_field ( options, dhcphdr->file, sizeof ( dhcphdr->file ),
466                            ( ( overloading & DHCP_OPTION_OVERLOAD_FILE ) ?
467                              0 : DHCP_BOOTFILE_NAME ) );
468         merge_dhcp_field ( options, dhcphdr->sname, sizeof ( dhcphdr->sname ),
469                            ( ( overloading & DHCP_OPTION_OVERLOAD_SNAME ) ?
470                              0 : DHCP_TFTP_SERVER_NAME ) );
471
472         /* Set magic options for "yiaddr" and "siaddr", if present */
473         if ( dhcphdr->yiaddr.s_addr ) {
474                 set_dhcp_option ( options, DHCP_EB_YIADDR,
475                                   &dhcphdr->yiaddr, sizeof (dhcphdr->yiaddr) );
476         }
477         if ( dhcphdr->siaddr.s_addr ) {
478                 set_dhcp_option ( options, DHCP_EB_SIADDR,
479                                   &dhcphdr->siaddr, sizeof (dhcphdr->siaddr) );
480         }
481         
482         assert ( options->len <= options->max_len );
483
484         return options;
485 }
486
487 /****************************************************************************
488  *
489  * DHCP to UDP interface
490  *
491  */
492
493 /** A DHCP session */
494 struct dhcp_session {
495         /** Reference counter */
496         struct refcnt refcnt;
497         /** Job control interface */
498         struct job_interface job;
499         /** Data transfer interface */
500         struct xfer_interface xfer;
501
502         /** Network device being configured */
503         struct net_device *netdev;
504         /** Option block registration routine */
505         int ( * register_options ) ( struct dhcp_option_block *options );
506
507         /** State of the session
508          *
509          * This is a value for the @c DHCP_MESSAGE_TYPE option
510          * (e.g. @c DHCPDISCOVER).
511          */
512         int state;
513         /** Options obtained from server */
514         struct dhcp_option_block *options;
515         /** Retransmission timer */
516         struct retry_timer timer;
517 };
518
519 /**
520  * Free DHCP session
521  *
522  * @v refcnt            Reference counter
523  */
524 static void dhcp_free ( struct refcnt *refcnt ) {
525         struct dhcp_session *dhcp =
526                 container_of ( refcnt, struct dhcp_session, refcnt );
527
528         netdev_put ( dhcp->netdev );
529         dhcpopt_put ( dhcp->options );
530         free ( dhcp );
531 }
532
533 /**
534  * Mark DHCP session as complete
535  *
536  * @v dhcp              DHCP session
537  * @v rc                Return status code
538  */
539 static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
540
541         /* Block futher incoming messages */
542         job_nullify ( &dhcp->job );
543         xfer_nullify ( &dhcp->xfer );
544
545         /* Stop retry timer */
546         stop_timer ( &dhcp->timer );
547
548         /* Free resources and close interfaces */
549         xfer_close ( &dhcp->xfer, rc );
550         job_done ( &dhcp->job, rc );
551 }
552
553 /****************************************************************************
554  *
555  * Data transfer interface
556  *
557  */
558
559 /**
560  * Transmit DHCP request
561  *
562  * @v dhcp              DHCP session
563  * @ret rc              Return status code
564  */
565 static int dhcp_send_request ( struct dhcp_session *dhcp ) {
566         struct xfer_metadata meta = {
567                 .netdev = dhcp->netdev,
568         };
569         struct dhcp_packet dhcppkt;
570         struct io_buffer *iobuf;
571         int rc;
572         
573         DBGC ( dhcp, "DHCP %p transmitting %s\n",
574                dhcp, dhcp_msgtype_name ( dhcp->state ) );
575
576         assert ( ( dhcp->state == DHCPDISCOVER ) ||
577                  ( dhcp->state == DHCPREQUEST ) );
578
579         /* Start retry timer.  Do this first so that failures to
580          * transmit will be retried.
581          */
582         start_timer ( &dhcp->timer );
583
584         /* Allocate buffer for packet */
585         iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
586         if ( ! iobuf )
587                 return -ENOMEM;
588
589         /* Create DHCP packet in temporary buffer */
590         if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state,
591                                          iobuf->data, iob_tailroom ( iobuf ),
592                                          &dhcppkt ) ) != 0 ) {
593                 DBGC ( dhcp, "DHCP %p could not create DHCP packet: %s\n",
594                        dhcp, strerror ( rc ) );
595                 goto done;
596         }
597
598         /* Copy in options common to all requests */
599         if ( ( rc = copy_dhcp_packet_options ( &dhcppkt,
600                                                &dhcp_request_options ) ) != 0){
601                 DBGC ( dhcp, "DHCP %p could not set common DHCP options: %s\n",
602                        dhcp, strerror ( rc ) );
603                 goto done;
604         }
605
606         /* Copy any required options from previous server repsonse */
607         if ( dhcp->options ) {
608                 if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
609                                             DHCP_SERVER_IDENTIFIER,
610                                             DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
611                         DBGC ( dhcp, "DHCP %p could not set server identifier "
612                                "option: %s\n", dhcp, strerror ( rc ) );
613                         goto done;
614                 }
615                 if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
616                                             DHCP_EB_YIADDR,
617                                             DHCP_REQUESTED_ADDRESS ) ) != 0 ) {
618                         DBGC ( dhcp, "DHCP %p could not set requested address "
619                                "option: %s\n", dhcp, strerror ( rc ) );
620                         goto done;
621                 }
622         }
623
624         /* Transmit the packet */
625         iob_put ( iobuf, dhcppkt.len );
626         rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
627         iobuf = NULL;
628         if ( rc != 0 ) {
629                 DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
630                        dhcp, strerror ( rc ) );
631                 goto done;
632         }
633
634  done:
635         free_iob ( iobuf );
636         return rc;
637 }
638
639 /**
640  * Handle DHCP retry timer expiry
641  *
642  * @v timer             DHCP retry timer
643  * @v fail              Failure indicator
644  */
645 static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
646         struct dhcp_session *dhcp =
647                 container_of ( timer, struct dhcp_session, timer );
648
649         if ( fail ) {
650                 dhcp_finished ( dhcp, -ETIMEDOUT );
651         } else {
652                 dhcp_send_request ( dhcp );
653         }
654 }
655
656 /**
657  * Receive new data
658  *
659  * @v xfer              Data transfer interface
660  * @v iobuf             I/O buffer
661  * @v data              Received data
662  * @v len               Length of received data
663  * @ret rc              Return status code
664  */
665 static int dhcp_deliver_raw ( struct xfer_interface *xfer,
666                               const void *data, size_t len ) {
667         struct dhcp_session *dhcp =
668                 container_of ( xfer, struct dhcp_session, xfer );
669         const struct dhcphdr *dhcphdr = data;
670         struct dhcp_option_block *options;
671         unsigned int msgtype;
672
673         /* Check for matching transaction ID */
674         if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
675                 DBGC ( dhcp, "DHCP %p wrong transaction ID (wanted %08lx, "
676                         "got %08lx)\n", dhcp, ntohl ( dhcphdr->xid ),
677                         ntohl ( dhcp_xid ( dhcp->netdev ) ) );
678                 return 0;
679         };
680
681         /* Parse packet and create options structure */
682         options = dhcp_parse ( dhcphdr, len );
683         if ( ! options ) {
684                 DBGC ( dhcp, "DHCP %p could not parse DHCP packet\n", dhcp );
685                 return -EINVAL;
686         }
687
688         /* Determine message type */
689         msgtype = find_dhcp_num_option ( options, DHCP_MESSAGE_TYPE );
690         DBGC ( dhcp, "DHCP %p received %s\n",
691                dhcp, dhcp_msgtype_name ( msgtype ) );
692
693         /* Handle DHCP reply */
694         switch ( dhcp->state ) {
695         case DHCPDISCOVER:
696                 if ( msgtype != DHCPOFFER )
697                         goto out_discard;
698                 dhcp->state = DHCPREQUEST;
699                 break;
700         case DHCPREQUEST:
701                 if ( msgtype != DHCPACK )
702                         goto out_discard;
703                 dhcp->state = DHCPACK;
704                 break;
705         default:
706                 assert ( 0 );
707                 goto out_discard;
708         }
709
710         /* Stop timer and update stored options */
711         stop_timer ( &dhcp->timer );
712         if ( dhcp->options )
713                 dhcpopt_put ( dhcp->options );
714         dhcp->options = options;
715
716         /* Transmit next packet, or terminate session */
717         if ( dhcp->state < DHCPACK ) {
718                 dhcp_send_request ( dhcp );
719         } else {
720                 dhcp->register_options ( dhcp->options );
721                 dhcp_finished ( dhcp, 0 );
722         }
723         return 0;
724
725  out_discard:
726         dhcpopt_put ( options );
727         return 0;
728 }
729
730 /** DHCP data transfer interface operations */
731 static struct xfer_interface_operations dhcp_xfer_operations = {
732         .close          = ignore_xfer_close,
733         .vredirect      = xfer_vopen,
734         .request        = ignore_xfer_request,
735         .seek           = ignore_xfer_seek,
736         .deliver_iob    = xfer_deliver_as_raw,
737         .deliver_raw    = dhcp_deliver_raw,
738 };
739
740 /****************************************************************************
741  *
742  * Job control interface
743  *
744  */
745
746 /**
747  * Handle kill() event received via job control interface
748  *
749  * @v job               DHCP job control interface
750  */
751 static void dhcp_job_kill ( struct job_interface *job ) {
752         struct dhcp_session *dhcp =
753                 container_of ( job, struct dhcp_session, job );
754
755         /* Terminate DHCP session */
756         dhcp_finished ( dhcp, -ECANCELED );
757 }
758
759 /** DHCP job control interface operations */
760 static struct job_interface_operations dhcp_job_operations = {
761         .done           = ignore_job_done,
762         .kill           = dhcp_job_kill,
763         .progress       = ignore_job_progress,
764 };
765
766 /****************************************************************************
767  *
768  * Instantiator
769  *
770  */
771
772 /**
773  * Start DHCP on a network device
774  *
775  * @v job               Job control interface
776  * @v netdev            Network device
777  * @v register_options  DHCP option block registration routine
778  * @ret rc              Return status code
779  *
780  * Starts DHCP on the specified network device.  If successful, the @c
781  * register_options() routine will be called with the acquired
782  * options.
783  */
784 int start_dhcp ( struct job_interface *job, struct net_device *netdev,
785                  int ( * register_options ) ( struct dhcp_option_block * ) ) {
786         static struct sockaddr_in server = {
787                 .sin_family = AF_INET,
788                 .sin_addr.s_addr = INADDR_BROADCAST,
789                 .sin_port = htons ( BOOTPS_PORT ),
790         };
791         static struct sockaddr_in client = {
792                 .sin_family = AF_INET,
793                 .sin_port = htons ( BOOTPC_PORT ),
794         };
795         struct dhcp_session *dhcp;
796         int rc;
797
798         /* Allocate and initialise structure */
799         dhcp = malloc ( sizeof ( *dhcp ) );
800         if ( ! dhcp )
801                 return -ENOMEM;
802         memset ( dhcp, 0, sizeof ( *dhcp ) );
803         dhcp->refcnt.free = dhcp_free;
804         job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
805         xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
806         dhcp->netdev = netdev_get ( netdev );
807         dhcp->register_options = register_options;
808         dhcp->timer.expired = dhcp_timer_expired;
809         dhcp->state = DHCPDISCOVER;
810
811         /* Instantiate child objects and attach to our interfaces */
812         if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
813                                        ( struct sockaddr * ) &server,
814                                        ( struct sockaddr * ) &client ) ) != 0 )
815                 goto err;
816
817         /* Start timer to initiate initial DHCPREQUEST */
818         start_timer ( &dhcp->timer );
819
820         /* Attach parent interface, mortalise self, and return */
821         job_plug_plug ( &dhcp->job, job );
822         ref_put ( &dhcp->refcnt );
823         return 0;
824
825  err:
826         dhcp_finished ( dhcp, rc );
827         ref_put ( &dhcp->refcnt );
828         return rc;
829 }