summaryrefslogtreecommitdiff
path: root/agent/mibgroup/ip-mib/data_access/ipv6scopezone_linux.c
blob: 7d606415bcf4c826c9699baf1c36557dff069c8e (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
/*
 *  Interface MIB architecture support
 *
 * $Id: ipv6scopezone_linux.c 14170 2007-04-29 02:22:12Z varun_c $
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/data_access/scopezone.h>

#if defined (NETSNMP_ENABLE_IPV6)
static int _scopezone_v6(netsnmp_container* container, int idx_offset);
#endif

/*
 *
 * @retval  0 success
 * @retval -1 no container specified
 * @retval -2 could not open file
 * @retval -3 could not create entry (probably malloc)
 * @retval -4 file format error
 */
int
netsnmp_access_scopezone_container_arch_load(netsnmp_container* container,
                                             u_int load_flags)
{
    int rc1 = 0;
#if defined (NETSNMP_ENABLE_IPV6)
    int idx_offset = 0;

    if (NULL == container) {
        snmp_log(LOG_ERR, "no container specified/found for access_scopezone_\n");
        return -1;
    }

    rc1 = _scopezone_v6(container, idx_offset);
#endif
    if(rc1 > 0)
        rc1 = 0;
    return rc1;
}

#if defined (NETSNMP_ENABLE_IPV6)

/* scope identifiers, from kernel - include/net/ipv6.h */
#define IPV6_ADDR_LOOPBACK      0x0010U
#define IPV6_ADDR_LINKLOCAL     0x0020U
#define IPV6_ADDR_SITELOCAL     0x0040U

static int
_scopezone_v6(netsnmp_container* container, int idx_offset)
{

    /*
     * On Linux, we support only link-local scope zones.
     * Each interface, which has link-local address, gets unique scope
     * zone index.
     */
    FILE           *in;
    char            line[80], addr[40];
    int             if_index, pfx_len, scope, flags, rc = 0;
    int             last_if_index = -1;
    netsnmp_v6scopezone_entry *entry;
    
    netsnmp_assert(NULL != container);

#define PROCFILE "/proc/net/if_inet6"
    if (!(in = fopen(PROCFILE, "r"))) {
        DEBUGMSGTL(("access:scopezone:container","could not open " PROCFILE "\n"));
        return -2;
    }
    
    /*
     * address index prefix_len scope status if_name
     */
    while (fgets(line, sizeof(line), in)) {
        /*
         * fe800000000000000200e8fffe5b5c93 05 40 20 80 eth0
         *             A                    D  P  S  F  I
         * A: address
         * D: device number
         * P: prefix len
         * S: scope (see include/net/ipv6.h, net/ipv6/addrconf.c)
         * F: flags (see include/linux/rtnetlink.h, net/ipv6/addrconf.c)
         * I: interface
         */
        rc = sscanf(line, "%39s %04x %02x %02x %02x\n",
                    addr, &if_index, &pfx_len, &scope, &flags);
        if( 5 != rc ) {
            snmp_log(LOG_ERR, PROCFILE " data format error (%d!=5), line ==|%s|\n",
                     rc, line);
            continue;
        }
        DEBUGMSGTL(("access:scopezone:container",
                    "addr %s, index %d, pfx %d, scope %d, flags 0x%X\n",
                    addr, if_index, pfx_len, scope, flags));

        if (! (scope & IPV6_ADDR_LINKLOCAL)) {
            DEBUGMSGTL(("access:scopezone:container", 
                        "The address is not link-local, skipping\n"));
            continue;
        }
        /* 
         * Check that the interface was not inserted before, just in case
         * one interface has two or more link-local addresses.
         */
        if (last_if_index == if_index) {
            DEBUGMSGTL(("access:scopezone:container", 
                        "The interface was already inserted, skipping\n"));
            continue;
        }

        last_if_index = if_index; 
        entry = netsnmp_access_scopezone_entry_create();
        if(NULL == entry) {
            rc = -3;
            break;
        }
        entry->ns_scopezone_index = ++idx_offset;
        entry->index = if_index;
        entry->scopezone_linklocal = if_index;
 
        CONTAINER_INSERT(container, entry);
    }
    fclose(in);
    if(rc<0)
        return rc;

    return idx_offset;
}
#endif