• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.net.netlink.NetlinkConstants;
20 import libcore.io.SizeOf;
21 
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.nio.ByteOrder;
25 import java.nio.ByteBuffer;
26 
27 
28 /**
29  * struct nlattr
30  *
31  * see: <linux_src>/include/uapi/linux/netlink.h
32  *
33  * @hide
34  */
35 public class StructNlAttr {
36     // Already aligned.
37     public static final int NLA_HEADERLEN  = 4;
38     public static final int NLA_F_NESTED   = (1 << 15);
39 
makeNestedType(short type)40     public static short makeNestedType(short type) {
41         return (short) (type | NLA_F_NESTED);
42     }
43 
44     // Return a (length, type) object only, without consuming any bytes in
45     // |byteBuffer| and without copying or interpreting any value bytes.
46     // This is used for scanning over a packed set of struct nlattr's,
47     // looking for instances of a particular type.
peek(ByteBuffer byteBuffer)48     public static StructNlAttr peek(ByteBuffer byteBuffer) {
49         if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
50             return null;
51         }
52         final int baseOffset = byteBuffer.position();
53 
54         // Assume the byte order of the buffer is the expected byte order of the value.
55         final StructNlAttr struct = new StructNlAttr(byteBuffer.order());
56         // The byte order of nla_len and nla_type is always native.
57         final ByteOrder originalOrder = byteBuffer.order();
58         byteBuffer.order(ByteOrder.nativeOrder());
59         try {
60             struct.nla_len = byteBuffer.getShort();
61             struct.nla_type = byteBuffer.getShort();
62         } finally {
63             byteBuffer.order(originalOrder);
64         }
65 
66         byteBuffer.position(baseOffset);
67         if (struct.nla_len < NLA_HEADERLEN) {
68             // Malformed.
69             return null;
70         }
71         return struct;
72     }
73 
parse(ByteBuffer byteBuffer)74     public static StructNlAttr parse(ByteBuffer byteBuffer) {
75         final StructNlAttr struct = peek(byteBuffer);
76         if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
77             return null;
78         }
79 
80         final int baseOffset = byteBuffer.position();
81         byteBuffer.position(baseOffset + NLA_HEADERLEN);
82 
83         int valueLen = ((int) struct.nla_len) & 0xffff;
84         valueLen -= NLA_HEADERLEN;
85         if (valueLen > 0) {
86             struct.nla_value = new byte[valueLen];
87             byteBuffer.get(struct.nla_value, 0, valueLen);
88             byteBuffer.position(baseOffset + struct.getAlignedLength());
89         }
90         return struct;
91     }
92 
93     public short nla_len = (short) NLA_HEADERLEN;
94     public short nla_type;
95     public byte[] nla_value;
96 
97     // The byte order used to read/write the value member. Netlink length and
98     // type members are always read/written in native order.
99     private ByteOrder mByteOrder = ByteOrder.nativeOrder();
100 
StructNlAttr()101     public StructNlAttr() {}
102 
StructNlAttr(ByteOrder byteOrder)103     public StructNlAttr(ByteOrder byteOrder) {
104         mByteOrder = byteOrder;
105     }
106 
StructNlAttr(short type, byte value)107     public StructNlAttr(short type, byte value) {
108         nla_type = type;
109         setValue(new byte[1]);
110         nla_value[0] = value;
111     }
112 
StructNlAttr(short type, short value)113     public StructNlAttr(short type, short value) {
114         this(type, value, ByteOrder.nativeOrder());
115     }
116 
StructNlAttr(short type, short value, ByteOrder order)117     public StructNlAttr(short type, short value, ByteOrder order) {
118         this(order);
119         nla_type = type;
120         setValue(new byte[SizeOf.SHORT]);
121         getValueAsByteBuffer().putShort(value);
122     }
123 
StructNlAttr(short type, int value)124     public StructNlAttr(short type, int value) {
125         this(type, value, ByteOrder.nativeOrder());
126     }
127 
StructNlAttr(short type, int value, ByteOrder order)128     public StructNlAttr(short type, int value, ByteOrder order) {
129         this(order);
130         nla_type = type;
131         setValue(new byte[SizeOf.INT]);
132         getValueAsByteBuffer().putInt(value);
133     }
134 
StructNlAttr(short type, InetAddress ip)135     public StructNlAttr(short type, InetAddress ip) {
136         nla_type = type;
137         setValue(ip.getAddress());
138     }
139 
StructNlAttr(short type, StructNlAttr... nested)140     public StructNlAttr(short type, StructNlAttr... nested) {
141         this();
142         nla_type = makeNestedType(type);
143 
144         int payloadLength = 0;
145         for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
146         setValue(new byte[payloadLength]);
147 
148         final ByteBuffer buf = getValueAsByteBuffer();
149         for (StructNlAttr nla : nested) {
150             nla.pack(buf);
151         }
152     }
153 
getAlignedLength()154     public int getAlignedLength() {
155         return NetlinkConstants.alignedLengthOf(nla_len);
156     }
157 
getValueAsByteBuffer()158     public ByteBuffer getValueAsByteBuffer() {
159         if (nla_value == null) { return null; }
160         final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
161         byteBuffer.order(mByteOrder);
162         return byteBuffer;
163     }
164 
getValueAsInt(int defaultValue)165     public int getValueAsInt(int defaultValue) {
166         final ByteBuffer byteBuffer = getValueAsByteBuffer();
167         if (byteBuffer == null || byteBuffer.remaining() != SizeOf.INT) {
168             return defaultValue;
169         }
170         return getValueAsByteBuffer().getInt();
171     }
172 
getValueAsInetAddress()173     public InetAddress getValueAsInetAddress() {
174         if (nla_value == null) { return null; }
175 
176         try {
177             return InetAddress.getByAddress(nla_value);
178         } catch (UnknownHostException ignored) {
179             return null;
180         }
181     }
182 
pack(ByteBuffer byteBuffer)183     public void pack(ByteBuffer byteBuffer) {
184         final ByteOrder originalOrder = byteBuffer.order();
185         final int originalPosition = byteBuffer.position();
186 
187         byteBuffer.order(ByteOrder.nativeOrder());
188         try {
189             byteBuffer.putShort(nla_len);
190             byteBuffer.putShort(nla_type);
191             if (nla_value != null) byteBuffer.put(nla_value);
192         } finally {
193             byteBuffer.order(originalOrder);
194         }
195         byteBuffer.position(originalPosition + getAlignedLength());
196     }
197 
setValue(byte[] value)198     private void setValue(byte[] value) {
199         nla_value = value;
200         nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
201     }
202 
203     @Override
toString()204     public String toString() {
205         return "StructNlAttr{ "
206                 + "nla_len{" + nla_len + "}, "
207                 + "nla_type{" + nla_type + "}, "
208                 + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
209                 + "}";
210     }
211 }
212