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