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