Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
ISC Open Source Projects
Kea
Commits
d06b0d68
Commit
d06b0d68
authored
Oct 04, 2013
by
Marcin Siodelski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[3180] Implemented support for callback functions to parse options.
parent
23c94464
Changes
27
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1021 additions
and
279 deletions
+1021
-279
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.cc
+99
-0
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/dhcp4_srv.h
+12
-0
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
+110
-7
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/dhcp6_srv.h
+18
-0
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+74
-1
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/dhcp6_test_utils.h
+1
-0
src/lib/dhcp/libdhcp++.cc
src/lib/dhcp/libdhcp++.cc
+4
-4
src/lib/dhcp/libdhcp++.h
src/lib/dhcp/libdhcp++.h
+3
-3
src/lib/dhcp/option.cc
src/lib/dhcp/option.cc
+10
-3
src/lib/dhcp/option.h
src/lib/dhcp/option.h
+38
-2
src/lib/dhcp/option6_ia.cc
src/lib/dhcp/option6_ia.cc
+6
-2
src/lib/dhcp/option6_iaaddr.cc
src/lib/dhcp/option6_iaaddr.cc
+4
-2
src/lib/dhcp/option6_iaprefix.cc
src/lib/dhcp/option6_iaprefix.cc
+3
-1
src/lib/dhcp/option_custom.cc
src/lib/dhcp/option_custom.cc
+4
-1
src/lib/dhcp/option_definition.cc
src/lib/dhcp/option_definition.cc
+17
-9
src/lib/dhcp/option_definition.h
src/lib/dhcp/option_definition.h
+11
-4
src/lib/dhcp/option_int.h
src/lib/dhcp/option_int.h
+4
-2
src/lib/dhcp/option_int_array.h
src/lib/dhcp/option_int_array.h
+2
-2
src/lib/dhcp/pkt4.cc
src/lib/dhcp/pkt4.cc
+11
-7
src/lib/dhcp/pkt4.h
src/lib/dhcp/pkt4.h
+13
-1
src/lib/dhcp/pkt6.cc
src/lib/dhcp/pkt6.cc
+28
-13
src/lib/dhcp/pkt6.h
src/lib/dhcp/pkt6.h
+15
-3
src/lib/dhcp/tests/libdhcp++_unittest.cc
src/lib/dhcp/tests/libdhcp++_unittest.cc
+6
-6
src/lib/dhcp/tests/option_definition_unittest.cc
src/lib/dhcp/tests/option_definition_unittest.cc
+2
-2
src/lib/dhcp/tests/option_unittest.cc
src/lib/dhcp/tests/option_unittest.cc
+126
-0
src/lib/dhcp/tests/pkt4_unittest.cc
src/lib/dhcp/tests/pkt4_unittest.cc
+275
-177
src/lib/dhcp/tests/pkt6_unittest.cc
src/lib/dhcp/tests/pkt6_unittest.cc
+125
-27
No files found.
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)
};