Browse Source

[3807] Improved log messages for the DHCPv6 server.

Also added a few minor corrections to the DHCPv4 server and implemented
new Option6StatusCode.
Marcin Siodelski 10 years ago
parent
commit
329c1c9ae1

+ 7 - 4
src/bin/dhcp4/dhcp4_messages.mes

@@ -404,9 +404,12 @@ The second argument includes the error string.
 
 % DHCP4_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
 A debug message noting that the server has received the specified type of
-packet on the specified interface.  Note that a packet marked as UNKNOWN
-may well be a valid DHCP packet, just a type not expected by the server
-(e.g. it will report a received OFFER packet as UNKNOWN).
+packet on the specified interface. The first argument specifies the
+client and transaction identification information. The second and third
+argument specify the name of the DHCPv4 message and its numeric type
+respectively. The remaining arguments specify the source address,
+destination IP address and the name of the interface on which the
+message has been received.
 
 % DHCP4_PACKET_SEND %1: sending packet %2 (type %3) from %4:%5 to %6:%7 on interface %8
 This debug message is issued when the server is sending the response to
@@ -584,7 +587,7 @@ It lists some information about the parameters with which the server
 is running.
 
 % DHCP4_SUBNET_DATA %1: the selected subnet details: %2
-This debug message includes the details of the subnet selected fot
+This debug message includes the details of the subnet selected for
 the client. The first argument includes the client and the
 transaction identification information. The second arguments
 includes the subnet details.

+ 1 - 1
src/bin/dhcp4/dhcp4_srv.cc

