blob: adda08850a3eaed46d44bf4404df3761f84e3cd2 [file] [log] [blame]
Yi Tsengc7403c22017-06-19 16:23:22 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tsengc7403c22017-06-19 16:23:22 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onlab.packet.dhcp;
18
19import com.google.common.collect.Maps;
20import org.onlab.packet.DeserializationException;
21import org.onlab.packet.Deserializer;
22import org.onlab.packet.IPacket;
23import org.slf4j.Logger;
24
25import java.nio.ByteBuffer;
26import java.util.Map;
27import java.util.Objects;
28
29import static org.slf4j.LoggerFactory.getLogger;
30
31/**
32 * Representation of DHCP relay agent option (option 82).
33 */
34public class DhcpRelayAgentOption extends DhcpOption {
35 private static final int SUB_OPT_DEFAULT_LEN = 2;
36 private final Logger log = getLogger(getClass());
37 private final Map<Byte, DhcpOption> subOptions = Maps.newHashMap();
38
39 // Sub-option codes for option 82
40 public enum RelayAgentInfoOptions {
41 CIRCUIT_ID((byte) 1),
42 REMOTE_ID((byte) 2),
43 DOCSIS((byte) 4),
44 LINK_SELECTION((byte) 5),
45 SUBSCRIBER_ID((byte) 6),
46 RADIUS((byte) 7),
47 AUTH((byte) 8),
48 VENDOR_SPECIFIC((byte) 9),
49 RELAY_AGENT_FLAGS((byte) 10),
50 SERVER_ID_OVERRIDE((byte) 11),
51 VIRTUAL_SUBNET_SELECTION((byte) 151),
52 VIRTUAL_SUBNET_SELECTION_CTRL((byte) 152);
53
54 private byte value;
55 public byte getValue() {
56 return value;
57 }
58 RelayAgentInfoOptions(byte value) {
59 this.value = value;
60 }
61 }
62
63 @Override
64 public byte[] serialize() {
65 int totalLen = 0;
66 totalLen += subOptions.size() * SUB_OPT_DEFAULT_LEN;
67 totalLen += subOptions.values().stream().mapToInt(DhcpOption::getLength).sum();
68 totalLen += DEFAULT_LEN;
69 ByteBuffer byteBuffer = ByteBuffer.allocate(totalLen);
70 byteBuffer.put(code);
71 byteBuffer.put(length);
72 subOptions.values().forEach(subOpt -> {
73 byteBuffer.put(subOpt.code);
74 byteBuffer.put(subOpt.length);
75 byteBuffer.put(subOpt.data);
76 });
77 return byteBuffer.array();
78 }
79
80 @Override
81 public IPacket deserialize(byte[] data, int offset, int length) {
82 try {
83 return deserializer().deserialize(data, offset, length);
84 } catch (DeserializationException e) {
85 log.warn("can't deserialize DHCP relay agent information option {}", e);
86 return null;
87 }
88 }
89
90 /**
91 * Deserializer function for DHCP relay agent option.
92 *
93 * @return deserializer function
94 */
95 public static Deserializer<DhcpOption> deserializer() {
96 return (data, offset, length) -> {
97 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
98 ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, length);
99 relayOption.code = byteBuffer.get();
100 relayOption.length = byteBuffer.get();
101
102 while (byteBuffer.remaining() >= DEFAULT_LEN) {
103 byte subOptCode = byteBuffer.get();
104 byte subOptLen = byteBuffer.get();
Yi Tsengb4fdb042017-08-07 13:32:32 -0700105 int subOptLenInt = UNSIGNED_BYTE_MASK & subOptLen;
106 byte[] subOptData = new byte[subOptLenInt];
Yi Tsengc7403c22017-06-19 16:23:22 -0700107 byteBuffer.get(subOptData);
108
109 DhcpOption subOption = new DhcpOption();
110 subOption.code = subOptCode;
111 subOption.length = subOptLen;
112 subOption.data = subOptData;
113 relayOption.subOptions.put(subOptCode, subOption);
114 }
115
116 return relayOption;
117 };
118 }
119
120 /**
121 * Gets sub-option from this option by given option code.
122 *
123 * @param code the option code
124 * @return sub-option of given code; null if there is no sub-option for given
125 * code
126 */
127 public DhcpOption getSubOption(byte code) {
128 return subOptions.get(code);
129 }
130
131 /**
132 * Adds a sub-option for this option.
133 *
134 * @param subOption the sub-option
135 */
136 public void addSubOption(DhcpOption subOption) {
137 this.length += SUB_OPT_DEFAULT_LEN + subOption.length;
138 this.subOptions.put(subOption.getCode(), subOption);
139 }
140
141 /**
142 * Removes a sub-option by given sub-option code.
143 *
144 * @param code the code for sub-option
145 * @return sub-option removed; null of sub-option not exists
146 */
147 public DhcpOption removeSubOption(byte code) {
148 DhcpOption subOption = subOptions.remove(code);
149 if (subOption != null) {
150 this.length -= SUB_OPT_DEFAULT_LEN + subOption.length;
151 }
152 return subOption;
153 }
154
155 @Override
156 public boolean equals(Object obj) {
157 if (!super.equals(obj)) {
158 return false;
159 }
160 if (!(obj instanceof DhcpRelayAgentOption)) {
161 return false;
162 }
163 DhcpRelayAgentOption that = (DhcpRelayAgentOption) obj;
164 return Objects.equals(this.subOptions, that.subOptions);
165 }
166
167 @Override
168 public int hashCode() {
169 return Objects.hash(super.hashCode(), subOptions);
170 }
171}