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