1 /*
2  * Copyright (C) 2020 The Android Open Source Project
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 
17 package android.net.netlink;
18 
19 import java.nio.ByteBuffer;
20 
21 /**
22  * Base class for IPv6 neighbour discovery options.
23  */
24 public class NdOption {
25     public static final int STRUCT_SIZE = 2;
26 
27     /** The option type. */
28     public final byte type;
29     /** The length of the option in 8-byte units. Actually an unsigned 8-bit integer */
30     public final int length;
31 
32     /** Constructs a new NdOption. */
33     NdOption(byte type, int length) {
34         this.type = type;
35         this.length = length;
36     }
37 
38     /**
39      * Parses a neighbour discovery option.
40      *
41      * Parses (and consumes) the option if it is of a known type. If the option is of an unknown
42      * type, advances the buffer (so the caller can continue parsing if desired) and returns
43      * {@link #UNKNOWN}. If the option claims a length of 0, returns null because parsing cannot
44      * continue.
45      *
46      * No checks are performed on the length other than ensuring it is not 0, so if a caller wants
47      * to deal with options that might overflow the structure that contains them, it must explicitly
48      * set the buffer's limit to the position at which that structure ends.
49      *
50      * @param buf the buffer to parse.
51      * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option.
52      */
53     public static NdOption parse(ByteBuffer buf) {
54         if (buf == null || buf.remaining() < STRUCT_SIZE) return null;
55 
56         // Peek the type without advancing the buffer.
57         byte type = buf.get(buf.position());
58         int length = Byte.toUnsignedInt(buf.get(buf.position() + 1));
59         if (length == 0) return null;
60 
61         switch (type) {
62             case StructNdOptPref64.TYPE:
63                 return StructNdOptPref64.parse(buf);
64 
65             default:
66                 int newPosition = Math.min(buf.limit(), buf.position() + length * 8);
67                 buf.position(newPosition);
68                 return UNKNOWN;
69         }
70     }
71 
72     void writeToByteBuffer(ByteBuffer buf) {
73         buf.put(type);
74         buf.put((byte) length);
75     }
76 
77     @Override
78     public String toString() {
79         return String.format("NdOption(%d, %d)", Byte.toUnsignedInt(type), length);
80     }
81 
82     public static final NdOption UNKNOWN = new NdOption((byte) 0, 0);
83 }
84