@@ -364,7 +364,7 @@ Dhcpv4Srv::run() {
             // This is not an error because we might have received a SIGTERM,
             // SIGINT or SIGHUP which are handled by the server. For signals
             // that are not handled by the server we rely on the default
-            // behavior of the system, but there is nothing we should log here.
+            // behavior of the system.
             LOG_DEBUG(packet_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_SIGNAL)
                 .arg(signal_set_->getNext());
         } catch (const std::exception& e) {

+ 22 - 9
src/bin/dhcp6/dhcp6_log.h

@@ -25,26 +25,39 @@ namespace dhcp {
 /// @name Constants defining debug levels for logging in DHCPv6 server.
 //@{
 
-// Debug levels used to log information during startup and shutdown.
+/// @brief Debug level used to log information during server startup.
 const int DBG_DHCP6_START = DBGLVL_START_SHUT;
+
+/// @brief Debug level used to log information during server shutdown.
 const int DBG_DHCP6_SHUT = DBGLVL_START_SHUT;
 
-// Debug level used to log setting information (such as configuration changes).
+/// @brief Debug level used to log receiving commands.
 const int DBG_DHCP6_COMMAND = DBGLVL_COMMAND;
 
-// Trace basic operations within the code.
+/// @brief Debug level used to trace basic operations within the code.
 const int DBG_DHCP6_BASIC = DBGLVL_TRACE_BASIC;
 
-// Trace hook related operations
+/// @brief Debug level used to trace hook related operations
 const int DBG_DHCP6_HOOKS = DBGLVL_TRACE_BASIC;
 
-// Trace detailed operations, including errors raised when processing invalid
-// packets.  (These are not logged at severities of WARN or higher for fear
-// that a set of deliberately invalid packets set to the server could overwhelm
-// the logging.)
+/// @brief Debug level used to log the traces with some basic data.
+///
+/// The basic data includes summary information, e.g. summary of the
+/// information returned by a particular function. It may also include
+/// more detailed information in cases when it is warranted and the
+/// extraction of the data doesn't impact the server's performance
+/// significantly.
+const int DBG_DHCP6_BASIC_DATA = DBGLVL_TRACE_BASIC_DATA;
+
+/// @brief Debug level used to trace detailed errors.
+///
+/// Trace detailed operations, including errors raised when processing invalid
+/// packets.  (These are not logged at severities of WARN or higher for fear
+/// that a set of deliberately invalid packets set to the server could overwhelm
+/// the logging.)
 const int DBG_DHCP6_DETAIL = DBGLVL_TRACE_DETAIL;
 
-// This level is used to log the contents of packets received and sent.
+/// @brief This level is used to log the contents of packets received and sent.
 const int DBG_DHCP6_DETAIL_DATA = DBGLVL_TRACE_DETAIL_DATA;
 
 //@}

+ 285 - 174
src/bin/dhcp6/dhcp6_messages.mes

@@ -19,6 +19,50 @@ This message is printed when DHCPv6 server enabled an interface to be used
 to receive DHCPv6 traffic. IPv6 socket on this interface will be opened once
 Interface Manager starts up procedure of opening sockets.
 
+% DHCP6_ADD_GLOBAL_STATUS_CODE %1: adding Status Code to DHCPv6 packet: %2
+This message is logged when the server is adding the top-level
+Status Code option. The first argument includes the client and the
+transaction identification information. The second argument includes
+the details of the status code.
+
+% DHCP6_ADD_STATUS_CODE_FOR_IA %1: adding Status Code to IA with iaid=%2: %3
+This message is logged when the server is adding the Status Code
+option to an IA. The first argument includes the client and the
+transaction identification information. The second argument specifies
+the IAID. The third argument includes the details of the status code.
+
+% DHCP6_BUFFER_RECEIVED received buffer from %1:%2 to %3:%4 over interface %5
+This debug message is logged when the server has received a packet
+over the socket. When the message is logged the contents of the received
+packet hasn't been parsed yet. The only available information is the
+interface and the source and destination addresses/ports.
+
+% DHCP6_BUFFER_UNPACK parsing buffer received from %1 to %2 over interface %3
+This debug message is issued when the server starts parsing the received
+buffer holding the DHCPv6 message. The arguments specify the source and
+destination addresses as well as the interface over which the buffer has
+been received.
+
+% DHCP6_BUFFER_WAIT waiting for next DHCPv6 packet with timeout %1 ms
+This debug message is issued when the server enters the state when it
+waits for new packets. The argument specifies the timeout for the server
+to wait for the packet. When this time elapses the server will pass
+through its main loop to perform handling of any pending signals
+and timers. After that, it will enter the wait state again.
+
+% DHCP6_BUFFER_WAIT_SIGNAL signal received while waiting for next packet, next waiting signal is %1
+This debug message is issued when the server was waiting for the
+packet, but the wait has been interrupted by the signal received
+by the process. The signal will be handled before the server starts
+waiting for next packets. The argument specifies the next signal to
+be handled by the server.
+
+% DHCP6_BUFFER_WAIT_TIMEOUT timeout %1 ms reached while waiting for the next packet
+This debug message is issued when the timeout has occurred while
+waiting for the next packet. The server will now handle signals
+received and ready timers before waiting for next packets again.
+The argument specifies the timeout value in milliseconds.
+
 % DHCP6_CCSESSION_STARTED control channel session started on socket %1
 A debug message issued during startup after the IPv6 DHCP server has
 successfully established a session with the Kea control channel.
@@ -31,11 +75,6 @@ to establish a session with the Kea control channel.
 This debug message informs that incoming packet has been assigned to specified
 class or classes. This is a norma
 
-% DHCP6_CLIENTID_MISSING mandatory client-id option is missing, message from %1 dropped
-This error message indicates that the received message is being dropped
-because it does not include the mandatory client-id option necessary for
-address assignment.  The most likely cause is a problem with the client.
-
 % DHCP6_COMMAND_RECEIVED received command %1, arguments: %2
 A debug message listing the command (and possible arguments) received
 from the Kea control system by the IPv6 DHCP server.
@@ -83,37 +122,82 @@ lease and other information.
 This debug message is logged when the new Name Change Request has been created
 to perform the DNS Update, which adds new RRs.
 
-% DHCP6_DDNS_CREATE_REMOVE_NAME_CHANGE_REQUEST created name change request: %1
+% DHCP6_DDNS_CREATE_REMOVE_NAME_CHANGE_REQUEST %1: created name change request: %2
 This debug message is logged when the new Name Change Request has been created
-to perform the DNS Update, which removes RRs from the DNS.
+to perform the DNS Update, which removes RRs from the DNS. The first argument
+includes the client and transaction identification information. The second
+argument specifies the details of the generated name change request.
+
+% DHCP6_DDNS_FQDN_GENERATED %1: generated FQDN for the client: %2
+This debug message is logged when the server generated FQDN (name)
+for the client which message is processed. The names may be
+generated by the server when required by the server's policy or
+when the client doesn't provide any specific FQDN in its message
+to the server. The first argument includes the client and
+transaction identification information. The second argument includes
+the generated FQDN.
+
+% DHCP6_DDNS_GENERATED_FQDN_UPDATE_FAIL %1: failed to update the lease using address %2, after generating FQDN for a client, reason: %3
+This message indicates the failure when trying to update the lease and/or
+options in the server's response with the hostname generated by the server
+from the acquired address. The first argument includes the client and the
+transaction identification information. The second argument is a leased
+address. The third argument includes the reason for the failure.
 
-% DHCP6_DDNS_LEASE_ASSIGN_FQDN_CHANGE FQDN for the allocated lease: %1 has changed. New values: hostname = %2, reverse mapping = %3, forward mapping = %4
+% DHCP6_DDNS_LEASE_ASSIGN_FQDN_CHANGE FQDN %1: FQDN for the allocated lease: %2 has changed. New values: hostname = %3, reverse mapping = %4, forward mapping = %5
 This debug message is logged when FQDN mapping for a particular lease has
 been changed by the recent Request message. This mapping will be changed in DNS.
+The first argument includes the client and the transaction identification
+information. The second argument holds the details about the lease for which
+the FQDN information and/or mappings have changed. The remaining arguments
+hold the new FQDN information and flags for mappings.
 
-% DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE FQDN for the renewed lease: %1 has changed. New values: hostname = %2, reverse mapping = %3, forward mapping = %4
+% DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE FQDN %1: FQDN for the renewed lease: %2 has changed. New values: hostname = %3, reverse mapping = %4, forward mapping = %5
 This debug message is logged when FQDN mapping for a particular lease has been
 changed by the recent Renew message. This mapping will be changed in DNS.
+The first argument includes the client and the transaction identification
+information. The second argument holds the details about the lease for which
+the FQDN information and/or mappings have changed. The remaining arguments
+hold the new FQDN information and flags for mappings.
 
-% DHCP6_DDNS_RECEIVE_FQDN received DHCPv6 Client FQDN Option: %1
+% DHCP6_DDNS_RECEIVE_FQDN %1: received DHCPv6 Client FQDN option: %2
 This debug message is logged when server has found the DHCPv6 Client FQDN Option
-sent by a client and started processing it.
+sent by a client and started processing it. The first argument includes the
+client and transaction identification information. The second argument
+includes the received FQDN.
 
-% DHCP6_DDNS_REMOVE_INVALID_HOSTNAME invalid FQDN: %1 for the lease: %2 when removing DNS bindings
+% DHCP6_DDNS_REMOVE_INVALID_HOSTNAME %1: invalid FQDN %2 for the lease: %3 when removing DNS bindings
 This error message is issued when a lease being deleted contains an indication
 that the DNS Update has been performed for it, but the FQDN held in the lease
 database has invalid format and can't be transformed to the canonical on-wire
-format.
+format. The first argument includes the client and transaction identification
+information.
 
 % DHCP6_DDNS_REQUEST_SEND_FAILED failed sending a request to kea-dhcp-ddns, error: %1,  ncr: %2
 This error message indicates that IPv6 DHCP server failed to send a DDNS
 update reqeust to the DHCP-DDNS server. This is most likely a configuration or
 networking error.
 
+% DHCP6_DDNS_RESPONSE_FQDN_DATA %1: including FQDN option in the server's response: %2
+This debug message is issued when the server is adding the Client FQDN
+option in its response to the client. The first argument includes the
+client and transaction identification information. The second argument
+includes the details of the FQDN option being included. Note that the
+name carried in the FQDN option may be modified by the server when
+the lease is acquired for the client.
+
 % DHCP6_DDNS_SEND_FQDN sending DHCPv6 Client FQDN Option to the client: %1
 This debug message is logged when server includes an DHCPv6 Client FQDN Option
 in its response to the client.
 
+% DHCP6_DDNS_SKIP_REMOVE_NAME_CHANGE_REQUEST %1: skip creating name change request for lease: %2
+This debug message is logged when the server determines that removal
+name change request should not be sent to the DNS, because the DNS
+updates are disabled on the DHCP server, or no DNS update has been
+performed for the processed lease. The first argument includes the
+client and the transaction identification information. The second
+argument provides the details of the lease.
+
 % DHCP6_DEACTIVATE_INTERFACE deactivate interface %1
 This message is printed when DHCPv6 server disables an interface from being
 used to receive DHCPv6 traffic. Sockets on this interface will not be opened
@@ -127,19 +211,7 @@ as a result of receiving SIGHUP signal.
 This is an error message logged when the dynamic reconfiguration of the
 DHCP server failed.
 
-% DHCP6_EXTEND_LEASE_SUBNET_SELECTED the %1 subnet was selected for client extending its lease
-This is a debug message informing that a given subnet was selected. It will
-be used for extending lifetime of the lease. This is one of the early steps
-in the processing of incoming client message.
-
-% DHCP6_EXTEND_LEASE_SUBNET_SELECT_FAILED failed to select a subnet for received %1: src=%2 type=%3
-This warning message is output when a Renew or Rebind was received from a
-subnet for which the DHCPv6 server has not been configured. The cause is
-most likely due to a misconfiguration of the server. The packet processing
-will continue, but the response will only contain generic configuration
-parameters and no addresses or prefixes.
-
-% DHCP6_EXTEND_NA_UNKNOWN received unknown IA_NA from client (duid=%1, iaid=%2) in subnet %3
+% DHCP6_EXTEND_NA_UNKNOWN %1: received unknown IA_NA with iaid=%2 in subnet %3
 This warning message is printed when client attempts to extend the lease
 for the address (in the IA_NA option) but no such lease is known by the server.
 It typically means that client has attempted to use its lease past its
@@ -147,6 +219,9 @@ lifetime: causes of this include a adjustment of the client's date/time
 setting or poor support on the client for sleep/recovery. A properly
 implemented client will recover from such a situation by restarting the
 lease allocation process after receiving a negative reply from the server.
+The first argument includes the client and the transaction identification
+information. The second argument holds IAID. The third argument holds the
+subnet information.
 
 An alternative cause could be that the server has lost its database
 recently and does not recognize its well-behaving clients. This is more
@@ -154,96 +229,67 @@ probable if you see many such messages. Clients will recover from this,
 but they will most likely get a different IP addresses and experience
 a brief service interruption.
 
-% DHCP6_EXTEND_NA_UNKNOWN_SUBNET %1 message received from client on unknown subnet (duid=%2, iaid=%3)
-A warning message indicating that a client is attempting to extend lease lifetime
-for the address, but the server does not have any information about the subnet this
-client belongs to. This may mean that faulty the mobile client changed its location
-and is trying to renew its old address (client is supposed to send confirm, not renew
-in such cases, according to RFC3315) or the server configuration has changed and
-information about existing subnet was removed. Note that in a sense this is worse
-case of DHCP6_EXTEND_NA_UNKNOWN, as not only the lease is unknown, but also the subnet
-is. Depending on the reasons of this condition, it may or may not correct on its own.
-
-% DHCP6_EXTEND_PD_NO_BINDING client sent a %1 message to extend lifetimes of prefixes for an unknown binding: duid=%2, iaid=%3, subnet=%4
-This warning message is logged when a client attempts to extend the lifetime of the
-prefix it is using, but the server was unable to find the binding to which
-this lease belongs. This error condition has different implications for the
-Renew and Rebind messages. For the former, the server will respond with NoBinding
-status code. For the latter, the server will discard the message.
-
-% DHCP6_EXTEND_PD_UNKNOWN_SUBNET %1 message received from client on unknown subnet (duid=%2, iaid=%3)
-A warning message indicating that a client is attempting to extend lease lifetime
-for the prefix, but the server doesn't have any information about the subnet this
-client belongs to.
-
 % DHCP6_HOOKS_LIBS_RELOAD_FAIL reload of hooks libraries failed
 A "libreload" command was issued to reload the hooks libraries but for
 some reason the reload failed.  Other error messages issued from the
 hooks framework will indicate the nature of the problem.
 
-% DHCP6_HOOK_BUFFER_RCVD_SKIP received DHCPv6 buffer was dropped because a callout set the skip flag
+% DHCP6_HOOK_BUFFER_RCVD_SKIP received buffer from %1 to %2 over interface %3 was dropped because a callout set the skip flag
 This debug message is printed when a callout installed on buffer6_receive
 hook point set the skip flag. For this particular hook point, the
 setting of the flag by a callout instructs the server to drop the packet.
+The arguments specify the source and destination address as well as
+the name of the interface over which the buffer has been received.
 
-% DHCP6_HOOK_BUFFER_SEND_SKIP prepared DHCPv6 response was dropped because a callout set the skip flag
+% DHCP6_HOOK_BUFFER_SEND_SKIP %1: prepared DHCPv6 response was dropped because a callout set the skip flag
 This debug message is printed when a callout installed on buffer6_send
 hook point set the skip flag. For this particular hook point, the
 setting of the flag by a callout instructs the server to drop the packet.
 Server completed all the processing (e.g. may have assigned, updated
 or released leases), but the response will not be send to the client.
+The argument includes the client and transaction identification
+information.
 
-% DHCP6_HOOK_LEASE6_EXTEND_SKIP DHCPv6 lease lifetime was not extended because a callout set the skip flag for message %1
-or lease6_rebind hook point set the skip flag. For this particular hook
-point, the setting of the flag by a callout instructs the server to not
-extend the lifetime for a lease. If client requested renewal of multiples
-leases (by sending multiple IA options), the server will skip the renewal
-of the one in question and will proceed with other renewals as usual.
-
-% DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP DHCPv6 address lease was not released because a callout set the skip flag
+% DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP %1: DHCPv6 address lease was not released because a callout set the skip flag
 This debug message is printed when a callout installed on the
 lease6_release hook point set the skip flag. For this particular hook
 point, the setting of the flag by a callout instructs the server to not
 release a lease. If a client requested the release of multiples leases
 (by sending multiple IA options), the server will retain this particular
-lease and proceed with other releases as usual.
+lease and proceed with other releases as usual. The argument holds the
+client and transaction identification information.
 
-% DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP DHCPv6 prefix lease was not released because a callout set the skip flag
+% DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP %1: prefix lease was not released because a callout set the skip flag
 This debug message is printed when a callout installed on lease6_release
 hook point set the skip flag. For this particular hook point, the
 setting of the flag by a callout instructs the server to not release
 a lease. If client requested release of multiples leases (by sending
 multiple IA options), the server will retains this particular lease and
-will proceed with other renewals as usual.
-
-% DHCP6_HOOK_LEASE6_RENEW_SKIP DHCPv6 lease was not renewed because a callout set the skip flag
-This debug message is printed when a callout installed on lease6_renew
-hook point set the skip flag. For this particular hook point, the setting
-of the flag by a callout instructs the server to not renew a lease. If
-client requested renewal of multiples leases (by sending multiple IA
-options), the server will skip the renewal of the one in question and
-will proceed with other renewals as usual.
+will proceed with other renewals as usual. The argument holds the
+client and transaction identification information.
 
-% DHCP6_HOOK_PACKET_RCVD_SKIP received DHCPv6 packet was dropped because a callout set the skip flag
+% DHCP6_HOOK_PACKET_RCVD_SKIP %1: packet is dropped, because a callout set the skip flag.
 This debug message is printed when a callout installed on the pkt6_receive
-hook point set the skip flag. For this particular hook point, the
-setting of the flag by a callout instructs the server to drop the packet.
+hook point sets the skip flag. For this particular hook point, the
+setting of the flag instructs the server to drop the packet.
 
-% DHCP6_HOOK_PACKET_SEND_SKIP prepared DHCPv6 response was not sent because a callout set the skip flag
+% DHCP6_HOOK_PACKET_SEND_SKIP %1: prepared DHCPv6 response was not sent because a callout set the skip flag
 This debug message is printed when a callout installed on the pkt6_send
 hook point set the skip flag. For this particular hook point, the setting
 of the flag by a callout instructs the server to drop the packet. This
 effectively means that the client will not get any response, even though
 the server processed client's request and acted on it (e.g. possibly
-allocated a lease).
+allocated a lease). The argument specifies the client and transaction
+identification information.
 
