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 21 import java.net.InetAddress; 22 import java.net.UnknownHostException; 23 import java.nio.ByteOrder; 24 import java.nio.ByteBuffer; 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 // Assume the byte order of the buffer is the expected byte order of the value. 54 final StructNlAttr struct = new StructNlAttr(byteBuffer.order()); 55 // The byte order of nla_len and nla_type is always native. 56 final ByteOrder originalOrder = byteBuffer.order(); 57 byteBuffer.order(ByteOrder.nativeOrder()); 58 try { 59 struct.nla_len = byteBuffer.getShort(); 60 struct.nla_type = byteBuffer.getShort(); 61 } finally { 62 byteBuffer.order(originalOrder); 63 } 64 65 byteBuffer.position(baseOffset); 66 if (struct.nla_len < NLA_HEADERLEN) { 67 // Malformed. 68 return null; 69 } 70 return struct; 71 } 72 parse(ByteBuffer byteBuffer)73 public static StructNlAttr parse(ByteBuffer byteBuffer) { 74 final StructNlAttr struct = peek(byteBuffer); 75 if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) { 76 return null; 77 } 78 79 final int baseOffset = byteBuffer.position(); 80 byteBuffer.position(baseOffset + NLA_HEADERLEN); 81 82 int valueLen = ((int) struct.nla_len) & 0xffff; 83 valueLen -= NLA_HEADERLEN; 84 if (valueLen > 0) { 85 struct.nla_value = new byte[valueLen]; 86 byteBuffer.get(struct.nla_value, 0, valueLen); 87 byteBuffer.position(baseOffset + struct.getAlignedLength()); 88 } 89 return struct; 90 } 91 92 public short nla_len = (short) NLA_HEADERLEN; 93 public short nla_type; 94 public byte[] nla_value; 95 96 // The byte order used to read/write the value member. Netlink length and 97 // type members are always read/written in native order. 98 private ByteOrder mByteOrder = ByteOrder.nativeOrder(); 99 StructNlAttr()100 public StructNlAttr() {} 101 StructNlAttr(ByteOrder byteOrder)102 public StructNlAttr(ByteOrder byteOrder) { 103 mByteOrder = byteOrder; 104 } 105 StructNlAttr(short type, byte value)106 public StructNlAttr(short type, byte value) { 107 nla_type = type; 108 setValue(new byte[1]); 109 nla_value[0] = value; 110 } 111 StructNlAttr(short type, short value)112 public StructNlAttr(short type, short value) { 113 this(type, value, ByteOrder.nativeOrder()); 114 } 115 StructNlAttr(short type, short value, ByteOrder order)116 public StructNlAttr(short type, short value, ByteOrder order) { 117 this(order); 118 nla_type = type; 119 setValue(new byte[Short.BYTES]); 120 getValueAsByteBuffer().putShort(value); 121 } 122 StructNlAttr(short type, int value)123 public StructNlAttr(short type, int value) { 124 this(type, value, ByteOrder.nativeOrder()); 125 } 126 StructNlAttr(short type, int value, ByteOrder order)127 public StructNlAttr(short type, int value, ByteOrder order) { 128 this(order); 129 nla_type = type; 130 setValue(new byte[Integer.BYTES]); 131 getValueAsByteBuffer().putInt(value); 132 } 133 StructNlAttr(short type, InetAddress ip)134 public StructNlAttr(short type, InetAddress ip) { 135 nla_type = type; 136 setValue(ip.getAddress()); 137 } 138 StructNlAttr(short type, StructNlAttr... nested)139 public StructNlAttr(short type, StructNlAttr... nested) { 140 this(); 141 nla_type = makeNestedType(type); 142 143 int payloadLength = 0; 144 for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength(); 145 setValue(new byte[payloadLength]); 146 147 final ByteBuffer buf = getValueAsByteBuffer(); 148 for (StructNlAttr nla : nested) { 149 nla.pack(buf); 150 } 151 } 152 getAlignedLength()153 public int getAlignedLength() { 154 return NetlinkConstants.alignedLengthOf(nla_len); 155 } 156 getValueAsByteBuffer()157 public ByteBuffer getValueAsByteBuffer() { 158 if (nla_value == null) { return null; } 159 final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); 160 byteBuffer.order(mByteOrder); 161 return byteBuffer; 162 } 163 getValueAsInt(int defaultValue)164 public int getValueAsInt(int defaultValue) { 165 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 166 if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { 167 return defaultValue; 168 } 169 return getValueAsByteBuffer().getInt(); 170 } 171 getValueAsInetAddress()172 public InetAddress getValueAsInetAddress() { 173 if (nla_value == null) { return null; } 174 175 try { 176 return InetAddress.getByAddress(nla_value); 177 } catch (UnknownHostException ignored) { 178 return null; 179 } 180 } 181 pack(ByteBuffer byteBuffer)182 public void pack(ByteBuffer byteBuffer) { 183 final ByteOrder originalOrder = byteBuffer.order(); 184 final int originalPosition = byteBuffer.position(); 185 186 byteBuffer.order(ByteOrder.nativeOrder()); 187 try { 188 byteBuffer.putShort(nla_len); 189 byteBuffer.putShort(nla_type); 190 if (nla_value != null) byteBuffer.put(nla_value); 191 } finally { 192 byteBuffer.order(originalOrder); 193 } 194 byteBuffer.position(originalPosition + getAlignedLength()); 195 } 196 setValue(byte[] value)197 private void setValue(byte[] value) { 198 nla_value = value; 199 nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0)); 200 } 201 202 @Override toString()203 public String toString() { 204 return "StructNlAttr{ " 205 + "nla_len{" + nla_len + "}, " 206 + "nla_type{" + nla_type + "}, " 207 + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, " 208 + "}"; 209 } 210 } 211