WIP: Refactor DHCP

https://github.com/trema/pio/issues/60#issuecomment-39295599

で頂いたコメントで作成しました。
※`Dhcp::Message`と`Dhcp::Discover`がほぼ同じですので、rakeした時に失敗します。

頂いたコメントの意図を外していましたら、何卒ご指摘ください。
宜しくお願いします。

====
はじめから書き直すことにしました。（2014/06/19）
更新ごとにつらつらと書いていきます。
@yasuhito 何かありましたら追記をお願いします。
## 方針：
- 既存のコードやＡＰＩは流用する（可能な限り）
- 基本的なメッセージタイプはすべて網羅する
  - ACK
  - NACK
  - OFFER
  - DISCOVER
  - REQUEST
  - INFORM
  - RELEASE
- クラスの追加
  - RequestRelay
  - ReplyRelay
  - INFORM
  - RELEASE
  - NACK
  - OFFER
- メソッドの追加
  - Router
  - DNS
  - Hostname
  - Vendor Class Id
- 質問系メソッドの追加
  - boot_request?/ boot_reply?
  - ack?/offer?/nack?/discover?/request?/release?/decline?/inform?
- オプショナル・義務的フィールドの明確化
- RFC2131(http://srgia.com/docs/rfc2131j.html)   に準拠する（できるだけ）  
- RFC2132(http://tools.ietf.org/html/rfc2132)  に基づく値のチェック
  - もし与えられたオプション値がこれに従っていない場合はraise等する。（厳密化）
- 定数の排除（できるだけユーザに不用意に定数など見せたくない）
- 数値はすべてhex値に修正。

## Pio::Dhcp 新仕様
### クライアントメッセージオプション対応表

|Option|Discover|Request|Inform|Release|Decline|
|---------|---------|---------|---------|---------|---------| 
|destination_mac|TBD|TBD|TBD|TBD|TBD|
|source_mac|TBD|TBD|TBD|TBD|TBD|
|ether_type|TBD|TBD|TBD|TBD|TBD|
|ip_version|TBD|TBD|TBD|TBD|TBD|
|ip_header_length|TBD|TBD|TBD|TBD|TBD|
|ip_type_of_service|TBD|TBD|TBD|TBD|TBD|
|ip_total_length|TBD|TBD|TBD|TBD|TBD|
|ip_identifier|TBD|TBD|TBD|TBD|TBD|
|ip_flag|TBD|TBD|TBD|TBD|TBD|
|ip_fragment|TBD|TBD|TBD|TBD|TBD|
|ip_ttl|TBD|TBD|TBD|TBD|TBD|
|ip_protocol|TBD|TBD|TBD|TBD|TBD|
|ip_header_checksum|TBD|TBD|TBD|TBD|TBD|
|ip_source_address|TBD|TBD|TBD|TBD|TBD|
|ip_destination_address|TBD|TBD|TBD|TBD|TBD|
|udp_src_port|TBD|TBD|TBD|TBD|TBD|
|udp_dst_port|TBD|TBD|TBD|TBD|TBD|
|udp_length|TBD|TBD|TBD|TBD|TBD|
|udp_checksum|TBD|TBD|TBD|TBD|TBD|
|boot_message_type|TBD|TBD|TBD|TBD|TBD|
|message_type|TBD|TBD|TBD|TBD|TBD|
|hw_addr_type|TBD|TBD|TBD|TBD|TBD|
|hw_addr_len|TBD|TBD|TBD|TBD|TBD|
|hops|TBD|TBD|TBD|TBD|TBD|
|transaction_id|TBD|TBD|TBD|TBD|TBD|
|seconds|TBD|TBD|TBD|TBD|TBD|
|bootp_flags|TBD|TBD|TBD|TBD|TBD|
|client_ip_address|TBD|TBD|TBD|TBD|TBD|
|your_ip_address|TBD|TBD|TBD|TBD|TBD|
|next_server_ip_address|TBD|TBD|TBD|TBD|TBD|
|relay_agent_ip_address|TBD|TBD|TBD|TBD|TBD|
|client_mac_address|TBD|TBD|TBD|TBD|TBD|
|server_host_name|TBD|TBD|TBD|TBD|TBD|
|boot_file_name|TBD|TBD|TBD|TBD|TBD|
|server_identifier|TBD|TBD|TBD|TBD|TBD|
|renewal_time_value|TBD|TBD|TBD|TBD|TBD|
|rebinding_time_value|TBD|TBD|TBD|TBD|TBD|
|ip_address_lease_time|TBD|TBD|TBD|TBD|TBD|
|client_identifier|TBD|TBD|TBD|TBD|TBD|
|requested_ip_address|TBD|TBD|TBD|TBD|TBD|
|parameters_list|TBD|TBD|TBD|TBD|TBD|

### サーバメッセージオプション対応表

|Option|Offer|Ack|Nack|
|---------|---------|---------|---------|
|destination_mac|TBD|TBD|TBD|
|source_mac|TBD|TBD|TBD|
|ether_type|TBD|TBD|TBD|
|ip_version|TBD|TBD|TBD|
|ip_header_length|TBD|TBD|TBD|
|ip_type_of_service|TBD|TBD|TBD|
|ip_total_length|TBD|TBD|TBD|
|ip_identifier|TBD|TBD|TBD|
|ip_flag|TBD|TBD|TBD|
|ip_fragment|TBD|TBD|TBD|
|ip_ttl|TBD|TBD|TBD|
|ip_protocol|TBD|TBD|TBD|
|ip_header_checksum|TBD|TBD|TBD|
|ip_source_address|TBD|TBD|TBD|
|ip_destination_address|TBD|TBD|TBD|
|udp_src_port|TBD|TBD|TBD|
|udp_dst_port|TBD|TBD|TBD|
|udp_length|TBD|TBD|TBD|
|udp_checksum|TBD|TBD|TBD|
|boot_message_type|TBD|TBD|TBD|
|message_type|TBD|TBD|TBD|
|hw_addr_type|TBD|TBD|TBD|
|hw_addr_len|TBD|TBD|TBD|
|hops|TBD|TBD|TBD|
|transaction_id|TBD|TBD|TBD|
|seconds|TBD|TBD|TBD|
|bootp_flags|TBD|TBD|TBD|
|client_ip_address|TBD|TBD|TBD|
|your_ip_address|TBD|TBD|TBD|
|next_server_ip_address|TBD|TBD|TBD|
|relay_agent_ip_address|TBD|TBD|TBD|
|client_mac_address|TBD|TBD|TBD|
|server_host_name|TBD|TBD|TBD|
|boot_file_name|TBD|TBD|TBD|
|server_identifier|TBD|TBD|TBD|
|renewal_time_value|TBD|TBD|TBD|
|rebinding_time_value|TBD|TBD|TBD|
|ip_address_lease_time|TBD|TBD|TBD|
|subnet_mask|TBD|TBD|TBD|

### クライアントメッセージのブロードキャストとユニキャストの使用
- ユニキャスト：
  - DHCP サーバーのアドレスを知っている場合、クライアントは DHCPDISCOVER や DHCPREQUEST で IP ブロードキャストアドレスではなく、そのユニキャストアドレスを使用しても良い。
  - クライアントはサーバーに DHCPRELEASE メッセージをユニキャストする
  - 既知の DHCP サーバーに DHCPINFORM メッセージを送信する場合にも、クライアントはユニキャストを使用しても良い。

- ブロードキャスト：
  - DHCPサーバのアドレスを知らない限り、ＤＨＣＰクライアントは、DHCPDISCOVER、DHCPREQUEST、DHCPINRFORM の各メッセージをブロードキャストする
  - クライアントがサーバーによって提供された IP アドレスを使用を拒否するなら、クライアントは DHCPDECLINE メッセージをブロードキャストする。 

### サーバーメッセージの振る舞いについて

## 変更点：  

## 既存の指摘点の対応について：  
- https://github.com/trema/pio/pull/65#issuecomment-40326078
についての対応

## 質問事項
- message.rbとかで書いている、`def_delegators`が`packet_in`が提供するメソッドとかぶっています。必要ですか？

- テスト方針について：これまでジェネレータが出したフレームでテストを書くことがありましたが、今回は実際にスニファしたデータをベースにテストを作成したいと考えています。そのため、テストコードからはどのオプションがmandatoryかoptionalかわからなくなるかもしれませんが、その辺ドキュメントすればいいかなと思います。また、そういった場合、最小限・最大のオプションそれぞれのテストをどうしようか、言ったところはありますが、ご意見・ご指摘お願いします。


- dhcpのtlvデータを読み込むためのメソッドを自動生成などして、行数をうまいこと減らしたいです
````ruby
      def message_type
        get_tlv_field(Dhcp::MESSAGE_TYPE_TLV)
      end

      def server_identifier
        get_tlv_field(Dhcp::SERVER_IDENTIFIER_TLV)
      end

      def client_identifier
        get_tlv_field(Dhcp::CLIENT_IDENTIFIER_TLV)
      end
````
これが今後要望などあると、追加するためのメソッドとともに増えてくるので、
行数と修正にかかる時間、デグレーションを減らしたい考えです。いい方法などあれば教えてください。