-% DHCP6_HOOK_SUBNET6_SELECT_SKIP no subnet was selected because a callout set the skip flag
+% DHCP6_HOOK_SUBNET6_SELECT_SKIP %1: no subnet was selected because a callout set the skip flag
 This debug message is printed when a callout installed on the
 subnet6_select hook point set the skip flag. For this particular hook
 point, the setting of the flag instructs the server not to choose a
 subnet, an action that severely limits further processing; the server
 will be only able to offer global options - no addresses or prefixes
-will be assigned.
+will be assigned. The argument holds the client and transaction
+identification information.
 
 % DHCP6_INIT_FAIL failed to initialize Kea server: %1
 The server has failed to establish communication with the rest of Kea,
@@ -251,28 +297,42 @@ failed to read JSON configuration file or excountered any other critical
 issue that prevents it from starting up properly. Attached error message
 provides more details about the issue.
 
-% DHCP6_LEASE_ADVERT address lease %1 advertised (client duid=%2, iaid=%3)
-This debug message indicates that the server successfully advertised
-an address lease. It is up to the client to choose one server out of the
-advertised servers and continue allocation with that server. This
-is a normal behavior and indicates successful operation.
+% DHCP6_LEASE_ADVERT %1: lease for address %2 and iaid=%3 will be advertised
+This debug message indicates that the server will advertise an
+address to the client in the ADVERTISE message. The client will
+request allocation of this address with the REQUEST message sent
+in the next message exchange. The first argument includes the client
+and transaction identification information. The remaining arguments
+hold the allocated address and IAID.
 
-% DHCP6_LEASE_ADVERT_FAIL failed to advertise an address lease for client duid=%1, iaid=%2
+% DHCP6_LEASE_ADVERT_FAIL %1: failed to advertise an address lease for iaid=%2
 This message indicates that in response to a received SOLICIT, the server
 failed to advertise a non-temporary lease for a given client. There may
 be many reasons for such failure. Each failure is logged in a separate
-log entry.
+log entry. The first argument holds the client and transaction identification
+information. The second argument holds the IAID.
 
-% DHCP6_LEASE_ALLOC address lease %1 has been allocated (client duid=%2, iaid=%3)
+% DHCP6_LEASE_ALLOC %1: lease for address %2 and iaid=%3 has been allocated
 This debug message indicates that in response to a client's REQUEST
 message, the server successfully granted an non-temporary address
 lease. This is a normal behavior and indicates successful operation.
+The first argument includes the client and transaction identification
+information. The remaining arguments hold the allocated address and
+IAID.
 
-% DHCP6_LEASE_ALLOC_FAIL failed to grant an address lease for client duid=%1, iaid=%2
+% DHCP6_LEASE_ALLOC_FAIL %1: failed to grant an address lease for iaid=%2
 This message indicates that in response to a received REQUEST, the server
 failed to grant a non-temporary address lease for the client. There may
 be many reasons for such failure. Each failure is logged in a separate
-log entry.
+log entry. The first argument holds the client and transaction identification
+information. The second argument holds the IAID.
+
+% DHCP6_LEASE_DATA %1: detailed lease information for iaid=%2: %3
+This debug message is used to print the detailed information about the
+allocated lease or a lease which will be advertised to the client.
+The first argument holds the client and the transaction identification
+information. The second argument holds the IAID. The third argument
+holds the detailed lease information.
 
 % DHCP6_LEASE_DATABASE_TIMERS_EXEC_FAIL failed to execute timer-based functions for lease database: %1
 A warning message executed when a server process is unable to execute
@@ -281,24 +341,24 @@ action is a Lease File Cleanup. One of the reasons for the failure is
 a misconfiguration of the lease database, whereby the lease database
 hasn't been selected.
 
-% DHCP6_LEASE_NA_WITHOUT_DUID address lease for address %1 does not have a DUID
+% DHCP6_LEASE_NA_WITHOUT_DUID %1: address lease for address %2 does not have a DUID
 This error message indicates a database consistency problem. The lease
 database has an entry indicating that the given address is in use,
 but the lease does not contain any client identification. This is most
 likely due to a software error: please raise a bug report. As a temporary
-workaround, manually remove the lease entry from the database.
+workaround, manually remove the lease entry from the database. The first
+argument includes the client and transaction identification information.
+The second argument holds the address to be released.
 
-% DHCP6_LEASE_PD_WITHOUT_DUID prefix lease for address %1 does not have a DUID
+% DHCP6_LEASE_PD_WITHOUT_DUID %1: lease for prefix %2/%3 does not have a DUID
 This error message indicates a database consistency failure. The lease
 database has an entry indicating that the given prefix is in use,
 but the lease does not contain any client identification. This is most
 likely due to a software error: please raise a bug report. As a temporary
