blob: 498704d89bbb77e5b6e17175b7e81dcd53dab577 [file] [log] [blame]
Yi Tsengc7403c22017-06-19 16:23:22 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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();
105 byte[] subOptData = new byte[subOptLen];
106 byteBuffer.get(subOptData);
107
108 DhcpOption subOption = new DhcpOption();
109 subOption.code = subOptCode;
110 subOption.length = subOptLen;
111 subOption.data = subOptData;
112 relayOption.subOptions.put(subOptCode, subOption);
113 }
114
115 return relayOption;
116 };
117 }
118
119 /**
120 * Gets sub-option from this option by given option code.
121 *
122 * @param code the option code
123 * @return sub-option of given code; null if there is no sub-option for given
124 * code
125 */
126 public DhcpOption getSubOption(byte code) {
127 return subOptions.get(code);
128 }
129
130 /**
131 * Adds a sub-option for this option.
132 *
133 * @param subOption the sub-option
134 */
135 public void addSubOption(DhcpOption subOption) {
136 this.length += SUB_OPT_DEFAULT_LEN + subOption.length;
137 this.subOptions.put(subOption.getCode(), subOption);
138 }
139
140 /**
141 * Removes a sub-option by given sub-option code.
142 *
143 * @param code the code for sub-option
144 * @return sub-option removed; null of sub-option not exists
145 */
146 public DhcpOption removeSubOption(byte code) {
147 DhcpOption subOption = subOptions.remove(code);
148 if (subOption != null) {
149 this.length -= SUB_OPT_DEFAULT_LEN + subOption.length;
150 }
151 return subOption;
152 }
153
154 @Override
155 public boolean equals(Object obj) {
156 if (!super.equals(obj)) {
157 return false;
158 }
159 if (!(obj instanceof DhcpRelayAgentOption)) {
160 return false;
161 }
162 DhcpRelayAgentOption that = (DhcpRelayAgentOption) obj;
163 return Objects.equals(this.subOptions, that.subOptions);
164 }
165
166 @Override
167 public int hashCode() {
168 return Objects.hash(super.hashCode(), subOptions);
169 }
170}