summaryrefslogtreecommitdiff
path: root/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java
blob: 79d5ff4ad8562251439bedd680739561b68d3589 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.net.module.util.netlink;

import android.system.Os;
import android.system.OsConstants;

import java.nio.ByteBuffer;

/**
 * struct nda_cacheinfo
 *
 * see: <linux_src>/include/uapi/linux/neighbour.h
 *
 * @hide
 */
public class StructNdaCacheInfo {
    // Already aligned.
    public static final int STRUCT_SIZE = 16;

    private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
    }

    /**
     * Parse a nd cacheinfo netlink attribute from a {@link ByteBuffer}.
     *
     * @param byteBuffer The buffer from which to parse the nd cacheinfo attribute.
     * @return the parsed nd cacheinfo attribute, or {@code null} if the nd cacheinfo attribute
     *         could not be parsed successfully (for example, if it was truncated).
     */
    public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
        if (!hasAvailableSpace(byteBuffer)) return null;

        // The ByteOrder must have already been set by the caller.  In most
        // cases ByteOrder.nativeOrder() is correct, with the possible
        // exception of usage within unittests.
        final StructNdaCacheInfo struct = new StructNdaCacheInfo();
        struct.ndm_used = byteBuffer.getInt();
        struct.ndm_confirmed = byteBuffer.getInt();
        struct.ndm_updated = byteBuffer.getInt();
        struct.ndm_refcnt = byteBuffer.getInt();
        return struct;
    }

    // TODO: investigate whether this can change during device runtime and
    // decide what (if anything) should be done about that.
    private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);

    private static long ticksToMilliSeconds(int intClockTicks) {
        final long longClockTicks = (long) intClockTicks & 0xffffffff;
        return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
    }

    /**
     * Explanatory notes, for reference.
     *
     * Before being returned to user space, the neighbor entry times are
     * converted to clock_t's like so:
     *
     *     ndm_used      = jiffies_to_clock_t(now - neigh->used);
     *     ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
     *     ndm_updated   = jiffies_to_clock_t(now - neigh->updated);
     *
     * meaning that these values are expressed as "clock ticks ago".  To
     * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
     * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
     * in centiseconds.
     *
     * These values are unsigned, but fortunately being expressed as "some
     * clock ticks ago", these values are typically very small (and
     * 2^31 centiseconds = 248 days).
     *
     * By observation, it appears that:
     *     ndm_used: the last time ARP/ND took place for this neighbor
     *     ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
     *                    higher layer confirmation (TCP or MSG_CONFIRM)
     *                    was received
     *     ndm_updated: the time when the current NUD state was entered
     */
    public int ndm_used;
    public int ndm_confirmed;
    public int ndm_updated;
    public int ndm_refcnt;

    public StructNdaCacheInfo() {}

    /**
     * The last time ARP/ND took place for this neighbor.
     */
    public long lastUsed() {
        return ticksToMilliSeconds(ndm_used);
    }

    /**
     * The last time ARP/ND succeeded for this neighbor or higher layer confirmation (TCP or
     * MSG_CONFIRM) was received.
     */
    public long lastConfirmed() {
        return ticksToMilliSeconds(ndm_confirmed);
    }

    /**
     * The time when the current NUD state was entered.
     */
    public long lastUpdated() {
        return ticksToMilliSeconds(ndm_updated);
    }

    @Override
    public String toString() {
        return "NdaCacheInfo{ "
                + "ndm_used{" + lastUsed() + "}, "
                + "ndm_confirmed{" + lastConfirmed() + "}, "
                + "ndm_updated{" + lastUpdated() + "}, "
                + "ndm_refcnt{" + ndm_refcnt + "} "
                + "}";
    }
}