content: /*
   * Copyright (C) 2015 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.net.netlink;
  
  import android.net.netlink.NetlinkConstants;
  import android.net.netlink.NetlinkErrorMessage;
  import android.net.netlink.RtNetlinkNeighborMessage;
  import android.net.netlink.StructNlAttr;
  import android.net.netlink.StructNlMsgHdr;
  import android.util.Log;
  
  import java.nio.ByteBuffer;
  
  
  /**
   * NetlinkMessage base class for other, more specific netlink message types.
   *
   * Classes that extend NetlinkMessage should:
   *     - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
   *     - returning either null (parse errors) or a new object of the subclass
   *       type (cast-able to NetlinkMessage)
   *
   * NetlinkMessage.parse() should be updated to know which nlmsg_type values
   * correspond with which message subclasses.
   *
   * @hide
   */
  public class NetlinkMessage {
      private final static String TAG = "NetlinkMessage";
  
      public static NetlinkMessage parse(ByteBuffer byteBuffer) {
          final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
          final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
          if (nlmsghdr == null) {
              return null;
          }
  
          int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
          payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
          if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
              // Malformed message or runt buffer.  Pretend the buffer was consumed.
              byteBuffer.position(byteBuffer.limit());
              return null;
          }
  
          switch (nlmsghdr.nlmsg_type) {
              //case NetlinkConstants.NLMSG_NOOP:
              case NetlinkConstants.NLMSG_ERROR:
                  return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
              case NetlinkConstants.NLMSG_DONE:
                  byteBuffer.position(byteBuffer.position() + payloadLength);
                  return new NetlinkMessage(nlmsghdr);
              //case NetlinkConstants.NLMSG_OVERRUN:
              case NetlinkConstants.RTM_NEWNEIGH:
              case NetlinkConstants.RTM_DELNEIGH:
              case NetlinkConstants.RTM_GETNEIGH:
                  return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
              case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
                  return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
              default:
                  if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
                      // Netlink control message.  Just parse the header for now,
                      // pretending the whole message was consumed.
                      byteBuffer.position(byteBuffer.position() + payloadLength);
                      return new NetlinkMessage(nlmsghdr);
                  }
                  return null;
          }
      }
  
      protected StructNlMsgHdr mHeader;
  
      public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
          mHeader = nlmsghdr;
      }
  
      public StructNlMsgHdr getHeader() {
          return mHeader;
      }
  
      @Override
      public String toString() {
          return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
      }
  }
  