Home | History | Annotate | Download | only in netlink
      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 
     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.
     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 
     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 
    101     public StructNlAttr() {}
    102 
    103     public StructNlAttr(ByteOrder byteOrder) {
    104         mByteOrder = byteOrder;
    105     }
    106 
    107     public StructNlAttr(short type, byte value) {
    108         nla_type = type;
    109         setValue(new byte[1]);
    110         nla_value[0] = value;
    111     }
    112 
    113     public StructNlAttr(short type, short value) {
    114         this(type, value, ByteOrder.nativeOrder());
    115     }
    116 
    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 
    124     public StructNlAttr(short type, int value) {
    125         this(type, value, ByteOrder.nativeOrder());
    126     }
    127 
    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 
    135     public StructNlAttr(short type, InetAddress ip) {
    136         nla_type = type;
    137         setValue(ip.getAddress());
    138     }
    139 
    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 
    154     public int getAlignedLength() {
    155         return NetlinkConstants.alignedLengthOf(nla_len);
    156     }
    157 
    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 
    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 
    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 
    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 
    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
    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