1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ip;
import static android.net.netlink.NetlinkConstants.hexify;
import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
import static android.system.OsConstants.AF_NETLINK;
import static android.system.OsConstants.SOCK_DGRAM;
import static android.system.OsConstants.SOCK_NONBLOCK;
import android.annotation.NonNull;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
import android.net.netlink.NetlinkSocket;
import android.net.util.PacketReader;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
import android.os.Handler;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* A simple base class to listen for netlink broadcasts.
*
* Opens a netlink socket of the given family and binds to the specified groups. Polls the socket
* from the event loop of the passed-in {@link Handler}, and calls the subclass-defined
* {@link #processNetlinkMessage} method on the handler thread for each netlink message that
* arrives. Currently ignores all netlink errors.
*/
public class NetlinkMonitor extends PacketReader {
protected final SharedLog mLog;
protected final String mTag;
private final int mFamily;
private final int mBindGroups;
private static final boolean DBG = false;
/**
* Constructs a new {@code NetlinkMonitor} instance.
*
* @param h The Handler on which to poll for messages and on which to call
* {@link #processNetlinkMessage}.
* @param log A SharedLog to log to.
* @param tag The log tag to use for log messages.
* @param family the Netlink socket family to, e.g., {@code NETLINK_ROUTE}.
* @param bindGroups the netlink groups to bind to.
*/
public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag,
int family, int bindGroups) {
super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
mLog = log.forSubComponent(tag);
mTag = tag;
mFamily = family;
mBindGroups = bindGroups;
}
@Override
protected FileDescriptor createFd() {
FileDescriptor fd = null;
try {
fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, mFamily);
Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups));
NetlinkSocket.connectToKernel(fd);
if (DBG) {
final SocketAddress nlAddr = Os.getsockname(fd);
Log.d(mTag, "bound to sockaddr_nl{" + nlAddr.toString() + "}");
}
} catch (ErrnoException | SocketException e) {
logError("Failed to create rtnetlink socket", e);
closeSocketQuietly(fd);
return null;
}
return fd;
}
@Override
protected void handlePacket(byte[] recvbuf, int length) {
final long whenMs = SystemClock.elapsedRealtime();
final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
byteBuffer.order(ByteOrder.nativeOrder());
while (byteBuffer.remaining() > 0) {
try {
final int position = byteBuffer.position();
final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
if (nlMsg == null || nlMsg.getHeader() == null) {
byteBuffer.position(position);
mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
break;
}
if (nlMsg instanceof NetlinkErrorMessage) {
mLog.e("netlink error: " + nlMsg);
continue;
}
processNetlinkMessage(nlMsg, whenMs);
} catch (Exception e) {
mLog.e("Error handling netlink message", e);
}
}
}
// TODO: move NetworkStackUtils to frameworks/libs/net for NetworkStackUtils#closeSocketQuietly.
private void closeSocketQuietly(FileDescriptor fd) {
try {
SocketUtils.closeSocket(fd);
} catch (IOException ignored) {
}
}
/**
* Processes one netlink message. Must be overridden by subclasses.
* @param nlMsg the message to process.
* @param whenMs the timestamp, as measured by {@link SystemClock#elapsedRealtime}, when the
* message was received.
*/
protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { }
}
|