-workaround, manually remove the lease entry from the database.
-
-% DHCP6_NAME_GEN_UPDATE_FAIL failed to update the lease using address %1, after generating FQDN for a client, reason: %2
-This message indicates the failure when trying to update the lease and/or
-options in the server's response with the hostname generated by the server
-from the acquired address.
+workaround, manually remove the lease entry from the database. The
+first argument includes client and transaction identification
+information. The second and third argument hold the prefix and the
+prefix length.
 
 % DHCP6_NOT_RUNNING IPv6 DHCP server is not running
 A warning message is issued when an attempt is made to shut down the
@@ -321,26 +381,33 @@ server is about to open sockets on the specified port.
 A warning message issued when IfaceMgr fails to open and bind a socket. The reason
 for the failure is appended as an argument of the log message.
 
-% DHCP6_PACKET_MISMATCH_SERVERID_DROP dropping packet %1 (transid=%2, interface=%3) having mismatched server identifier
+% DHCP6_PACKET_DROP_PARSE_FAIL failed to parse packet from %1 to %2, received over interace %3, reason: %4
+The DHCPv4 server has received a packet that it is unable to
+interpret. The reason why the packet is invalid is included in the message.
+
+% DHCP6_PACKET_DROP_SERVERID_MISMATCH %1: dropping packet with server identifier: %2, server is using: %3
 A debug message noting that server has received message with server identifier
 option that not matching server identifier that server is using.
 
-% DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet: %1
-The DHCPv6 server has received a packet that it is unable to interpret.
-There may be many causes: truncated header, truncated or malformed option,
-trailing padding that contains garbage etc. More information is specified
-as a parameter.
+% DHCP6_PACKET_DROP_UNICAST %1: dropping unicast %2 packet as this packet should be sent to multicast
+This debug message is issued when the server drops the unicast packet,
+because packets of this type must be sent to multicast. The first argument
+specifies the client and transaction identification information, the
+second argument specifies packet type.
 
 % DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3
 This is a general catch-all message indicating that the processing of the
 specified packet type from the indicated address failed.  The reason is given in the
 message.  The server will not send a response but will instead ignore the packet.
 
-% DHCP6_PACKET_RECEIVED %1 packet received
-A debug message noting that the server has received the specified type
-of packet.  Note that a packet marked as UNKNOWN may well be a valid
-DHCP packet, just a type not expected by the server (e.g. it will report
-a received OFFER packet as UNKNOWN).
+% DHCP6_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
+A debug message noting that the server has received the specified type of
+packet on the specified interface. The first argument specifies the
+client and transaction identification information. The second and third
+argument specify the name of the DHCPv6 message and its numeric type
+respectively. The remaining arguments specify the source address,
+destination IP address and the name of the interface on which the
+message has been received.
 
 % DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
 The IPv6 DHCP server tried to receive a packet but an error
@@ -394,96 +461,142 @@ of the named configuration element, or the creation succeeded but the
 parsing actions and committal of changes failed.  The reason for the
 failure is given in the message.
 
-% DHCP6_PD_LEASE_ADVERT prefix lease %1/%2 advertised (client duid=%3, iaid=%4)
-This debug message indicates that the server successfully advertised
-a prefix lease. It is up to the client to choose one server out of the
-advertised servers and continue allocation with that server. This
-is a normal behavior and indicates successful operation.
+% DHCP6_PD_LEASE_ADVERT %1: lease for prefix %2/%3 and iaid=%4 will be advertised
+This debug message indicates that the server will advertise a
+prefix to the client in the ADVERTISE message. The client will
+request allocation of this prefix with the REQUEST message sent
+in the next message exchange. The first argument includes the client
+and transaction identification information. The remaining arguments
+hold the allocated prefix, prefix length and IAID.
 
-% DHCP6_PD_LEASE_ADVERT_FAIL failed to advertise a prefix lease for client duid=%1, iaid=%2
+% DHCP6_PD_LEASE_ADVERT_FAIL %1: failed to advertise a prefix lease for iaid=%2
 This message indicates that in response to a received SOLICIT, the
-server failed to advertise a prefix lease for the client. There may
+server failed to advertise a prefix lease for a given client. There may
 be many reasons for such failure. Each failure is logged in a separate
-log entry.
+log entry. The first argument holds the client and transaction identification
+information. The second argument holds the IAID.
 
-% DHCP6_PD_LEASE_ALLOC prefix lease %1/%2 has been allocated (client duid=%3, iaid=%4)
+% DHCP6_PD_LEASE_ALLOC %1: lease for prefix %2/%3 and iaid=%4 has been allocated
 This debug message indicates that in response to a client's REQUEST
-message, the server successfully granted a prefix delegation lease. This
-is a normal behavior and indicates successful operation.
-
-% DHCP6_PD_LEASE_ALLOC_FAIL failed to grant a prefix lease for client duid=%1, iaid=%2
-This message indicates that the server failed to grant (in response to
-received REQUEST) a prefix lease for a given client. There may be many reasons
-for such failure. Each failure is logged in a separate log entry.
+message, the server successfully granted an non-temporary address
+lease. This is a normal behavior and indicates successful operation.
+The first argument includes the client and transaction identification
+information. The remaining arguments hold the allocated prefix,
+prefix lenngth and and IAID.
 
-% DHCP6_PROCESS_IA_NA_REQUEST server is processing IA_NA option (duid=%1, iaid=%2, hint=%3)
+% DHCP6_PD_LEASE_ALLOC_FAIL %1: failed to grant a prefix lease for iaid=%2
+This message indicates that in response to a received REQUEST, the server
+failed to grant a prefix lease for the client. There may be many reasons
+for such failure. Each failure is logged in a separate log entry. The first
+argument holds the client and transaction identification information.
+The second argument holds the IAID.
+
+% DHCP6_PROCESS_IA_NA_EXTEND %1: extending lease lifetime for IA_NA option with iaid=%2
+This message is logged when the server is starting to extend the lifetime
+of the address lease associated with the particular IAID. The first argument
+includes the client and transaction identification information. The second
+argument contains the IAID.
+
+% DHCP6_PROCESS_IA_NA_RELEASE %1: releasing lease for IA_NA option with iaid=%2
+This message is logged when the server is trying to release the client's
+as a result of receiving the RELEASE message. The first argument
+includes the client and transaction identification information. The second
+argument contains the IAID.
+
+% DHCP6_PROCESS_IA_NA_REQUEST %1: server is processing IA_NA option with iaid=%2 and hint=%3
 This is a debug message that indicates the processing of a received
-IA_NA option. It may optionally contain an address that may be used by
-the server as a hint for possible requested address.
-
-% DHCP6_PROCESS_IA_PD_REQUEST server is processing IA_PD option (duid=%1, iaid=%2, hint=%3)
+IA_NA option. The first argument contains the client and the transaction
+identification information. The second argument holds the IAID of the
+IA_NA option. The third argument may hold the hint for the server
+about the address that the client would like to have allocated.
+If there is no hint, the argument should provide the text indicating
+that the hint hasn't been sent.
+
+% DHCP6_PROCESS_IA_PD_EXTEND %1: extending lease lifetime for IA_PD option with iaid=%2
+This message is logged when the server is starting to extend the lifetime
+of the prefix lease associated with the particular IAID. The first argument
+includes the client and transaction identification information. The second
+argument contains the IAID.
+
+% DHCP6_PROCESS_IA_PD_REQUEST %1: server is processing IA_PD option with iaid=%2 and hint=%3
 This is a debug message that indicates a processing of received IA_PD
-option. It may optionally contain an prefix that may be used by the server
-as a hint for possible requested prefix.
-
-% DHCP6_QUERY_DATA received packet length %1, data length %2, data is %3
-A debug message listing the data received from the client or relay.
-
-% DHCP6_RELEASE_MISSING_CLIENTID client (address=%1) sent RELEASE message without mandatory client-id
-This warning message indicates that client sent RELEASE message without
-mandatory client-id option. This is most likely caused by a buggy client
-(or a relay that malformed forwarded message). This request will not be
-processed and a response with error status code will be sent back.
-
-% DHCP6_RELEASE_NA address %1 belonging to client duid=%2, iaid=%3 was released properly
+option. The first argument contains the client and the transaction
+identification information. The second argument holds the IAID of the
+IA_PD option. The third argument may hold the hint for the server
+about the prefix that the client would like to have allocated.
+If there is no hint, the argument should provide the text indicating
+that the hint hasn't been sent.
+
+% DHCP6_QUERY_DATA %1, packet details: %2
+A debug message printing the details of the received packet. The first
+argument includes the client and the transaction identification
+information.
+
+% DHCP6_RELEASE_NA %1: binding for address %2 and iaid=%3 was released properly
 This debug message indicates that an address was released properly. It
 is a normal operation during client shutdown.
 
