Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
d06b0d68
Commit
d06b0d68
authored
Oct 04, 2013
by
Marcin Siodelski
Browse files
[3180] Implemented support for callback functions to parse options.
parent
23c94464
Changes
27
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
d06b0d68
...
...
@@ -35,6 +35,7 @@
#include
<hooks/hooks_manager.h>
#include
<boost/algorithm/string/erase.hpp>
#include
<boost/bind.hpp>
#include
<iomanip>
#include
<fstream>
...
...
@@ -197,6 +198,15 @@ Dhcpv4Srv::run() {
continue
;
}
// In order to parse the DHCP options, the server needs to use some
// configuration information such as: existing option spaces, option
// definitions etc. This is the kind of information which is not
// available in the libdhcp, so we need to supply our own implementation
// of the option parsing function here, which would rely on the
// configuration data.
query
->
setCallback
(
boost
::
bind
(
&
Dhcpv4Srv
::
unpackOptions
,
this
,
_1
,
_2
,
_3
));
bool
skip_unpack
=
false
;
// The packet has just been received so contains the uninterpreted wire
...
...
@@ -1164,6 +1174,95 @@ Dhcpv4Srv::openActiveSockets(const uint16_t port,
}
}
size_t
Dhcpv4Srv
::
unpackOptions
(
const
OptionBuffer
&
buf
,
const
std
::
string
&
option_space
,
isc
::
dhcp
::
OptionCollection
&
options
)
{
size_t
offset
=
0
;
OptionDefContainer
option_defs
;
if
(
option_space
==
"dhcp6"
)
{
// Get the list of stdandard option definitions.
option_defs
=
LibDHCP
::
getOptionDefs
(
Option
::
V6
);
}
else
if
(
!
option_space
.
empty
())
{
OptionDefContainerPtr
option_defs_ptr
=
CfgMgr
::
instance
().
getOptionDefs
(
option_space
);
if
(
option_defs_ptr
!=
NULL
)
{
option_defs
=
*
option_defs_ptr
;
}
}
// Get the search index #1. It allows to search for option definitions
// using option code.
const
OptionDefContainerTypeIndex
&
idx
=
option_defs
.
get
<
1
>
();
// The buffer being read comprises a set of options, each starting with
// a one-byte type code and a one-byte length field.
while
(
offset
+
1
<=
buf
.
size
())
{
uint8_t
opt_type
=
buf
[
offset
++
];
// DHO_END is a special, one octet long option
if
(
opt_type
==
DHO_END
)
return
(
offset
);
// just return. Don't need to add DHO_END option
// DHO_PAD is just a padding after DHO_END. Let's continue parsing
// in case we receive a message without DHO_END.
if
(
opt_type
==
DHO_PAD
)
continue
;
if
(
offset
+
1
>=
buf
.
size
())
{
// opt_type must be cast to integer so as it is not treated as
// unsigned char value (a number is presented in error message).
isc_throw
(
OutOfRange
,
"Attempt to parse truncated option "
<<
static_cast
<
int
>
(
opt_type
));
}
uint8_t
opt_len
=
buf
[
offset
++
];
if
(
offset
+
opt_len
>
buf
.
size
())
{
isc_throw
(
OutOfRange
,
"Option parse failed. Tried to parse "
<<
offset
+
opt_len
<<
" bytes from "
<<
buf
.
size
()
<<
"-byte long buffer."
);
}
// Get all definitions with the particular option code. Note that option code
// is non-unique within this container however at this point we expect
// to get one option definition with the particular code. If more are
// returned we report an error.
const
OptionDefContainerTypeRange
&
range
=
idx
.
equal_range
(
opt_type
);
// Get the number of returned option definitions for the option code.
size_t
num_defs
=
distance
(
range
.
first
,
range
.
second
);
OptionPtr
opt
;
if
(
num_defs
>
1
)
{
// Multiple options of the same code are not supported right now!
isc_throw
(
isc
::
Unexpected
,
"Internal error: multiple option definitions"
" for option type "
<<
static_cast
<
int
>
(
opt_type
)
<<
" returned. Currently it is not supported to initialize"
<<
" multiple option definitions for the same option code."
<<
" This will be supported once support for option spaces"
<<
" is implemented"
);
}
else
if
(
num_defs
==
0
)
{
opt
=
OptionPtr
(
new
Option
(
Option
::
V4
,
opt_type
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
opt
->
setEncapsulatedSpace
(
"dhcp4"
);
}
else
{
// The option definition has been found. Use it to create
// the option instance from the provided buffer chunk.
const
OptionDefinitionPtr
&
def
=
*
(
range
.
first
);
assert
(
def
);
opt
=
def
->
optionFactory
(
Option
::
V4
,
opt_type
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
,
boost
::
bind
(
&
Dhcpv4Srv
::
unpackOptions
,
this
,
_1
,
_2
,
_3
));
}
options
.
insert
(
std
::
make_pair
(
opt_type
,
opt
));
offset
+=
opt_len
;
}
return
(
offset
);
}
}
// namespace dhcp
}
// namespace isc
src/bin/dhcp4/dhcp4_srv.h
View file @
d06b0d68
...
...
@@ -351,6 +351,18 @@ protected:
private:
/// @brief Implements a callback function to parse options in the message.
///
/// @param buf a A buffer holding options in on-wire format.
/// @param option_space A name of the option space which holds definitions
/// of to be used to parse options in the packets.
/// @param [out] options A reference to the collection where parsed options
/// will be stored.
/// @return An offset to the first byte after last parsed option.
size_t
unpackOptions
(
const
OptionBuffer
&
buf
,
const
std
::
string
&
option_space
,
isc
::
dhcp
::
OptionCollection
&
options
);
/// @brief Constructs netmask option based on subnet4
/// @param subnet subnet for which the netmask will be calculated
///
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
d06b0d68
...
...
@@ -229,6 +229,15 @@ bool Dhcpv6Srv::run() {
continue
;
}
// In order to parse the DHCP options, the server needs to use some
// configuration information such as: existing option spaces, option
// definitions etc. This is the kind of information which is not
// available in the libdhcp, so we need to supply our own implementation
// of the option parsing function here, which would rely on the
// configuration data.
query
->
setCallback
(
boost
::
bind
(
&
Dhcpv6Srv
::
unpackOptions
,
this
,
_1
,
_2
,
_3
,
_4
,
_5
));
bool
skip_unpack
=
false
;
// The packet has just been received so contains the uninterpreted wire
...
...
@@ -703,7 +712,7 @@ Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
void
Dhcpv6Srv
::
sanityCheck
(
const
Pkt6Ptr
&
pkt
,
RequirementLevel
clientid
,
RequirementLevel
serverid
)
{
Option
::
OptionCollection
client_ids
=
pkt
->
getOptions
(
D6O_CLIENTID
);
OptionCollection
client_ids
=
pkt
->
getOptions
(
D6O_CLIENTID
);
switch
(
clientid
)
{
case
MANDATORY
:
if
(
client_ids
.
size
()
!=
1
)
{
...
...
@@ -724,7 +733,7 @@ Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
break
;
}
Option
::
OptionCollection
server_ids
=
pkt
->
getOptions
(
D6O_SERVERID
);
OptionCollection
server_ids
=
pkt
->
getOptions
(
D6O_SERVERID
);
switch
(
serverid
)
{
case
FORBIDDEN
:
if
(
!
server_ids
.
empty
())
{
...
...
@@ -870,7 +879,7 @@ Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
//
// @todo: expand this to cover IA_PD and IA_TA once we implement support for
// prefix delegation and temporary addresses.
for
(
Option
::
OptionCollection
::
iterator
opt
=
question
->
options_
.
begin
();
for
(
OptionCollection
::
iterator
opt
=
question
->
options_
.
begin
();
opt
!=
question
->
options_
.
end
();
++
opt
)
{
switch
(
opt
->
second
->
getType
())
{
case
D6O_IA_NA
:
{
...
...
@@ -1052,8 +1061,8 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
// Get all IAs from the answer. For each IA, holding an address we will
// create a corresponding NameChangeRequest.
Option
::
OptionCollection
answer_ias
=
answer
->
getOptions
(
D6O_IA_NA
);
for
(
Option
::
OptionCollection
::
const_iterator
answer_ia
=
OptionCollection
answer_ias
=
answer
->
getOptions
(
D6O_IA_NA
);
for
(
OptionCollection
::
const_iterator
answer_ia
=
answer_ias
.
begin
();
answer_ia
!=
answer_ias
.
end
();
++
answer_ia
)
{
// @todo IA_NA may contain multiple addresses. We should process
// each address individually. Currently we get only one.
...
...
@@ -1493,7 +1502,7 @@ Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply,
}
DuidPtr
duid
(
new
DUID
(
opt_duid
->
getData
()));
for
(
Option
::
OptionCollection
::
iterator
opt
=
renew
->
options_
.
begin
();
for
(
OptionCollection
::
iterator
opt
=
renew
->
options_
.
begin
();
opt
!=
renew
->
options_
.
end
();
++
opt
)
{
switch
(
opt
->
second
->
getType
())
{
case
D6O_IA_NA
:
{
...
...
@@ -1543,7 +1552,7 @@ Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
DuidPtr
duid
(
new
DUID
(
opt_duid
->
getData
()));
int
general_status
=
STATUS_Success
;
for
(
Option
::
OptionCollection
::
iterator
opt
=
release
->
options_
.
begin
();
for
(
OptionCollection
::
iterator
opt
=
release
->
options_
.
begin
();
opt
!=
release
->
options_
.
end
();
++
opt
)
{
switch
(
opt
->
second
->
getType
())
{
case
D6O_IA_NA
:
{
...
...
@@ -1868,5 +1877,99 @@ Dhcpv6Srv::openActiveSockets(const uint16_t port) {
}
}
size_t
Dhcpv6Srv
::
unpackOptions
(
const
OptionBuffer
&
buf
,
const
std
::
string
&
option_space
,
isc
::
dhcp
::
OptionCollection
&
options
,
size_t
*
relay_msg_offset
,
size_t
*
relay_msg_len
)
{
size_t
offset
=
0
;
size_t
length
=
buf
.
size
();
OptionDefContainer
option_defs
;
if
(
option_space
==
"dhcp6"
)
{
// Get the list of stdandard option definitions.
option_defs
=
LibDHCP
::
getOptionDefs
(
Option
::
V6
);
}
else
if
(
!
option_space
.
empty
())
{
OptionDefContainerPtr
option_defs_ptr
=
CfgMgr
::
instance
().
getOptionDefs
(
option_space
);
if
(
option_defs_ptr
!=
NULL
)
{
option_defs
=
*
option_defs_ptr
;
}
}
// Get the search index #1. It allows to search for option definitions
// using option code.
const
OptionDefContainerTypeIndex
&
idx
=
option_defs
.
get
<
1
>
();
// The buffer being read comprises a set of options, each starting with
// a two-byte type code and a two-byte length field.
while
(
offset
+
4
<=
length
)
{
uint16_t
opt_type
=
isc
::
util
::
readUint16
(
&
buf
[
offset
]);
offset
+=
2
;
uint16_t
opt_len
=
isc
::
util
::
readUint16
(
&
buf
[
offset
]);
offset
+=
2
;
if
(
offset
+
opt_len
>
length
)
{
// @todo: consider throwing exception here.
return
(
offset
);
}
if
(
opt_type
==
D6O_RELAY_MSG
&&
relay_msg_offset
&&
relay_msg_len
)
{
// remember offset of the beginning of the relay-msg option
*
relay_msg_offset
=
offset
;
*
relay_msg_len
=
opt_len
;
// do not create that relay-msg option
offset
+=
opt_len
;
continue
;
}
// Get all definitions with the particular option code. Note that option
// code is non-unique within this container however at this point we
// expect to get one option definition with the particular code. If more
// are returned we report an error.
const
OptionDefContainerTypeRange
&
range
=
idx
.
equal_range
(
opt_type
);
// Get the number of returned option definitions for the option code.
size_t
num_defs
=
distance
(
range
.
first
,
range
.
second
);
OptionPtr
opt
;
if
(
num_defs
>
1
)
{
// Multiple options of the same code are not supported right now!
isc_throw
(
isc
::
Unexpected
,
"Internal error: multiple option definitions"
" for option type "
<<
opt_type
<<
" returned. Currently it is not"
" supported to initialize multiple option definitions"
" for the same option code. This will be supported once"
" support for option spaces is implemented"
);
}
else
if
(
num_defs
==
0
)
{
// @todo Don't crash if definition does not exist because only a few
// option definitions are initialized right now. In the future
// we will initialize definitions for all options and we will
// remove this elseif. For now, return generic option.
opt
=
OptionPtr
(
new
Option
(
Option
::
V6
,
opt_type
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
opt
->
setEncapsulatedSpace
(
"dhcp6"
);
}
else
{
// The option definition has been found. Use it to create
// the option instance from the provided buffer chunk.
const
OptionDefinitionPtr
&
def
=
*
(
range
.
first
);
assert
(
def
);
opt
=
def
->
optionFactory
(
Option
::
V6
,
opt_type
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
,
boost
::
bind
(
&
Dhcpv6Srv
::
unpackOptions
,
this
,
_1
,
_2
,
_3
,
_4
,
_5
));
}
// add option to options
options
.
insert
(
std
::
make_pair
(
opt_type
,
opt
));
offset
+=
opt_len
;
}
return
(
offset
);
}
};
};
src/bin/dhcp6/dhcp6_srv.h
View file @
d06b0d68
...
...
@@ -459,6 +459,24 @@ protected:
/// simulates transmission of a packet. For that purpose it is protected.
virtual
void
sendPacket
(
const
Pkt6Ptr
&
pkt
);
/// @brief Implements a callback function to parse options in the message.
///
/// @param buf a A buffer holding options in on-wire format.
/// @param option_space A name of the option space which holds definitions
/// of to be used to parse options in the packets.
/// @param [out] options A reference to the collection where parsed options
/// will be stored.
/// @param relay_msg_offset Reference to a size_t structure. If specified,
/// offset to beginning of relay_msg option will be stored in it.
/// @param relay_msg_len reference to a size_t structure. If specified,
/// length of the relay_msg option will be stored in it.
/// @return An offset to the first byte after last parsed option.
size_t
unpackOptions
(
const
OptionBuffer
&
buf
,
const
std
::
string
&
option_space
,
isc
::
dhcp
::
OptionCollection
&
options
,
size_t
*
relay_msg_offset
,
size_t
*
relay_msg_len
);
private:
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
d06b0d68
...
...
@@ -24,6 +24,7 @@
#include
<dhcp/option6_client_fqdn.h>
#include
<dhcp/option6_ia.h>
#include
<dhcp/option6_iaaddr.h>
#include
<dhcp/option_int.h>
#include
<dhcp/option_int_array.h>
#include
<dhcp/iface_mgr.h>
#include
<dhcp6/config_parser.h>
...
...
@@ -2157,7 +2158,7 @@ TEST_F(Dhcpv6SrvTest, portsRelayedTraffic) {
// Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
// @todo Uncomment this test as part of #3180 work.
// Kea code currently fails to handle docsis traffic.
TEST_F
(
Dhcpv6SrvTest
,
DISABLED_
docsisTraffic
)
{
TEST_F
(
Dhcpv6SrvTest
,
docsisTraffic
)
{
NakedDhcpv6Srv
srv
(
0
);
...
...
@@ -2181,6 +2182,78 @@ TEST_F(Dhcpv6SrvTest, DISABLED_docsisTraffic) {
/// that is relayed properly, etc.
}
// This test verifies that the following option structure can be parsed:
// - option (option space 'foobar')
// - sub option (option space 'foo')
// - sub option (option space 'bar')
TEST_F
(
Dhcpv6SrvTest
,
unpackOptions
)
{
// Create option definition for each level of encapsulation. Each option
// definition is for the option code 1. Options may have the same
// option code because they belong to different option spaces.
// Top level option encapsulates options which belong to 'space-foo'.
OptionDefinitionPtr
opt_def
(
new
OptionDefinition
(
"option-foobar"
,
1
,
"uint32"
,
"space-foo"
));
\
// Middle option encapsulates options which belong to 'space-bar'
OptionDefinitionPtr
opt_def2
(
new
OptionDefinition
(
"option-foo"
,
1
,
"uint16"
,
"space-bar"
));
// Low level option doesn't encapsulate any option space.
OptionDefinitionPtr
opt_def3
(
new
OptionDefinition
(
"option-bar"
,
1
,
"uint8"
));
// Add option definitions to the Configuration Manager. Each goes under
// different option space.
CfgMgr
&
cfgmgr
=
CfgMgr
::
instance
();
ASSERT_NO_THROW
(
cfgmgr
.
addOptionDef
(
opt_def
,
"space-foobar"
));
ASSERT_NO_THROW
(
cfgmgr
.
addOptionDef
(
opt_def2
,
"space-foo"
));
ASSERT_NO_THROW
(
cfgmgr
.
addOptionDef
(
opt_def3
,
"space-bar"
));
// Create the buffer holding the structure of options.
const
char
raw_data
[]
=
{
// First option starts here.
0x00
,
0x01
,
// option code = 1
0x00
,
0x0F
,
// option length = 15
0x00
,
0x01
,
0x02
,
0x03
,
// This option carries uint32 value
// Sub option starts here.
0x00
,
0x01
,
// option code = 1
0x00
,
0x07
,
// option length = 7
0x01
,
0x02
,
// this option carries uint16 value
// Last option starts here.
0x00
,
0x01
,
// option code = 1
0x00
,
0x01
,
// option length = 1
0x00
// This option carries a single uint8 value and has no sub options.
};
OptionBuffer
buf
(
raw_data
,
raw_data
+
sizeof
(
raw_data
));
// Parse options.
NakedDhcpv6Srv
srv
(
0
);
OptionCollection
options
;
ASSERT_NO_THROW
(
srv
.
unpackOptions
(
buf
,
"space-foobar"
,
options
,
0
,
0
));
// There should be one top level option.
ASSERT_EQ
(
1
,
options
.
size
());
boost
::
shared_ptr
<
OptionInt
<
uint32_t
>
>
option_foobar
=
boost
::
dynamic_pointer_cast
<
OptionInt
<
uint32_t
>
>
(
options
.
begin
()
->
second
);
ASSERT_TRUE
(
option_foobar
);
EXPECT_EQ
(
1
,
option_foobar
->
getType
());
EXPECT_EQ
(
0x00010203
,
option_foobar
->
getValue
());
// There should be a middle level option held in option_foobar.
boost
::
shared_ptr
<
OptionInt
<
uint16_t
>
>
option_foo
=
boost
::
dynamic_pointer_cast
<
OptionInt
<
uint16_t
>
>
(
option_foobar
->
getOption
(
1
));
ASSERT_TRUE
(
option_foo
);
EXPECT_EQ
(
1
,
option_foo
->
getType
());
EXPECT_EQ
(
0x0102
,
option_foo
->
getValue
());
// Finally, there should be a low level option under option_foo.
boost
::
shared_ptr
<
OptionInt
<
uint8_t
>
>
option_bar
=
boost
::
dynamic_pointer_cast
<
OptionInt
<
uint8_t
>
>
(
option_foo
->
getOption
(
1
));
ASSERT_TRUE
(
option_bar
);
EXPECT_EQ
(
1
,
option_bar
->
getType
());
EXPECT_EQ
(
0x0
,
option_bar
->
getValue
());
}
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
...
...
src/bin/dhcp6/tests/dhcp6_test_utils.h
View file @
d06b0d68
...
...
@@ -110,6 +110,7 @@ public:
using
Dhcpv6Srv
::
sanityCheck
;
using
Dhcpv6Srv
::
loadServerID
;
using
Dhcpv6Srv
::
writeServerID
;
using
Dhcpv6Srv
::
unpackOptions
;
using
Dhcpv6Srv
::
name_change_reqs_
;
/// @brief packets we pretend to receive
...
...
src/lib/dhcp/libdhcp++.cc
View file @
d06b0d68
...
...
@@ -128,7 +128,7 @@ LibDHCP::optionFactory(Option::Universe u,
size_t
LibDHCP
::
unpackOptions6
(
const
OptionBuffer
&
buf
,
isc
::
dhcp
::
Option
::
OptionCollection
&
options
,
isc
::
dhcp
::
OptionCollection
&
options
,
size_t
*
relay_msg_offset
/* = 0 */
,
size_t
*
relay_msg_len
/* = 0 */
)
{
size_t
offset
=
0
;
...
...
@@ -206,7 +206,7 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
}
size_t
LibDHCP
::
unpackOptions4
(
const
OptionBuffer
&
buf
,
isc
::
dhcp
::
Option
::
OptionCollection
&
options
)
{
isc
::
dhcp
::
OptionCollection
&
options
)
{
size_t
offset
=
0
;
// Get the list of stdandard option definitions.
...
...
@@ -282,8 +282,8 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
void
LibDHCP
::
packOptions
(
isc
::
util
::
OutputBuffer
&
buf
,
const
Option
::
OptionCollection
&
options
)
{
for
(
Option
::
OptionCollection
::
const_iterator
it
=
options
.
begin
();
const
OptionCollection
&
options
)
{
for
(
OptionCollection
::
const_iterator
it
=
options
.
begin
();
it
!=
options
.
end
();
++
it
)
{
it
->
second
->
pack
(
buf
);
}
...
...
src/lib/dhcp/libdhcp++.h
View file @
d06b0d68
...
...
@@ -100,7 +100,7 @@ public:
/// @param buf output buffer (assembled options will be stored here)
/// @param options collection of options to store to
static
void
packOptions
(
isc
::
util
::
OutputBuffer
&
buf
,
const
isc
::
dhcp
::
Option
::
OptionCollection
&
options
);
const
isc
::
dhcp
::
OptionCollection
&
options
);
/// @brief Parses provided buffer as DHCPv4 options and creates Option objects.
///
...
...
@@ -111,7 +111,7 @@ public:
/// @param options Reference to option container. Options will be
/// put here.
static
size_t
unpackOptions4
(
const
OptionBuffer
&
buf
,
isc
::
dhcp
::
Option
::
OptionCollection
&
options
);
isc
::
dhcp
::
OptionCollection
&
options
);
/// @brief Parses provided buffer as DHCPv6 options and creates Option objects.
///
...
...
@@ -133,7 +133,7 @@ public:
/// length of the relay_msg option will be stored in it.
/// @return offset to the first byte after last parsed option
static
size_t
unpackOptions6
(
const
OptionBuffer
&
buf
,
isc
::
dhcp
::
Option
::
OptionCollection
&
options
,
isc
::
dhcp
::
OptionCollection
&
options
,
size_t
*
relay_msg_offset
=
0
,
size_t
*
relay_msg_len
=
0
);
...
...
src/lib/dhcp/option.cc
View file @
d06b0d68
...
...
@@ -126,6 +126,13 @@ void Option::unpack(OptionBufferConstIter begin,
void
Option
::
unpackOptions
(
const
OptionBuffer
&
buf
)
{
// If custom option parsing function has been set, use this function
// to parse options. Otherwise, use standard function from libdhcp++.
if
(
!
callback_
.
empty
())
{
callback_
(
buf
,
getEncapsulatedSpace
(),
options_
,
0
,
0
);
return
;
}
switch
(
universe_
)
{
case
V4
:
LibDHCP
::
unpackOptions4
(
buf
,
options_
);
...
...
@@ -146,7 +153,7 @@ uint16_t Option::len() {
int
length
=
getHeaderLen
()
+
data_
.
size
();
// ... and sum of lengths of all suboptions
for
(
Option
::
OptionCollection
::
iterator
it
=
options_
.
begin
();
for
(
OptionCollection
::
iterator
it
=
options_
.
begin
();
it
!=
options_
.
end
();
++
it
)
{
length
+=
(
*
it
).
second
->
len
();
...
...
@@ -169,7 +176,7 @@ Option::valid() {
}
OptionPtr
Option
::
getOption
(
uint16_t
opt_type
)
{
isc
::
dhcp
::
Option
::
OptionCollection
::
const_iterator
x
=
isc
::
dhcp
::
OptionCollection
::
const_iterator
x
=
options_
.
find
(
opt_type
);
if
(
x
!=
options_
.
end
()
)
{
return
(
*
x
).
second
;
...
...
@@ -178,7 +185,7 @@ OptionPtr Option::getOption(uint16_t opt_type) {
}
bool
Option
::
delOption
(
uint16_t
opt_type
)
{
isc
::
dhcp
::
Option
::
OptionCollection
::
iterator
x
=
options_
.
find
(
opt_type
);
isc
::
dhcp
::
OptionCollection
::
iterator
x
=
options_
.
find
(
opt_type
);
if
(
x
!=
options_
.
end
()
)
{
options_
.
erase
(
x
);
return
true
;
// delete successful
...
...
src/lib/dhcp/option.h
View file @
d06b0d68
...
...
@@ -17,6 +17,7 @@
#include
<util/buffer.h>
#include
<boost/function.hpp>
#include
<boost/shared_ptr.hpp>
#include
<map>
...
...
@@ -44,6 +45,14 @@ typedef boost::shared_ptr<OptionBuffer> OptionBufferPtr;
class
Option
;
typedef
boost
::
shared_ptr
<
Option
>
OptionPtr
;
/// A collection of DHCPv6 options
typedef
std
::
multimap
<
unsigned
int
,
OptionPtr
>
OptionCollection
;
/// This type describes a callback function to parse options from buffer.
typedef
boost
::
function
<
size_t
(
const
OptionBuffer
&
,
const
std
::
string
,
OptionCollection
&
,
size_t
*
,
size_t
*
)
>
UnpackOptionsCallback
;
class
Option
{
public:
...
...
@@ -56,8 +65,6 @@ public:
/// defines option universe DHCPv4 or DHCPv6
enum
Universe
{
V4
,
V6
};
/// a collection of DHCPv6 options
typedef
std
::
multimap
<
unsigned
int
,
OptionPtr
>
OptionCollection
;
/// @brief a factory function prototype
///
...
...
@@ -290,6 +297,29 @@ public:
data_
.
assign
(
first
,
last
);
}
/// @brief Sets the name of the option space encapsulated by this option.
///
/// @param encapsulated_space name of the option space encapsulated by
/// this option.
void
setEncapsulatedSpace
(
const
std
::
string
&
encapsulated_space
)
{
encapsulated_space_
=
encapsulated_space
;
}
/// @brief Returns the name of the option space encapsulated by this option.
///
/// @return name of the option space encapsulated by this option.
std
::
string
getEncapsulatedSpace
()
const
{
return
(
encapsulated_space_
);
}
/// @brief Set callback function to be used to parse options.
///
/// @param callback An instance of the callback function or NULL to
/// uninstall callback.
void
setCallback
(
UnpackOptionsCallback
callback
)
{
callback_
=
callback
;
}
/// just to force that every option has virtual dtor
virtual
~
Option
();
...
...
@@ -372,6 +402,12 @@ protected:
/// collection for storing suboptions
OptionCollection
options_
;
/// Name of the option space being encapsulated by this option.
std
::
string
encapsulated_space_
;
/// A callback to be called to unpack options from the packet.
UnpackOptionsCallback
callback_
;
/// @todo probably 2 different containers have to be used for v4 (unique
/// options) and v6 (options with the same type can repeat)
};
...
...
src/lib/dhcp/option6_ia.cc
View file @
d06b0d68
// Copyright (C) 2011-201
2
Internet Systems Consortium, Inc. ("ISC")