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