1 /*
2  * Copyright (C) 2021 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 android.net.MacAddress;
20 import android.system.OsConstants;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 import androidx.annotation.VisibleForTesting;
25 
26 import java.nio.ByteBuffer;
27 
28 /**
29  * A NetlinkMessage subclass for rtnetlink link messages.
30  *
31  * RtNetlinkLinkMessage.parse() must be called with a ByteBuffer that contains exactly one netlink
32  * message.
33  *
34  * see also:
35  *
36  *     include/uapi/linux/rtnetlink.h
37  *
38  * @hide
39  */
40 public class RtNetlinkLinkMessage extends NetlinkMessage {
41     public static final short IFLA_ADDRESS   = 1;
42     public static final short IFLA_IFNAME    = 3;
43     public static final short IFLA_MTU       = 4;
44     public static final short IFLA_INET6_ADDR_GEN_MODE = 8;
45     public static final short IFLA_AF_SPEC = 26;
46 
47     public static final short IN6_ADDR_GEN_MODE_NONE = 1;
48 
49     private int mMtu;
50     @NonNull
51     private StructIfinfoMsg mIfinfomsg;
52     @Nullable
53     private MacAddress mHardwareAddress;
54     @Nullable
55     private String mInterfaceName;
56 
RtNetlinkLinkMessage(@onNull StructNlMsgHdr header)57     private RtNetlinkLinkMessage(@NonNull StructNlMsgHdr header) {
58         super(header);
59         mIfinfomsg = null;
60         mMtu = 0;
61         mHardwareAddress = null;
62         mInterfaceName = null;
63     }
64 
getMtu()65     public int getMtu() {
66         return mMtu;
67     }
68 
69     @NonNull
getIfinfoHeader()70     public StructIfinfoMsg getIfinfoHeader() {
71         return mIfinfomsg;
72     }
73 
74     @Nullable
getHardwareAddress()75     public MacAddress getHardwareAddress() {
76         return mHardwareAddress;
77     }
78 
79     @Nullable
getInterfaceName()80     public String getInterfaceName() {
81         return mInterfaceName;
82     }
83 
84     /**
85      * Parse rtnetlink link message from {@link ByteBuffer}. This method must be called with a
86      * ByteBuffer that contains exactly one netlink message.
87      *
88      * @param header netlink message header.
89      * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes.
90      */
91     @Nullable
parse(@onNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer)92     public static RtNetlinkLinkMessage parse(@NonNull final StructNlMsgHdr header,
93             @NonNull final ByteBuffer byteBuffer) {
94         final RtNetlinkLinkMessage linkMsg = new RtNetlinkLinkMessage(header);
95 
96         linkMsg.mIfinfomsg = StructIfinfoMsg.parse(byteBuffer);
97         if (linkMsg.mIfinfomsg == null) return null;
98 
99         // IFLA_MTU
100         final int baseOffset = byteBuffer.position();
101         StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFLA_MTU, byteBuffer);
102         if (nlAttr != null) {
103             linkMsg.mMtu = nlAttr.getValueAsInt(0 /* default value */);
104         }
105 
106         // IFLA_ADDRESS
107         byteBuffer.position(baseOffset);
108         nlAttr = StructNlAttr.findNextAttrOfType(IFLA_ADDRESS, byteBuffer);
109         if (nlAttr != null) {
110             linkMsg.mHardwareAddress = nlAttr.getValueAsMacAddress();
111         }
112 
113         // IFLA_IFNAME
114         byteBuffer.position(baseOffset);
115         nlAttr = StructNlAttr.findNextAttrOfType(IFLA_IFNAME, byteBuffer);
116         if (nlAttr != null) {
117             linkMsg.mInterfaceName = nlAttr.getValueAsString();
118         }
119 
120         return linkMsg;
121     }
122 
123     /**
124      * Write a rtnetlink link message to {@link ByteBuffer}.
125      */
126     @VisibleForTesting
pack(ByteBuffer byteBuffer)127     protected void pack(ByteBuffer byteBuffer) {
128         getHeader().pack(byteBuffer);
129         mIfinfomsg.pack(byteBuffer);
130 
131         if (mMtu != 0) {
132             final StructNlAttr mtu = new StructNlAttr(IFLA_MTU, mMtu);
133             mtu.pack(byteBuffer);
134         }
135         if (mHardwareAddress != null) {
136             final StructNlAttr hardwareAddress = new StructNlAttr(IFLA_ADDRESS, mHardwareAddress);
137             hardwareAddress.pack(byteBuffer);
138         }
139         if (mInterfaceName != null) {
140             final StructNlAttr ifname = new StructNlAttr(IFLA_IFNAME, mInterfaceName);
141             ifname.pack(byteBuffer);
142         }
143     }
144 
145     @Override
toString()146     public String toString() {
147         return "RtNetlinkLinkMessage{ "
148                 + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, "
149                 + "Ifinfomsg{" + mIfinfomsg.toString() + "}, "
150                 + "Hardware Address{" + mHardwareAddress + "}, "
151                 + "MTU{" + mMtu + "}, "
152                 + "Ifname{" + mInterfaceName + "} "
153                 + "}";
154     }
155 }
156