RtNetlinkNeighborMessage.java revision 9ce5d602cd5d732ae10efe0b648b43ddf60d65c9
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 17package android.net.netlink; 18 19import android.net.netlink.StructNdaCacheInfo; 20import android.net.netlink.StructNdMsg; 21import android.net.netlink.StructNlAttr; 22import android.net.netlink.StructNlMsgHdr; 23import android.net.netlink.NetlinkMessage; 24import android.system.OsConstants; 25import android.util.Log; 26 27import java.net.InetAddress; 28import java.net.Inet6Address; 29import java.nio.ByteBuffer; 30import java.nio.ByteOrder; 31 32 33/** 34 * A NetlinkMessage subclass for netlink error messages. 35 * 36 * see also: <linux_src>/include/uapi/linux/neighbour.h 37 * 38 * @hide 39 */ 40public class RtNetlinkNeighborMessage extends NetlinkMessage { 41 public static final short NDA_UNSPEC = 0; 42 public static final short NDA_DST = 1; 43 public static final short NDA_LLADDR = 2; 44 public static final short NDA_CACHEINFO = 3; 45 public static final short NDA_PROBES = 4; 46 public static final short NDA_VLAN = 5; 47 public static final short NDA_PORT = 6; 48 public static final short NDA_VNI = 7; 49 public static final short NDA_IFINDEX = 8; 50 public static final short NDA_MASTER = 9; 51 52 private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) { 53 while (byteBuffer != null && byteBuffer.remaining() > 0) { 54 final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer); 55 if (nlAttr == null) { 56 break; 57 } 58 if (nlAttr.nla_type == attrType) { 59 return StructNlAttr.parse(byteBuffer); 60 } 61 if (byteBuffer.remaining() < nlAttr.getAlignedLength()) { 62 break; 63 } 64 byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength()); 65 } 66 return null; 67 } 68 69 public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { 70 final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header); 71 72 neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer); 73 if (neighMsg.mNdmsg == null) { 74 return null; 75 } 76 77 // Some of these are message-type dependent, and not always present. 78 final int baseOffset = byteBuffer.position(); 79 StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer); 80 if (nlAttr != null) { 81 neighMsg.mDestination = nlAttr.getValueAsInetAddress(); 82 } 83 84 byteBuffer.position(baseOffset); 85 nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer); 86 if (nlAttr != null) { 87 neighMsg.mLinkLayerAddr = nlAttr.nla_value; 88 } 89 90 byteBuffer.position(baseOffset); 91 nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer); 92 if (nlAttr != null) { 93 neighMsg.mNumProbes = nlAttr.getValueAsInt(0); 94 } 95 96 byteBuffer.position(baseOffset); 97 nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer); 98 if (nlAttr != null) { 99 neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); 100 } 101 102 final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; 103 final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( 104 neighMsg.mHeader.nlmsg_len - kMinConsumed); 105 if (byteBuffer.remaining() < kAdditionalSpace) { 106 byteBuffer.position(byteBuffer.limit()); 107 } else { 108 byteBuffer.position(baseOffset + kAdditionalSpace); 109 } 110 111 return neighMsg; 112 } 113 114 /** 115 * A convenience method to create an RTM_GETNEIGH request message. 116 */ 117 public static byte[] newGetNeighborsRequest(int seqNo) { 118 final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; 119 final byte[] bytes = new byte[length]; 120 final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); 121 byteBuffer.order(ByteOrder.nativeOrder()); 122 123 final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); 124 nlmsghdr.nlmsg_len = length; 125 nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH; 126 nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP; 127 nlmsghdr.nlmsg_seq = seqNo; 128 nlmsghdr.pack(byteBuffer); 129 130 final StructNdMsg ndmsg = new StructNdMsg(); 131 ndmsg.pack(byteBuffer); 132 133 return bytes; 134 } 135 136 /** 137 * A convenience method to create an RTM_NEWNEIGH message, to modify 138 * the kernel's state information for a specific neighbor. 139 */ 140 public static byte[] newNewNeighborMessage( 141 int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) { 142 final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); 143 nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH; 144 nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_REPLACE; 145 nlmsghdr.nlmsg_seq = seqNo; 146 147 final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr); 148 msg.mNdmsg = new StructNdMsg(); 149 msg.mNdmsg.ndm_family = 150 (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); 151 msg.mNdmsg.ndm_ifindex = ifIndex; 152 msg.mNdmsg.ndm_state = nudState; 153 msg.mDestination = ip; 154 msg.mLinkLayerAddr = llAddr; // might be null 155 156 final byte[] bytes = new byte[msg.getRequiredSpace()]; 157 nlmsghdr.nlmsg_len = bytes.length; 158 final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); 159 byteBuffer.order(ByteOrder.nativeOrder()); 160 msg.pack(byteBuffer); 161 return bytes; 162 } 163 164 private StructNdMsg mNdmsg; 165 private InetAddress mDestination; 166 private byte[] mLinkLayerAddr; 167 private int mNumProbes; 168 private StructNdaCacheInfo mCacheInfo; 169 170 private RtNetlinkNeighborMessage(StructNlMsgHdr header) { 171 super(header); 172 mNdmsg = null; 173 mDestination = null; 174 mLinkLayerAddr = null; 175 mNumProbes = 0; 176 mCacheInfo = null; 177 } 178 179 public StructNdMsg getNdHeader() { 180 return mNdmsg; 181 } 182 183 public InetAddress getDestination() { 184 return mDestination; 185 } 186 187 public byte[] getLinkLayerAddress() { 188 return mLinkLayerAddr; 189 } 190 191 public int getProbes() { 192 return mNumProbes; 193 } 194 195 public StructNdaCacheInfo getCacheInfo() { 196 return mCacheInfo; 197 } 198 199 public int getRequiredSpace() { 200 int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; 201 if (mDestination != null) { 202 spaceRequired += NetlinkConstants.alignedLengthOf( 203 StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length); 204 } 205 if (mLinkLayerAddr != null) { 206 spaceRequired += NetlinkConstants.alignedLengthOf( 207 StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length); 208 } 209 // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO 210 // attributes appended. Fix later, if necessary. 211 return spaceRequired; 212 } 213 214 private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) { 215 final StructNlAttr nlAttr = new StructNlAttr(); 216 nlAttr.nla_type = nlType; 217 nlAttr.nla_value = nlValue; 218 nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length); 219 nlAttr.pack(byteBuffer); 220 } 221 222 public void pack(ByteBuffer byteBuffer) { 223 getHeader().pack(byteBuffer) ; 224 mNdmsg.pack(byteBuffer); 225 226 if (mDestination != null) { 227 packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer); 228 } 229 if (mLinkLayerAddr != null) { 230 packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer); 231 } 232 } 233 234 @Override 235 public String toString() { 236 final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); 237 return "RtNetlinkNeighborMessage{ " 238 + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " 239 + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " 240 + "destination{" + ipLiteral + "} " 241 + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " 242 + "probes{" + mNumProbes + "} " 243 + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " 244 + "}"; 245 } 246} 247