1 /*
2  * Copyright (C) 2020 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 @file:JvmName("NetlinkTestUtils")
18 
19 package com.android.testutils
20 
21 import com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH
22 import com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNEIGH
23 import libcore.util.HexEncoding
24 import libcore.util.HexEncoding.encodeToString
25 import java.net.Inet6Address
26 import java.net.InetAddress
27 
28 private const val VRRP_MAC_ADDR = "00005e000164"
29 
30 /**
31  * Make a RTM_NEWNEIGH netlink message.
32  */
33 @JvmOverloads
makeNewNeighMessagenull34 fun makeNewNeighMessage(
35     neighAddr: InetAddress,
36     nudState: Short,
37     linkLayerAddr: String = VRRP_MAC_ADDR
38 ) = makeNeighborMessage(
39         neighAddr = neighAddr,
40         type = RTM_NEWNEIGH,
41         nudState = nudState,
42         linkLayerAddr = linkLayerAddr
43 )
44 
45 /**
46  * Make a RTM_DELNEIGH netlink message.
47  */
48 fun makeDelNeighMessage(
49     neighAddr: InetAddress,
50     nudState: Short
51 ) = makeNeighborMessage(
52         neighAddr = neighAddr,
53         type = RTM_DELNEIGH,
54         nudState = nudState
55 )
56 
57 private fun makeNeighborMessage(
58     neighAddr: InetAddress,
59     type: Short,
60     nudState: Short,
61     linkLayerAddr: String = VRRP_MAC_ADDR
62 ) = HexEncoding.decode(
63     /* ktlint-disable indent */
64     // -- struct nlmsghdr --
65                          // length = 88 or 76:
66     (if (neighAddr is Inet6Address) "58000000" else "4c000000") +
67     type.toLEHex() +     // type
68     "0000" +             // flags
69     "00000000" +         // seqno
70     "00000000" +         // pid (0 == kernel)
71     // struct ndmsg
72                          // family (AF_INET6 or AF_INET)
73     (if (neighAddr is Inet6Address) "0a" else "02") +
74     "00" +               // pad1
75     "0000" +             // pad2
76     "15000000" +         // interface index (21 == wlan0, on test device)
77     nudState.toLEHex() + // NUD state
78     "00" +               // flags
79     "01" +               // type
80     // -- struct nlattr: NDA_DST --
81                          // length = 20 or 8:
82     (if (neighAddr is Inet6Address) "1400" else "0800") +
83     "0100" +             // type (1 == NDA_DST, for neighbor messages)
84                          // IP address:
85     encodeToString(neighAddr.address) +
86     // -- struct nlattr: NDA_LLADDR --
87     "0a00" +             // length = 10
88     "0200" +             // type (2 == NDA_LLADDR, for neighbor messages)
89     linkLayerAddr +      // MAC Address(default == 00:00:5e:00:01:64)
90     "0000" +             // padding, for 4 byte alignment
91     // -- struct nlattr: NDA_PROBES --
92     "0800" +             // length = 8
93     "0400" +             // type (4 == NDA_PROBES, for neighbor messages)
94     "01000000" +         // number of probes
95     // -- struct nlattr: NDA_CACHEINFO --
96     "1400" +             // length = 20
97     "0300" +             // type (3 == NDA_CACHEINFO, for neighbor messages)
98     "05190000" +         // ndm_used, as "clock ticks ago"
99     "05190000" +         // ndm_confirmed, as "clock ticks ago"
100     "190d0000" +         // ndm_updated, as "clock ticks ago"
101     "00000000",          // ndm_refcnt
102     false /* allowSingleChar */)
103     /* ktlint-enable indent */
104 
105 /**
106  * Convert a [Short] to a little-endian hex string.
107  */
108 private fun Short.toLEHex() = String.format("%04x", java.lang.Short.reverseBytes(this))
109