On Mon, Jan 23, 2017 at 08:39:17PM +1000, Jonathan Matthew wrote:
> For network boot clients, dhcpd(8) can supply a filename for the initial
> boot file for the client, which is something like pxeboot (or pxelinux.0).
> EFI and BIOS clients need different boot files, though, so the server
> needs to know what mode the client is booting in, in order to supply the
> right filename.  RFC 4578 defines DHCP client option 93 for this purpose.
> 
> The ISC dhcpd approach to using this looks something like this:
> 
>   option arch code 93 = unsigned integer 16;
> 
>   if option arch = 00:00 {
>     filename "bios/pxelinux.0";
>   } elsif  option arch = 00:07 {
>      filename "efi.x64/syslinux.efi";
>   }
> 
> which seems a bit complicated, and also a lot of work to implement.  Instead
> I propose adding 'efi-filename' (and 'efi32-filename', though I'm not sure
> that's worth doing) next to the existing 'filename' statement and having
> dhcpd itself interpret the option values to figure out which one should be
> used.
> 
> I don't actually need this yet because we don't have many EFI-only client
> machines, so we can just run everything in legacy mode, but some day this
> may change.
> 
> Does this seem reasonable?

How will values 10 (32 bit arm) and 11 (64 bit arm) be handled
in future if this went in?  Wouldn't it be better to map the arch numbers
to strings?

The uefi spec refers to
http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#processor-architecture
Which also lists different numbers for PXE vs boot from HTTP.

> 
> Index: conflex.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/conflex.c,v
> retrieving revision 1.16
> diff -u -p -u -p -r1.16 conflex.c
> --- conflex.c 6 Feb 2016 23:50:10 -0000       1.16
> +++ conflex.c 23 Jan 2017 08:09:15 -0000
> @@ -310,6 +310,8 @@ static const struct keywords {
>       { "dynamic-bootp",                      TOK_DYNAMIC_BOOTP },
>       { "dynamic-bootp-lease-cutoff",         TOK_DYNAMIC_BOOTP_LEASE_CUTOFF 
> },
>       { "dynamic-bootp-lease-length",         TOK_DYNAMIC_BOOTP_LEASE_LENGTH 
> },
> +     { "efi-filename",                       TOK_EFI64_FILENAME },
> +     { "efi32-filename",                     TOK_EFI32_FILENAME },
>       { "ends",                               TOK_ENDS },
>       { "ethernet",                           TOK_ETHERNET },
>       { "filename",                           TOK_FILENAME },
> Index: confpars.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/confpars.c,v
> retrieving revision 1.28
> diff -u -p -u -p -r1.28 confpars.c
> --- confpars.c        17 Aug 2016 00:55:33 -0000      1.28
> +++ confpars.c        23 Jan 2017 08:09:15 -0000
> @@ -380,6 +380,14 @@ parse_statement(FILE *cfile, struct grou
>               group->filename = parse_string(cfile);
>               break;
>  
> +     case TOK_EFI32_FILENAME:
> +             group->efi32_filename = parse_string(cfile);
> +             break;
> +
> +     case TOK_EFI64_FILENAME:
> +             group->efi64_filename = parse_string(cfile);
> +             break;
> +
>       case TOK_SERVER_NAME:
>               group->server_name = parse_string(cfile);
>               break;
> Index: dhcp.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/dhcp.c,v
> retrieving revision 1.52
> diff -u -p -u -p -r1.52 dhcp.c
> --- dhcp.c    24 Oct 2016 21:05:55 -0000      1.52
> +++ dhcp.c    23 Jan 2017 08:09:15 -0000
> @@ -699,6 +699,35 @@ nak_lease(struct packet *packet, struct 
>           outgoing.packet_length, from, &to, NULL);
>  }
>  
> +static const char *
> +group_filename(struct group *group, struct packet *packet)
> +{
> +     u_int16_t arch, *opt;
> +     int i;
> +
> +     opt = (u_int16_t *)packet->options[DHO_DHCP_CLIENT_ARCHITECTURE].data;
> +     for (i = 0; i < packet->options[DHO_DHCP_CLIENT_ARCHITECTURE].len;
> +         i += 2) {
> +             arch = betoh16(*opt++);
> +             switch (arch) {
> +             case DCA_EFI_IA32:
> +                     if (group->efi32_filename != NULL)
> +                             return group->efi32_filename;
> +                     break;
> +                     
> +             case DCA_EFI_BC:
> +             case DCA_EFI_X86_64:
> +                     if (group->efi64_filename != NULL)
> +                             return group->efi64_filename;
> +                     break;
> +             default:
> +                     break;
> +             }
> +     }
> +
> +     return group->filename;
> +}
> +
>  void
>  ack_lease(struct packet *packet, struct lease *lease, unsigned int offer,
>      time_t when)
> @@ -707,6 +736,7 @@ ack_lease(struct packet *packet, struct 
>       struct lease_state *state;
>       time_t lease_time, offered_lease_time, max_lease_time, 
> default_lease_time;
>       struct class *vendor_class, *user_class;
> +     const char *filename;
>       int ulafdr, i;
>  
>       /* If we're already acking this lease, don't do it again. */
> @@ -808,21 +838,20 @@ ack_lease(struct packet *packet, struct 
>        * Choose a filename; first from the host_decl, if any, then from
>        * the user class, then from the vendor class.
>        */
> -     if (lease->host && lease->host->group->filename)
> -             strlcpy(state->filename, lease->host->group->filename,
> -                 sizeof state->filename);
> -     else if (user_class && user_class->group->filename)
> -             strlcpy(state->filename, user_class->group->filename,
> -                 sizeof state->filename);
> -     else if (vendor_class && vendor_class->group->filename)
> -             strlcpy(state->filename, vendor_class->group->filename,
> -                 sizeof state->filename);
> +     if (lease->host && (filename = group_filename(lease->host->group,
> +         packet)))
> +             strlcpy(state->filename, filename, sizeof state->filename);
> +     else if (user_class && (filename = group_filename(user_class->group,
> +         packet)))
> +             strlcpy(state->filename, filename, sizeof state->filename);
> +     else if (vendor_class && (filename = group_filename(vendor_class->group,
> +         packet)))
> +             strlcpy(state->filename, filename, sizeof state->filename);
>       else if (packet->raw->file[0])
>               strlcpy(state->filename, packet->raw->file,
>                   sizeof state->filename);
> -     else if (lease->subnet->group->filename)
> -             strlcpy(state->filename, lease->subnet->group->filename,
> -                 sizeof state->filename);
> +     else if ((filename = group_filename(lease->subnet->group, packet)))
> +             strlcpy(state->filename, filename, sizeof state->filename);
>       else
>               strlcpy(state->filename, "", sizeof state->filename);
>  
> Index: dhcp.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/dhcp.h,v
> retrieving revision 1.10
> diff -u -p -u -p -r1.10 dhcp.h
> --- dhcp.h    21 Jan 2014 03:07:51 -0000      1.10
> +++ dhcp.h    23 Jan 2017 08:09:15 -0000
> @@ -171,6 +171,7 @@ struct dhcp_packet {
>  #define DHO_NDS_SERVERS                      85
>  #define DHO_NDS_TREE_NAME            86
>  #define DHO_NDS_CONTEXT                      87
> +#define DHO_DHCP_CLIENT_ARCHITECTURE 93
>  #define DHO_CLASSLESS_STATIC_ROUTES  121
>  #define DHO_TFTP_CONFIG_FILE         144
>  #define DHO_VOIP_CONFIGURATION_SERVER        150
> @@ -192,3 +193,9 @@ struct dhcp_packet {
>  #define RAI_CIRCUIT_ID       1
>  #define RAI_REMOTE_ID        2
>  #define RAI_AGENT_ID 3
> +
> +/* DHCP client architectures (RFC 4578) */
> +#define DCA_X86_LEGACY       0
> +#define DCA_EFI_IA32 6
> +#define DCA_EFI_BC   7
> +#define DCA_EFI_X86_64       9
> Index: dhcpd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/dhcpd.conf.5,v
> retrieving revision 1.17
> diff -u -p -u -p -r1.17 dhcpd.conf.5
> --- dhcpd.conf.5      11 Jun 2015 12:48:32 -0000      1.17
> +++ dhcpd.conf.5      23 Jan 2017 08:09:15 -0000
> @@ -609,15 +609,28 @@ The
>  statement may also be used for DHCP clients.
>  .Pp
>  The
> -.Ic filename
> -statement
> +.Ic filename ,
> +.Ic efi-filename ,
> +and
> +.Ic efi32-filename
> +statements
>  .Pp
>  .D1 Ic filename Qq Ar filename ;
> +.D1 Ic efi-filename Qq Ar filename ;
> +.D1 Ic efi32-filename Qq Ar filename ;
>  .Pp
>  The
> -.Ic filename
> -statement can be used to specify the name of the initial boot file which
> +.Ic filename ,
> +.Ic efi-filename ,
> +and
> +.Ic efi32-filename
> +statements can be used to specify the name of the initial boot file which
>  is to be loaded by a client.
> +If specified,
> +.Ic efi-filename
> +will be used for 64-bit EFI clients, and
> +.Ic efi32-filename
> +will be used for 32-bit EFI clients.
>  The
>  .Ar filename
>  should be a filename recognizable to whatever file transfer protocol
> Index: dhcpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/dhcpd.h,v
> retrieving revision 1.55
> diff -u -p -u -p -r1.55 dhcpd.h
> --- dhcpd.h   6 Oct 2016 16:12:43 -0000       1.55
> +++ dhcpd.h   23 Jan 2017 08:09:15 -0000
> @@ -211,6 +211,8 @@ struct group {
>       time_t bootp_lease_length;
>  
>       char *filename;
> +     char *efi32_filename;
> +     char *efi64_filename;
>       char *server_name;
>       struct iaddr next_server;
>  
> Index: dhctoken.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/dhcpd/dhctoken.h,v
> retrieving revision 1.7
> diff -u -p -u -p -r1.7 dhctoken.h
> --- dhctoken.h        5 Dec 2013 22:31:35 -0000       1.7
> +++ dhctoken.h        23 Jan 2017 08:09:15 -0000
> @@ -91,6 +91,8 @@
>  #define TOK_TOKEN_NOT                        334
>  #define TOK_ALWAYS_REPLY_RFC1048     335
>  #define TOK_IPSEC_TUNNEL             336
> +#define TOK_EFI32_FILENAME           337
> +#define TOK_EFI64_FILENAME           338
>  
>  #define is_identifier(x)     ((x) >= TOK_FIRST_TOKEN &&      \
>                                (x) != TOK_STRING &&   \
> 

Reply via email to