blob: d4b572cd7d17625112a9ff6ae2016d57df5e383f [file] [log] [blame]
Erik Kline6193aa32015-01-20 12:28:26 +09001/*
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.util.Log;
25
26import java.net.InetAddress;
27import java.nio.ByteBuffer;
28import java.nio.ByteOrder;
29
30
31/**
32 * A NetlinkMessage subclass for netlink error messages.
33 *
34 * see also: <linux_src>/include/uapi/linux/neighbour.h
35 *
36 * @hide
37 */
38public class RtNetlinkNeighborMessage extends NetlinkMessage {
39 public static final short NDA_UNSPEC = 0;
40 public static final short NDA_DST = 1;
41 public static final short NDA_LLADDR = 2;
42 public static final short NDA_CACHEINFO = 3;
43 public static final short NDA_PROBES = 4;
44 public static final short NDA_VLAN = 5;
45 public static final short NDA_PORT = 6;
46 public static final short NDA_VNI = 7;
47 public static final short NDA_IFINDEX = 8;
48 public static final short NDA_MASTER = 9;
49
50 private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
51 while (byteBuffer != null && byteBuffer.remaining() > 0) {
52 final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
53 if (nlAttr == null) {
54 break;
55 }
56 if (nlAttr.nla_type == attrType) {
57 return StructNlAttr.parse(byteBuffer);
58 }
59 if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
60 break;
61 }
62 byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
63 }
64 return null;
65 }
66
67 public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
68 final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
69
70 neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
71 if (neighMsg.mNdmsg == null) {
72 return null;
73 }
74
75 // Some of these are message-type dependent, and not always present.
76 final int baseOffset = byteBuffer.position();
77 StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
78 if (nlAttr != null) {
79 neighMsg.mDestination = nlAttr.getValueAsInetAddress();
80 }
81
82 byteBuffer.position(baseOffset);
83 nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
84 if (nlAttr != null) {
85 neighMsg.mLinkLayerAddr = nlAttr.nla_value;
86 }
87
88 byteBuffer.position(baseOffset);
89 nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
90 if (nlAttr != null) {
91 neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
92 }
93
94 byteBuffer.position(baseOffset);
95 nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
96 if (nlAttr != null) {
97 neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
98 }
99
100 final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
101 final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
102 neighMsg.mHeader.nlmsg_len - kMinConsumed);
103 if (byteBuffer.remaining() < kAdditionalSpace) {
104 byteBuffer.position(byteBuffer.limit());
105 } else {
106 byteBuffer.position(baseOffset + kAdditionalSpace);
107 }
108
109 return neighMsg;
110 }
111
112 /**
113 * A convenience method to create an RTM_GETNEIGH request message.
114 */
115 public static byte[] newGetNeighborsRequest(int seqNo) {
116 final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
117 final byte[] bytes = new byte[length];
118 final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
119 byteBuffer.order(ByteOrder.nativeOrder());
120
121 final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
122 nlmsghdr.nlmsg_len = length;
123 nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
124 nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP;
125 nlmsghdr.nlmsg_seq = seqNo;
126 nlmsghdr.pack(byteBuffer);
127
128 final StructNdMsg ndmsg = new StructNdMsg();
129 ndmsg.pack(byteBuffer);
130
131 return bytes;
132 }
133
134 private StructNdMsg mNdmsg;
135 private InetAddress mDestination;
136 private byte[] mLinkLayerAddr;
137 private int mNumProbes;
138 private StructNdaCacheInfo mCacheInfo;
139
140 private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
141 super(header);
142 mNdmsg = null;
143 mDestination = null;
144 mLinkLayerAddr = null;
145 mNumProbes = 0;
146 mCacheInfo = null;
147 }
148
149 public StructNdMsg getNdHeader() {
150 return mNdmsg;
151 }
152
153 public InetAddress getDestination() {
154 return mDestination;
155 }
156
157 public byte[] getLinkLayerAddress() {
158 return mLinkLayerAddr;
159 }
160
161 public int getProbes() {
162 return mNumProbes;
163 }
164
165 public StructNdaCacheInfo getCacheInfo() {
166 return mCacheInfo;
167 }
168
169 @Override
170 public String toString() {
171 final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
172 return "RtNetlinkNeighborMessage{ "
173 + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
174 + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
175 + "destination{" + ipLiteral + "} "
176 + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
177 + "probes{" + mNumProbes + "} "
178 + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
179 + "}";
180 }
181}