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