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