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