-% DHCP6_RELEASE_NA_FAIL failed to remove address lease for address %1 for duid=%2, iaid=%3
+% DHCP6_RELEASE_NA_FAIL %1: failed to remove address lease for address %2 and iaid=%3
 This error message indicates that the software failed to remove an address
 lease from the lease database.  It probably due to an error during a
 database operation: resolution will most likely require administrator
 intervention (e.g. check if DHCP process has sufficient privileges to
 update the database). It may also be triggered if a lease was manually
-removed from the database during RELEASE message processing.
+removed from the database during RELEASE message processing. The first
+argument holds the client and transaction identification information.
+The second and third argument hold the released address and IAID
+respectively.
 
-% DHCP6_RELEASE_NA_FAIL_WRONG_DUID client (duid=%1) tried to release address %2, but it belongs to another client (duid=%3)
+% DHCP6_RELEASE_NA_FAIL_WRONG_DUID %1: client tried to release address %2, but it belongs to another client using duid=%3
 This warning message indicates that a client tried to release an address
 that belongs to a different client. This should not happen in normal
 circumstances and may indicate a misconfiguration of the client.  However,
 since the client releasing the address will stop using it anyway, there
 is a good chance that the situation will correct itself.
 
-% DHCP6_RELEASE_NA_FAIL_WRONG_IAID client (duid=%1) tried to release address %2, but it used wrong IAID (expected %3, but got %4)
+% DHCP6_RELEASE_NA_FAIL_WRONG_IAID %1: client tried to release address %2, but it used wrong IAID (expected %3, but got %4)
 This warning message indicates that client tried to release an address
 that does belong to it, but the address was expected to be in a different
 IA (identity association) container. This probably means that the client's
 support for multiple addresses is flawed.
 
-% DHCP6_RELEASE_PD prefix %1 belonging to client duid=%2, iaid=%3 was released properly
+% DHCP6_RELEASE_PD %1: prefix %2/%3 for iaid=%4 was released properly
 This debug message indicates that a prefix was released properly. It
-is a normal operation during client shutdown.
+is a normal operation during client shutdown. The first argument holds
+the client and transaction identification information. The second and
+third argument define the prefix and its length. The forth argument
+holds IAID.
 
-% DHCP6_RELEASE_PD_FAIL failed to remove prefix lease for address %1 for duid=%2, iaid=%3
+% DHCP6_RELEASE_PD_FAIL %1: failed to release prefix %2/%3 for iaid=%4
 This error message indicates that the software failed to remove a prefix
 lease from the lease database.  It probably due to an error during a
 database operation: resolution will most likely require administrator
 intervention (e.g. check if DHCP process has sufficient privileges to
 update the database). It may also be triggered if a lease was manually
-removed from the database during RELEASE message processing.
+removed from the database during RELEASE message processing. The
+first argument hold the client and transaction identification
+information. The second and third argument define the prefix and
+its length. The forth argument holds the IAID.
 
-% DHCP6_RELEASE_PD_FAIL_WRONG_DUID client (duid=%1) tried to release prefix %2, but it belongs to another client (duid=%3)
+% DHCP6_RELEASE_PD_FAIL_WRONG_DUID %1: client tried to release prefix %2/%3, but it belongs to another client (duid=%4)
 This warning message indicates that client tried to release a prefix
 that belongs to a different client. This should not happen in normal
 circumstances and may indicate a misconfiguration of the client.  However,
 since the client releasing the prefix will stop using it anyway, there
-is a good chance that the situation will correct itself.
+is a good chance that the situation will correct itself. The first
+argument includes the client and the transaction identification
+information. The second and third argument include the prefix and
+prefix length. The last argument holds the DUID of the client holding
+the lease.
 
-% DHCP6_RELEASE_PD_FAIL_WRONG_IAID client (duid=%1) tried to release prefix %2, but it used wrong IAID (expected %3, but got %4)
+% DHCP6_RELEASE_PD_FAIL_WRONG_IAID %1: client tried to release prefix %2/%3, but it used wrong IAID (expected %4, but got %5)
 This warning message indicates that client tried to release a prefix
 that does belong to it, but the address was expected to be in a different
 IA (identity association) container. This probably means that the client's
-support for multiple prefixes is flawed.
+support for multiple prefixes is flawed. The first argument includes the
+client and transaction identification information. The second and third
+argument identify the prefix. The forth and fifth argument hold the
+expected IAID and IAID found respectively.
 
 % DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3
 This message indicates that received DHCPv6 packet is invalid.  This may be due
@@ -565,17 +678,26 @@ This is a debug message issued during the IPv6 DHCP server startup.
 It lists some information about the parameters with which the server
 is running.
 
-% DHCP6_SUBNET_SELECTED the %1 subnet was selected for client assignment
-This is a debug message informing that a given subnet was selected. It will
-be used for address and option assignment. This is one of the early steps
-in the processing of incoming client message.
-
-% DHCP6_SUBNET_SELECTION_FAILED failed to select a subnet for incoming packet, src=%1 type=%2
-This warning message is output when a packet was received from a subnet for
-which the DHCPv6 server has not been configured. The cause is most likely due
-to a misconfiguration of the server. The packet processing will continue, but
-the response will only contain generic configuration parameters and no
-addresses or prefixes.
+% DHCP6_SUBNET_DATA %1: the selected subnet details: %2
+This debug message includes the details of the subnet selected for
+the client. The first argument includes the client and the
+transaction identification information. The second arguments
+includes the subnet details.
+
+% DHCP6_SUBNET_SELECTED %1: the subnet with ID %2 was selected for client assignments
+This is a debug message noting the selection of a subnet to be used for
+address and option assignment. Subnet selection is one of the early
+steps in the processing of incoming client message. The first
+argument includes the client and the transaction identification
+information. The second argument holds the selected subnet id.
+
+% DHCP6_SUBNET_SELECTION_FAILED %1: failed to select subnet for the client
+This debug message indicates that the server failed to select the
+subnet for the client which has sent a message to the server.
+The cause is likely due to a misconfiguration of the server. The packet
+processing will continue, but the response will only contain generic
+configuration and no addresses or prefixes. The argument includes
+the client and the transaction identification information.
 
 % DHCP6_UNKNOWN_MSG_RECEIVED received unknown message (type %d) on interface %2
 This debug message is printed when server receives a message of unknown type.
@@ -583,14 +705,3 @@ That could either mean missing functionality or invalid or broken relay or clien
 The list of formally defined message types is available here:
 http://www.iana.org/assignments/dhcpv6-parameters.
 
-% DHCP6_UNKNOWN_RELEASE_NA received RELEASE from unknown client (IA_NA, duid=%1, iaid=%2)
-This warning message is printed when client attempts to release an address
-lease, but no such lease is known by the server. See the explanation
-of the status code DHCP6_UNKNOWN_RENEW_NA for possible reasons for
-such behavior.
-
-% DHCP6_UNKNOWN_RELEASE_PD received RELEASE from unknown client (IA_PD, duid=%1, iaid=%2)
-This warning message is printed when client attempts to release an prefix
-lease, but no such lease is known by the server. See the explanation
-of the status code DHCP6_UNKNOWN_RENEW_PD for possible reasons for
-such behavior.

File diff suppressed because it is too large
+ 338 - 275
src/bin/dhcp6/dhcp6_srv.cc


+ 7 - 10
src/bin/dhcp6/dhcp6_srv.h

@@ -255,13 +255,6 @@ protected:
     /// @return Reply message to be sent to the client.
     Pkt6Ptr processInfRequest(const Pkt6Ptr& inf_request);
 
-    /// @brief Creates status-code option.
-    ///
-    /// @param code status code value (see RFC3315)
-    /// @param text textual explanation (will be sent in status code option)
-    /// @return status-code option
-    OptionPtr createStatusCode(uint16_t code, const std::string& text);
-
     /// @brief Selects a subnet for a given client's packet.
     ///
     /// @param question client's message
@@ -530,9 +523,12 @@ protected:
     /// own.
     /// If ddns updates are disabled, this method returns immediately.
     ///
+    /// @param query A pointer to the packet sent by the client for which the
+    /// name change request should be sent.
     /// @param lease A lease for which the the removal of corresponding DNS
     /// records will be performed.
-    void createRemovalNameChangeRequest(const Lease6Ptr& lease);
+    void createRemovalNameChangeRequest(const Pkt6Ptr& query,
+                                        const Lease6Ptr& lease);
 
     /// @brief Attempts to extend the lifetime of IAs.
     ///
