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 android.system.OsConstants; 20 21 import java.nio.ByteBuffer; 22 23 /** 24 * struct ndmsg 25 * 26 * see: <linux_src>/include/uapi/linux/neighbour.h 27 * 28 * @hide 29 */ 30 public class StructNdMsg { 31 // Already aligned. 32 public static final int STRUCT_SIZE = 12; 33 34 // Neighbor Cache Entry States 35 public static final short NUD_NONE = 0x00; 36 public static final short NUD_INCOMPLETE = 0x01; 37 public static final short NUD_REACHABLE = 0x02; 38 public static final short NUD_STALE = 0x04; 39 public static final short NUD_DELAY = 0x08; 40 public static final short NUD_PROBE = 0x10; 41 public static final short NUD_FAILED = 0x20; 42 public static final short NUD_NOARP = 0x40; 43 public static final short NUD_PERMANENT = 0x80; 44 45 /** 46 * Convert neighbor cache entry state integer to string. 47 */ stringForNudState(short nudState)48 public static String stringForNudState(short nudState) { 49 switch (nudState) { 50 case NUD_NONE: return "NUD_NONE"; 51 case NUD_INCOMPLETE: return "NUD_INCOMPLETE"; 52 case NUD_REACHABLE: return "NUD_REACHABLE"; 53 case NUD_STALE: return "NUD_STALE"; 54 case NUD_DELAY: return "NUD_DELAY"; 55 case NUD_PROBE: return "NUD_PROBE"; 56 case NUD_FAILED: return "NUD_FAILED"; 57 case NUD_NOARP: return "NUD_NOARP"; 58 case NUD_PERMANENT: return "NUD_PERMANENT"; 59 default: 60 return "unknown NUD state: " + String.valueOf(nudState); 61 } 62 } 63 64 /** 65 * Check whether a neighbor is connected or not. 66 */ isNudStateConnected(short nudState)67 public static boolean isNudStateConnected(short nudState) { 68 return ((nudState & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)) != 0); 69 } 70 71 /** 72 * Check whether a neighbor is in the valid NUD state or not. 73 */ isNudStateValid(short nudState)74 public static boolean isNudStateValid(short nudState) { 75 return (isNudStateConnected(nudState) 76 || ((nudState & (NUD_PROBE | NUD_STALE | NUD_DELAY)) != 0)); 77 } 78 79 // Neighbor Cache Entry Flags 80 public static byte NTF_USE = (byte) 0x01; 81 public static byte NTF_SELF = (byte) 0x02; 82 public static byte NTF_MASTER = (byte) 0x04; 83 public static byte NTF_PROXY = (byte) 0x08; 84 public static byte NTF_ROUTER = (byte) 0x80; 85 stringForNudFlags(byte flags)86 private static String stringForNudFlags(byte flags) { 87 final StringBuilder sb = new StringBuilder(); 88 if ((flags & NTF_USE) != 0) { 89 sb.append("NTF_USE"); 90 } 91 if ((flags & NTF_SELF) != 0) { 92 if (sb.length() > 0) { 93 sb.append("|"); 94 } 95 sb.append("NTF_SELF"); 96 } 97 if ((flags & NTF_MASTER) != 0) { 98 if (sb.length() > 0) { 99 sb.append("|"); 100 } 101 sb.append("NTF_MASTER"); 102 } 103 if ((flags & NTF_PROXY) != 0) { 104 if (sb.length() > 0) { 105 sb.append("|"); 106 } 107 sb.append("NTF_PROXY"); 108 } 109 if ((flags & NTF_ROUTER) != 0) { 110 if (sb.length() > 0) { 111 sb.append("|"); 112 } 113 sb.append("NTF_ROUTER"); 114 } 115 return sb.toString(); 116 } 117 hasAvailableSpace(ByteBuffer byteBuffer)118 private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { 119 return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; 120 } 121 122 /** 123 * Parse a neighbor discovery netlink message header from a {@link ByteBuffer}. 124 * 125 * @param byteBuffer The buffer from which to parse the nd netlink message header. 126 * @return the parsed nd netlink message header, or {@code null} if the nd netlink message 127 * header could not be parsed successfully (for example, if it was truncated). 128 */ parse(ByteBuffer byteBuffer)129 public static StructNdMsg parse(ByteBuffer byteBuffer) { 130 if (!hasAvailableSpace(byteBuffer)) return null; 131 132 // The ByteOrder must have already been set by the caller. In most 133 // cases ByteOrder.nativeOrder() is correct, with the possible 134 // exception of usage within unittests. 135 final StructNdMsg struct = new StructNdMsg(); 136 struct.ndm_family = byteBuffer.get(); 137 final byte pad1 = byteBuffer.get(); 138 final short pad2 = byteBuffer.getShort(); 139 struct.ndm_ifindex = byteBuffer.getInt(); 140 struct.ndm_state = byteBuffer.getShort(); 141 struct.ndm_flags = byteBuffer.get(); 142 struct.ndm_type = byteBuffer.get(); 143 return struct; 144 } 145 146 public byte ndm_family; 147 public int ndm_ifindex; 148 public short ndm_state; 149 public byte ndm_flags; 150 public byte ndm_type; 151 StructNdMsg()152 public StructNdMsg() { 153 ndm_family = (byte) OsConstants.AF_UNSPEC; 154 } 155 156 /** 157 * Write the neighbor discovery message header to {@link ByteBuffer}. 158 */ pack(ByteBuffer byteBuffer)159 public void pack(ByteBuffer byteBuffer) { 160 // The ByteOrder must have already been set by the caller. In most 161 // cases ByteOrder.nativeOrder() is correct, with the exception 162 // of usage within unittests. 163 byteBuffer.put(ndm_family); 164 byteBuffer.put((byte) 0); // pad1 165 byteBuffer.putShort((short) 0); // pad2 166 byteBuffer.putInt(ndm_ifindex); 167 byteBuffer.putShort(ndm_state); 168 byteBuffer.put(ndm_flags); 169 byteBuffer.put(ndm_type); 170 } 171 172 /** 173 * Check whether a neighbor is connected or not. 174 */ nudConnected()175 public boolean nudConnected() { 176 return isNudStateConnected(ndm_state); 177 } 178 179 /** 180 * Check whether a neighbor is in the valid NUD state or not. 181 */ nudValid()182 public boolean nudValid() { 183 return isNudStateValid(ndm_state); 184 } 185 186 @Override toString()187 public String toString() { 188 final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")"; 189 final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")"; 190 return "StructNdMsg{ " 191 + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, " 192 + "ifindex{" + ndm_ifindex + "}, " 193 + "state{" + stateStr + "}, " 194 + "flags{" + flagsStr + "}, " 195 + "type{" + ndm_type + "} " 196 + "}"; 197 } 198 } 199