dhcpservice dead code removal
[netvirt.git] / dhcpservice / api / src / main / java / org / opendaylight / netvirt / dhcpservice / api / DHCP.java
1 /*
2  * Copyright (c) 2015, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.dhcpservice.api;
10
11 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.BOOTREPLY;
12 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_MAX_SIZE;
13 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_MIN_SIZE;
14 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_NOOPT_HDR_SIZE;
15 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.HTYPE_ETHER;
16 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.MAGIC_COOKIE;
17 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.OPT_MESSAGE_TYPE;
18
19 import com.google.common.collect.ImmutableMap;
20 import java.net.InetAddress;
21 import java.net.UnknownHostException;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import org.apache.commons.lang3.ArrayUtils;
28 import org.apache.commons.lang3.tuple.ImmutablePair;
29 import org.apache.commons.lang3.tuple.Pair;
30 import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
31 import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
32 import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
33 import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
34 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
35 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class DHCP extends Packet {
40     private static final Logger LOG = LoggerFactory.getLogger(DHCP.class);
41
42     private static final String OP      = "Op";
43     private static final String HTYPE   = "Htype";
44     private static final String HLEN    = "Hlen";
45     private static final String HOPS    = "Hops";
46     private static final String XID     = "Xid";
47     private static final String SECS    = "Secs";
48     private static final String FLAGS   = "Flags";
49     private static final String CIADDR  = "Ciaddr";
50     private static final String YIADDR  = "Yiaddr";
51     private static final String SIADDR  = "Siaddr";
52     private static final String GIADDR  = "Giaddr";
53     private static final String CHADDR  = "Chaddr";
54     private static final String SNAME   = "Sname";
55     private static final String FILE    = "File";
56     private static final String MCOOKIE = "Mcookie";
57     private static final String OPTIONS = "Options";
58     private DHCPOptions dhcpOptions = null;
59
60     private static final ImmutableMap<String, Pair<Integer, Integer>> FIELD_COORDINATES =
61         ImmutableMap.<String, Pair<Integer, Integer>>builderWithExpectedSize(16)
62             .put(OP, new ImmutablePair<>(0, 8))
63             .put(HTYPE, new ImmutablePair<>(8, 8))
64             .put(HLEN, new ImmutablePair<>(16, 8))
65             .put(HOPS, new ImmutablePair<>(24, 8))
66             .put(XID, new ImmutablePair<>(32, 32))
67             .put(SECS, new ImmutablePair<>(64, 16))
68             .put(FLAGS, new ImmutablePair<>(80, 16))
69             .put(CIADDR, new ImmutablePair<>(96, 32))
70             .put(YIADDR, new ImmutablePair<>(128, 32))
71             .put(SIADDR, new ImmutablePair<>(160, 32))
72             .put(GIADDR, new ImmutablePair<>(192, 32))
73             .put(CHADDR, new ImmutablePair<>(224, 128))
74             .put(SNAME, new ImmutablePair<>(352, 512))
75             .put(FILE, new ImmutablePair<>(864, 1024))
76             .put(MCOOKIE, new ImmutablePair<>(1888, 32))
77             .put(OPTIONS, new ImmutablePair<>(1920, 0))
78             .build();
79
80     private final Map<String, byte[]> fieldValues;
81
82     public DHCP() {
83         this(false);
84     }
85
86     public DHCP(boolean writeAccess) {
87         super(writeAccess);
88         fieldValues = new HashMap<>();
89         hdrFieldCoordMap = FIELD_COORDINATES;
90         hdrFieldsMap = fieldValues;
91         corrupted = false;
92
93         setOp(BOOTREPLY);
94         setHtype(HTYPE_ETHER);
95         setHlen((byte)6);
96         setHops((byte)0);
97         setXid(0);
98         setSecs((short) 0);
99         setFlags((short) 0);
100         setCiaddr(0);
101         setYiaddr(0);
102         setSiaddr(0);
103         setGiaddr(0);
104         setChaddr(new byte[16]);
105         setSname(new byte[64]);
106         setFile(new byte[128]);
107         setMcookie(MAGIC_COOKIE);
108         setOptions(new byte[0]);
109         this.dhcpOptions = new DHCPOptions();
110     }
111
112     public byte getHtype() {
113         return (BitBufferHelper.getByte(fieldValues.get(HTYPE)));
114     }
115
116     public byte getHlen() {
117         return (BitBufferHelper.getByte(fieldValues.get(HLEN)));
118     }
119
120     public int getXid() {
121         return (BitBufferHelper.getInt(fieldValues.get(XID)));
122     }
123
124     public short getFlags() {
125         return (BitBufferHelper.getShort(fieldValues.get(FLAGS)));
126     }
127
128     public byte[] getCiaddr() {
129         return fieldValues.get(CIADDR);
130     }
131
132
133     public byte[] getGiaddr() {
134         return fieldValues.get(GIADDR);
135     }
136
137     public byte[] getChaddr() {
138         return fieldValues.get(CHADDR);
139     }
140
141     public byte[] getOptions() {
142         return fieldValues.get(OPTIONS);
143     }
144
145 //    TODO:
146 //    public byte[] getPadding() {
147 //        return this.pad;
148 //    }
149
150     // Setters
151     @Override
152     public void setHeaderField(String headerField, byte[] readValue) {
153         if (headerField.equals(OPTIONS) && (readValue == null || readValue.length == 0)) {
154             hdrFieldsMap.remove(headerField);
155             return;
156         }
157         hdrFieldsMap.put(headerField, readValue);
158     }
159
160     public DHCP setOp(byte dhcpOp) {
161         byte[] op = BitBufferHelper.toByteArray(dhcpOp);
162         fieldValues.put(OP, op);
163         return this;
164     }
165
166     public DHCP setHtype(byte dhcpHtype) {
167         byte[] htype = BitBufferHelper.toByteArray(dhcpHtype);
168         fieldValues.put(HTYPE, htype);
169         return this;
170     }
171
172     public DHCP setHlen(byte dhcpHlen) {
173         byte[] hlen = BitBufferHelper.toByteArray(dhcpHlen);
174         fieldValues.put(HLEN, hlen);
175         return this;
176     }
177
178     public DHCP setHops(byte dhcpHops) {
179         byte[] hops = BitBufferHelper.toByteArray(dhcpHops);
180         fieldValues.put(HOPS, hops);
181         return this;
182     }
183
184     public DHCP setXid(int dhcpXid) {
185         byte[] xid = BitBufferHelper.toByteArray(dhcpXid);
186         fieldValues.put(XID, xid);
187         return this;
188     }
189
190     public DHCP setSecs(short dhcpSecs) {
191         byte[] secs = BitBufferHelper.toByteArray(dhcpSecs);
192         fieldValues.put(SECS, secs);
193         return this;
194     }
195
196     public DHCP setFlags(short dhcpFlags) {
197         byte[] flags = BitBufferHelper.toByteArray(dhcpFlags);
198         fieldValues.put(FLAGS, flags);
199         return this;
200     }
201
202     public DHCP setCiaddr(byte[] ciaddr) {
203         fieldValues.put(CIADDR, ciaddr);
204         return this;
205     }
206
207     public DHCP setCiaddr(int dhcpCiaddr) {
208         byte[] ciaddr = BitBufferHelper.toByteArray(dhcpCiaddr);
209         fieldValues.put(CIADDR, ciaddr);
210         return this;
211     }
212
213     public DHCP setYiaddr(int dhcpYiaddr) {
214         byte[] yiaddr = BitBufferHelper.toByteArray(dhcpYiaddr);
215         fieldValues.put(YIADDR, yiaddr);
216         return this;
217     }
218
219     public DHCP setYiaddr(String dhcpYiaddr) {
220         byte[] yiaddr = NetUtils.parseInetAddress(dhcpYiaddr).getAddress();
221         fieldValues.put(YIADDR, yiaddr);
222         return this;
223     }
224
225     public DHCP setSiaddr(int dhcpSiaddr) {
226         byte[] siaddr = BitBufferHelper.toByteArray(dhcpSiaddr);
227         fieldValues.put(SIADDR, siaddr);
228         return this;
229     }
230
231     public DHCP setSiaddr(String dhcpSiaddr) {
232         byte[] siaddr = NetUtils.parseInetAddress(dhcpSiaddr).getAddress();
233         fieldValues.put(SIADDR, siaddr);
234         return this;
235     }
236
237     public DHCP setGiaddr(byte[] giaddr) {
238         fieldValues.put(GIADDR, giaddr);
239         return this;
240     }
241
242     public DHCP setGiaddr(int dhcpGiaddr) {
243         byte[] giaddr = BitBufferHelper.toByteArray(dhcpGiaddr);
244         fieldValues.put(GIADDR, giaddr);
245         return this;
246     }
247
248     public DHCP setChaddr(byte[] chaddr) {
249         fieldValues.put(CHADDR, chaddr);
250         return this;
251     }
252
253     public DHCP setSname(byte[] sname) {
254         fieldValues.put(SNAME, sname);
255         return this;
256     }
257
258     public DHCP setFile(byte[] file) {
259         fieldValues.put(FILE, file);
260         return this;
261     }
262
263     public DHCP setMcookie(int dhcpMc) {
264         byte[] mc = BitBufferHelper.toByteArray(dhcpMc);
265         fieldValues.put(MCOOKIE, mc);
266         return this;
267     }
268
269     public DHCP setOptions(byte[] options) {
270         fieldValues.put(OPTIONS, options);
271         return this;
272     }
273
274 //    public void setPadding(byte[] pad) {
275 //        this.pad = pad;
276 //    }
277
278     /**
279      * This method deserializes the data bits obtained from the wire into the
280      * respective header and payload which are of type Packet.
281      *
282      * @param data       byte[] data from wire to deserialize
283      * @param bitOffset  int    bit position where packet header starts in data
284      *        array
285      * @param size       int    size of packet in bits
286      * @return Packet
287      * @throws PacketException the packet deserialization failed
288      *
289      * <p>Note: Copied from org.opendaylight.controller.sal.packet.Packet</p>
290      */
291     @Override
292     // We can’t do much about PacketException (yet; see https://git.opendaylight.org/gerrit/65837)
293     @SuppressWarnings("checkstyle:AvoidHidingCauseException")
294     public Packet deserialize(byte[] data, int bitOffset, int size)
295             throws PacketException {
296
297         // Deserialize the header fields one by one
298         int startOffset = 0;
299         int numBits = 0;
300         for (Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
301                 .entrySet()) {
302             String hdrField = pairs.getKey();
303             startOffset = bitOffset + this.getfieldOffset(hdrField);
304             if (hdrField.equals(OPTIONS)) {
305                 numBits = (size - DHCP_NOOPT_HDR_SIZE) * 8;
306             } else {
307                 numBits = this.getfieldnumBits(hdrField);
308             }
309             byte[] hdrFieldBytes = null;
310             try {
311                 hdrFieldBytes = BitBufferHelper.getBits(data, startOffset,
312                         numBits);
313             } catch (BufferException e) {
314                 throw new PacketException(e.getMessage());
315             }
316
317             /*
318              * Store the raw read value, checks the payload type and set the
319              * payloadClass accordingly
320              */
321             this.setHeaderField(hdrField, hdrFieldBytes);
322
323             if (LOG.isTraceEnabled()) {
324                 LOG.trace("{}: {}: {} (offset {} bitsize {})",
325                         this.getClass().getSimpleName(), hdrField,
326                         HexEncode.bytesToHexString(hdrFieldBytes),
327                         startOffset, numBits);
328             }
329         }
330
331         // Deserialize the payload now
332         int payloadStart = startOffset + numBits;
333         int payloadSize = data.length * Byte.SIZE - payloadStart;
334
335         if (payloadClass != null) {
336             try {
337                 payload = payloadClass.newInstance();
338             } catch (InstantiationException | IllegalAccessException e) {
339                 throw new RuntimeException(
340                         "Error parsing payload for Ethernet packet", e);
341             }
342             payload.deserialize(data, payloadStart, payloadSize);
343             payload.setParent(this);
344         } else {
345             /*
346              *  The payload class was not set, it means no class for parsing
347              *  this payload is present. Let's store the raw payload if any.
348              */
349             int start = payloadStart / Byte.SIZE;
350             int stop = start + payloadSize / Byte.SIZE;
351             rawPayload = Arrays.copyOfRange(data, start, stop);
352         }
353         // Take care of computation that can be done only after deserialization
354         postDeserializeCustomOperation(data, payloadStart - getHeaderSize());
355
356         return this;
357     }
358
359     @Override
360     public byte[] serialize() throws PacketException {
361         this.setOptions(this.dhcpOptions.serialize());
362         byte[] data = super.serialize();
363         // Check for OPT_END at end of options
364         if (data.length > DHCP_MAX_SIZE) {
365             // shouldn't have happened
366             // Add exception?
367             LOG.error("DHCP Packet too big");
368         } else if (data[data.length - 1] != (byte)255) {
369             // DHCP Options not ended properly
370             //throw new PacketException("Missing DHCP Option END");
371             LOG.error("Missing DHCP Option END");
372         } else if (data.length < DHCP_MIN_SIZE) {
373             byte[] padding = new byte[DHCP_MIN_SIZE - data.length];
374             LOG.debug("DHCP Pkt too small: {}, padding added {}",
375                     data.length, padding.length);
376             data = ArrayUtils.addAll(data, padding);
377         }
378         return data;
379     }
380
381     @Override
382     /**
383      * Gets the number of bits for the fieldname specified
384      * If the fieldname has variable length like "Options", then this value is computed using the header length
385      * @param fieldname - String
386      * @return number of bits for fieldname - int
387      */
388     public int getfieldnumBits(String fieldName) {
389         if (fieldName.equals(OPTIONS)) {
390             byte[] barr = fieldValues.get(OPTIONS);
391             return (barr.length) * Byte.SIZE;
392         }
393         return hdrFieldCoordMap.get(fieldName).getRight();
394     }
395
396     @Override
397     public int getHeaderSize() {
398         byte[] barr = fieldValues.get(OPTIONS);
399         int len = 0;
400         if (barr != null) {
401             len = barr.length;
402         }
403         return (DHCP_NOOPT_HDR_SIZE + len) * 8;
404     }
405
406     @Override
407     protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) {
408         //TODO: Anything need to be done here?
409         // Check for MAGIC_COOKIE. This means we only support DHCP, not BOOTP
410         int cookie = BitBufferHelper.getInt(fieldValues.get(MCOOKIE));
411         if (cookie != MAGIC_COOKIE) {
412             LOG.debug("Not DHCP packet");
413             // Throw exception?
414         }
415         // parse options into DHCPOptions
416         this.dhcpOptions.deserialize(this.getOptions());
417         // reset options byte array, this will also drop padding
418         this.setOptions(this.dhcpOptions.serialize());
419     }
420
421     // Set/get operations for Options
422     public void setMsgType(byte type) {
423         dhcpOptions.setOptionByte(OPT_MESSAGE_TYPE, type);
424     }
425
426     public byte getMsgType() {
427         return dhcpOptions.getOptionByte(OPT_MESSAGE_TYPE);
428     }
429
430     public void setOptionBytes(byte code, byte[] opt) {
431         dhcpOptions.setOption(code, opt);
432     }
433
434     public byte[] getOptionBytes(byte code) {
435         return dhcpOptions.getOptionBytes(code);
436     }
437
438     public void setOptionInt(byte code, int opt) {
439         dhcpOptions.setOptionInt(code, opt);
440     }
441
442     public InetAddress getOptionInetAddr(byte code) {
443         return dhcpOptions.getOptionInetAddr(code);
444     }
445
446     public void setOptionInetAddr(byte code, String addr) throws UnknownHostException {
447         dhcpOptions.setOptionStrAddr(code, addr);
448     }
449
450     public void setOptionStrAddrs(byte code, List<String> opt) throws UnknownHostException {
451         dhcpOptions.setOptionStrAddrs(code, opt);
452     }
453
454     public void setOptionString(byte code, String str) {
455         dhcpOptions.setOptionString(code, str);
456     }
457
458     public boolean containsOption(byte code) {
459         // TODO Auto-generated method stub
460         return dhcpOptions.containsOption(code);
461     }
462
463     public void unsetOption(byte code) {
464         dhcpOptions.unsetOption(code);
465     }
466
467     @Override
468     public String toString() {
469         StringBuilder ret = new StringBuilder();
470         ret.append(super.toString()).append(dhcpOptions);
471
472         return ret.toString();
473     }
474 }