@@ -728,13 +724,14 @@ private:
     /// If there are any differences (different fwd or rev flags, or different
     /// hostname) a DNS update for removing entry will be generated.
     ///
+    /// @param query a pointer to the client's message
     /// @param old_lease old version of the lease
     /// @param new_lease new version of the lease (may be NULL)
     /// @param hostname specifies hostname (for printing purposes)
     /// @param do_fwd specifies if reverse updates are enabled (for printing purposes)
     /// @param do_rev specifies if reverse updates are enabled (for printing purposes)
-    void conditionalNCRRemoval(Lease6Ptr& old_lease, Lease6Ptr& new_lease,
-                               const std::string& hostname,
+    void conditionalNCRRemoval(const Pkt6Ptr& query, Lease6Ptr& old_lease,
+                               Lease6Ptr& new_lease, const std::string& hostname,
                                bool do_fwd, bool do_rev);
 
     /// @brief Allocation Engine.

+ 7 - 6
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -17,6 +17,7 @@
 #include <dhcp/option_custom.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/pkt6.h>
 #include <dhcpsrv/lease.h>
@@ -143,10 +144,10 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
                 {
                     // Check if the server has sent status code. If no status
                     // code, assume the status code to be 0.
-                    OptionCustomPtr status_code = boost::dynamic_pointer_cast<
-                        OptionCustom>(ia->getOption(D6O_STATUS_CODE));
+                    Option6StatusCodePtr status_code = boost::dynamic_pointer_cast<
+                        Option6StatusCode>(ia->getOption(D6O_STATUS_CODE));
                     lease_info.status_code_ =
-                        status_code ? status_code->readInteger<uint16_t>(0) : 0;
+                        status_code ? status_code->getStatusCode() : 0;
                 }
                 break;
 
@@ -159,13 +160,13 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
     }
 
     // Get the global status code.
-    OptionCustomPtr status_code = boost::dynamic_pointer_cast<
-        OptionCustom>(reply->getOption(D6O_STATUS_CODE));
+    Option6StatusCodePtr status_code = boost::dynamic_pointer_cast<
+        Option6StatusCode>(reply->getOption(D6O_STATUS_CODE));
     // If status code has been sent, we override the default status code:
     // Success and record that we have received the status code.
     if (status_code) {
         config_.received_status_code_ = true;
-        config_.status_code_ = status_code->readInteger<uint16_t>(0);
+        config_.status_code_ = status_code->getStatusCode();
     }
 }
 

+ 0 - 24
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -1019,30 +1019,6 @@ TEST_F(Dhcpv6SrvTest, pdReleaseReject) {
     testReleaseReject(Lease::TYPE_PD, IOAddress("2001:db8:1:2::"));
 }
 
-// This test verifies if the status code option is generated properly.
-TEST_F(Dhcpv6SrvTest, StatusCode) {
-    NakedDhcpv6Srv srv(0);
-
-    // a dummy content for client-id
-    uint8_t expected[] = {
-        0x0, 0xD, // option code = 13
-        0x0, 0x7, // option length = 7
-        0x0, 0x3, // status code = 3
-        0x41, 0x42, 0x43, 0x44, 0x45 // string value ABCDE
-    };
-    // Create the option.
-    OptionPtr status = srv.createStatusCode(3, "ABCDE");
-    // Allocate an output buffer. We will store the option
-    // in wire format here.
-    OutputBuffer buf(sizeof(expected));
-    // Prepare the wire format.
-    ASSERT_NO_THROW(status->pack(buf));
-    // Check that the option buffer has valid length (option header + data).
-    ASSERT_EQ(sizeof(expected), buf.getLength());
-    // Verify the contents of the option.
-    EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
-}
-
 // This test verifies if the sanityCheck() really checks options presence.
 TEST_F(Dhcpv6SrvTest, sanityCheck) {
     NakedDhcpv6Srv srv(0);

+ 4 - 3
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -14,6 +14,7 @@
 
 #include <config.h>
 #include <gtest/gtest.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/json_config_parser.h>
 #include <config/ccsession.h>
@@ -829,8 +830,8 @@ NakedDhcpv6SrvTest::checkIA_NAStatusCode(
     EXPECT_EQ(expected_t1, ia->getT1());
     EXPECT_EQ(expected_t2, ia->getT2());
 
-    isc::dhcp::OptionCustomPtr status =
-        boost::dynamic_pointer_cast<isc::dhcp::OptionCustom>
+    isc::dhcp::Option6StatusCodePtr status =
+        boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
         (ia->getOption(D6O_STATUS_CODE));
 
     // It is ok to not include status success as this is the default
@@ -847,7 +848,7 @@ NakedDhcpv6SrvTest::checkIA_NAStatusCode(
         // status code option content is just a text explanation
         // what went wrong.
         EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
-                  status->readInteger<uint16_t>(0));
+                  status->getStatusCode());
     }
 }
 

+ 4 - 4
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -25,6 +25,7 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaprefix.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option.h>
@@ -101,7 +102,6 @@ public:
     using Dhcpv6Srv::processClientFqdn;
     using Dhcpv6Srv::createNameChangeRequests;
     using Dhcpv6Srv::createRemovalNameChangeRequest;
-    using Dhcpv6Srv::createStatusCode;
     using Dhcpv6Srv::selectSubnet;
     using Dhcpv6Srv::testServerID;
     using Dhcpv6Srv::testUnicast;
@@ -256,8 +256,8 @@ public:
     void checkMsgStatusCode(const isc::dhcp::Pkt6Ptr& msg,
                             uint16_t expected_status)
     {
-        isc::dhcp::OptionCustomPtr status =
-            boost::dynamic_pointer_cast<isc::dhcp::OptionCustom>
+        isc::dhcp::Option6StatusCodePtr status =
+            boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
                 (msg->getOption(D6O_STATUS_CODE));
 
         // It is ok to not include status success as this is the default
@@ -273,7 +273,7 @@ public:
             // status code option content is just a text explanation
             // what went wrong.
             EXPECT_EQ(static_cast<uint16_t>(expected_status),
-                      status->readInteger<uint16_t>(0));
+                      status->getStatusCode());
         }
     }
 

+ 15 - 15
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -22,6 +22,7 @@
 #include <dhcp/option6_client_fqdn.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp/option_int_array.h>
 #include <dhcpsrv/lease.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
@@ -256,16 +257,9 @@ public:
     /// Status Code option.
     ///
     /// @return An object representing the Status Code option.
-    OptionCustomPtr createStatusCode(const uint16_t code,
+    Option6StatusCodePtr createStatusCode(const uint16_t code,
                                      const std::string& msg) {
-        OptionDefinition def("status-code", D6O_STATUS_CODE, "record");
-        def.addRecordField("uint16");
-        def.addRecordField("string");
-        OptionCustomPtr opt_status(new OptionCustom(def, Option::V6));
-        opt_status->writeInteger(code);
-        if (!msg.empty()) {
-            opt_status->writeString(msg, 1);
-        }
+        Option6StatusCodePtr opt_status(new Option6StatusCode(code, msg));
         return (opt_status);
     }
 
@@ -731,7 +725,8 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
     // as if we typed domain-name in lower case.
     lease_->hostname_ = "MYHOST.example.com.";
 
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 
     ASSERT_EQ(1, d2_mgr_.getQueueSize());
     verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
@@ -756,7 +751,8 @@ TEST_F(FqdnDhcpv6SrvTest, noRemovalsWhenDisabled) {
     lease_->hostname_ = "MYHOST.example.com.";
 
     // When DDNS is disabled an attempt to send a request will throw.
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 }
 
 
@@ -767,7 +763,8 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
     lease_->fqdn_rev_ = true;
     lease_->hostname_ = "myhost.example.com.";
 
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 
     ASSERT_EQ(1, d2_mgr_.getQueueSize());
 
@@ -785,7 +782,8 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoUpdate) {
     lease_->fqdn_fwd_ = false;
     lease_->fqdn_rev_ = false;
 
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 
     ASSERT_EQ(0, d2_mgr_.getQueueSize());
 
@@ -798,7 +796,8 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoHostname) {
     lease_->fqdn_rev_ = true;
     lease_->hostname_ = "";
 
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 
     ASSERT_EQ(0, d2_mgr_.getQueueSize());
 
@@ -812,7 +811,8 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestWrongHostname) {
     lease_->fqdn_rev_ = true;
     lease_->hostname_ = "myhost..example.com.";
 
-    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(lease_));
+    Pkt6Ptr pkt(new Pkt6(DHCPREQUEST, 1234));
+    ASSERT_NO_THROW(srv_->createRemovalNameChangeRequest(pkt, lease_));
 
     ASSERT_EQ(0, d2_mgr_.getQueueSize());
 

