184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline/* 284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Copyright (C) 2017 The Android Open Source Project 384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Licensed under the Apache License, Version 2.0 (the "License"); 584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * you may not use this file except in compliance with the License. 684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * You may obtain a copy of the License at 784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * http://www.apache.org/licenses/LICENSE-2.0 984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 1084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Unless required by applicable law or agreed to in writing, software 1184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * distributed under the License is distributed on an "AS IS" BASIS, 1284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * See the License for the specific language governing permissions and 1484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * limitations under the License. 1584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline */ 1684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 1784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klinepackage android.net.ip; 1884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 198bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Klineimport static android.net.netlink.NetlinkConstants.hexify; 208bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Klineimport static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; 218bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Klineimport static android.net.netlink.NetlinkConstants.stringForNlMsgType; 228bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline 238bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Klineimport android.net.MacAddress; 2484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.NetlinkErrorMessage; 2584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.NetlinkMessage; 2684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.NetlinkSocket; 2784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.RtNetlinkNeighborMessage; 2884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.StructNdMsg; 2984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.netlink.StructNlMsgHdr; 3084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.util.PacketReader; 3184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.net.util.SharedLog; 3284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.os.Handler; 3384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.os.SystemClock; 3484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.system.ErrnoException; 3584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.system.NetlinkSocketAddress; 3684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.system.Os; 3784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.system.OsConstants; 3884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport android.util.Log; 3984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 4084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport com.android.internal.util.BitUtils; 4184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 4284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport libcore.io.IoUtils; 4384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport libcore.io.Libcore; 4484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 4584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.io.FileDescriptor; 4684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.net.InetAddress; 4784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.net.SocketAddress; 4884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.net.SocketException; 4984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.nio.ByteBuffer; 5084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.nio.ByteOrder; 5184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport java.util.StringJoiner; 5284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 5384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 5484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline/** 5584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * IpNeighborMonitor. 5684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 5784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Monitors the kernel rtnetlink neighbor notifications and presents to callers 5884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * NeighborEvents describing each event. Callers can provide a consumer instance 5984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * to both filter (e.g. by interface index and IP address) and handle the 6084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * generated NeighborEvents. 6184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 6284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * @hide 6384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline */ 6484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klinepublic class IpNeighborMonitor extends PacketReader { 6584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private static final String TAG = IpNeighborMonitor.class.getSimpleName(); 6684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private static final boolean DBG = false; 6784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private static final boolean VDBG = false; 6884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 6984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline /** 7084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) 7184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * for the given IP address on the specified interface index. 7284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * 7384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * @return 0 if the request was successfully passed to the kernel; otherwise return 7484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * a non-zero error code. 7584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline */ 7684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { 7784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; 7884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (DBG) { Log.d(TAG, msgSnippet); } 7984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 8084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( 8184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); 8284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 8384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline try { 8484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg); 8584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } catch (ErrnoException e) { 8684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Log.e(TAG, "Error " + msgSnippet + ": " + e); 8784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return -e.errno; 8884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 8984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 9084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return 0; 9184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 9284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 9384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public static class NeighborEvent { 9484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final long elapsedMs; 9584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final short msgType; 9684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final int ifindex; 9784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final InetAddress ip; 9884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final short nudState; 998bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline final MacAddress macAddr; 10084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 10184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, 1028bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline short nudState, MacAddress macAddr) { 10384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline this.elapsedMs = elapsedMs; 10484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline this.msgType = msgType; 10584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline this.ifindex = ifindex; 10684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline this.ip = ip; 10784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline this.nudState = nudState; 1088bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline this.macAddr = macAddr; 10984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 11084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 11184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline boolean isConnected() { 1128bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); 11384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 11484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 11584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline boolean isValid() { 1168bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); 11784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 11884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 11984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline @Override 12084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public String toString() { 12184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); 12284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return j.add("@" + elapsedMs) 1238bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline .add(stringForNlMsgType(msgType)) 12484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline .add("if=" + ifindex) 12584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline .add(ip.getHostAddress()) 12684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline .add(StructNdMsg.stringForNudState(nudState)) 1278bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline .add("[" + macAddr + "]") 12884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline .toString(); 12984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 13084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 13184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 13284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public interface NeighborEventConsumer { 13384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline // Every neighbor event received on the netlink socket is passed in 13484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline // here. Subclasses should filter for events of interest. 13584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public void accept(NeighborEvent event); 13684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 13784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 13884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private final SharedLog mLog; 13984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private final NeighborEventConsumer mConsumer; 14084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 14184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { 14284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); 14384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mLog = log.forSubComponent(TAG); 14484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; 14584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 14684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 14784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline @Override 14884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline protected FileDescriptor createFd() { 14984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline FileDescriptor fd = null; 15084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 15184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline try { 15284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE); 15384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH))); 15484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0))); 15584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 15684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (VDBG) { 15784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd); 15884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Log.d(TAG, "bound to sockaddr_nl{" 15984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline + BitUtils.uint32(nlAddr.getPortId()) + ", " 16084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline + nlAddr.getGroupsMask() 16184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline + "}"); 16284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 16384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } catch (ErrnoException|SocketException e) { 16484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline logError("Failed to create rtnetlink socket", e); 16584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline IoUtils.closeQuietly(fd); 16684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return null; 16784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 16884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 16984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return fd; 17084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 17184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 17284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline @Override 17384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline protected void handlePacket(byte[] recvbuf, int length) { 17484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final long whenMs = SystemClock.elapsedRealtime(); 17584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 17684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); 17784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline byteBuffer.order(ByteOrder.nativeOrder()); 17884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 17984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline parseNetlinkMessageBuffer(byteBuffer, whenMs); 18084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 18184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 18284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) { 18384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline while (byteBuffer.remaining() > 0) { 18484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final int position = byteBuffer.position(); 18584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); 18684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (nlMsg == null || nlMsg.getHeader() == null) { 18784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline byteBuffer.position(position); 1888bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); 18984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline break; 19084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 19184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 19284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final int srcPortId = nlMsg.getHeader().nlmsg_pid; 19384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (srcPortId != 0) { 19484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId)); 19584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline break; 19684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 19784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 19884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (nlMsg instanceof NetlinkErrorMessage) { 19984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mLog.e("netlink error: " + nlMsg); 20084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline continue; 20184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { 20284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mLog.i("non-rtnetlink neighbor msg: " + nlMsg); 20384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline continue; 20484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 20584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 20684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs); 20784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 20884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 20984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 21084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline private void evaluateRtNetlinkNeighborMessage( 21184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline RtNetlinkNeighborMessage neighMsg, long whenMs) { 21284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final short msgType = neighMsg.getHeader().nlmsg_type; 21384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final StructNdMsg ndMsg = neighMsg.getNdHeader(); 21484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (ndMsg == null) { 21584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mLog.e("RtNetlinkNeighborMessage without ND message header!"); 21684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline return; 21784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 21884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 21984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final int ifindex = ndMsg.ndm_ifindex; 22084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final InetAddress destination = neighMsg.getDestination(); 22184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final short nudState = 2228bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline (msgType == RTM_DELNEIGH) 22384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline ? StructNdMsg.NUD_NONE 22484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline : ndMsg.ndm_state; 22584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 22684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline final NeighborEvent event = new NeighborEvent( 2278bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline whenMs, msgType, ifindex, destination, nudState, 2288bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline getMacAddress(neighMsg.getLinkLayerAddress())); 22984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 23084714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (VDBG) { 23184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Log.d(TAG, neighMsg.toString()); 23284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 23384714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline if (DBG) { 23484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline Log.d(TAG, event.toString()); 23584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 23684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline 23784714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline mConsumer.accept(event); 23884714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline } 2398bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline 2408bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline private static MacAddress getMacAddress(byte[] linkLayerAddress) { 2418bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline if (linkLayerAddress != null) { 2428bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline try { 2438bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline return MacAddress.fromBytes(linkLayerAddress); 2448bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline } catch (IllegalArgumentException e) { 2458bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); 2468bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline } 2478bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline } 2488bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline 2498bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline return null; 2508bd00d5f7ced34a45173e45537dc3100d62ee6a5Erik Kline } 25184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline} 252