option.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <string.h>
  15. #include <stdint.h>
  16. #include <arpa/inet.h>
  17. #include <sstream>
  18. #include <iomanip>
  19. #include <boost/shared_array.hpp>
  20. #include "exceptions/exceptions.h"
  21. #include "option.h"
  22. #include "libdhcp.h"
  23. using namespace std;
  24. using namespace isc::dhcp;
  25. Option::Option(Universe u, unsigned short type)
  26. :universe_(u), type_(type) {
  27. }
  28. Option::Option(Universe u, unsigned short type, boost::shared_array<char> buf,
  29. unsigned int offset, unsigned int len)
  30. :universe_(u), type_(type), data_(buf),
  31. data_len_(len), offset_(offset)
  32. {
  33. // sanity checks
  34. // TODO: universe must be in V4 and V6
  35. }
  36. unsigned int
  37. Option::pack(boost::shared_array<char> buf,
  38. unsigned int buf_len,
  39. unsigned int offset) {
  40. switch (universe_) {
  41. case V4:
  42. return pack4(buf, buf_len, offset);
  43. case V6:
  44. return pack6(buf, buf_len, offset);
  45. default:
  46. isc_throw(BadValue, "Unknown universe defined for Option " << type_);
  47. }
  48. }
  49. unsigned int
  50. Option::pack4(boost::shared_array<char> buf,
  51. unsigned int buf_len,
  52. unsigned int offset) {
  53. if ( offset+len() > buf_len ) {
  54. isc_throw(OutOfRange, "Failed to pack v4 option=" <<
  55. type_ << ",len=" << data_len_ << ": too small buffer.");
  56. }
  57. char *ptr = &buf[offset];
  58. ptr[0] = type_;
  59. ptr[1] = data_len_;
  60. ptr += 2;
  61. memcpy(ptr, &data_[0], data_len_+4);
  62. return offset + len();
  63. }
  64. unsigned int
  65. Option::pack6(boost::shared_array<char> buf,
  66. unsigned int buf_len,
  67. unsigned int offset) {
  68. if ( offset+len() > buf_len ) {
  69. isc_throw(OutOfRange, "Failed to pack v6 option=" <<
  70. type_ << ",len=" << len() << ": too small buffer.");
  71. }
  72. char * ptr = &buf[offset];
  73. *(uint16_t*)ptr = htons(type_);
  74. ptr += 2;
  75. *(uint16_t*)ptr = htons(data_len_);
  76. ptr += 2;
  77. memcpy(ptr, &data_[offset_], data_len_);
  78. return offset + len();
  79. }
  80. unsigned int
  81. Option::unpack(boost::shared_array<char> buf,
  82. unsigned int buf_len,
  83. unsigned int offset,
  84. unsigned int parse_len) {
  85. switch (universe_) {
  86. case V4:
  87. return unpack4(buf, buf_len, offset, parse_len);
  88. case V6:
  89. return unpack6(buf, buf_len, offset, parse_len);
  90. default:
  91. isc_throw(BadValue, "Unknown universe defined for Option " << type_);
  92. }
  93. return 0; // should not happen
  94. }
  95. unsigned int
  96. Option::unpack4(boost::shared_array<char>,
  97. unsigned int ,
  98. unsigned int ,
  99. unsigned int ) {
  100. isc_throw(Unexpected, "IPv4 support not implemented yet.");
  101. return 0;
  102. }
  103. unsigned int
  104. Option::unpack6(boost::shared_array<char> buf,
  105. unsigned int buf_len,
  106. unsigned int offset,
  107. unsigned int parse_len) {
  108. if (buf_len < offset+parse_len) {
  109. isc_throw(OutOfRange, "Failed to unpack DHCPv6 option len="
  110. << parse_len << " offset=" << offset << " from buffer (length="
  111. << buf_len << "): too small buffer.");
  112. }
  113. data_ = buf;
  114. offset_ = offset;
  115. data_len_ = buf_len;
  116. return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
  117. optionLst_);
  118. }
  119. unsigned short Option::len() {
  120. switch (universe_) {
  121. case V4:
  122. return data_len_ + 2; // DHCPv4 option header length: 2 bytes
  123. case V6:
  124. return data_len_ + 4; // DHCPv6 option header length: 4 bytes
  125. default:
  126. isc_throw(BadValue, "Unknown universe defined for Option " << type_);
  127. }
  128. return 0; // should not happen
  129. }
  130. bool Option::valid() {
  131. // total length of buffer is not stored. shared_array is not very useful.
  132. // we should either add buf_len field or better replace shared_array
  133. // with shared_ptr to array
  134. if (universe_ != V4 &&
  135. universe_ != V6) {
  136. return (false);
  137. }
  138. return (true);
  139. }
  140. void
  141. isc::dhcp::Option::addOption(boost::shared_ptr<isc::dhcp::Option> opt) {
  142. optionLst_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
  143. }
  144. std::string Option::toText() {
  145. std::stringstream tmp;
  146. tmp << type_ << "(len=" << data_len_ << "):";
  147. for (unsigned int i=0; i<data_len_; i++) {
  148. if (i) {
  149. tmp << ":";
  150. }
  151. tmp << setfill('0') << setw(2) << hex << (unsigned short)(unsigned char)data_[offset_+i];
  152. }
  153. return tmp.str();
  154. }
  155. unsigned short
  156. Option::getType() {
  157. return type_;
  158. }
  159. Option::~Option() {
  160. }