• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.net.module.util.netlink;
18 
19 import androidx.annotation.NonNull;
20 import androidx.annotation.Nullable;
21 
22 import java.nio.ByteBuffer;
23 
24 /**
25  * struct nlmsghdr
26  *
27  * see <linux_src>/include/uapi/linux/netlink.h
28  *
29  * @hide
30  */
31 public class StructNlMsgHdr {
32     // Already aligned.
33     public static final int STRUCT_SIZE = 16;
34 
35     public static final short NLM_F_REQUEST = 0x0001;
36     public static final short NLM_F_MULTI   = 0x0002;
37     public static final short NLM_F_ACK     = 0x0004;
38     public static final short NLM_F_ECHO    = 0x0008;
39     // Flags for a GET request.
40     public static final short NLM_F_ROOT    = 0x0100;
41     public static final short NLM_F_MATCH   = 0x0200;
42     public static final short NLM_F_DUMP    = NLM_F_ROOT | NLM_F_MATCH;
43     // Flags for a NEW request.
44     public static final short NLM_F_REPLACE   = 0x100;
45     public static final short NLM_F_EXCL      = 0x200;
46     public static final short NLM_F_CREATE    = 0x400;
47     public static final short NLM_F_APPEND    = 0x800;
48 
49     // TODO: Probably need to distinguish the flags which have the same value. For example,
50     // NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200).
stringForNlMsgFlags(short flags)51     private static String stringForNlMsgFlags(short flags) {
52         final StringBuilder sb = new StringBuilder();
53         if ((flags & NLM_F_REQUEST) != 0) {
54             sb.append("NLM_F_REQUEST");
55         }
56         if ((flags & NLM_F_MULTI) != 0) {
57             if (sb.length() > 0) {
58                 sb.append("|");
59             }
60             sb.append("NLM_F_MULTI");
61         }
62         if ((flags & NLM_F_ACK) != 0) {
63             if (sb.length() > 0) {
64                 sb.append("|");
65             }
66             sb.append("NLM_F_ACK");
67         }
68         if ((flags & NLM_F_ECHO) != 0) {
69             if (sb.length() > 0) {
70                 sb.append("|");
71             }
72             sb.append("NLM_F_ECHO");
73         }
74         if ((flags & NLM_F_ROOT) != 0) {
75             if (sb.length() > 0) {
76                 sb.append("|");
77             }
78             sb.append("NLM_F_ROOT");
79         }
80         if ((flags & NLM_F_MATCH) != 0) {
81             if (sb.length() > 0) {
82                 sb.append("|");
83             }
84             sb.append("NLM_F_MATCH");
85         }
86         return sb.toString();
87     }
88 
hasAvailableSpace(ByteBuffer byteBuffer)89     private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
90         return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
91     }
92 
93     /**
94      * Parse netlink message header from buffer.
95      */
96     @Nullable
parse(@onNull ByteBuffer byteBuffer)97     public static StructNlMsgHdr parse(@NonNull ByteBuffer byteBuffer) {
98         if (!hasAvailableSpace(byteBuffer)) return null;
99 
100         // The ByteOrder must have already been set by the caller.  In most
101         // cases ByteOrder.nativeOrder() is correct, with the exception
102         // of usage within unittests.
103         final StructNlMsgHdr struct = new StructNlMsgHdr();
104         struct.nlmsg_len = byteBuffer.getInt();
105         struct.nlmsg_type = byteBuffer.getShort();
106         struct.nlmsg_flags = byteBuffer.getShort();
107         struct.nlmsg_seq = byteBuffer.getInt();
108         struct.nlmsg_pid = byteBuffer.getInt();
109 
110         if (struct.nlmsg_len < STRUCT_SIZE) {
111             // Malformed.
112             return null;
113         }
114         return struct;
115     }
116 
117     public int nlmsg_len;
118     public short nlmsg_type;
119     public short nlmsg_flags;
120     public int nlmsg_seq;
121     public int nlmsg_pid;
122 
StructNlMsgHdr()123     public StructNlMsgHdr() {
124         nlmsg_len = 0;
125         nlmsg_type = 0;
126         nlmsg_flags = 0;
127         nlmsg_seq = 0;
128         nlmsg_pid = 0;
129     }
130 
131     /**
132      * Write netlink message header to ByteBuffer.
133      */
pack(ByteBuffer byteBuffer)134     public void pack(ByteBuffer byteBuffer) {
135         // The ByteOrder must have already been set by the caller.  In most
136         // cases ByteOrder.nativeOrder() is correct, with the possible
137         // exception of usage within unittests.
138         byteBuffer.putInt(nlmsg_len);
139         byteBuffer.putShort(nlmsg_type);
140         byteBuffer.putShort(nlmsg_flags);
141         byteBuffer.putInt(nlmsg_seq);
142         byteBuffer.putInt(nlmsg_pid);
143     }
144 
145     @Override
toString()146     public String toString() {
147         return toString(null /* unknown netlink family */);
148     }
149 
150     /**
151      * Transform a netlink header into a string. The netlink family is required for transforming
152      * a netlink type integer into a string.
153      * @param nlFamily netlink family. Using Integer will not incur autoboxing penalties because
154      *                 family values are small, and all Integer objects between -128 and 127 are
155      *                 statically cached. See Integer.IntegerCache.
156      * @return A list of header elements.
157      */
158     @NonNull
toString(@ullable Integer nlFamily)159     public String toString(@Nullable Integer nlFamily) {
160         final String typeStr = "" + nlmsg_type
161                 + "(" + (nlFamily == null
162                 ? "" : NetlinkConstants.stringForNlMsgType(nlmsg_type, nlFamily))
163                 + ")";
164         final String flagsStr = "" + nlmsg_flags
165                 + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
166         return "StructNlMsgHdr{ "
167                 + "nlmsg_len{" + nlmsg_len + "}, "
168                 + "nlmsg_type{" + typeStr + "}, "
169                 + "nlmsg_flags{" + flagsStr + "}, "
170                 + "nlmsg_seq{" + nlmsg_seq + "}, "
171                 + "nlmsg_pid{" + nlmsg_pid + "} "
172                 + "}";
173     }
174 }
175