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