1 /*
2  *  Interface MIB architecture support for Solaris
3  */
4 #include <net-snmp/net-snmp-config.h>
5 #include <net-snmp/net-snmp-features.h>
6 #include <net-snmp/net-snmp-includes.h>
7 #include "if-mib/ifTable/ifTable_constants.h"
8 #include "kernel_sunos5.h"
9 #include "mibII/mibII_common.h"
10 
11 #include <net-snmp/agent/net-snmp-agent-includes.h>
12 
13 #include <net-snmp/data_access/interface.h>
14 #include "if-mib/data_access/interface.h"
15 #include "interface_private.h"
16 #include <sys/ioctl.h>
17 #include <sys/sockio.h>
18 #include <strings.h>
19 #include <string.h>
20 
21 netsnmp_feature_child_of(interface_arch_set_admin_status, interface_all);
22 
23 static int _set_ip_flags_v4(netsnmp_interface_entry *, mib2_ifEntry_t *);
24 static int _match_ifname_v4addr(void *ifname, void *ipaddr);
25 static int _get_v4addr(mib2_ifEntry_t *ife, mib2_ipAddrEntry_t *e);
26 
27 static int _set_ip_flags_v6(netsnmp_interface_entry *, mib2_ifEntry_t *);
28 #ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
29 static int _get_v6addr(mib2_ifEntry_t *ife, mib2_ipv6AddrEntry_t *ipv6e);
30 static int _match_ifname_v6addr(void *ifname, void *ipaddr);
31 #endif
32 
33 void
netsnmp_arch_interface_init(void)34 netsnmp_arch_interface_init(void)
35 {
36     init_kernel_sunos5();
37 }
38 
39 /*
40  * find the ifIndex for an interface name
41  *
42  * @retval 0 : no index found
43  * @retval >0: ifIndex for interface
44  */
45 oid
netsnmp_arch_interface_index_find(const char * name)46 netsnmp_arch_interface_index_find(const char *name)
47 {
48 #if defined(HAVE_IF_NAMETOINDEX)
49     return if_nametoindex(name);
50 #else /* use GIFINDEX */
51     return solaris2_if_nametoindex(name, strlen(name));
52 #endif /* defined(HAVE_IF_NAMETOINDEX) */
53 }
54 
55 /*
56  * @retval  0 success
57  * @retval -1 no container specified
58  * @retval -2 could not create entry (probably malloc)
59  */
60 int
netsnmp_arch_interface_container_load(netsnmp_container * container,u_int l_flags)61 netsnmp_arch_interface_container_load(netsnmp_container* container,
62                                       u_int l_flags)
63 {
64     netsnmp_interface_entry *entry = NULL;
65     mib2_ifEntry_t          ife;
66     int                     rc;
67     req_e                   req = GET_FIRST;
68     int                     error = 0;
69 
70     DEBUGMSGTL(("access:interface:container:arch", "load (flags %u)\n",
71                 l_flags));
72 
73     if (container == NULL) {
74         snmp_log(LOG_ERR,
75                  "no container specified/found for interface\n");
76         return -1;
77     }
78 
79     while ((rc = getMibstat(MIB_INTERFACES, &ife, sizeof(ife), req,
80             &Get_everything, NULL)) == 0) {
81 
82         req = GET_NEXT;
83 
84         DEBUGMSGTL(("access:interface:container:arch",
85                     "processing '%s'\n", ife.ifDescr.o_bytes));
86         entry =
87             netsnmp_access_interface_entry_create(ife.ifDescr.o_bytes,
88                                                   ife.ifIndex);
89         if (entry == NULL) {
90             error = 1;
91             break;
92         }
93         entry->ns_flags = 0;
94 
95         if (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP4_ONLY &&
96             _set_ip_flags_v4(entry, &ife) == 0) {
97             netsnmp_access_interface_entry_free(entry);
98             continue;
99         } else if (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP6_ONLY &&
100                    _set_ip_flags_v6(entry, &ife) == 0) {
101             netsnmp_access_interface_entry_free(entry);
102             continue;
103         } else {
104             (void) _set_ip_flags_v4(entry, &ife);
105             (void) _set_ip_flags_v6(entry, &ife);
106         }
107 
108         /*
109          * collect the information needed by IF-MIB
110          */
111         entry->paddr = (char*)malloc(ife.ifPhysAddress.o_length);
112         if (entry->paddr == NULL) {
113             netsnmp_access_interface_entry_free(entry);
114             error = 1;
115             break;
116         }
117         entry->paddr_len = ife.ifPhysAddress.o_length;
118         (void)memcpy(entry->paddr, ife.ifPhysAddress.o_bytes,
119                      ife.ifPhysAddress.o_length);
120 
121         entry->type = ife.ifType;
122         entry->mtu = ife.ifMtu;
123         entry->speed = ife.ifSpeed;
124         entry->speed_high = entry->speed / 1000000;
125         entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;
126         entry->oper_status = ife.ifOperStatus;
127         entry->admin_status = ife.ifAdminStatus;
128 
129         if (ife.flags & IFF_PROMISC)
130             entry->promiscuous = 1;
131 
132         entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_ACTIVE;
133 
134         /*
135          * Interface Stats.
136          */
137         if (! (l_flags & NETSNMP_ACCESS_INTERFACE_LOAD_NO_STATS)) {
138             entry->ns_flags |=
139                 NETSNMP_INTERFACE_FLAGS_HAS_BYTES |
140                 NETSNMP_INTERFACE_FLAGS_HAS_DROPS |
141                 NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS;
142             if (ife.ifHCInOctets > 0 || ife.ifHCOutOctets > 0) {
143                 /*
144                  * We make the assumption that if we have
145                  * a 64-bit Octet counter, then the other
146                  * counters are 64-bit as well.
147                  */
148                 DEBUGMSGTL(("access:interface:container:arch",
149                             "interface '%s' have 64-bit stat counters\n",
150                             entry->name));
151                 entry->ns_flags |=
152                     NETSNMP_INTERFACE_FLAGS_HAS_HIGH_BYTES |
153                     NETSNMP_INTERFACE_FLAGS_HAS_HIGH_PACKETS;
154                 /* in stats */
155                 entry->stats.ibytes.low = ife.ifHCInOctets & 0xffffffff;
156                 entry->stats.ibytes.high = ife.ifHCInOctets >> 32;
157                 entry->stats.iucast.low = ife.ifHCInUcastPkts & 0xffffffff;
158                 entry->stats.iucast.high = ife.ifHCInUcastPkts >> 32;
159                 entry->stats.imcast.low = ife.ifHCInMulticastPkts & 0xffffffff;
160                 entry->stats.imcast.high = ife.ifHCInMulticastPkts >> 32;
161                 entry->stats.ibcast.low = ife.ifHCInBroadcastPkts & 0xffffffff;
162                 entry->stats.ibcast.high = ife.ifHCInBroadcastPkts >> 32;
163                 /* out stats */
164                 entry->stats.obytes.low = ife.ifHCOutOctets & 0xffffffff;
165                 entry->stats.obytes.high = ife.ifHCOutOctets >> 32;
166                 entry->stats.oucast.low = ife.ifHCOutUcastPkts & 0xffffffff;
167                 entry->stats.oucast.high = ife.ifHCOutUcastPkts >> 32;
168                 entry->stats.omcast.low = ife.ifHCOutMulticastPkts & 0xffffffff;
169                 entry->stats.omcast.high = ife.ifHCOutMulticastPkts >> 32;
170                 entry->stats.obcast.low = ife.ifHCOutBroadcastPkts & 0xffffffff;
171                 entry->stats.obcast.high = ife.ifHCOutBroadcastPkts >> 32;
172             } else {
173                 DEBUGMSGTL(("access:interface:container:arch",
174                             "interface '%s' have 32-bit stat counters\n",
175                             entry->name));
176                 /* in stats */
177                 entry->stats.ibytes.low = ife.ifInOctets;
178                 entry->stats.iucast.low = ife.ifInUcastPkts;
179                 entry->stats.imcast.low = ife.ifHCInMulticastPkts & 0xffffffff;
180                 entry->stats.ibcast.low = ife.ifHCInBroadcastPkts & 0xffffffff;
181                 /* out stats */
182                 entry->stats.obytes.low = ife.ifOutOctets;
183                 entry->stats.oucast.low = ife.ifOutUcastPkts;
184                 entry->stats.omcast.low = ife.ifHCOutMulticastPkts & 0xffffffff;
185                 entry->stats.obcast.low = ife.ifHCOutBroadcastPkts & 0xffffffff;
186             }
187             /* in stats */
188             entry->stats.ierrors = ife.ifInErrors;
189             entry->stats.idiscards = ife.ifInDiscards;
190             entry->stats.iunknown_protos = ife.ifInUnknownProtos;
191             entry->stats.inucast = ife.ifInNUcastPkts;
192             /* out stats */
193             entry->stats.oerrors = ife.ifOutErrors;
194             entry->stats.odiscards = ife.ifOutDiscards;
195             entry->stats.onucast = ife.ifOutNUcastPkts;
196             entry->stats.oqlen = ife.ifOutQLen;
197 
198             /* other stats */
199             entry->stats.collisions = ife.ifCollisions;
200         }
201 
202         netsnmp_access_interface_entry_overrides(entry);
203 
204         /*
205          * add to container
206          */
207         CONTAINER_INSERT(container, entry);
208     }
209     DEBUGMSGTL(("access:interface:container:arch", "rc = %d\n", rc));
210 
211     if (error) {
212         DEBUGMSGTL(("access:interface:container:arch",
213                     "error %d, free container\n", error));
214         netsnmp_access_interface_container_free(container,
215             NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
216         return -2;
217     }
218 
219     return 0;
220 }
221 /**
222  * @internal
223  */
224 static int
_set_ip_flags_v4(netsnmp_interface_entry * entry,mib2_ifEntry_t * ife)225 _set_ip_flags_v4(netsnmp_interface_entry *entry, mib2_ifEntry_t *ife)
226 {
227     mib2_ipAddrEntry_t ipv4e;
228 
229     if (_get_v4addr(ife, &ipv4e) > 0) {
230         entry->reasm_max_v4 = ipv4e.ipAdEntReasmMaxSize;
231         entry->ns_flags |=
232             NETSNMP_INTERFACE_FLAGS_HAS_IPV4 |
233             NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX;
234 #if defined( SOLARIS_HAVE_RFC4293_SUPPORT )
235         entry->retransmit_v4 = ipv4e.ipAdEntRetransmitTime;
236         entry->ns_flags |=
237             NETSNMP_INTERFACE_FLAGS_HAS_V4_RETRANSMIT;
238 #endif
239         return (1);
240     }
241     return (0);
242 }
243 
244 /**
245  * @internal
246  */
247 static int
_set_ip_flags_v6(netsnmp_interface_entry * entry,mib2_ifEntry_t * ife)248 _set_ip_flags_v6(netsnmp_interface_entry *entry, mib2_ifEntry_t *ife)
249 {
250 #ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
251     mib2_ipv6AddrEntry_t ipv6e;
252 
253     if (_get_v6addr(ife, &ipv6e) > 0) {
254         entry->ns_flags |=
255             NETSNMP_INTERFACE_FLAGS_HAS_IPV6;
256 #if defined( SOLARIS_HAVE_RFC4293_SUPPORT )
257         if (ipv6e.ipv6AddrIdentifierLen <= sizeof(entry->v6_if_id)) {
258             entry->v6_if_id_len = ipv6e.ipv6AddrIdentifierLen;
259             (void)memcpy(&entry->v6_if_id, &ipv6e.ipv6AddrIdentifier,
260                          entry->v6_if_id_len);
261             entry->ns_flags |=
262                 NETSNMP_INTERFACE_FLAGS_HAS_V6_IFID;
263         }
264         entry->reasm_max_v6 = ipv6e.ipv6AddrReasmMaxSize;
265         entry->retransmit_v6 = ipv6e.ipv6AddrRetransmitTime;
266         entry->reachable_time = ipv6e.ipv6AddrReachableTime;
267         entry->ns_flags |=
268             NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX |
269             NETSNMP_INTERFACE_FLAGS_HAS_V6_RETRANSMIT |
270             NETSNMP_INTERFACE_FLAGS_HAS_V6_REACHABLE;
271 
272         /* XXX forwarding info missing */
273 #else
274         /* XXX Don't have this info, 1500 is the minimum */
275         entry->reasm_max_v6 = 1500;
276         entry->ns_flags |=
277             NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX; /* ??? */
278 #endif /* SOLARIS_HAVE_RFC4293_SUPPORT */
279         return (1);
280     }
281 #endif /* SOLARIS_HAVE_IPV6_MIB_SUPPORT */
282     return (0);
283 }
284 
285 /**
286  * @internal
287  */
288 static int
_match_ifname_v4addr(void * ifname,void * ipaddr)289 _match_ifname_v4addr(void *ifname, void *ipaddr)
290 {
291     DeviceName *devname = &((mib2_ipAddrEntry_t *)ipaddr)->ipAdEntIfIndex;
292 
293     return (strncmp((char *)ifname, devname->o_bytes, devname->o_length));
294 
295 }
296 
297 /**
298  * @internal
299  *
300  * Search for address entry that belongs to the IF entry.
301  * Returns 1 if an address was found, in which case the entry
302  * will be stored in ipv4e. If not entry was found, 0 is returned.
303  *
304  */
305 static int
_get_v4addr(mib2_ifEntry_t * ife,mib2_ipAddrEntry_t * ipv4e)306 _get_v4addr(mib2_ifEntry_t *ife, mib2_ipAddrEntry_t *ipv4e)
307 {
308     int    rc;
309 
310     if ((rc = getMibstat(MIB_IP_ADDR, ipv4e, sizeof(*ipv4e), GET_EXACT,
311         &_match_ifname_v4addr, &ife->ifDescr.o_bytes)) == 0)
312         return (1);
313     memset(ipv4e, '\0', sizeof(*ipv4e));
314     return (0);
315 }
316 
317 #ifdef SOLARIS_HAVE_IPV6_MIB_SUPPORT
318 /**
319  * @internal
320  */
321 static int
_match_ifname_v6addr(void * ifname,void * ipaddr)322 _match_ifname_v6addr(void *ifname, void *ipaddr)
323 {
324     DeviceName *devname = &((mib2_ipv6AddrEntry_t*)ipaddr)->ipv6AddrIfIndex;
325 
326     return (strncmp((char *)ifname, devname->o_bytes, devname->o_length));
327 
328 }
329 
330 /**
331  * @internal
332  *
333  * Search for address entry that belongs to the IF entry.
334  * Returns 1 if an address was found, in which case the entry
335  * will be stored in ipv4e. If not entry was found, 0 is returned.
336  *
337  */
338 static int
_get_v6addr(mib2_ifEntry_t * ife,mib2_ipv6AddrEntry_t * ipv6e)339 _get_v6addr(mib2_ifEntry_t *ife, mib2_ipv6AddrEntry_t *ipv6e)
340 {
341     int    rc;
342 
343     if ((rc = getMibstat(MIB_IP6_ADDR, ipv6e, sizeof(*ipv6e), GET_EXACT,
344         &_match_ifname_v6addr, &ife->ifDescr.o_bytes)) == 0) {
345         return (1);
346     }
347     memset(ipv6e, '\0', sizeof(*ipv6e));
348     return (0);
349 }
350 #endif /* SOLARIS_HAVE_IPV6_MIB_SUPPORT */
351 
352 #ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS
353 int
netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,int ifAdminStatus_val)354 netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
355                               int ifAdminStatus_val)
356 {
357     DEBUGMSGTL(("access:interface:arch", "set_admin_status\n"));
358 
359     /*
360      * XXX Not supported yet
361      */
362     return (-1);
363 }
364 #endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ARCH_SET_ADMIN_STATUS */
365