16193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline/*
26193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * Copyright (C) 2015 The Android Open Source Project
36193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *
46193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * Licensed under the Apache License, Version 2.0 (the "License");
56193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * you may not use this file except in compliance with the License.
66193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * You may obtain a copy of the License at
76193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *
86193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *      http://www.apache.org/licenses/LICENSE-2.0
96193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *
106193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * Unless required by applicable law or agreed to in writing, software
116193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * distributed under the License is distributed on an "AS IS" BASIS,
126193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * See the License for the specific language governing permissions and
146193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * limitations under the License.
156193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline */
166193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
176193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klinepackage android.net.netlink;
186193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
19cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Klineimport static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
20cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Klineimport static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
21cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Klineimport static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
22cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Klineimport static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
23cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline
246193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.net.netlink.StructNdaCacheInfo;
256193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.net.netlink.StructNdMsg;
266193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.net.netlink.StructNlAttr;
276193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.net.netlink.StructNlMsgHdr;
286193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.net.netlink.NetlinkMessage;
299ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Klineimport android.system.OsConstants;
306193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport android.util.Log;
316193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
326193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport java.net.InetAddress;
339ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Klineimport java.net.Inet6Address;
346193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport java.nio.ByteBuffer;
356193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klineimport java.nio.ByteOrder;
366193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
376193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
386193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline/**
396193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * A NetlinkMessage subclass for netlink error messages.
406193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *
416193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * see also: <linux_src>/include/uapi/linux/neighbour.h
426193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline *
436193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline * @hide
446193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline */
456193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Klinepublic class RtNetlinkNeighborMessage extends NetlinkMessage {
466193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_UNSPEC    = 0;
476193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_DST       = 1;
486193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_LLADDR    = 2;
496193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_CACHEINFO = 3;
506193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_PROBES    = 4;
516193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_VLAN      = 5;
526193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_PORT      = 6;
536193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_VNI       = 7;
546193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_IFINDEX   = 8;
556193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static final short NDA_MASTER    = 9;
566193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
576193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
586193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        while (byteBuffer != null && byteBuffer.remaining() > 0) {
596193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
606193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            if (nlAttr == null) {
616193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                break;
626193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            }
636193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            if (nlAttr.nla_type == attrType) {
646193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                return StructNlAttr.parse(byteBuffer);
656193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            }
666193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
676193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                break;
686193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            }
696193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
706193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
716193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return null;
726193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
736193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
746193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
756193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
766193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
776193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
786193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (neighMsg.mNdmsg == null) {
796193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            return null;
806193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
816193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
826193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        // Some of these are message-type dependent, and not always present.
836193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final int baseOffset = byteBuffer.position();
846193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
856193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (nlAttr != null) {
866193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            neighMsg.mDestination = nlAttr.getValueAsInetAddress();
876193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
886193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
896193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        byteBuffer.position(baseOffset);
906193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
916193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (nlAttr != null) {
926193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            neighMsg.mLinkLayerAddr = nlAttr.nla_value;
936193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
946193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
956193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        byteBuffer.position(baseOffset);
966193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
976193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (nlAttr != null) {
986193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
996193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
1006193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1016193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        byteBuffer.position(baseOffset);
1026193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
1036193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (nlAttr != null) {
1046193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
1056193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
1066193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1076193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
1086193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
1096193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                neighMsg.mHeader.nlmsg_len - kMinConsumed);
1106193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        if (byteBuffer.remaining() < kAdditionalSpace) {
1116193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            byteBuffer.position(byteBuffer.limit());
1126193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        } else {
1136193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline            byteBuffer.position(baseOffset + kAdditionalSpace);
1146193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        }
1156193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1166193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return neighMsg;
1176193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1186193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1196193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    /**
1206193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline     * A convenience method to create an RTM_GETNEIGH request message.
1216193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline     */
1226193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public static byte[] newGetNeighborsRequest(int seqNo) {
1236193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
1246193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final byte[] bytes = new byte[length];
1256193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
1266193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        byteBuffer.order(ByteOrder.nativeOrder());
1276193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1286193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
1296193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlmsghdr.nlmsg_len = length;
1306193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
131cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
1326193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlmsghdr.nlmsg_seq = seqNo;
1336193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        nlmsghdr.pack(byteBuffer);
1346193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1356193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final StructNdMsg ndmsg = new StructNdMsg();
1366193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        ndmsg.pack(byteBuffer);
1376193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1386193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return bytes;
1396193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1406193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1419ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    /**
1429ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline     * A convenience method to create an RTM_NEWNEIGH message, to modify
1439ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline     * the kernel's state information for a specific neighbor.
1449ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline     */
1459ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    public static byte[] newNewNeighborMessage(
1469ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
1479ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
1489ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
149cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
1509ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlmsghdr.nlmsg_seq = seqNo;
1519ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
1529ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
1539ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mNdmsg = new StructNdMsg();
1549ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mNdmsg.ndm_family =
1559ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
1569ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mNdmsg.ndm_ifindex = ifIndex;
1579ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mNdmsg.ndm_state = nudState;
1589ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mDestination = ip;
1599ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.mLinkLayerAddr = llAddr;  // might be null
1609ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
1619ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        final byte[] bytes = new byte[msg.getRequiredSpace()];
1629ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlmsghdr.nlmsg_len = bytes.length;
1639ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
1649ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        byteBuffer.order(ByteOrder.nativeOrder());
1659ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        msg.pack(byteBuffer);
1669ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        return bytes;
1679ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
1689ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
1696193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private StructNdMsg mNdmsg;
1706193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private InetAddress mDestination;
1716193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private byte[] mLinkLayerAddr;
1726193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private int mNumProbes;
1736193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private StructNdaCacheInfo mCacheInfo;
1746193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1756193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
1766193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        super(header);
1776193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        mNdmsg = null;
1786193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        mDestination = null;
1796193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        mLinkLayerAddr = null;
1806193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        mNumProbes = 0;
1816193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        mCacheInfo = null;
1826193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1836193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1846193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public StructNdMsg getNdHeader() {
1856193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return mNdmsg;
1866193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1876193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1886193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public InetAddress getDestination() {
1896193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return mDestination;
1906193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1916193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1926193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public byte[] getLinkLayerAddress() {
1936193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return mLinkLayerAddr;
1946193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1956193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
1966193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public int getProbes() {
1976193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return mNumProbes;
1986193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
1996193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
2006193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public StructNdaCacheInfo getCacheInfo() {
2016193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return mCacheInfo;
2026193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
2036193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline
2049ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    public int getRequiredSpace() {
2059ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
2069ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        if (mDestination != null) {
2079ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            spaceRequired += NetlinkConstants.alignedLengthOf(
2089ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline                    StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
2099ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
2109ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        if (mLinkLayerAddr != null) {
2119ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            spaceRequired += NetlinkConstants.alignedLengthOf(
2129ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline                    StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
2139ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
2149ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
2159ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        // attributes appended.  Fix later, if necessary.
2169ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        return spaceRequired;
2179ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
2189ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
2199ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
2209ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        final StructNlAttr nlAttr = new StructNlAttr();
2219ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlAttr.nla_type = nlType;
2229ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlAttr.nla_value = nlValue;
2239ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
2249ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        nlAttr.pack(byteBuffer);
2259ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
2269ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
2279ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    public void pack(ByteBuffer byteBuffer) {
2289ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        getHeader().pack(byteBuffer) ;
2299ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        mNdmsg.pack(byteBuffer);
2309ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
2319ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        if (mDestination != null) {
2329ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
2339ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
2349ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        if (mLinkLayerAddr != null) {
2359ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
2369ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
2379ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
2389ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
2396193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    @Override
2406193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    public String toString() {
2416193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
2426193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline        return "RtNetlinkNeighborMessage{ "
2436193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
2446193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
2456193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "destination{" + ipLiteral + "} "
2466193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
2476193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "probes{" + mNumProbes + "} "
2486193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
2496193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline                + "}";
2506193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline    }
2516193aa3305bc2aa5b7f0a983f4b08c99065cfb82Erik Kline}
252