• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2021 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.cts
18 
19 import android.Manifest.permission.MANAGE_TEST_NETWORKS
20 import android.app.Instrumentation
21 import android.content.Context
22 import android.net.ConnectivityManager
23 import android.net.DscpPolicy
24 import android.net.InetAddresses
25 import android.net.IpPrefix
26 import android.net.LinkAddress
27 import android.net.LinkProperties
28 import android.net.MacAddress
29 import android.net.Network
30 import android.net.NetworkAgent
31 import android.net.NetworkAgent.DSCP_POLICY_STATUS_DELETED
32 import android.net.NetworkAgent.DSCP_POLICY_STATUS_SUCCESS
33 import android.net.NetworkAgentConfig
34 import android.net.NetworkCapabilities
35 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
36 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
37 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
38 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
39 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
40 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
41 import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
42 import android.net.NetworkCapabilities.TRANSPORT_TEST
43 import android.net.NetworkRequest
44 import android.net.RouteInfo
45 import android.net.TestNetworkInterface
46 import android.net.TestNetworkManager
47 import android.net.TestNetworkManager.TestInterfaceRequest
48 import android.net.cts.util.CtsNetUtils.TestNetworkCallback
49 import android.os.HandlerThread
50 import android.os.SystemClock
51 import android.platform.test.annotations.AppModeFull
52 import android.system.ErrnoException
53 import android.system.Os
54 import android.system.OsConstants.AF_INET
55 import android.system.OsConstants.AF_INET6
56 import android.system.OsConstants.ENETUNREACH
57 import android.system.OsConstants.IPPROTO_UDP
58 import android.system.OsConstants.SOCK_DGRAM
59 import android.system.OsConstants.SOCK_NONBLOCK
60 import android.util.Log
61 import android.util.Range
62 import androidx.test.InstrumentationRegistry
63 import androidx.test.runner.AndroidJUnit4
64 import com.android.net.module.util.IpUtils
65 import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4
66 import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6
67 import com.android.net.module.util.Struct
68 import com.android.net.module.util.structs.EthernetHeader
69 import com.android.testutils.ArpResponder
70 import com.android.testutils.CompatUtil
71 import com.android.testutils.ConnectivityModuleTest
72 import com.android.testutils.DevSdkIgnoreRule
73 import com.android.testutils.RouterAdvertisementResponder
74 import com.android.testutils.SC_V2
75 import com.android.testutils.PollPacketReader
76 import com.android.testutils.TestableNetworkAgent
77 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnDscpPolicyStatusUpdated
78 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
79 import com.android.testutils.TestableNetworkCallback
80 import com.android.testutils.assertParcelingIsLossless
81 import com.android.testutils.runAsShell
82 import java.net.Inet4Address
83 import java.net.Inet6Address
84 import java.net.InetSocketAddress
85 import java.nio.ByteBuffer
86 import java.nio.ByteOrder
87 import java.util.regex.Pattern
88 import kotlin.test.assertEquals
89 import kotlin.test.assertNotNull
90 import kotlin.test.assertTrue
91 import kotlin.test.fail
92 import org.junit.After
93 import org.junit.Assume.assumeTrue
94 import org.junit.Before
95 import org.junit.Rule
96 import org.junit.Test
97 import org.junit.runner.RunWith
98 
99 private const val MAX_PACKET_LENGTH = 1500
100 
101 private const val IP4_PREFIX_LEN = 32
102 private const val IP6_PREFIX_LEN = 128
103 
104 private val instrumentation: Instrumentation
105     get() = InstrumentationRegistry.getInstrumentation()
106 
107 private const val TAG = "DscpPolicyTest"
108 private const val PACKET_TIMEOUT_MS = 2_000L
109 private const val IPV6_ADDRESS_WAIT_TIME_MS = 10_000L
110 
111 @AppModeFull(reason = "Instant apps cannot create test networks")
112 @RunWith(AndroidJUnit4::class)
113 @ConnectivityModuleTest
114 class DscpPolicyTest {
115     @JvmField
116     @Rule
117     val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
118 
119     private val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1")
120     private val TEST_TARGET_IPV4_ADDR =
121             InetAddresses.parseNumericAddress("203.0.113.1") as Inet4Address
122     private val TEST_TARGET_IPV6_ADDR =
123         InetAddresses.parseNumericAddress("2001:4860:4860::8888") as Inet6Address
124     private val TEST_ROUTER_IPV6_ADDR =
125         InetAddresses.parseNumericAddress("fe80::1234") as Inet6Address
126     private val TEST_TARGET_MAC_ADDR = MacAddress.fromString("12:34:56:78:9a:bc")
127 
128     private val realContext = InstrumentationRegistry.getContext()
129     private val cm = realContext.getSystemService(ConnectivityManager::class.java)!!
130 
131     private val agentsToCleanUp = mutableListOf<NetworkAgent>()
132     private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>()
133 
134     private val handlerThread = HandlerThread(DscpPolicyTest::class.java.simpleName)
135 
136     private lateinit var srcAddressV6: Inet6Address
137     private lateinit var iface: TestNetworkInterface
138     private lateinit var tunNetworkCallback: TestNetworkCallback
139     private lateinit var reader: PollPacketReader
140     private lateinit var arpResponder: ArpResponder
141     private lateinit var raResponder: RouterAdvertisementResponder
142 
143     private fun getKernelVersion(): IntArray {
144         // Example:
145         // 4.9.29-g958411d --> 4.9
146         val release = Os.uname().release
147         val m = Pattern.compile("^(\\d+)\\.(\\d+)").matcher(release)
148         assertTrue(m.find(), "No pattern in release string: " + release)
149         return intArrayOf(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)))
150     }
151 
152     // TODO: replace with DeviceInfoUtils#isKernelVersionAtLeast
153     private fun kernelIsAtLeast(major: Int, minor: Int): Boolean {
154         val version = getKernelVersion()
155         return (version.get(0) > major || (version.get(0) == major && version.get(1) >= minor))
156     }
157 
158     @Before
159     fun setUp() {
160         // For BPF support kernel needs to be at least 5.15.
161         assumeTrue(kernelIsAtLeast(5, 15))
162 
163         runAsShell(MANAGE_TEST_NETWORKS) {
164             val tnm = realContext.getSystemService(TestNetworkManager::class.java)!!
165 
166             // Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
167             // address.
168             val req = TestInterfaceRequest.Builder()
169                     .setTap()
170                     .addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
171                     .build()
172             iface = tnm.createTestInterface(req)
173             assertNotNull(iface)
174         }
175 
176         handlerThread.start()
177         reader = PollPacketReader(
178                 handlerThread.threadHandler,
179                 iface.fileDescriptor.fileDescriptor,
180                 MAX_PACKET_LENGTH)
181         reader.startAsyncForTest()
182 
183         arpResponder = ArpResponder(reader, mapOf(TEST_TARGET_IPV4_ADDR to TEST_TARGET_MAC_ADDR))
184         arpResponder.start()
185         raResponder = RouterAdvertisementResponder(reader)
186         raResponder.addRouterEntry(TEST_TARGET_MAC_ADDR, TEST_ROUTER_IPV6_ADDR)
187         raResponder.start()
188     }
189 
190     @After
191     fun tearDown() {
192         if (!kernelIsAtLeast(5, 15)) {
193             return
194         }
195         raResponder.stop()
196         arpResponder.stop()
197 
198         agentsToCleanUp.forEach { it.unregister() }
199         callbacksToCleanUp.forEach { cm.unregisterNetworkCallback(it) }
200 
201         // reader.stop() cleans up tun fd
202         reader.handler.post { reader.stop() }
203         // quitSafely processes all events in the queue, except delayed messages.
204         handlerThread.quitSafely()
205         handlerThread.join()
206     }
207 
208     private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) {
209         cm.requestNetwork(request, callback)
210         callbacksToCleanUp.add(callback)
211     }
212 
213     private fun makeTestNetworkRequest(specifier: String? = null): NetworkRequest {
214         return NetworkRequest.Builder()
215                 .clearCapabilities()
216                 .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
217                 .addTransportType(TRANSPORT_TEST)
218                 .also {
219                     if (specifier != null) {
220                         it.setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(specifier))
221                     }
222                 }
223                 .build()
224     }
225 
226     private fun waitForGlobalIpv6Address(network: Network): Inet6Address {
227         // Wait for global IPv6 address to be available
228         var inet6Addr: Inet6Address? = null
229         val onLinkPrefix = raResponder.prefix
230         val startTime = SystemClock.elapsedRealtime()
231         while (SystemClock.elapsedRealtime() - startTime < IPV6_ADDRESS_WAIT_TIME_MS) {
232             SystemClock.sleep(50 /* ms */)
233             val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
234             try {
235                 network.bindSocket(sock)
236 
237                 try {
238                     // Pick any arbitrary port
239                     Os.connect(sock, TEST_TARGET_IPV6_ADDR, 12345)
240                 } catch (e: ErrnoException) {
241                     // there may not be an address available yet.
242                     if (e.errno == ENETUNREACH) continue
243                     throw e
244                 }
245                 val sockAddr = Os.getsockname(sock) as InetSocketAddress
246                 if (onLinkPrefix.contains(sockAddr.address)) {
247                     inet6Addr = sockAddr.address as Inet6Address
248                     break
249                 }
250             } finally {
251                 Os.close(sock)
252             }
253         }
254         assertNotNull(inet6Addr)
255         return inet6Addr!!
256     }
257 
258     private fun createConnectedNetworkAgent(
259         context: Context = realContext,
260         specifier: String? = iface.getInterfaceName()
261     ): Pair<TestableNetworkAgent, TestableNetworkCallback> {
262         val callback = TestableNetworkCallback()
263         // Ensure this NetworkAgent is never unneeded by filing a request with its specifier.
264         requestNetwork(makeTestNetworkRequest(specifier = specifier), callback)
265 
266         val nc = NetworkCapabilities().apply {
267             addTransportType(TRANSPORT_TEST)
268             removeCapability(NET_CAPABILITY_TRUSTED)
269             removeCapability(NET_CAPABILITY_INTERNET)
270             addCapability(NET_CAPABILITY_NOT_SUSPENDED)
271             addCapability(NET_CAPABILITY_NOT_ROAMING)
272             addCapability(NET_CAPABILITY_NOT_VPN)
273             addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
274             if (null != specifier) {
275                 setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(specifier))
276             }
277         }
278         val lp = LinkProperties().apply {
279             addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
280             addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
281             setInterfaceName(specifier)
282         }
283         val config = NetworkAgentConfig.Builder().build()
284         val agent = TestableNetworkAgent(context, handlerThread.looper, nc, lp, config)
285         agentsToCleanUp.add(agent)
286 
287         // Connect the agent and verify initial status callbacks.
288         runAsShell(MANAGE_TEST_NETWORKS) { agent.register() }
289         agent.markConnected()
290         agent.expectCallback<OnNetworkCreated>()
291         agent.expectSignalStrengths(intArrayOf())
292         agent.expectValidationBypassedStatus()
293 
294         val network = agent.network ?: fail("Expected a non-null network")
295         srcAddressV6 = waitForGlobalIpv6Address(network)
296         return agent to callback
297     }
298 
299     fun ByteArray.toHex(): String = joinToString(separator = "") {
300         eachByte -> "%02x".format(eachByte)
301     }
302 
303     fun sendPacket(
304         agent: TestableNetworkAgent,
305         sendV6: Boolean,
306         dstPort: Int = 0,
307         times: Int = 1
308     ) {
309         val testString = "test string"
310         val testPacket = ByteBuffer.wrap(testString.toByteArray(Charsets.UTF_8))
311         var packetFound = false
312 
313         val socket = Os.socket(if (sendV6) AF_INET6 else AF_INET, SOCK_DGRAM or SOCK_NONBLOCK,
314                 IPPROTO_UDP)
315         checkNotNull(agent.network).bindSocket(socket)
316 
317         val origPacket = testPacket.readAsArray()
318         repeat(times) {
319             Os.sendto(socket, origPacket, 0 /* bytesOffset */, origPacket.size, 0 /* flags */,
320                 if (sendV6) TEST_TARGET_IPV6_ADDR else TEST_TARGET_IPV4_ADDR, dstPort)
321         }
322         Os.close(socket)
323     }
324 
325     fun parseV4PacketDscp(buffer: ByteBuffer): Int {
326         // Validate checksum before parsing packet.
327         val calCheck = IpUtils.ipChecksum(buffer, Struct.getSize(EthernetHeader::class.java))
328         assertEquals(0, calCheck, "Invalid IPv4 header checksum")
329 
330         val ip_ver = buffer.get()
331         val tos = buffer.get()
332         val length = buffer.getShort()
333         val id = buffer.getShort()
334         val offset = buffer.getShort()
335         val ttl = buffer.get()
336         val ipType = buffer.get()
337         val checksum = buffer.getShort()
338 
339         if (ipType.toInt() == 2 /* IPPROTO_IGMP */ && ip_ver.toInt() == 0x46) {
340             // Need to ignore 'igmp v3 report' with 'router alert' option
341         } else {
342             assertEquals(0x45, ip_ver.toInt(), "Invalid IPv4 version or IPv4 options present")
343         }
344         return tos.toInt().shr(2)
345     }
346 
347     fun parseV6PacketDscp(buffer: ByteBuffer): Int {
348         val ip_ver = buffer.get()
349         val tc = buffer.get()
350         val fl = buffer.getShort()
351         val length = buffer.getShort()
352         val proto = buffer.get()
353         val hop = buffer.get()
354 
355         assertEquals(6, ip_ver.toInt().shr(4), "Invalid IPv6 version")
356 
357         // DSCP is bottom 4 bits of ip_ver and top 2 of tc.
358         val ip_ver_bottom = ip_ver.toInt().and(0xf)
359         val tc_dscp = tc.toInt().shr(6)
360         return ip_ver_bottom.toInt().shl(2) + tc_dscp
361     }
362 
363     fun parsePacketIp(
364         buffer: ByteBuffer,
365         sendV6: Boolean
366     ): Boolean {
367         val ipAddr = if (sendV6) ByteArray(16) else ByteArray(4)
368         buffer.get(ipAddr)
369         val srcIp = if (sendV6) Inet6Address.getByAddress(ipAddr)
370                 else Inet4Address.getByAddress(ipAddr)
371         buffer.get(ipAddr)
372         val dstIp = if (sendV6) Inet6Address.getByAddress(ipAddr)
373                 else Inet4Address.getByAddress(ipAddr)
374 
375         Log.e(TAG, "IP Src:" + srcIp + " dst: " + dstIp)
376 
377         if ((sendV6 && srcIp == srcAddressV6 && dstIp == TEST_TARGET_IPV6_ADDR) ||
378                 (!sendV6 && srcIp == LOCAL_IPV4_ADDRESS && dstIp == TEST_TARGET_IPV4_ADDR)) {
379             Log.e(TAG, "IP return true")
380             return true
381         }
382         Log.e(TAG, "IP return false")
383         return false
384     }
385 
386     fun parsePacketPort(
387         buffer: ByteBuffer,
388         srcPort: Int,
389         dstPort: Int
390     ): Boolean {
391         if (srcPort == 0 && dstPort == 0) return true
392 
393         val packetSrcPort = buffer.getShort().toInt()
394         val packetDstPort = buffer.getShort().toInt()
395 
396         Log.e(TAG, "Port Src:" + packetSrcPort + " dst: " + packetDstPort)
397 
398         if ((srcPort == 0 || (srcPort != 0 && srcPort == packetSrcPort)) &&
399                 (dstPort == 0 || (dstPort != 0 && dstPort == packetDstPort))) {
400             Log.e(TAG, "Port return true")
401             return true
402         }
403         Log.e(TAG, "Port return false")
404         return false
405     }
406 
407     fun validatePacket(
408         agent: TestableNetworkAgent,
409         sendV6: Boolean = false,
410         dscpValue: Int = 0,
411         dstPort: Int = 0,
412         times: Int = 1
413     ) {
414         var packetFound = 0
415         sendPacket(agent, sendV6, dstPort, times)
416         // TODO: grab source port from socket in sendPacket
417 
418         Log.e(TAG, "find DSCP value:" + dscpValue)
419         val packets = generateSequence { reader.poll(PACKET_TIMEOUT_MS) }
420         for (packet in packets) {
421             val buffer = ByteBuffer.wrap(packet, 0, packet.size).order(ByteOrder.BIG_ENDIAN)
422 
423             // TODO: consider using Struct.parse for all packet parsing.
424             val etherHdr = Struct.parse(EthernetHeader::class.java, buffer)
425             val expectedType = if (sendV6) ETHER_TYPE_IPV6 else ETHER_TYPE_IPV4
426             if (etherHdr.etherType != expectedType) {
427                 continue
428             }
429             val dscp = if (sendV6) parseV6PacketDscp(buffer) else parseV4PacketDscp(buffer)
430             Log.e(TAG, "DSCP value:" + dscp)
431 
432             // TODO: Add source port comparison. Use 0 for now.
433             if (parsePacketIp(buffer, sendV6) && parsePacketPort(buffer, 0, dstPort)) {
434                 Log.e(TAG, "DSCP value found")
435                 assertEquals(dscpValue, dscp)
436                 packetFound++
437             }
438         }
439         assertTrue(packetFound == times)
440     }
441 
442     fun validatePackets(
443         agent: TestableNetworkAgent,
444         sendV6: Boolean = false,
445         dscpValue: Int = 0,
446         dstPort: Int = 0
447     ) {
448         // We send two packets from the same socket to verify
449         // socket caching works correctly.
450         validatePacket(agent, sendV6, dscpValue, dstPort, 2)
451         // Try one more time from a different socket.
452         validatePacket(agent, sendV6, dscpValue, dstPort, 1)
453     }
454 
455     fun doRemovePolicyTest(
456         agent: TestableNetworkAgent,
457         callback: TestableNetworkCallback,
458         policyId: Int
459     ) {
460         val portNumber = 1111 * policyId
461         agent.sendRemoveDscpPolicy(policyId)
462         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
463             assertEquals(policyId, it.policyId)
464             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
465         }
466     }
467 
468     @Test
469     fun testDscpPolicyAddPolicies(): Unit = createConnectedNetworkAgent().let {
470                 (agent, callback) ->
471         val policy = DscpPolicy.Builder(1, 1)
472                 .setDestinationPortRange(Range(4444, 4444)).build()
473         agent.sendAddDscpPolicy(policy)
474         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
475             assertEquals(1, it.policyId)
476             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
477         }
478         validatePackets(agent, dscpValue = 1, dstPort = 4444)
479 
480         agent.sendRemoveDscpPolicy(1)
481         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
482             assertEquals(1, it.policyId)
483             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
484         }
485 
486         val policy2 = DscpPolicy.Builder(1, 4)
487                 .setDestinationPortRange(Range(5555, 5555))
488                 .setDestinationAddress(TEST_TARGET_IPV4_ADDR)
489                 .setSourceAddress(LOCAL_IPV4_ADDRESS)
490                 .setProtocol(IPPROTO_UDP).build()
491         agent.sendAddDscpPolicy(policy2)
492         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
493             assertEquals(1, it.policyId)
494             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
495         }
496 
497         validatePackets(agent, dscpValue = 4, dstPort = 5555)
498 
499         agent.sendRemoveDscpPolicy(1)
500         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
501             assertEquals(1, it.policyId)
502             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
503         }
504     }
505 
506     @Test
507     fun testDscpPolicyAddV6Policies(): Unit = createConnectedNetworkAgent().let {
508                 (agent, callback) ->
509         val policy = DscpPolicy.Builder(1, 1)
510                 .setDestinationPortRange(Range(4444, 4444)).build()
511         agent.sendAddDscpPolicy(policy)
512         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
513             assertEquals(1, it.policyId)
514             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
515         }
516         validatePackets(agent, true, dscpValue = 1, dstPort = 4444)
517 
518         agent.sendRemoveDscpPolicy(1)
519         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
520             assertEquals(1, it.policyId)
521             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
522         }
523 
524         val policy2 = DscpPolicy.Builder(1, 4)
525                 .setDestinationPortRange(Range(5555, 5555))
526                 .setDestinationAddress(TEST_TARGET_IPV6_ADDR)
527                 .setSourceAddress(srcAddressV6)
528                 .setProtocol(IPPROTO_UDP).build()
529         agent.sendAddDscpPolicy(policy2)
530         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
531             assertEquals(1, it.policyId)
532             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
533         }
534         validatePackets(agent, true, dscpValue = 4, dstPort = 5555)
535 
536         agent.sendRemoveDscpPolicy(1)
537         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
538             assertEquals(1, it.policyId)
539             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
540         }
541     }
542 
543     @Test
544     // Remove policies in the same order as addition.
545     fun testRemoveDscpPolicy_RemoveSameOrderAsAdd(): Unit = createConnectedNetworkAgent().let {
546                 (agent, callback) ->
547         val policy = DscpPolicy.Builder(1, 1).setDestinationPortRange(Range(1111, 1111)).build()
548         agent.sendAddDscpPolicy(policy)
549         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
550             assertEquals(1, it.policyId)
551             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
552             validatePackets(agent, dscpValue = 1, dstPort = 1111)
553         }
554 
555         val policy2 = DscpPolicy.Builder(2, 1).setDestinationPortRange(Range(2222, 2222)).build()
556         agent.sendAddDscpPolicy(policy2)
557         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
558             assertEquals(2, it.policyId)
559             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
560             validatePackets(agent, dscpValue = 1, dstPort = 2222)
561         }
562 
563         val policy3 = DscpPolicy.Builder(3, 1).setDestinationPortRange(Range(3333, 3333)).build()
564         agent.sendAddDscpPolicy(policy3)
565         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
566             assertEquals(3, it.policyId)
567             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
568             validatePackets(agent, dscpValue = 1, dstPort = 3333)
569         }
570 
571         /* Remove Policies and check CE is no longer set */
572         doRemovePolicyTest(agent, callback, 1)
573         validatePackets(agent, dscpValue = 0, dstPort = 1111)
574         doRemovePolicyTest(agent, callback, 2)
575         validatePackets(agent, dscpValue = 0, dstPort = 2222)
576         doRemovePolicyTest(agent, callback, 3)
577         validatePackets(agent, dscpValue = 0, dstPort = 3333)
578     }
579 
580     @Test
581     fun testRemoveDscpPolicy_RemoveImmediatelyAfterAdd(): Unit =
582             createConnectedNetworkAgent().let { (agent, callback) ->
583         val policy = DscpPolicy.Builder(1, 1).setDestinationPortRange(Range(1111, 1111)).build()
584         agent.sendAddDscpPolicy(policy)
585         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
586             assertEquals(1, it.policyId)
587             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
588             validatePackets(agent, dscpValue = 1, dstPort = 1111)
589         }
590         doRemovePolicyTest(agent, callback, 1)
591 
592         val policy2 = DscpPolicy.Builder(2, 1).setDestinationPortRange(Range(2222, 2222)).build()
593         agent.sendAddDscpPolicy(policy2)
594         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
595             assertEquals(2, it.policyId)
596             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
597             validatePackets(agent, dscpValue = 1, dstPort = 2222)
598         }
599         doRemovePolicyTest(agent, callback, 2)
600 
601         val policy3 = DscpPolicy.Builder(3, 1).setDestinationPortRange(Range(3333, 3333)).build()
602         agent.sendAddDscpPolicy(policy3)
603         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
604             assertEquals(3, it.policyId)
605             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
606             validatePackets(agent, dscpValue = 1, dstPort = 3333)
607         }
608         doRemovePolicyTest(agent, callback, 3)
609     }
610 
611     @Test
612     // Remove policies in reverse order from addition.
613     fun testRemoveDscpPolicy_RemoveReverseOrder(): Unit =
614             createConnectedNetworkAgent().let { (agent, callback) ->
615         val policy = DscpPolicy.Builder(1, 1).setDestinationPortRange(Range(1111, 1111)).build()
616         agent.sendAddDscpPolicy(policy)
617         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
618             assertEquals(1, it.policyId)
619             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
620             validatePackets(agent, dscpValue = 1, dstPort = 1111)
621         }
622 
623         val policy2 = DscpPolicy.Builder(2, 1).setDestinationPortRange(Range(2222, 2222)).build()
624         agent.sendAddDscpPolicy(policy2)
625         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
626             assertEquals(2, it.policyId)
627             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
628             validatePackets(agent, dscpValue = 1, dstPort = 2222)
629         }
630 
631         val policy3 = DscpPolicy.Builder(3, 1).setDestinationPortRange(Range(3333, 3333)).build()
632         agent.sendAddDscpPolicy(policy3)
633         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
634             assertEquals(3, it.policyId)
635             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
636             validatePackets(agent, dscpValue = 1, dstPort = 3333)
637         }
638 
639         /* Remove Policies and check CE is no longer set */
640         doRemovePolicyTest(agent, callback, 3)
641         doRemovePolicyTest(agent, callback, 2)
642         doRemovePolicyTest(agent, callback, 1)
643     }
644 
645     @Test
646     fun testRemoveDscpPolicy_InvalidPolicy(): Unit = createConnectedNetworkAgent().let {
647                 (agent, callback) ->
648         agent.sendRemoveDscpPolicy(3)
649         // Is there something to add in TestableNetworkCallback to NOT expect a callback?
650         // Or should we send DSCP_POLICY_STATUS_DELETED in any case or a different STATUS?
651     }
652 
653     @Test
654     fun testRemoveAllDscpPolicies(): Unit = createConnectedNetworkAgent().let {
655                 (agent, callback) ->
656         val policy = DscpPolicy.Builder(1, 1)
657                 .setDestinationPortRange(Range(1111, 1111)).build()
658         agent.sendAddDscpPolicy(policy)
659         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
660             assertEquals(1, it.policyId)
661             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
662             validatePackets(agent, dscpValue = 1, dstPort = 1111)
663         }
664 
665         val policy2 = DscpPolicy.Builder(2, 1)
666                 .setDestinationPortRange(Range(2222, 2222)).build()
667         agent.sendAddDscpPolicy(policy2)
668         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
669             assertEquals(2, it.policyId)
670             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
671             validatePackets(agent, dscpValue = 1, dstPort = 2222)
672         }
673 
674         val policy3 = DscpPolicy.Builder(3, 1)
675                 .setDestinationPortRange(Range(3333, 3333)).build()
676         agent.sendAddDscpPolicy(policy3)
677         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
678             assertEquals(3, it.policyId)
679             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
680             validatePackets(agent, dscpValue = 1, dstPort = 3333)
681         }
682 
683         agent.sendRemoveAllDscpPolicies()
684         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
685             assertEquals(1, it.policyId)
686             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
687             validatePackets(agent, false, dstPort = 1111)
688         }
689         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
690             assertEquals(2, it.policyId)
691             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
692             validatePackets(agent, false, dstPort = 2222)
693         }
694         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
695             assertEquals(3, it.policyId)
696             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
697             validatePackets(agent, false, dstPort = 3333)
698         }
699     }
700 
701     @Test
702     fun testAddDuplicateDscpPolicy(): Unit = createConnectedNetworkAgent().let {
703                 (agent, callback) ->
704         val policy = DscpPolicy.Builder(1, 1).setDestinationPortRange(Range(4444, 4444)).build()
705         agent.sendAddDscpPolicy(policy)
706         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
707             assertEquals(1, it.policyId)
708             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
709             validatePackets(agent, dscpValue = 1, dstPort = 4444)
710         }
711 
712         val policy2 = DscpPolicy.Builder(1, 1).setDestinationPortRange(Range(5555, 5555)).build()
713         agent.sendAddDscpPolicy(policy2)
714         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
715             assertEquals(1, it.policyId)
716             assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
717 
718             // Sending packet with old policy should fail
719             validatePackets(agent, dscpValue = 0, dstPort = 4444)
720             validatePackets(agent, dscpValue = 1, dstPort = 5555)
721         }
722 
723         agent.sendRemoveDscpPolicy(1)
724         agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
725             assertEquals(1, it.policyId)
726             assertEquals(DSCP_POLICY_STATUS_DELETED, it.status)
727         }
728     }
729 
730     @Test
731     fun testParcelingDscpPolicyIsLossless(): Unit = createConnectedNetworkAgent().let {
732                 (agent, callback) ->
733         val policyId = 1
734         val dscpValue = 1
735         val range = Range(4444, 4444)
736         val srcPort = 555
737 
738         // Check that policy with partial parameters is lossless.
739         val policy = DscpPolicy.Builder(policyId, dscpValue).setDestinationPortRange(range).build()
740         assertEquals(policyId, policy.policyId)
741         assertEquals(dscpValue, policy.dscpValue)
742         assertEquals(range, policy.destinationPortRange)
743         assertParcelingIsLossless(policy)
744 
745         // Check that policy with all parameters is lossless.
746         val policy2 = DscpPolicy.Builder(policyId, dscpValue).setDestinationPortRange(range)
747                 .setSourceAddress(LOCAL_IPV4_ADDRESS)
748                 .setDestinationAddress(TEST_TARGET_IPV4_ADDR)
749                 .setSourcePort(srcPort)
750                 .setProtocol(IPPROTO_UDP).build()
751         assertEquals(policyId, policy2.policyId)
752         assertEquals(dscpValue, policy2.dscpValue)
753         assertEquals(range, policy2.destinationPortRange)
754         assertEquals(TEST_TARGET_IPV4_ADDR, policy2.destinationAddress)
755         assertEquals(LOCAL_IPV4_ADDRESS, policy2.sourceAddress)
756         assertEquals(srcPort, policy2.sourcePort)
757         assertEquals(IPPROTO_UDP, policy2.protocol)
758         assertParcelingIsLossless(policy2)
759     }
760 
761     @Test
762     fun testSendDscpPolicyWithoutInterfaceName() {
763         val nc = NetworkCapabilities().apply {
764             addTransportType(TRANSPORT_TEST)
765         }
766         val agent = TestableNetworkAgent(
767                 realContext,
768                 handlerThread.looper,
769                 nc,
770                 LinkProperties() /* note: no interface name */,
771                 NetworkAgentConfig.Builder().build()
772         )
773         agentsToCleanUp.add(agent)
774         runAsShell(MANAGE_TEST_NETWORKS) { agent.register() }
775         // Without the fix, this will crash the system with SIGSEGV.
776         agent.sendAddDscpPolicy(DscpPolicy.Builder(1, 1).build())
777         // Will receive OnNetworkCreated first if the agent is created early. To avoid reading
778         // the flag here, use eventuallyExpect.
779         agent.eventuallyExpect<OnDscpPolicyStatusUpdated>()
780     }
781 }
782 
readAsArraynull783 private fun ByteBuffer.readAsArray(): ByteArray {
784     val out = ByteArray(remaining())
785     get(out)
786     return out
787 }
788 
assertHasServicenull789 private fun <T> Context.assertHasService(manager: Class<T>): T {
790     return getSystemService(manager) ?: fail("Service $manager not found")
791 }
792