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