pxe: support pxe clients with custom vendor-class

From 606d638918edb0e0ec07fe27eb68d06fb5ebd981 Mon Sep 17 00:00:00 2001
From: Miao Wang <shankerwangmiao@gmail.com>
Date: Fri, 4 Dec 2020 09:59:37 +0800
Subject: [PATCH v2] pxe: support pxe clients with custom vendor-class

According to UEFI[1] and PXE[2] specs, PXE clients are required to have
`PXEClient` identfier in the vendor-class field of DHCP requests, and
PXE servers should also include that identifier in their responses.
However, the firmware of servers from a few vendors[3] are customized to
include a different identifier. This patch adds an option named
`dhcp-pxe-vendor` to provide a list of such identifiers. The identifier
used in responses sent from dnsmasq is identical to that in the coresponding
request.

[1]: https://uefi.org/sites/default/files/resources/UEFI%20Spec%202.8B%20May%202020.pdf
[2]: http://www.pix.net/software/pxeboot/archive/pxespec.pdf
[3]: For instance, TaiShan servers from Huawei, which are Arm64-based,
       send `HW-Client` in PXE requests up to now.

Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
This commit is contained in:
Wang Shanker
2020-12-04 10:17:35 +08:00
committed by Simon Kelley
parent f60fea1fb0
commit 4ded96209e
4 changed files with 121 additions and 28 deletions

View File

@@ -1481,6 +1481,22 @@ to allow netbooting. This mode is enabled using the
keyword in keyword in
.B --dhcp-range. .B --dhcp-range.
.TP .TP
.B --dhcp-pxe-vendor=<vendor>[,...]
According to UEFI and PXE specifications, DHCP packets between PXE clients and
proxy PXE servers should have
.I PXEClient
in their vendor-class field. However, the firmware of computers from a few
vendors is customized to carry a different identifier in that field. This option
is used to consider such identifiers valid for identifying PXE clients. For
instance
.B --dhcp-pxe-vendor=PXEClient,HW-Client
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
.I HW-Client
in as their identifier.
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
.TP
.B \-X, --dhcp-lease-max=<number> .B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The Limits dnsmasq to the specified maximum number of DHCP leases. The
default is 1000. This limit is to prevent DoS attacks from hosts which default is 1000. This limit is to prevent DoS attacks from hosts which

View File

