• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 androidx.annotation.Nullable;
20 
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 
26 
27 /**
28  * struct nlattr
29  *
30  * see: <linux_src>/include/uapi/linux/netlink.h
31  *
32  * @hide
33  */
34 public class StructNlAttr {
35     // Already aligned.
36     public static final int NLA_HEADERLEN  = 4;
37     public static final int NLA_F_NESTED   = (1 << 15);
38 
makeNestedType(short type)39     public static short makeNestedType(short type) {
40         return (short) (type | NLA_F_NESTED);
41     }
42 
43     // Return a (length, type) object only, without consuming any bytes in
44     // |byteBuffer| and without copying or interpreting any value bytes.
45     // This is used for scanning over a packed set of struct nlattr's,
46     // looking for instances of a particular type.
peek(ByteBuffer byteBuffer)47     public static StructNlAttr peek(ByteBuffer byteBuffer) {
48         if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
49             return null;
50         }
51         final int baseOffset = byteBuffer.position();
52 
53         final StructNlAttr struct = new StructNlAttr();
54         final ByteOrder originalOrder = byteBuffer.order();
55         byteBuffer.order(ByteOrder.nativeOrder());
56         try {
57             struct.nla_len = byteBuffer.getShort();
58             struct.nla_type = byteBuffer.getShort();
59         } finally {
60             byteBuffer.order(originalOrder);
61         }
62 
63         byteBuffer.position(baseOffset);
64         if (struct.nla_len < NLA_HEADERLEN) {
65             // Malformed.
66             return null;
67         }
68         return struct;
69     }
70 
parse(ByteBuffer byteBuffer)71     public static StructNlAttr parse(ByteBuffer byteBuffer) {
72         final StructNlAttr struct = peek(byteBuffer);
73         if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
74             return null;
75         }
76 
77         final int baseOffset = byteBuffer.position();
78         byteBuffer.position(baseOffset + NLA_HEADERLEN);
79 
80         int valueLen = ((int) struct.nla_len) & 0xffff;
81         valueLen -= NLA_HEADERLEN;
82         if (valueLen > 0) {
83             struct.nla_value = new byte[valueLen];
84             byteBuffer.get(struct.nla_value, 0, valueLen);
85             byteBuffer.position(baseOffset + struct.getAlignedLength());
86         }
87         return struct;
88     }
89 
90     /**
91      * Find next netlink attribute with a given type from {@link ByteBuffer}.
92      *
93      * @param attrType The given netlink attribute type is requested for.
94      * @param byteBuffer The buffer from which to find the netlink attribute.
95      * @return the found netlink attribute, or {@code null} if the netlink attribute could not be
96      *         found or parsed successfully (for example, if it was truncated).
97      */
98     @Nullable
findNextAttrOfType(short attrType, @Nullable ByteBuffer byteBuffer)99     public static StructNlAttr findNextAttrOfType(short attrType,
100             @Nullable ByteBuffer byteBuffer) {
101         while (byteBuffer != null && byteBuffer.remaining() > 0) {
102             final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
103             if (nlAttr == null) {
104                 break;
105             }
106             if (nlAttr.nla_type == attrType) {
107                 return StructNlAttr.parse(byteBuffer);
108             }
109             if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
110                 break;
111             }
112             byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
113         }
114         return null;
115     }
116 
117     public short nla_len = (short) NLA_HEADERLEN;
118     public short nla_type;
119     public byte[] nla_value;
120 
StructNlAttr()121     public StructNlAttr() {}
122 
StructNlAttr(short type, byte value)123     public StructNlAttr(short type, byte value) {
124         nla_type = type;
125         setValue(new byte[1]);
126         nla_value[0] = value;
127     }
128 
StructNlAttr(short type, short value)129     public StructNlAttr(short type, short value) {
130         this(type, value, ByteOrder.nativeOrder());
131     }
132 
StructNlAttr(short type, short value, ByteOrder order)133     public StructNlAttr(short type, short value, ByteOrder order) {
134         nla_type = type;
135         setValue(new byte[Short.BYTES]);
136         final ByteBuffer buf = getValueAsByteBuffer();
137         final ByteOrder originalOrder = buf.order();
138         try {
139             buf.order(order);
140             buf.putShort(value);
141         } finally {
142             buf.order(originalOrder);
143         }
144     }
145 
StructNlAttr(short type, int value)146     public StructNlAttr(short type, int value) {
147         this(type, value, ByteOrder.nativeOrder());
148     }
149 
StructNlAttr(short type, int value, ByteOrder order)150     public StructNlAttr(short type, int value, ByteOrder order) {
151         nla_type = type;
152         setValue(new byte[Integer.BYTES]);
153         final ByteBuffer buf = getValueAsByteBuffer();
154         final ByteOrder originalOrder = buf.order();
155         try {
156             buf.order(order);
157             buf.putInt(value);
158         } finally {
159             buf.order(originalOrder);
160         }
161     }
162 
StructNlAttr(short type, InetAddress ip)163     public StructNlAttr(short type, InetAddress ip) {
164         nla_type = type;
165         setValue(ip.getAddress());
166     }
167 
StructNlAttr(short type, StructNlAttr... nested)168     public StructNlAttr(short type, StructNlAttr... nested) {
169         this();
170         nla_type = makeNestedType(type);
171 
172         int payloadLength = 0;
173         for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
174         setValue(new byte[payloadLength]);
175 
176         final ByteBuffer buf = getValueAsByteBuffer();
177         for (StructNlAttr nla : nested) {
178             nla.pack(buf);
179         }
180     }
181 
getAlignedLength()182     public int getAlignedLength() {
183         return NetlinkConstants.alignedLengthOf(nla_len);
184     }
185 
186     /**
187      * Get attribute value as BE16.
188      */
getValueAsBe16(short defaultValue)189     public short getValueAsBe16(short defaultValue) {
190         final ByteBuffer byteBuffer = getValueAsByteBuffer();
191         if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) {
192             return defaultValue;
193         }
194         final ByteOrder originalOrder = byteBuffer.order();
195         try {
196             byteBuffer.order(ByteOrder.BIG_ENDIAN);
197             return byteBuffer.getShort();
198         } finally {
199             byteBuffer.order(originalOrder);
200         }
201     }
202 
getValueAsBe32(int defaultValue)203     public int getValueAsBe32(int defaultValue) {
204         final ByteBuffer byteBuffer = getValueAsByteBuffer();
205         if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
206             return defaultValue;
207         }
208         final ByteOrder originalOrder = byteBuffer.order();
209         try {
210             byteBuffer.order(ByteOrder.BIG_ENDIAN);
211             return byteBuffer.getInt();
212         } finally {
213             byteBuffer.order(originalOrder);
214         }
215     }
216 
getValueAsByteBuffer()217     public ByteBuffer getValueAsByteBuffer() {
218         if (nla_value == null) { return null; }
219         final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
220         // By convention, all buffers in this library are in native byte order because netlink is in
221         // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only
222         // order accepted by NetlinkMessage.parse.
223         byteBuffer.order(ByteOrder.nativeOrder());
224         return byteBuffer;
225     }
226 
227     /**
228      * Get attribute value as byte.
229      */
getValueAsByte(byte defaultValue)230     public byte getValueAsByte(byte defaultValue) {
231         final ByteBuffer byteBuffer = getValueAsByteBuffer();
232         if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) {
233             return defaultValue;
234         }
235         return getValueAsByteBuffer().get();
236     }
237 
getValueAsInt(int defaultValue)238     public int getValueAsInt(int defaultValue) {
239         final ByteBuffer byteBuffer = getValueAsByteBuffer();
240         if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
241             return defaultValue;
242         }
243         return getValueAsByteBuffer().getInt();
244     }
245 
getValueAsInetAddress()246     public InetAddress getValueAsInetAddress() {
247         if (nla_value == null) { return null; }
248 
249         try {
250             return InetAddress.getByAddress(nla_value);
251         } catch (UnknownHostException ignored) {
252             return null;
253         }
254     }
255 
pack(ByteBuffer byteBuffer)256     public void pack(ByteBuffer byteBuffer) {
257         final ByteOrder originalOrder = byteBuffer.order();
258         final int originalPosition = byteBuffer.position();
259 
260         byteBuffer.order(ByteOrder.nativeOrder());
261         try {
262             byteBuffer.putShort(nla_len);
263             byteBuffer.putShort(nla_type);
264             if (nla_value != null) byteBuffer.put(nla_value);
265         } finally {
266             byteBuffer.order(originalOrder);
267         }
268         byteBuffer.position(originalPosition + getAlignedLength());
269     }
270 
setValue(byte[] value)271     private void setValue(byte[] value) {
272         nla_value = value;
273         nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
274     }
275 
276     @Override
toString()277     public String toString() {
278         return "StructNlAttr{ "
279                 + "nla_len{" + nla_len + "}, "
280                 + "nla_type{" + nla_type + "}, "
281                 + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
282                 + "}";
283     }
284 }
285