• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 com.android.net.module.util.netlink;
18 
19 import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
20 import static android.system.OsConstants.AF_NETLINK;
21 import static android.system.OsConstants.EIO;
22 import static android.system.OsConstants.EPROTO;
23 import static android.system.OsConstants.ETIMEDOUT;
24 import static android.system.OsConstants.NETLINK_INET_DIAG;
25 import static android.system.OsConstants.NETLINK_ROUTE;
26 import static android.system.OsConstants.SOCK_CLOEXEC;
27 import static android.system.OsConstants.SOCK_DGRAM;
28 import static android.system.OsConstants.SOL_SOCKET;
29 import static android.system.OsConstants.SO_RCVBUF;
30 import static android.system.OsConstants.SO_RCVTIMEO;
31 import static android.system.OsConstants.SO_SNDTIMEO;
32 
33 import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
34 import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
35 import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR;
36 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
37 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
38 
39 import android.net.util.SocketUtils;
40 import android.system.ErrnoException;
41 import android.system.Os;
42 import android.system.OsConstants;
43 import android.system.StructTimeval;
44 import android.util.Log;
45 
46 import androidx.annotation.NonNull;
47 import androidx.annotation.Nullable;
48 
49 import java.io.FileDescriptor;
50 import java.io.IOException;
51 import java.io.InterruptedIOException;
52 import java.net.Inet6Address;
53 import java.net.InetAddress;
54 import java.net.SocketException;
55 import java.nio.ByteBuffer;
56 import java.nio.ByteOrder;
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.List;
60 import java.util.Objects;
61 import java.util.function.Consumer;
62 
63 /**
64  * Utilities for netlink related class that may not be able to fit into a specific class.
65  * @hide
66  */
67 public class NetlinkUtils {
68     private static final String TAG = "NetlinkUtils";
69     /** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */
70     private static final int TCP_ESTABLISHED = 1;
71     private static final int TCP_SYN_SENT = 2;
72     private static final int TCP_SYN_RECV = 3;
73 
74     public static final int TCP_ALIVE_STATE_FILTER =
75             (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV);
76 
77     public static final int UNKNOWN_MARK = 0xffffffff;
78     public static final int NULL_MASK = 0;
79 
80     // Initial mark value corresponds to the initValue in system/netd/include/Fwmark.h.
81     public static final int INIT_MARK_VALUE = 0;
82     // Corresponds to enum definition in bionic/libc/kernel/uapi/linux/inet_diag.h
83     public static final int INET_DIAG_INFO = 2;
84     public static final int INET_DIAG_MARK = 15;
85 
86     public static final long IO_TIMEOUT_MS = 3000L;
87 
88     public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
89     public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
90     public static final int SOCKET_DUMP_RECV_BUFSIZE = 128 * 1024;
91 
92     /**
93      * Return whether the input ByteBuffer contains enough remaining bytes for
94      * {@code StructNlMsgHdr}.
95      */
enoughBytesRemainForValidNlMsg(@onNull final ByteBuffer bytes)96     public static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) {
97         return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE;
98     }
99 
100     /**
101      * Parse netlink error message
102      *
103      * @param bytes byteBuffer to parse netlink error message
104      * @return NetlinkErrorMessage if bytes contains valid NetlinkErrorMessage, else {@code null}
105      */
106     @Nullable
parseNetlinkErrorMessage(ByteBuffer bytes)107     private static NetlinkErrorMessage parseNetlinkErrorMessage(ByteBuffer bytes) {
108         final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes);
109         if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) {
110             return null;
111         }
112 
113         final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
114         final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE;
115         if (payloadLength < 0 || payloadLength > bytes.remaining()) {
116             // Malformed message or runt buffer.  Pretend the buffer was consumed.
117             bytes.position(bytes.limit());
118             return null;
119         }
120 
121         return NetlinkErrorMessage.parse(nlmsghdr, bytes);
122     }
123 
124     /**
125      * Receive netlink ack message and check error
126      *
127      * @param fd fd to read netlink message
128      */
receiveNetlinkAck(final FileDescriptor fd)129     public static void receiveNetlinkAck(final FileDescriptor fd)
130             throws InterruptedIOException, ErrnoException {
131         final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS);
132         // recvMessage() guaranteed to not return null if it did not throw.
133         final NetlinkErrorMessage response = parseNetlinkErrorMessage(bytes);
134         if (response != null && response.getNlMsgError() != null) {
135             final int errno = response.getNlMsgError().error;
136             if (errno != 0) {
137                 // TODO: consider ignoring EINVAL (-22), which appears to be
138                 // normal when probing a neighbor for which the kernel does
139                 // not already have / no longer has a link layer address.
140                 Log.e(TAG, "receiveNetlinkAck, errmsg=" + response.toString());
141                 // Note: convert kernel errnos (negative) into userspace errnos (positive).
142                 throw new ErrnoException(response.toString(), Math.abs(errno));
143             }
144         } else {
145             final String errmsg;
146             if (response == null) {
147                 bytes.position(0);
148                 errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
149             } else {
150                 errmsg = response.toString();
151             }
152             Log.e(TAG, "receiveNetlinkAck, errmsg=" + errmsg);
153             throw new ErrnoException(errmsg, EPROTO);
154         }
155     }
156 
157     /**
158      * Send one netlink message to kernel via netlink socket.
159      *
160      * @param nlProto netlink protocol type.
161      * @param msg the raw bytes of netlink message to be sent.
162      */
sendOneShotKernelMessage(int nlProto, byte[] msg)163     public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
164         final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
165         final FileDescriptor fd = netlinkSocketForProto(nlProto, SOCKET_RECV_BUFSIZE);
166 
167         try {
168             connectToKernel(fd);
169             sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS);
170             receiveNetlinkAck(fd);
171         } catch (InterruptedIOException e) {
172             Log.e(TAG, errPrefix, e);
173             throw new ErrnoException(errPrefix, ETIMEDOUT, e);
174         } catch (SocketException e) {
175             Log.e(TAG, errPrefix, e);
176             throw new ErrnoException(errPrefix, EIO, e);
177         } finally {
178             closeSocketQuietly(fd);
179         }
180     }
181 
182     /**
183      * Send an RTM_NEWADDR message to kernel to add or update an IP address.
184      *
185      * @param ifIndex interface index.
186      * @param ip IP address to be added.
187      * @param prefixlen IP address prefix length.
188      * @param flags IP address flags.
189      * @param scope IP address scope.
190      * @param preferred The preferred lifetime of IP address.
191      * @param valid The valid lifetime of IP address.
192      */
sendRtmNewAddressRequest(int ifIndex, @NonNull final InetAddress ip, short prefixlen, int flags, byte scope, long preferred, long valid)193     public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final InetAddress ip,
194             short prefixlen, int flags, byte scope, long preferred, long valid) {
195         Objects.requireNonNull(ip, "IP address to be added should not be null.");
196         final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip,
197                 prefixlen, flags, scope, ifIndex, preferred, valid);
198         try {
199             NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
200             return true;
201         } catch (ErrnoException e) {
202             Log.e(TAG, "Fail to send RTM_NEWADDR to add " + ip.getHostAddress(), e);
203             return false;
204         }
205     }
206 
207     /**
208      * Send an RTM_DELADDR message to kernel to delete an IPv6 address.
209      *
210      * @param ifIndex interface index.
211      * @param ip IPv6 address to be deleted.
212      * @param prefixlen IPv6 address prefix length.
213      */
sendRtmDelAddressRequest(int ifIndex, final Inet6Address ip, short prefixlen)214     public static boolean sendRtmDelAddressRequest(int ifIndex, final Inet6Address ip,
215             short prefixlen) {
216         Objects.requireNonNull(ip, "IPv6 address to be deleted should not be null.");
217         final byte[] msg = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqNo*/, ip,
218                 prefixlen, ifIndex);
219         try {
220             NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
221             return true;
222         } catch (ErrnoException e) {
223             Log.e(TAG, "Fail to send RTM_DELADDR to delete " + ip.getHostAddress(), e);
224             return false;
225         }
226     }
227 
228     /**
229      * Create netlink socket with the given netlink protocol type and buffersize.
230      *
231      * @param nlProto the netlink protocol
232      * @param bufferSize the receive buffer size to set when the value is not 0
233      *
234      * @return fd the fileDescriptor of the socket.
235      * @throws ErrnoException if the FileDescriptor not connect to be created successfully
236      */
netlinkSocketForProto(int nlProto, int bufferSize)237     public static FileDescriptor netlinkSocketForProto(int nlProto, int bufferSize)
238             throws ErrnoException {
239         final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, nlProto);
240         if (bufferSize > 0) {
241             Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, bufferSize);
242         }
243         return fd;
244     }
245 
246     /**
247      * Create netlink socket with the given netlink protocol type. Receive buffer size is not set.
248      *
249      * @param nlProto the netlink protocol
250      *
251      * @return fd the fileDescriptor of the socket.
252      * @throws ErrnoException if the FileDescriptor not connect to be created successfully
253      */
netlinkSocketForProto(int nlProto)254     public static FileDescriptor netlinkSocketForProto(int nlProto)
255             throws ErrnoException {
256         return netlinkSocketForProto(nlProto, 0);
257     }
258 
259     /**
260      * Construct a netlink inet_diag socket.
261      */
createNetLinkInetDiagSocket()262     public static FileDescriptor createNetLinkInetDiagSocket() throws ErrnoException {
263         return netlinkSocketForProto(NETLINK_INET_DIAG);
264     }
265 
266     /**
267      * Connect the given file descriptor to the Netlink interface to the kernel.
268      *
269      * The fd must be a SOCK_DGRAM socket : create it with {@link #netlinkSocketForProto}
270      *
271      * @throws ErrnoException if the {@code fd} could not connect to kernel successfully
272      * @throws SocketException if there is an error accessing a socket.
273      */
connectToKernel(@onNull FileDescriptor fd)274     public static void connectToKernel(@NonNull FileDescriptor fd)
275             throws ErrnoException, SocketException {
276         Os.connect(fd, makeNetlinkSocketAddress(0, 0));
277     }
278 
checkTimeout(long timeoutMs)279     private static void checkTimeout(long timeoutMs) {
280         if (timeoutMs < 0) {
281             throw new IllegalArgumentException("Negative timeouts not permitted");
282         }
283     }
284 
285     /**
286      * Wait up to |timeoutMs| (or until underlying socket error) for a
287      * netlink message of at most |bufsize| size.
288      *
289      * Multi-threaded calls with different timeouts will cause unexpected results.
290      */
recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)291     public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
292             throws ErrnoException, IllegalArgumentException, InterruptedIOException {
293         checkTimeout(timeoutMs);
294 
295         Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
296 
297         final ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
298         final int length = Os.read(fd, byteBuffer);
299         if (length == bufsize) {
300             Log.w(TAG, "maximum read");
301         }
302         byteBuffer.position(0);
303         byteBuffer.limit(length);
304         byteBuffer.order(ByteOrder.nativeOrder());
305         return byteBuffer;
306     }
307 
308     /**
309      * Send a message to a peer to which this socket has previously connected.
310      *
311      * This waits at most |timeoutMs| milliseconds for the send to complete, will get the exception
312      * if it times out.
313      */
sendMessage( FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)314     public static int sendMessage(
315             FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
316             throws ErrnoException, IllegalArgumentException, InterruptedIOException {
317         checkTimeout(timeoutMs);
318         Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
319         return Os.write(fd, bytes, offset, count);
320     }
321 
322     private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
323 
324     /**
325      * Convert the system time in clock ticks(clock_t type in times(), not in clock()) to
326      * milliseconds. times() clock_t ticks at the kernel's USER_HZ (100) while clock() clock_t
327      * ticks at CLOCKS_PER_SEC (1000000).
328      *
329      * See the NOTES on https://man7.org/linux/man-pages/man2/times.2.html for the difference
330      * of clock_t used in clock() and times().
331      */
ticksToMilliSeconds(int intClockTicks)332     public static long ticksToMilliSeconds(int intClockTicks) {
333         final long longClockTicks = intClockTicks & 0xffffffffL;
334         return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
335     }
336 
NetlinkUtils()337     private NetlinkUtils() {}
338 
getAndProcessNetlinkDumpMessagesWithFd( FileDescriptor fd, byte[] dumpRequestMessage, int nlFamily, Class<T> msgClass, Consumer<T> func)339     private static <T extends NetlinkMessage> void getAndProcessNetlinkDumpMessagesWithFd(
340             FileDescriptor fd, byte[] dumpRequestMessage, int nlFamily, Class<T> msgClass,
341             Consumer<T> func)
342             throws SocketException, InterruptedIOException, ErrnoException {
343         // connecToKernel throws ErrnoException and SocketException, should be handled by caller
344         connectToKernel(fd);
345 
346         // sendMessage throws InterruptedIOException and ErrnoException,
347         // should be handled by caller
348         sendMessage(fd, dumpRequestMessage, 0, dumpRequestMessage.length, IO_TIMEOUT_MS);
349 
350         while (true) {
351             // recvMessage throws ErrnoException, InterruptedIOException
352             // should be handled by caller
353             final ByteBuffer buf = recvMessage(
354                     fd, NetlinkUtils.DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS);
355 
356             while (buf.remaining() > 0) {
357                 final int position = buf.position();
358                 final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, nlFamily);
359                 if (nlMsg == null) {
360                     // Move to the position where parse started for error log.
361                     buf.position(position);
362                     Log.e(TAG, "Failed to parse netlink message: " + hexify(buf));
363                     break;
364                 }
365 
366                 if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) {
367                     return;
368                 }
369 
370                 if (!msgClass.isInstance(nlMsg)) {
371                     Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg);
372                     continue;
373                 }
374 
375                 final T msg = (T) nlMsg;
376                 func.accept(msg);
377             }
378         }
379     }
380     /**
381      * Sends a netlink dump request and processes the returned dump messages
382      *
383      * @param <T> extends NetlinkMessage
384      * @param dumpRequestMessage netlink dump request message to be sent
385      * @param nlFamily netlink family
386      * @param msgClass expected class of the netlink message
387      * @param func function defined by caller to handle the dump messages
388      * @throws SocketException when fails to connect socket to kernel
389      * @throws InterruptedIOException when fails to read the dumpFd
390      * @throws ErrnoException when fails to create dump fd, send dump request
391      *                        or receive messages
392      */
getAndProcessNetlinkDumpMessages( byte[] dumpRequestMessage, int nlFamily, Class<T> msgClass, Consumer<T> func)393     public static <T extends NetlinkMessage> void getAndProcessNetlinkDumpMessages(
394             byte[] dumpRequestMessage, int nlFamily, Class<T> msgClass,
395             Consumer<T> func)
396             throws SocketException, InterruptedIOException, ErrnoException {
397         // Create socket
398         final FileDescriptor fd = netlinkSocketForProto(nlFamily, SOCKET_DUMP_RECV_BUFSIZE);
399         try {
400             getAndProcessNetlinkDumpMessagesWithFd(fd, dumpRequestMessage, nlFamily,
401                     msgClass, func);
402         } finally {
403             closeSocketQuietly(fd);
404         }
405     }
406 
407     /**
408      * Construct a RTM_GETROUTE message for dumping multicast IPv6 routes from kernel.
409      */
newIpv6MulticastRouteDumpRequest()410     private static byte[] newIpv6MulticastRouteDumpRequest() {
411         final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
412         nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETROUTE;
413         nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
414         final short shortZero = 0;
415 
416         // family must be RTNL_FAMILY_IP6MR to dump IPv6 multicast routes.
417         // dstLen, srcLen, tos and scope must be zero in FIB dump request.
418         // protocol, flags must be 0, and type must be RTN_MULTICAST (if not 0) for multicast
419         // dump request.
420         // table or RTA_TABLE attributes can be used to dump a specific routing table.
421         // RTA_OIF attribute can be used to dump only routes containing given oif.
422         // Here no attributes are set so the kernel can return all multicast routes.
423         final StructRtMsg rtMsg =
424                 new StructRtMsg(RTNL_FAMILY_IP6MR /* family */, shortZero /* dstLen */,
425                         shortZero /* srcLen */, shortZero /* tos */, shortZero /* table */,
426                         shortZero /* protocol */, shortZero /* scope */, shortZero /* type */,
427                         0L /* flags */);
428         final RtNetlinkRouteMessage msg =
429             new RtNetlinkRouteMessage(nlmsghdr, rtMsg);
430 
431         final int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructRtMsg.STRUCT_SIZE;
432         nlmsghdr.nlmsg_len = spaceRequired;
433         final byte[] bytes = new byte[NetlinkConstants.alignedLengthOf(spaceRequired)];
434         final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
435         byteBuffer.order(ByteOrder.nativeOrder());
436         msg.pack(byteBuffer);
437         return bytes;
438      }
439 
440     /**
441      * Get the list of IPv6 multicast route messages from kernel.
442      */
getIpv6MulticastRoutes()443     public static List<RtNetlinkRouteMessage> getIpv6MulticastRoutes() {
444         final byte[] dumpMsg = newIpv6MulticastRouteDumpRequest();
445         List<RtNetlinkRouteMessage> routes = new ArrayList<>();
446         Consumer<RtNetlinkRouteMessage> handleNlDumpMsg = (msg) -> {
447             if (msg.getRtmFamily() == RTNL_FAMILY_IP6MR) {
448                 // Sent rtmFamily RTNL_FAMILY_IP6MR in dump request to make sure ipv6
449                 // multicast routes are included in netlink reply messages, the kernel
450                 // may also reply with other kind of routes, so we filter them out here.
451                 routes.add(msg);
452             }
453         };
454         try {
455             NetlinkUtils.<RtNetlinkRouteMessage>getAndProcessNetlinkDumpMessages(
456                     dumpMsg, NETLINK_ROUTE, RtNetlinkRouteMessage.class,
457                     handleNlDumpMsg);
458         } catch (SocketException | InterruptedIOException | ErrnoException e) {
459             Log.e(TAG, "Failed to dump multicast routes");
460             return routes;
461         }
462 
463         return routes;
464     }
465 
closeSocketQuietly(final FileDescriptor fd)466     private static void closeSocketQuietly(final FileDescriptor fd) {
467         try {
468             SocketUtils.closeSocket(fd);
469         } catch (IOException e) {
470             // Nothing we can do here
471         }
472     }
473 
474     /**
475      * Sends a netlink request to set flags for given interface
476      *
477      * @param interfaceName The name of the network interface to query.
478      * @param flags power-of-two integer flags to set or unset. A flag to set should be passed as
479      *        is as a power-of-two value, and a flag to remove should be passed inversed as -1 with
480      *        a single bit down. For example: IFF_UP, ~IFF_BROADCAST...
481      * @return true if the request finished successfully, otherwise false.
482      */
setInterfaceFlags(@onNull String interfaceName, int... flags)483     public static boolean setInterfaceFlags(@NonNull String interfaceName, int... flags) {
484         final RtNetlinkLinkMessage ntMsg =
485                 RtNetlinkLinkMessage.createSetFlagsMessage(interfaceName, /*seqNo*/ 0, flags);
486         if (ntMsg == null) {
487             Log.e(TAG, "Failed to create message to set interface flags for interface "
488                     + interfaceName + ", input flags are: " + Arrays.toString(flags));
489             return false;
490         }
491         final byte[] msg = ntMsg.pack(ByteOrder.nativeOrder());
492         try {
493             NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
494             return true;
495         } catch (ErrnoException e) {
496             Log.e(TAG, "Failed to set flags for: " + interfaceName, e);
497             return false;
498         }
499     }
500 
501     /**
502      * Sends a netlink request to set MTU for given interface
503      *
504      * @param interfaceName The name of the network interface to query.
505      * @param mtu MTU value to set for the interface.
506      * @return true if the request finished successfully, otherwise false.
507      */
setInterfaceMtu(@onNull String interfaceName, int mtu)508     public static boolean setInterfaceMtu(@NonNull String interfaceName, int mtu) {
509         if (mtu < 68) {
510             Log.e(TAG, "Invalid mtu: " + mtu + ", mtu should be greater than 68 referring RFC791");
511             return false;
512         }
513         final RtNetlinkLinkMessage ntMsg =
514                 RtNetlinkLinkMessage.createSetMtuMessage(interfaceName, /*seqNo*/ 0, mtu);
515         if (ntMsg == null) {
516             Log.e(TAG, "Failed to create message to set MTU to " + mtu
517                     + "for interface " + interfaceName);
518             return false;
519         }
520         final byte[] msg = ntMsg.pack(ByteOrder.nativeOrder());
521         try {
522             NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
523             return true;
524         } catch (ErrnoException e) {
525             Log.e(TAG, "Failed to set MTU to " + mtu + " for: " + interfaceName, e);
526             return false;
527         }
528     }
529 }
530