decoded the packet and executed the scopes that it matches). */
if (!universe)
return 0;
-
+
/* If we don't have a decoding function for it, we can't decode
it. */
if (!universe -> decode)
if (len > 63) {
log_info ("fancy bits in fqdn option");
return 0;
- }
+ }
if (len == 0) {
terminated = 1;
break;
/*
* Set offsets for buffer data to be copied into filename
- * and servername fields
+ * and servername fields
*/
if (mb_size > agent_size)
mb_max = mb_size - agent_size;
of2 = mb_max;
mb_max += DHCP_SNAME_LEN;
}
-
+
/*
* Preload the option priority list with protocol-mandatory options.
* This effectively gives these options the highest priority.
static void
vsio_options(struct option_cache *oc,
struct packet *packet,
- struct lease *dummy_lease,
+ struct lease *dummy_lease,
struct client_state *dummy_client_state,
struct option_state *dummy_opt_state,
struct option_state *opt_state,
struct binding_scope **dummy_binding_scope,
- struct universe *universe,
+ struct universe *universe,
void *void_vsio_state) {
struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
struct data_string ds;
memset(&ds, 0, sizeof(ds));
if (evaluate_option_cache(&ds, packet, NULL,
- NULL, opt_state, NULL,
+ NULL, opt_state, NULL,
&global_scope, oc, MDL)) {
total_len = ds.len + universe->tag_size + universe->length_size;
if (total_len <= (vs->buflen - vs->bufpos)) {
if (universe->length_size == 1) {
vs->buf[vs->bufpos++] = ds.len;
} else if (universe->length_size == 2) {
- putUShort((unsigned char *)vs->buf+vs->bufpos,
+ putUShort((unsigned char *)vs->buf+vs->bufpos,
ds.len);
vs->bufpos += 2;
} else if (universe->length_size == 4) {
- putULong((unsigned char *)vs->buf+vs->bufpos,
+ putULong((unsigned char *)vs->buf+vs->bufpos,
ds.len);
vs->bufpos += 4;
}
}
}
+/*!
+ *
+ * \brief Add a v6 option to the buffer
+ *
+ * Put the requested v6 option including tag, length and value
+ * into the specified buffer. If there isn't enough space for
+ * the entire option it is skipped.
+ *
+ * \param buf buffer to put the option
+ * \param buflen total length of buffer
+ * \param bufpos on input where to start putting the option
+ * on output the starting point for the next option
+ * \param code the option code number
+ * \param ds the string to put into the option
+ *
+ * \return void
+ */
+static void
+add_option6_data(char *buf, int buflen, int* bufpos, uint16_t code,
+ struct data_string* ds) {
+ if ((ds->len + 4) > (buflen - *bufpos)) {
+ log_debug("No space for option %d", code);
+ } else {
+ unsigned char* tmp = (unsigned char *)buf + *bufpos;
+ /* option tag */
+ putUShort(tmp, code);
+ /* option length */
+ putUShort(tmp+2, ds->len);
+ /* option data */
+ memcpy(tmp+4, ds->data, ds->len);
+ /* update position */
+ *bufpos += 4 + ds->len;
+ }
+}
+
+/*!
+ *
+ * \brief Add a v6 encapsulated option to a buffer
+ *
+ * Find the universe for the requested option and if it exists
+ * call it's encapsualtion routine to produce a data string which
+ * can then be added to the current buffer.
+ *
+ * Note 1: currently we only do simple encapsulations, where the
+ * entire value of the option is in the option universe. This is
+ * the 'E' format, we don't handle the 'e' format as we haven't
+ * defined any such universes yet. This means that if there is
+ * a simple value for the option store_options6 should handle it
+ * directly and not call this routine.
+ *
+ * \param buf buffer to put the option
+ * \param buflen total length of buffer
+ * \param bufpos on input where to start putting the option
+ * on output the starting point for the next option
+ * \param opt_state information about option values to use
+ * \param packet structure containing what we know about the packet
+ * \param encap_opt information about the structure of the option
+ * \param code the option code number
+ *
+ * \return void
+ */
+static void
+store_encap6 (char *buf, int buflen, int* bufpos,
+ struct option_state *opt_state, struct packet *packet,
+ struct option* encap_opt, uint16_t code) {
+ /* We need to extract the name of the universe
+ * to use for this option. We expect a format string
+ * of the form "Ename.". If we don't find a name we bail. */
+ struct data_string ds;
+ struct data_string name;
+ char* s = (char*)encap_opt->format;
+ char* t;
+ if ((s == NULL) || (*s != 'E') || (strlen(s) <= 2)) {
+ return;
+ }
+
+ t = strchr(++s, '.');
+ if ((t == NULL) || (t == s)) {
+ return;
+ }
+
+ memset(&ds, 0, sizeof(ds));
+ memset(&name, 0, sizeof(name));
+ name.data = (unsigned char *)s;
+ name.len = t - s;
+
+ /* Now we call the routine to find and encapsulate the requested
+ * option/universe. A return of 0 means no option information was
+ * available and nothing is added to the buffer */
+ if (option_space_encapsulate(&ds, packet, NULL, NULL, NULL, opt_state,
+ &global_scope, &name) != 0) {
+ add_option6_data(buf, buflen, bufpos, code, &ds);
+ data_string_forget(&ds, MDL);
+ }
+}
+
/*
* Stores the options from the DHCPv6 universe into the buffer given.
*
*/
int
-store_options6(char *buf, int buflen,
- struct option_state *opt_state,
+store_options6(char *buf, int buflen,
+ struct option_state *opt_state,
struct packet *packet,
const int *required_opts,
struct data_string *oro) {
*/
vsio_option_code = 0;
o = vsio_universe.enc_opt;
- while (o != NULL) {
+ while (o != NULL) {
if (o->universe == &dhcpv6_universe) {
vsio_option_code = o->code;
break;
- }
+ }
o = o->universe->enc_opt;
}
if (vsio_option_code == 0) {
vsio_wanted = 1;
}
- oc = lookup_option(&dhcpv6_universe,
+ oc = lookup_option(&dhcpv6_universe,
opt_state, required_opts[i]);
if (oc == NULL) {
continue;
NULL, opt_state,
NULL, &global_scope,
oc, MDL)) {
- if ((ds.len + 4) <=
- (buflen - bufpos)) {
- tmp = (unsigned char *)buf;
- tmp += bufpos;
- /* option tag */
- putUShort(tmp,
- required_opts[i]);
- /* option length */
- putUShort(tmp+2, ds.len);
- /* option data */
- memcpy(tmp+4, ds.data, ds.len);
- /* update position */
- bufpos += (4 + ds.len);
- } else {
- log_debug("No space for "
- "option %d",
- required_opts[i]);
- }
+ add_option6_data(buf, buflen, &bufpos,
+ (uint16_t)required_opts[i], &ds);
data_string_forget(&ds, MDL);
} else {
log_error("Error evaluating option %d",
memcpy(&code, oro->data+(i*2), 2);
code = ntohs(code);
- /*
+ /*
* See if we've already included this option because
* it is required.
*/
*/
if (code == vsio_option_code) {
vsio_wanted = 1;
+ continue;
}
- /*
+ /*
* Not already added, find this option.
*/
oc = lookup_option(&dhcpv6_universe, opt_state, code);
memset(&ds, 0, sizeof(ds));
- for (; oc != NULL ; oc = oc->next) {
- if (evaluate_option_cache(&ds, packet, NULL, NULL,
- opt_state, NULL,
- &global_scope, oc, MDL)) {
- if ((ds.len + 4) <= (buflen - bufpos)) {
- tmp = (unsigned char *)buf + bufpos;
- /* option tag */
- putUShort(tmp, code);
- /* option length */
- putUShort(tmp+2, ds.len);
- /* option data */
- memcpy(tmp+4, ds.data, ds.len);
- /* update position */
- bufpos += (4 + ds.len);
+ if (oc != NULL) {
+ /* We have a simple value for the option */
+ for (; oc != NULL ; oc = oc->next) {
+ if (evaluate_option_cache(&ds, packet, NULL,
+ NULL, opt_state, NULL,
+ &global_scope, oc,
+ MDL)) {
+ add_option6_data(buf, buflen, &bufpos,
+ code, &ds);
+ data_string_forget(&ds, MDL);
} else {
- log_debug("No space for option %d",
+ log_error("Error evaluating option %d",
code);
}
- data_string_forget(&ds, MDL);
- } else {
- log_error("Error evaluating option %d", code);
+ }
+ } else {
+ /*
+ * We don't have a simple value, check to see if we
+ * have an universe to encapsulate into an option.
+ */
+ struct option *encap_opt = NULL;
+ unsigned int code_int = code;
+
+ option_code_hash_lookup(&encap_opt,
+ dhcpv6_universe.code_hash,
+ &code_int, 0, MDL);
+ if (encap_opt != NULL) {
+ store_encap6(buf, buflen, &bufpos, opt_state,
+ packet, encap_opt, code);
+ option_dereference(&encap_opt, MDL);
}
}
}
for (i=0; i < opt_state->universe_count; i++) {
if (opt_state->universes[i] != NULL) {
o = universes[i]->enc_opt;
- if ((o != NULL) &&
+ if ((o != NULL) &&
(o->universe == &vsio_universe)) {
/*
* Add the data from this VSIO option.
vs.buflen = buflen;
vs.bufpos = bufpos+8;
option_space_foreach(packet, NULL,
- NULL,
+ NULL,
NULL, opt_state,
- NULL,
- universes[i],
+ NULL,
+ universes[i],
(void *)&vs,
vsio_options);
- /*
+ /*
* If there was actually data here,
* add the "header".
*/
unsigned code;
/*
- * These arguments are relative to the start of the buffer, so
+ * These arguments are relative to the start of the buffer, so
* reduce them by the current buffer index, and advance the
* buffer pointer to where we're going to start writing.
*/
/* Code for next option to try to store. */
code = priority_list [i];
-
+
/* Look up the option in the site option space if the code
is above the cutoff, otherwise in the DHCP option space. */
if (code >= cfg_options -> site_code_min)
name.data = (unsigned char *)s;
name.len = t - s;
}
-
+
/* If we found a universe, and there are options configured
for that universe, try to encapsulate it. */
if (name.len) {
if (!oc && !have_encapsulation) {
continue;
}
-
+
/* Find the value of the option... */
od.len = 0;
if (oc) {
}
/* Try to store the option. */
-
+
/* If the option's length is more than 255, we must store it
in multiple hunks. Store 255-byte hunks first. However,
in any case, if the option data will cross a buffer
option -> name,
&(option -> format [i]));
break;
- }
+ }
}
/* Check for too few bytes... */
* count.
*/
count = MRns_name_ntop(
- nbuff, op,
+ nbuff, op,
(endbuf-op)-1);
if (count <= 0) {
static void
count_options(struct option_cache *dummy_oc,
struct packet *dummy_packet,
- struct lease *dummy_lease,
+ struct lease *dummy_lease,
struct client_state *dummy_client_state,
struct option_state *dummy_opt_state,
struct option_state *opt_state,
struct binding_scope **dummy_binding_scope,
- struct universe *dummy_universe,
+ struct universe *dummy_universe,
void *void_accumulator) {
int *accumulator = (int *)void_accumulator;
static void
collect_oro(struct option_cache *oc,
struct packet *dummy_packet,
- struct lease *dummy_lease,
+ struct lease *dummy_lease,
struct client_state *dummy_client_state,
struct option_state *dummy_opt_state,
struct option_state *opt_state,
struct binding_scope **dummy_binding_scope,
- struct universe *dummy_universe,
+ struct universe *dummy_universe,
void *void_oro) {
struct data_string *oro = (struct data_string *)void_oro;
* option value contents).
*/
void
-build_server_oro(struct data_string *server_oro,
+build_server_oro(struct data_string *server_oro,
struct option_state *options,
const char *file, int line) {
int num_opts;
struct universe *u = NULL;
int status = 0;
- universe_hash_lookup(&u, universe_hash,
+ universe_hash_lookup(&u, universe_hash,
(const char *)name->data, name->len, MDL);
if (u == NULL) {
log_error("option_space_encapsulate: option space '%.*s' does "
exit:
for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
- if (result[i].len)
+ if (results[i].len)
data_string_forget(&results[i], MDL);
}
if (decoded_packet->options_valid &&
(op = lookup_option(&dhcp_universe,
- decoded_packet->options,
+ decoded_packet->options,
DHO_DHCP_MESSAGE_TYPE))) {
struct data_string dp;
memset(&dp, 0, sizeof dp);
if (len < 1) {
return 0;
}
- if ((packet[0] == DHCPV6_RELAY_FORW) ||
+ if ((packet[0] == DHCPV6_RELAY_FORW) ||
(packet[0] == DHCPV6_RELAY_REPL)) {
if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
return 1;
}
#ifdef DHCPv6
-void
-do_packet6(struct interface_info *interface, const char *packet,
- int len, int from_port, const struct iaddr *from,
+void
+do_packet6(struct interface_info *interface, const char *packet,
+ int len, int from_port, const struct iaddr *from,
isc_boolean_t was_unicast) {
unsigned char msg_type;
const struct dhcpv6_packet *msg;
- const struct dhcpv6_relay_packet *relay;
+ const struct dhcpv6_relay_packet *relay;
struct packet *decoded_packet;
#if defined (DEBUG_MEMORY_LEAKAGE)
unsigned long previous_outstanding = dmalloc_outstanding;
decoded_packet->unicast = was_unicast;
msg_type = packet[0];
- if ((msg_type == DHCPV6_RELAY_FORW) ||
+ if ((msg_type == DHCPV6_RELAY_FORW) ||
(msg_type == DHCPV6_RELAY_REPL)) {
int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
relay = (const struct dhcpv6_relay_packet *)packet;
memcpy(&decoded_packet->dhcpv6_peer_address,
relay->peer_address, sizeof(relay->peer_address));
- if (!parse_option_buffer(decoded_packet->options,
- relay->options, len - relaylen,
+ if (!parse_option_buffer(decoded_packet->options,
+ relay->options, len - relaylen,
&dhcpv6_universe)) {
/* no logging here, as parse_option_buffer() logs all
cases where it fails */
decoded_packet->dhcpv6_msg_type = msg->msg_type;
/* message-specific data */
- memcpy(decoded_packet->dhcpv6_transaction_id,
- msg->transaction_id,
+ memcpy(decoded_packet->dhcpv6_transaction_id,
+ msg->transaction_id,
sizeof(decoded_packet->dhcpv6_transaction_id));
- if (!parse_option_buffer(decoded_packet->options,
- msg->options, len - msglen,
+ if (!parse_option_buffer(decoded_packet->options,
+ msg->options, len - msglen,
&dhcpv6_universe)) {
/* no logging here, as parse_option_buffer() logs all
cases where it fails */
/* INSIST(data != NULL); */
option = NULL;
- if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
+ if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
&option_num, 0, MDL)) {
log_error("Attempting to add unknown option %d.", option_num);
return 0;
return 0;
}
- if (!make_const_data(&oc->expression,
- data,
+ if (!make_const_data(&oc->expression,
+ data,
data_len,
- 0,
- 0,
+ 0,
+ 0,
MDL)) {
log_error("No memory for constant data adding %s (option %d).",
option->name, option_num);
"a future version of ISC DHCP will reject this");
}
} else {
- /*
+ /*
* If hlen is 0 we don't have any identifier, we warn the user
* but continue processing the packet as we can.
*/