@@ -829,6 +829,7 @@ struct dhcp_opt {
#define DHOPT_RFC3925 2048 #define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096 #define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192 #define DHOPT_ADDR6 8192
#define DHOPT_VENDOR_PXE 16384
struct dhcp_boot { struct dhcp_boot {
char *file, *sname, *tftp_sname; char *file, *sname, *tftp_sname;
@@ -852,6 +853,8 @@ struct pxe_service {
struct pxe_service *next; struct pxe_service *next;
}; };
#define DHCP_PXE_DEF_VENDOR "PXEClient"
#define MATCH_VENDOR 1 #define MATCH_VENDOR 1
#define MATCH_USER 2 #define MATCH_USER 2
#define MATCH_CIRCUIT 3 #define MATCH_CIRCUIT 3
@@ -867,6 +870,11 @@ struct dhcp_vendor {
struct dhcp_vendor *next; struct dhcp_vendor *next;
}; };
struct dhcp_pxe_vendor {
char *data;
struct dhcp_pxe_vendor *next;
};
struct dhcp_mac { struct dhcp_mac {
unsigned int mask; unsigned int mask;
int hwaddr_len, hwaddr_type; int hwaddr_len, hwaddr_type;
@@ -1040,6 +1048,7 @@ extern struct daemon {
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6; struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_match_name *dhcp_name_match; struct dhcp_match_name *dhcp_name_match;
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;

View File

@@ -167,6 +167,7 @@ struct myoption {
#define LOPT_IGNORE_CLID 358 #define LOPT_IGNORE_CLID 358
#define LOPT_SINGLE_PORT 359 #define LOPT_SINGLE_PORT 359
#define LOPT_SCRIPT_TIME 360 #define LOPT_SCRIPT_TIME 360
#define LOPT_PXE_VENDOR 361
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -270,6 +271,7 @@ static const struct myoption opts[] =
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT }, { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE }, { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR }, { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{ "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
{ "interface-name", 1, 0, LOPT_INTNAME }, { "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST }, { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS }, { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
@@ -383,6 +385,7 @@ static struct {
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL }, { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL }, { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL }, { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
{ 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL }, { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL }, { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL }, { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
@@ -3672,8 +3675,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->val = opt_malloc(new->len); new->val = opt_malloc(new->len);
memcpy(new->val + 1, arg, new->len - 1); memcpy(new->val + 1, arg, new->len - 1);
new->u.vendor_class = (unsigned char *)"PXEClient"; new->u.vendor_class = NULL;
new->flags = DHOPT_VENDOR; new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
if (comma && atoi_check(comma, &timeout)) if (comma && atoi_check(comma, &timeout))
*(new->val) = timeout; *(new->val) = timeout;
@@ -3938,6 +3941,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
break; break;
case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
{
while (arg) {
struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
comma = split(arg);
new->data = opt_string_alloc(arg);
new->next = daemon->dhcp_pxe_vendors;
daemon->dhcp_pxe_vendors = new;
arg = comma;
}
}
break;
case LOPT_RELAY: /* --dhcp-relay */ case LOPT_RELAY: /* --dhcp-relay */
{ {
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay)); struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
@@ -5213,6 +5229,13 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->hostmaster = opt_string_alloc(buff); daemon->hostmaster = opt_string_alloc(buff);
} }
if (!daemon->dhcp_pxe_vendors)
{
daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
daemon->dhcp_pxe_vendors->next = NULL;
}
/* only one of these need be specified: the other defaults to the host-name */ /* only one of these need be specified: the other defaults to the host-name */
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget) if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
{ {

View File

@@ -30,7 +30,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt); static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val); static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term); int opt, const char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt); static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int offset, int size); static unsigned int option_uint(unsigned char *opt, int offset, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac, static void log_packet(char *type, void *addr, unsigned char *ext_mac,
@@ -54,17 +54,19 @@ static void do_options(struct dhcp_context *context,
int vendor_class_len, int vendor_class_len,
time_t now, time_t now,
unsigned int lease_time, unsigned int lease_time,
unsigned short fuzz); unsigned short fuzz,
const char *pxevendor);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term); static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid); static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
static int prune_vendor_opts(struct dhcp_netid *netid); static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now); static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
struct dhcp_boot *find_boot(struct dhcp_netid *netid); struct dhcp_boot *find_boot(struct dhcp_netid *netid);
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe); static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid); static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int loopback, size_t sz, time_t now, int unicast_dest, int loopback,
@@ -76,6 +78,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_mac *mac; struct dhcp_mac *mac;
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1; int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
const char *pxevendor = NULL;
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1); unsigned char *end = (unsigned char *)(mess + 1);
unsigned char *real_end = (unsigned char *)(mess + 1); unsigned char *real_end = (unsigned char *)(mess + 1);
@@ -647,7 +650,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end); clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0); netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
} }
} }
@@ -836,8 +839,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* Check if client is PXE client. */ /* Check if client is PXE client. */
if (daemon->enable_pxe && if (daemon->enable_pxe &&
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) && is_pxe_client(mess, sz, &pxevendor))
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
{ {
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17))) if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
{ {
@@ -899,7 +901,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK); option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr)); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
pxe_misc(mess, end, uuid); pxe_misc(mess, end, uuid, pxevendor);
prune_vendor_opts(tagif_netid); prune_vendor_opts(tagif_netid);
opt71.val = save71; opt71.val = save71;
@@ -979,7 +981,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK); mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr)); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
pxe_misc(mess, end, uuid); pxe_misc(mess, end, uuid, pxevendor);
prune_vendor_opts(tagif_netid); prune_vendor_opts(tagif_netid);
if ((pxe && !workaround) || !redirect4011) if ((pxe && !workaround) || !redirect4011)
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
@@ -1150,7 +1152,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_LEASE_TIME, 4, time); option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */ /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1499,7 +1501,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (rapid_commit) if (rapid_commit)
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0); option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
} }
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1566,7 +1568,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr), do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
*is_inform = 1; /* handle reply differently */ *is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1948,7 +1950,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
} }
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt, static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
char *string, int null_term) const char *string, int null_term)
{ {
unsigned char *p; unsigned char *p;
size_t len = strlen(string); size_t len = strlen(string);
@@ -2026,11 +2028,27 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
dopt->flags &= ~DHOPT_VENDOR_MATCH; dopt->flags &= ~DHOPT_VENDOR_MATCH;
if (opt && (dopt->flags & DHOPT_VENDOR)) if (opt && (dopt->flags & DHOPT_VENDOR))
{ {
int i, len = 0; const struct dhcp_pxe_vendor *pv;
if (dopt->u.vendor_class) struct dhcp_pxe_vendor dummy_vendor = {
len = strlen((char *)dopt->u.vendor_class); .data = (char *)dopt->u.vendor_class,
.next = NULL,
};
if (dopt->flags & DHOPT_VENDOR_PXE)
pv = daemon->dhcp_pxe_vendors;
else
pv = &dummy_vendor;
for (; pv; pv = pv->next)
{
int i, len = 0, matched = 0;
if (pv->data)
len = strlen(pv->data);
for (i = 0; i <= (option_len(opt) - len); i++) for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0) if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
{
matched = 1;
break;
}
if (matched)
{ {
dopt->flags |= DHOPT_VENDOR_MATCH; dopt->flags |= DHOPT_VENDOR_MATCH;
break; break;
@@ -2038,6 +2056,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
} }
} }
} }
}
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
struct dhcp_packet *mess, unsigned char *end, int null_term) struct dhcp_packet *mess, unsigned char *end, int null_term)
@@ -2087,11 +2106,13 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
return ret; return ret;
} }
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid) static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
{ {
unsigned char *p; unsigned char *p;
option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0); if (!pxevendor)
pxevendor="PXEClient";
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17))) if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
memcpy(p, uuid, 17); memcpy(p, uuid, 17);
} }
@@ -2308,6 +2329,29 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
return boot; return boot;
} }
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
{
const unsigned char *opt = NULL;
ssize_t conf_len = 0;
const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
if (!opt)
return 0;
for (; conf; conf = conf->next)
{
conf_len = strlen(conf->data);
if (option_len(opt) < conf_len)
continue;
if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
{
if (pxe_vendor)
*pxe_vendor = conf->data;
return 1;
}
}
return 0;
}
static void do_options(struct dhcp_context *context, static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess, struct dhcp_packet *mess,
unsigned char *end, unsigned char *end,
@@ -2322,7 +2366,8 @@ static void do_options(struct dhcp_context *context,
int vendor_class_len, int vendor_class_len,
time_t now, time_t now,
unsigned int lease_time, unsigned int lease_time,
unsigned short fuzz) unsigned short fuzz,
const char *pxevendor)
{ {
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts; struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot; struct dhcp_boot *boot;
@@ -2696,7 +2741,7 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1) if (context && pxe_arch != -1)
{ {
pxe_misc(mess, end, uuid); pxe_misc(mess, end, uuid, pxevendor);
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0)) if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
config_opts = pxe_opts(pxe_arch, tagif, context->local, now); config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
} }