+ 1 - 0
src/lib/dhcp/Makefile.am

@@ -32,6 +32,7 @@ libkea_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
 libkea_dhcp___la_SOURCES += option6_iaprefix.cc option6_iaprefix.h
 libkea_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
 libkea_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h
+libkea_dhcp___la_SOURCES += option6_status_code.cc option6_status_code.h
 libkea_dhcp___la_SOURCES += option_vendor.cc option_vendor.h
 libkea_dhcp___la_SOURCES += option_vendor_class.cc option_vendor_class.h
 libkea_dhcp___la_SOURCES += option_int.h

+ 144 - 0
src/lib/dhcp/option6_status_code.cc

@@ -0,0 +1,144 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/option6_status_code.h>
+#include <util/io_utilities.h>
+#include <iterator>
+#include <sstream>
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+/// @brief Minimum length of the option (when status message is empty).
+const size_t OPTION6_STATUS_CODE_MIN_LEN = sizeof(uint16_t);
+
+}; // end of anonymous namespace
+
+namespace isc {
+namespace dhcp {
+
+Option6StatusCode::Option6StatusCode(const uint16_t status_code,
+                                     const std::string& status_message)
+    : Option(Option::V6, D6O_STATUS_CODE),
+      status_code_(status_code), status_message_(status_message) {
+}
+
+Option6StatusCode::Option6StatusCode(OptionBufferConstIter begin,
+                                     OptionBufferConstIter end)
+    : Option(Option::V6, D6O_STATUS_CODE),
+      status_code_(STATUS_Success), status_message_() {
+
+    // Parse data 
+    unpack(begin, end);
+}
+
+void
+Option6StatusCode::pack(isc::util::OutputBuffer& buf) {
+    // Pack option header.
+    packHeader(buf);
+    // Write numeric status code.
+    buf.writeUint16(getStatusCode());
+    // If there is any status message, write it.
+    if (!status_message_.empty()) {
+        buf.writeData(&status_message_[0], status_message_.size());
+    }
+
+    // Status code has no options, so leave here.
+}
+
+void
+Option6StatusCode::unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+    // Make sure that the option is not truncated.
+    if (std::distance(begin, end) < OPTION6_STATUS_CODE_MIN_LEN) {
+        isc_throw(OutOfRange, "Status Code option ("
+                  << D6O_STATUS_CODE << ") truncated");
+    }
+
+    status_code_ = util::readUint16(&(*begin), std::distance(begin, end));
+    begin += sizeof(uint16_t);
+
+    status_message_.assign(begin, end);
+}
+
+uint16_t
+Option6StatusCode::len() {
+    return (getHeaderLen() + sizeof(uint16_t) + status_message_.size());
+}
+
+std::string
+Option6StatusCode::toText(int indent) {
+    std::ostringstream output;
+    output << headerToText(indent) << ": "
+        << getStatusCodeName() << "(" << getStatusCode() << ") "
+        << dataToText();
+
+    return (output.str());
+}
+
+std::string
+Option6StatusCode::dataToText() const {
+    std::ostringstream output;
+    // Add status code name and numeric status code.
+    output << getStatusCodeName() << "(" << getStatusCode() << ") ";
+
+    // Include status message in quotes if status code is
+    // non-empty.
+    if (!status_message_.empty()) {
+        output << "\"" << status_message_ << "\"";
+
+    } else {
+        output << "(no status message)";
+    }
+
+    return (output.str());
+}
+
+std::string
+Option6StatusCode::getStatusCodeName() const {
+    switch (getStatusCode()) {
+    case STATUS_Success:
+        return ("Success");
+    case STATUS_UnspecFail:
+        return ("UnspecFail");
+    case STATUS_NoAddrsAvail:
+        return ("NoAddrsAvail");
+    case STATUS_NoBinding:
+        return ("NoBinding");
+    case STATUS_NotOnLink:
+        return ("NotOnLink");
+    case STATUS_UseMulticast:
+        return ("UseMulticast");
+    case STATUS_NoPrefixAvail:
+        return ("NoPrefixAvail");
+    case STATUS_UnknownQueryType:
+        return ("UnknownQueryType");
+    case STATUS_MalformedQuery:
+        return ("MalformedQuery");
+    case STATUS_NotConfigured:
+        return ("NotConfigured");
+    case STATUS_NotAllowed:
+        return ("NotAllowed");
+    default:
+        ;
+    }
+    return ("(unknown status code)");
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc

+ 118 - 0
src/lib/dhcp/option6_status_code.h

@@ -0,0 +1,118 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef OPTION6_STATUS_CODE_H
+#define OPTION6_STATUS_CODE_H
+
+#include <dhcp/option.h>
+#include <boost/shared_ptr.hpp>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+class Option6StatusCode;
+
+/// @brief Pointer to the @c isc::dhcp::Option6StatusCode.
+typedef boost::shared_ptr<Option6StatusCode> Option6StatusCodePtr;
+
+/// @brief This class represents Status Code option (13) from RFC3315.
+class Option6StatusCode: public Option {
+public:
+    /// @brief Constructor, used for options constructed (during transmission).
+    ///
+    /// @param status_code Numeric status code, e.g. STATUS_NoAddrsAvail.
+    /// @param status_message Textual message for the statuscode.
+    Option6StatusCode(const uint16_t status_code, const std::string& status_message);
+
+    /// @brief Constructor, used for received options.
+    ///
+    /// @throw OutOfRange if specified option is truncated
+    ///
+    /// @param begin Iterator to first byte of option data
+    /// @param end Iterator to end of option data (first byte after option end).
+    Option6StatusCode(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+    /// @brief Writes option in wire-format.
+    ///
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf Pointer to the output buffer.
+    virtual void pack(isc::util::OutputBuffer& buf);
+
+    /// @brief Parses received buffer.
+    ///
+    /// @param begin Iterator to first byte of option data
+    /// @param end Iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+    /// @brief Returns total length of the option.
+    ///
+    /// The returned length is a sum of the option header and data fields.
+    virtual uint16_t len();
+
+    /// @brief Returns textual representation of the option.
+    ///
+    /// @param indent Number of spaces before printing text.
+    virtual std::string toText(int indent = 0);
+
+    /// @brief Returns textual representation of the option data.
+    ///
+    /// This method returns only the status code and the status
+    /// message. It excludes the option header.
+    std::string dataToText() const;
+
+    /// @brief Returns numeric status code.
+    uint16_t getStatusCode() const {
+        return (status_code_);        
+    }
+
+    /// @brief Returns the name of the status code.
+    std::string getStatusCodeName() const;
+
+    /// @brief Sets new numeric status code.
+    ///
+    /// @param status_code New numeric status code.
+    void setStatusCode(const uint16_t status_code) {
+        status_code_ = status_code;
+    }
+
+    /// @brief Returns status message.
+    const std::string& getStatusMessage() const {
+        return (status_message_);
+    }
+
+    /// @brief Sets new status message.
+    ///
+    /// @param status_message New status message (empty string is allowed).
+    void setStatusMessage(const std::string& status_message) {
+        status_message_ = status_message;
+    }
+
+private:
+
+    /// @brief Numeric status code.
+    uint16_t status_code_;
+
+    /// @brief Textual message.
+    std::string status_message_;
+
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif // OPTION6_STATUS_CODE_H

+ 12 - 0
src/lib/dhcp/option_definition.cc

@@ -22,6 +22,7 @@
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaprefix.h>
 #include <dhcp/option6_client_fqdn.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_definition.h>
 #include <dhcp/option_int.h>
@@ -428,6 +429,14 @@ OptionDefinition::haveVendorClass6Format() const {
 }
 
 bool
+OptionDefinition::haveStatusCodeFormat() const {
+    return (haveType(OPT_RECORD_TYPE) &&
+            (record_fields_.size() == 2) &&
+            (record_fields_[0] == OPT_UINT16_TYPE) &&
+            (record_fields_[1] == OPT_STRING_TYPE));
+}
+
+bool
 OptionDefinition::convertToBool(const std::string& value_str) const {
     // Case insensitve check that the input is one of: "true" or "false".
     if (boost::iequals(value_str, "true")) {
@@ -684,6 +693,9 @@ OptionDefinition::factorySpecialFormatOption(Option::Universe u,
         } else if (getCode() == D6O_VENDOR_CLASS && haveVendorClass6Format()) {
             // Vendor Class (option code 16).
             return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
+        } else if (getCode() == D6O_STATUS_CODE && haveStatusCodeFormat()) {
+            // Status Code (option code 13)
+            return (OptionPtr(new Option6StatusCode(begin, end)));
         }
     } else {
         if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {

+ 6 - 1
src/lib/dhcp/option_definition.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -365,6 +365,11 @@ public:
     /// @return true if option has the format of DHCPv6 Vendor Class option.
     bool haveVendorClass6Format() const;
 
+    /// @brief Check if the option has format of DHCPv6 Status Code option.
+    ///
+    /// @return true if option has the format of DHCPv6 Status code option.
+    bool haveStatusCodeFormat() const;
+
     /// @brief Option factory.
     ///
     /// This function creates an instance of DHCP option using

+ 1 - 0
src/lib/dhcp/tests/Makefile.am

@@ -59,6 +59,7 @@ libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc
 libdhcp___unittests_SOURCES += option6_ia_unittest.cc
 libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
 libdhcp___unittests_SOURCES += option6_iaprefix_unittest.cc
+libdhcp___unittests_SOURCES += option6_status_code_unittest.cc
 libdhcp___unittests_SOURCES += option_int_unittest.cc
 libdhcp___unittests_SOURCES += option_int_array_unittest.cc
 libdhcp___unittests_SOURCES += option_data_types_unittest.cc

+ 3 - 2
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,7 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaprefix.h>
+#include <dhcp/option6_status_code.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
@@ -1026,7 +1027,7 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
                                     typeid(Option));
 
     LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, begin, end,
-                                    typeid(OptionCustom));
+                                    typeid(Option6StatusCode));
 
     LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, begin, end,
                                     typeid(Option));

+ 177 - 0
src/lib/dhcp/tests/option6_status_code_unittest.cc

@@ -0,0 +1,177 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_status_code.h>
+#include <gtest/gtest.h>
+#include <cstring>
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+// This test verifies that the option can be created and that the
+// accessor methods return correct values used for the object
+// construction.
+TEST(Option6StatusCodeTest, accessors) {
+    Option6StatusCode status1(STATUS_NoAddrsAvail, "Sorry, NoAddrsAvail");
+    EXPECT_EQ(STATUS_NoAddrsAvail, status1.getStatusCode());
+    EXPECT_EQ("Sorry, NoAddrsAvail", status1.getStatusMessage());
+
+    Option6StatusCode status2(STATUS_NoBinding, "There is NoBinding");
+    EXPECT_EQ(STATUS_NoBinding, status2.getStatusCode());
+    EXPECT_EQ("There is NoBinding", status2.getStatusMessage());
+}
+
+// This test verifies that the status code and status message may
+// be modified.
+TEST(Option6StatusCodeTest, modifiers) {
+    Option6StatusCode status(STATUS_NoAddrsAvail, "Sorry, NoAddrsAvail");
+    ASSERT_EQ(STATUS_NoAddrsAvail, status.getStatusCode());
+    ASSERT_EQ("Sorry, NoAddrsAvail", status.getStatusMessage());
+
+    ASSERT_NO_THROW(status.setStatusCode(STATUS_Success));
+    ASSERT_NO_THROW(status.setStatusMessage("Success"));
+
+    EXPECT_EQ(STATUS_Success, status.getStatusCode());
+    EXPECT_EQ("Success", status.getStatusMessage());
+}
+
+// This test verifies that the option returns its length correctly.
+TEST(Option6StatusCodeTest, length) {
+    Option6StatusCode status(STATUS_Success, "");
+    EXPECT_EQ(6, status.len());
+
+    ASSERT_NO_THROW(status.setStatusMessage("non-empty message"));
+    EXPECT_EQ(23, status.len());
+}
+
+// This test verifies that the option can be encoded into the wire
+// format.
+TEST(Option6StatusCodeTest, pack) {
+    Option6StatusCode status(STATUS_NoBinding, "text");
+    util::OutputBuffer buf(10);
+    ASSERT_NO_THROW(status.pack(buf));
+
+    const uint8_t ref[] = {
+        0, 13, // Option code is 13
+        0, 6,  // Length is 6
+        0, 3,  // NoBinding
+        't', 'e', 'x', 't'
+    };
+
+    ASSERT_EQ(sizeof(ref), buf.getLength());
+    const void* packed = buf.getData();
+    EXPECT_EQ(0, memcmp(static_cast<const void*>(ref), packed, sizeof(ref)));
+}
+
+// This test verifies that the option can be encoded into the
+// wire format when the status message is empty.
+TEST(Option6StatusCodeTest, packEmptyStatusMessage) {
+    Option6StatusCode status(STATUS_NoAddrsAvail, "");
+    util::OutputBuffer buf(10);
+    ASSERT_NO_THROW(status.pack(buf));
+
+    const uint8_t ref[] = {
+        0, 13, // Option code is 13
+        0, 2,  // Length is 2
+        0, 2,  // NoAddrsAvail
+    };
+
+    ASSERT_EQ(sizeof(ref), buf.getLength());
+    const void* packed = buf.getData();
+    EXPECT_EQ(0, memcmp(static_cast<const void*>(ref), packed, sizeof(ref)));
+}
+
+
+// This test verifies that the option can be parsed from the wire
+// format.
+TEST(Option6StatusCodeTest, unpack) {
+    const uint8_t wire_data[] = {
+        0, 1,          // status code = UnspecFail
+        'x', 'y', 'z', // short text: xyz
+    };
+    OptionBuffer buf(wire_data, wire_data + sizeof(wire_data));
+
+    // Create option from buffer.
+    Option6StatusCodePtr status;
+    ASSERT_NO_THROW(status.reset(new Option6StatusCode(buf.begin(), buf.end())));
+
+    // Verify that the data was parsed correctly.
+    EXPECT_EQ(STATUS_UnspecFail, status->getStatusCode());
+    EXPECT_EQ("xyz", status->getStatusMessage());
+
+    // Remove the status message and leave only the status code.
+    buf.resize(2);
+    // Modify the status code.
+    buf[1] = 0;
+
+    ASSERT_NO_THROW(status.reset(new Option6StatusCode(buf.begin(), buf.end())));
+    EXPECT_EQ(STATUS_Success, status->getStatusCode());
+    EXPECT_TRUE(status->getStatusMessage().empty());
+}
+
+// This test verifies that the option data can be presented
+// in the textual form.
+TEST(Option6StatusCodeTest, dataToText) {
+    Option6StatusCode status(STATUS_NoBinding, "Sorry, no binding");
+    EXPECT_EQ("NoBinding(3) \"Sorry, no binding\"",
+              status.dataToText());
+}
+
+// This test verifies that the option can be presented in the
+// textual form.
+TEST(Option6StatusCodeTest, toText) {
+    Option6StatusCode status(STATUS_NoAddrsAvail, "Sorry, no address");
+    EXPECT_EQ("type=00013, len=00019: NoAddrsAvail(2) \"Sorry, no address\"",
+              status.toText());
+
+    Option6StatusCode status_empty(STATUS_NoBinding, "");
+    EXPECT_EQ("type=00013, len=00002: NoBinding(3) (no status message)",
+              status_empty.toText());
+}
+
+
+/// @brief Test that the status code name is returned correctly.
+///
+/// @param expected_name Expected name.
+/// @param status_code Status code for which test is performed.
+void testStatusName(const std::string& expected_name,
+                    const uint16_t status_code) {
+    Option6StatusCode status(status_code, "some text");
+    EXPECT_EQ(expected_name, status.getStatusCodeName());
+}
+
+// This test verifies that the status code name is
+// returned correctly.
+TEST(Option6StatusCodeTest, getStatusCodeName) {
+    testStatusName("Success", STATUS_Success);
+    testStatusName("UnspecFail", STATUS_UnspecFail);
+    testStatusName("NoAddrsAvail", STATUS_NoAddrsAvail);
+    testStatusName("NoBinding", STATUS_NoBinding);
+    testStatusName("NotOnLink", STATUS_NotOnLink);
+    testStatusName("UseMulticast", STATUS_UseMulticast);
+    testStatusName("NoPrefixAvail", STATUS_NoPrefixAvail);
+    testStatusName("UnknownQueryType", STATUS_UnknownQueryType);
+    testStatusName("MalformedQuery", STATUS_MalformedQuery);
+    testStatusName("NotConfigured", STATUS_NotConfigured);
+    testStatusName("NotAllowed", STATUS_NotAllowed);
+    testStatusName("(unknown status code)", 1234);
+}
+
+} // anonymous namespace