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