1 /*
2  * Copyright (C) 2019 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 android.net.netlink;
18 
19 import java.nio.ByteBuffer;
20 
21 
22 /**
23  * struct nlmsghdr
24  *
25  * see <linux_src>/include/uapi/linux/netlink.h
26  *
27  * @hide
28  */
29 public class StructNlMsgHdr {
30     // Already aligned.
31     public static final int STRUCT_SIZE = 16;
32 
33     public static final short NLM_F_REQUEST = 0x0001;
34     public static final short NLM_F_MULTI   = 0x0002;
35     public static final short NLM_F_ACK     = 0x0004;
36     public static final short NLM_F_ECHO    = 0x0008;
37     // Flags for a GET request.
38     public static final short NLM_F_ROOT    = 0x0100;
39     public static final short NLM_F_MATCH   = 0x0200;
40     public static final short NLM_F_DUMP    = NLM_F_ROOT|NLM_F_MATCH;
41     // Flags for a NEW request.
42     public static final short NLM_F_REPLACE   = 0x100;
43     public static final short NLM_F_EXCL      = 0x200;
44     public static final short NLM_F_CREATE    = 0x400;
45     public static final short NLM_F_APPEND    = 0x800;
46 
47 
stringForNlMsgFlags(short flags)48     public static String stringForNlMsgFlags(short flags) {
49         final StringBuilder sb = new StringBuilder();
50         if ((flags & NLM_F_REQUEST) != 0) {
51             sb.append("NLM_F_REQUEST");
52         }
53         if ((flags & NLM_F_MULTI) != 0) {
54             if (sb.length() > 0) { sb.append("|"); }
55             sb.append("NLM_F_MULTI");
56         }
57         if ((flags & NLM_F_ACK) != 0) {
58             if (sb.length() > 0) { sb.append("|"); }
59             sb.append("NLM_F_ACK");
60         }
61         if ((flags & NLM_F_ECHO) != 0) {
62             if (sb.length() > 0) { sb.append("|"); }
63             sb.append("NLM_F_ECHO");
64         }
65         if ((flags & NLM_F_ROOT) != 0) {
66             if (sb.length() > 0) { sb.append("|"); }
67             sb.append("NLM_F_ROOT");
68         }
69         if ((flags & NLM_F_MATCH) != 0) {
70             if (sb.length() > 0) { sb.append("|"); }
71             sb.append("NLM_F_MATCH");
72         }
73         return sb.toString();
74     }
75 
hasAvailableSpace(ByteBuffer byteBuffer)76     public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
77         return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
78     }
79 
parse(ByteBuffer byteBuffer)80     public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
81         if (!hasAvailableSpace(byteBuffer)) { return null; }
82 
83         // The ByteOrder must have already been set by the caller.  In most
84         // cases ByteOrder.nativeOrder() is correct, with the exception
85         // of usage within unittests.
86         final StructNlMsgHdr struct = new StructNlMsgHdr();
87         struct.nlmsg_len = byteBuffer.getInt();
88         struct.nlmsg_type = byteBuffer.getShort();
89         struct.nlmsg_flags = byteBuffer.getShort();
90         struct.nlmsg_seq = byteBuffer.getInt();
91         struct.nlmsg_pid = byteBuffer.getInt();
92 
93         if (struct.nlmsg_len < STRUCT_SIZE) {
94             // Malformed.
95             return null;
96         }
97         return struct;
98     }
99 
100     public int nlmsg_len;
101     public short nlmsg_type;
102     public short nlmsg_flags;
103     public int nlmsg_seq;
104     public int nlmsg_pid;
105 
StructNlMsgHdr()106     public StructNlMsgHdr() {
107         nlmsg_len = 0;
108         nlmsg_type = 0;
109         nlmsg_flags = 0;
110         nlmsg_seq = 0;
111         nlmsg_pid = 0;
112     }
113 
pack(ByteBuffer byteBuffer)114     public void pack(ByteBuffer byteBuffer) {
115         // The ByteOrder must have already been set by the caller.  In most
116         // cases ByteOrder.nativeOrder() is correct, with the possible
117         // exception of usage within unittests.
118         byteBuffer.putInt(nlmsg_len);
119         byteBuffer.putShort(nlmsg_type);
120         byteBuffer.putShort(nlmsg_flags);
121         byteBuffer.putInt(nlmsg_seq);
122         byteBuffer.putInt(nlmsg_pid);
123     }
124 
125     @Override
toString()126     public String toString() {
127         final String typeStr = "" + nlmsg_type
128                 + "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")";
129         final String flagsStr = "" + nlmsg_flags
130                 + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
131         return "StructNlMsgHdr{ "
132                 + "nlmsg_len{" + nlmsg_len + "}, "
133                 + "nlmsg_type{" + typeStr + "}, "
134                 + "nlmsg_flags{" + flagsStr + ")}, "
135                 + "nlmsg_seq{" + nlmsg_seq + "}, "
136                 + "nlmsg_pid{" + nlmsg_pid + "} "
137                 + "}";
138     }
139 }
140