blob: f0944072e5bacf77e1ee72847bed6bec972979c4 [file] [log] [blame]
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +09001/*
2 * Copyright (C) 2023 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
17package com.android.testutils
18
19import android.net.MacAddress
20import android.util.Log
21import com.android.net.module.util.Ipv6Utils
22import com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN
23import com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA
24import com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
25import com.android.net.module.util.Struct
26import com.android.net.module.util.structs.Icmpv6Header
27import com.android.net.module.util.structs.Ipv6Header
28import com.android.net.module.util.structs.LlaOption
29import com.android.net.module.util.structs.NsHeader
30import com.android.testutils.PacketReflector.IPV6_HEADER_LENGTH
31import java.lang.IllegalArgumentException
32import java.net.Inet6Address
33import java.nio.ByteBuffer
34
35private const val NS_TYPE = 135.toShort()
36
37/**
Yuyang Huangeb3c6312024-10-11 13:49:10 +090038 * A class that can be used to reply to Neighbor Solicitation packets on a [PollPacketReader].
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +090039 */
40class NSResponder(
Yuyang Huangeb3c6312024-10-11 13:49:10 +090041 reader: PollPacketReader,
42 table: Map<Inet6Address, MacAddress>,
43 name: String = NSResponder::class.java.simpleName
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +090044) : PacketResponder(reader, Icmpv6Filter(), name) {
45 companion object {
46 private val TAG = NSResponder::class.simpleName
47 }
48
49 // Copy the map if not already immutable (toMap) to make sure it is not modified
50 private val table = table.toMap()
51
Yuyang Huangeb3c6312024-10-11 13:49:10 +090052 override fun replyToPacket(packet: ByteArray, reader: PollPacketReader) {
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +090053 if (packet.size < IPV6_HEADER_LENGTH) {
54 return
55 }
56 val buf = ByteBuffer.wrap(packet, ETHER_HEADER_LEN, packet.size - ETHER_HEADER_LEN)
57 val ipv6Header = parseOrLog(Ipv6Header::class.java, buf) ?: return
58 val icmpHeader = parseOrLog(Icmpv6Header::class.java, buf) ?: return
59 if (icmpHeader.type != NS_TYPE) {
60 return
61 }
62 val ns = parseOrLog(NsHeader::class.java, buf) ?: return
63 val replyMacAddr = table[ns.target] ?: return
64 val slla = parseOrLog(LlaOption::class.java, buf) ?: return
65 val requesterMac = slla.linkLayerAddress
66
67 val tlla = LlaOption.build(ICMPV6_ND_OPTION_TLLA.toByte(), replyMacAddr)
68 reader.sendResponse(Ipv6Utils.buildNaPacket(
69 replyMacAddr /* srcMac */,
70 requesterMac /* dstMac */,
71 ns.target /* srcIp */,
72 ipv6Header.srcIp /* dstIp */,
73 NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED,
74 ns.target,
75 tlla))
76 }
77
78 private fun <T> parseOrLog(clazz: Class<T>, buf: ByteBuffer): T? where T : Struct {
79 return try {
80 Struct.parse(clazz, buf)
81 } catch (e: IllegalArgumentException) {
82 Log.e(TAG, "Invalid ${clazz.simpleName} in ICMPv6 packet", e)
83 null
84 }
85 }
86}