1
0
Files
2022-09-29 17:59:04 +03:00

1611 lines
39 KiB
C++

/*
* Copyright 1991 Silicon Graphics, Inc. All rights reserved.
*
* IP sub-agent
*
* $Revision: 1.6 $
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#include <sys/types.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <malloc.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <sys/hashing.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/in_pcb.h>
#include <sys/tcpipstats.h>
#include <sys/sysctl.h>
#include <sys/sysmp.h>
#include <alloca.h>
#include <errno.h>
extern "C" {
#include "exception.h"
};
#include <syslog.h>
#include <unistd.h>
#include <bstring.h>
#include <stdlib.h>
#include <stdio.h>
#include "oid.h"
#include "asn1.h"
#include "snmp.h"
#include "packet.h"
#include "subagent.h"
#include "sat.h"
#include "agent.h"
#include "table.h"
#include "ipsa.h"
#include "ifsa.h"
#include "rt.h"
#define SIN(s) ((struct sockaddr_in *) (&(s)))
#define SINPTR(p) ((struct sockaddr_in *)(p))
// this prototype no longer needed in sherwood
extern "C" { // Where's the real one?
extern int rsocket;
}
const subID ipForwarding = 1;
const subID ipDefaultTTL = 2;
const subID ipInReceives = 3;
const subID ipInHdrErrors = 4;
const subID ipInAddrErrors = 5;
const subID ipForwDatagrams = 6;
const subID ipInInUnknownProtos = 7;
const subID ipInDiscards = 8;
const subID ipInDelivers = 9;
const subID ipOutRequests = 10;
const subID ipOutDiscards = 11;
const subID ipOutNoRoutes = 12;
const subID ipReasmTimeout = 13;
const subID ipReasmReqds = 14;
const subID ipReasmOKs = 15;
const subID ipReasmFails = 16;
const subID ipFragOKs = 17;
const subID ipFragFails = 18;
const subID ipFragCreates = 19;
const subID ipAddrTable = 20;
const subID ipAdEntAddr = 1;
const subID ipAdEntIfIndex = 2;
const subID ipAdEntNetMask = 3;
const subID ipAdEntBcastAddr = 4;
const subID ipAdEntReasmMaxSize = 5;
const subID ipAdEntValid = 6; // Internal
const subID ipRouteTable = 21;
const subID ipRouteDest = 1;
const subID ipRouteIfIndex = 2;
const subID ipRouteMetric1 = 3;
const subID ipRouteMetric2 = 4;
const subID ipRouteMetric3 = 5;
const subID ipRouteMetric4 = 6;
const subID ipRouteNextHop = 7;
const subID ipRouteType = 8;
const subID ipRouteProto = 9;
const subID ipRouteAge = 10;
const subID ipRouteMask = 11;
const subID ipRouteMetric5 = 12;
const subID ipRouteInfo = 13;
const subID ipRouteValid = 14; // Internal
const subID ipNetToMediaTable = 22;
const subID ipNetToMediaIfIndex = 1;
const subID ipNetToMediaPhysAddress = 2;
const subID ipNetToMediaNetAddress = 3;
const subID ipNetToMediaType = 4;
const subID ipNetToMediaValid = 5; // Internal
const subID ipRoutingDiscards = 23;
const int forwardGateway = 1;
const int forwardHost = 2;
// const int routeTypeOther = 1; // Never referenced
const int routeTypeInvalid = 2;
const int routeTypeDirect = 3;
const int routeTypeIndirect = 4;
const int routeProtoOther = 1;
const int routeProtoNetmgmt = 3;
const int routeProtoIcmp = 4;
// const int mediaTypeOther = 1; // Never referenced
const int mediaTypeInvalid = 2;
const int mediaTypeDynamic = 3;
const int mediaTypeStatic = 4;
// For tables
static ipSubAgent *ipsa;
extern ifSubAgent *ifsa;
#ifdef sgi
struct ifreq ifreq[200];
int seqno = 0;
int install = 1;
u_long
check_netmask(u_long i_addr)
{
int s; /* socket fd */
int len;
struct ifconf ifconf;
struct ifreq *ifrp;
struct ifreq ifnetmask;
u_long if_mask, if_netnum;
struct in_addr if_addr;
s = 0;
len = 0;
ifconf.ifc_len = sizeof ifreq;
ifconf.ifc_req = ifreq;
if (ioctl(s, SIOCGIFCONF, (caddr_t)&ifconf) < 0 || ifconf.ifc_len <= 0) {
syslog(LOG_ERR, "'get interface config' ioctl failed (%m)");
return 0;
}
len = ifconf.ifc_len;
for (ifrp = &ifreq[0]; len > 0; len -= sizeof (struct ifreq), ifrp++) {
if (SINPTR(&ifrp->ifr_addr)->sin_family == AF_INET) {
strncpy(ifnetmask.ifr_name, ifrp->ifr_name,
sizeof(ifnetmask.ifr_name));
if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifnetmask) < 0) {
syslog(LOG_ERR, "'get interface netmask' ioctl failed (%m)");
return 0;
}
if_mask = SINPTR(&ifnetmask.ifr_addr)->sin_addr.s_addr;
if_addr = SINPTR(&ifrp->ifr_addr)->sin_addr;
if_netnum = if_mask & if_addr.s_addr;
if( (if_mask & i_addr) == if_netnum)
return if_mask;
}
}
return 0;
}
/*
* Return the netmask pertaining to an internet address.
*/
u_long
inet_maskof(u_long inaddr)
{
register u_long i = ntohl(inaddr);
register u_long mask, hmask;
if (i == 0) {
mask = 0;
} else if (IN_CLASSA(i)) {
mask = IN_CLASSA_NET;
} else if (IN_CLASSB(i)) {
mask = IN_CLASSB_NET;
} else
mask = IN_CLASSC_NET;
/*
* Check whether network is a subnet;
* if so, use the modified interpretation of `host'.
*/
/****
for (ifp = ifnet; ifp; ifp = ifp->int_next)
if ((ifp->int_netmask & i) == ifp->int_net)
mask = ifp->int_subnetmask;
***/
hmask = check_netmask(i);
if(hmask)
mask = hmask;
return (htonl(mask));
}
#define ADD 1
#define DELETE 2
#define CHANGE 3
int
rtioctl(int action, struct rtuentry *ort)
{
#ifndef RTM_ADD
if (install == 0)
return (errno = 0);
ort->rtu_rtflags = ort->rtu_flags;
switch (action) {
case ADD:
return (ioctl(s, SIOCADDRT, (char *)ort));
case DELETE:
return (ioctl(s, SIOCDELRT, (char *)ort));
default:
return (-1);
}
#else /* RTM_ADD */
struct {
struct rt_msghdr w_rtm;
struct sockaddr_in w_dst;
struct sockaddr w_gate;
#ifdef _HAVE_SA_LEN
struct sockaddr_in w_netmask;
#else
struct sockaddr_in_new w_netmask;
#endif
} w;
#define rtm w.w_rtm
bzero((char *)&w, sizeof(w));
rtm.rtm_msglen = sizeof(w);
rtm.rtm_version = RTM_VERSION;
rtm.rtm_type = (action == ADD ? RTM_ADD :
(action == DELETE ? RTM_DELETE : RTM_CHANGE));
#undef rt_dst
rtm.rtm_flags = ort->rtu_flags;
rtm.rtm_seq = ++seqno;
rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
w.w_dst.sin_family = AF_INET;
#ifdef _HAVE_SA_LEN
w.w_dst.sin_len = sizeof(w.w_dst);
#endif
w.w_gate.sa_family = AF_INET;
#ifdef _HAVE_SA_LEN
w.w_gate.sa_len = sizeof(w.w_gate);
#endif
if (rtm.rtm_flags & RTF_HOST) {
rtm.rtm_msglen -= sizeof(w.w_netmask);
} else {
#ifdef _HAVE_SA_LEN
register char *cp;
int len;
#endif
rtm.rtm_addrs |= RTA_NETMASK;
w.w_netmask.sin_addr.s_addr =
inet_maskof(w.w_dst.sin_addr.s_addr);
#ifdef _HAVE_SA_LEN
for (cp = (char *)(1 + &w.w_netmask.sin_addr);
--cp > (char *) &w.w_netmask; )
if (*cp)
break;
len = cp - (char *)&w.w_netmask;
if (len) {
len++;
w.w_netmask.sin_len = len;
len = 1 + ((len - 1) | (sizeof(long) - 1));
} else
len = sizeof(long);
rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
#endif
}
errno = 0;
return (install ? write(rsocket, (char *)&w, rtm.rtm_msglen) : (errno = 0));
#endif /* RTM_ADD */
}
#if 0
static int
sysctl( int *name, u_int namelen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen)
{
static int s = -1;
struct rtsysctl ctl;
if (s < 0) {
s = socket(AF_ROUTE, SOCK_RAW, 0);
if (s < 0)
return s;
}
ctl.name = name;
ctl.namelen = namelen;
ctl.oldp = oldp;
ctl.oldlen = *oldlenp;
ctl.newp = newp;
ctl.newlen = newlen;
if (0 > ioctl(s, _SIOCRTSYSCTL, &ctl))
return -1;
*oldlenp = ctl.oldlen;
return 0;
}
#endif
#endif /* sgi */
ipSubAgent::ipSubAgent(void)
{
// Store address for table update routines
ipsa = this;
// Export subtree
subtree = "1.3.6.1.2.1.4";
int rc = export("ip", &subtree);
if (rc != SNMP_ERR_genErr) {
log(LOG_ERR, 0, "error exporting IP subagent");
return;
}
// Define tables
addrtable = table(ipAddrTable, 4, updateIpAddrTable);
routetable = table(ipRouteTable, 4, updateIpRouteTable);
nettomediatable = table(ipNetToMediaTable, 5, updateNetToMediaTable);
}
ipSubAgent::~ipSubAgent(void)
{
unexport(&subtree);
delete addrtable;
delete routetable;
}
int
ipSubAgent::get(asnObjectIdentifier *o, asnObject **a, int *)
{
// Must be static to work correctly. Otherwise, sysmp gives
// errno = 14 (Bad address).
static struct kna kna_s;
struct kna *kna_p = &kna_s;
struct ipstat *ipstat_p;
// Pull out the subID array and length
subID *subid;
unsigned int len;
oid *oi = o->getValue();
oi->getValue(&subid, &len);
// Check that the subID array is of valid size
if (len == sublen)
return SNMP_ERR_noSuchName;
// Handle the tables separately
switch (subid[sublen]) {
case ipAddrTable:
if (len != sublen + 7
|| subid[sublen + 1] != 1
|| subid[sublen + 2] == 0
|| subid[sublen + 2] > ipAdEntReasmMaxSize)
return SNMP_ERR_noSuchName;
updateIpAddrTable();
return addrtable->get(oi, a);
case ipRouteTable:
if (len != sublen + 7
|| subid[sublen + 1] != 1
|| subid[sublen + 2] == 0
|| subid[sublen + 2] > ipRouteInfo)
return SNMP_ERR_noSuchName;
updateIpRouteTable();
return routetable->get(oi, a);
case ipNetToMediaTable:
if (len != sublen + 8
|| subid[sublen + 1] != 1
|| subid[sublen + 2] == 0
|| subid[sublen + 2] > ipNetToMediaType)
return SNMP_ERR_noSuchName;
updateNetToMediaTable();
return nettomediatable->get(oi, a);
}
// Check that the subID array is of valid size
if (len != sublen + 2 || subid[sublen + 1] != 0)
return SNMP_ERR_noSuchName;
// Get the pointer to the ipstat structure
int err = sysmp(MP_SAGET, MPSA_TCPIPSTATS, kna_p, sizeof(struct kna));
if (err < 0) {
exc_errlog(LOG_ERR, 0, "ip get: sysmp error: errno=%d", errno);
// No IP objects will be returned
return SNMP_ERR_noSuchName;
}
ipstat_p = &(kna_p->ipstat);
// Switch on the subID and assign the value to *a
switch (subid[sublen]) {
case ipForwarding :
{
int mib[4], i = 0;
size_t needed = sizeof(i);
mib[0] = CTL_NET;
mib[1] = PF_INET;
mib[2] = IPPROTO_IP;
mib[3] = IPCTL_FORWARDING;
if (sysctl(mib, 4, &i, &needed, NULL, 0) < 0) {
perror("sysctl");
}
if (i != 0)
*a = new asnInteger(forwardGateway);
else
*a = new asnInteger(forwardHost);
}
break;
case ipDefaultTTL :
*a = new asnInteger(IP_DEFAULT_MULTICAST_TTL);
break;
case ipInReceives :
*a = new snmpCounter((unsigned int) ipstat_p->ips_total);
break;
case ipInHdrErrors :
*a = new snmpCounter((unsigned int) (ipstat_p->ips_badhlen
+ ipstat_p->ips_badsum
+ ipstat_p->ips_badlen
+ ipstat_p->ips_badoptions));
break;
case ipInAddrErrors :
*a = new snmpCounter((unsigned int) ipstat_p->ips_cantforward);
break;
case ipForwDatagrams :
*a = new snmpCounter ((unsigned int) (ipstat_p->ips_forward
+ ipstat_p->ips_cantforward));
break;
case ipInInUnknownProtos :
*a = new snmpCounter((unsigned int) ipstat_p->ips_noproto);
break;
case ipInDiscards :
*a = new snmpCounter(0); // We can't have these
break;
case ipInDelivers :
*a = new snmpCounter((unsigned int) ipstat_p->ips_delivered);
break;
case ipOutRequests :
*a = new snmpCounter((unsigned int) (ipstat_p->ips_localout
- ipstat_p->ips_forward));
break;
case ipOutDiscards :
*a = new snmpCounter((unsigned int) ipstat_p->ips_odropped);
break;
case ipOutNoRoutes :
*a = new snmpCounter((unsigned int) ipstat_p->ips_noroute);
break;
case ipReasmTimeout :
*a = new asnInteger(IPFRAGTTL);
break;
case ipReasmReqds :
*a = new snmpCounter((unsigned int) ipstat_p->ips_fragments);
break;
case ipReasmOKs :
*a = new snmpCounter((unsigned int) ipstat_p->ips_reassembled);
break;
case ipReasmFails :
*a = new snmpCounter((unsigned int) (ipstat_p->ips_fragdropped
+ ipstat_p->ips_fragtimeout));
break;
case ipFragOKs :
*a = new snmpCounter((unsigned int) ipstat_p->ips_fragmented);
break;
case ipFragFails :
*a = new snmpCounter((unsigned int) ipstat_p->ips_cantfrag);
break;
case ipFragCreates :
*a = new snmpCounter((unsigned int) ipstat_p->ips_fragmented);
break;
case ipRoutingDiscards:
// XXX - Do we do this?
*a = new snmpCounter(0);
break;
default :
return SNMP_ERR_noSuchName;
}
return SNMP_ERR_noError;
}
int
ipSubAgent::getNext(asnObjectIdentifier *o, asnObject **a, int *t)
{
return simpleGetNext(o, a, t, ipRoutingDiscards);
}
int
ipSubAgent::set(asnObjectIdentifier *o, asnObject **a, int *)
{
subID *subid, s;
unsigned int len;
int rc;
asnObject *ao;
// Pull out the subID array and length
oid *oi = o->getValue();
oi->getValue(&subid, &len);
// Check that the subID array is of valid size
if (len == sublen)
return SNMP_ERR_noSuchName;
// Handle the tables separately
switch (subid[sublen]) {
case ipRouteTable:
if (len != sublen + 7
|| subid[sublen + 1] != 1
|| subid[sublen + 2] == 0
|| subid[sublen + 2] > ipRouteInfo)
return SNMP_ERR_noSuchName;
// Update the table
updateIpRouteTable();
// Check if the entry exists
rc = routetable->get(oi, &ao);
if (rc == SNMP_ERR_noSuchName) {
// Add a new row
#if _MIPS_SZLONG == 64
unsigned int addr;
#else
unsigned long addr;
#endif
snmpIPaddress p;
asnInteger i;
asnObjectIdentifier aoi = "0.0";
subID s = subid[sublen + 2];
// Set up new row
subid[sublen + 2] = ipRouteDest;
addr = (subid[sublen + 3] & 0xFF) << 24;
addr |= (subid[sublen + 4] & 0xFF) << 16;
addr |= (subid[sublen + 5] & 0xFF) << 8;
addr |= subid[sublen + 6] & 0xFF;
p = addr;
ao = &p;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteIfIndex;
i = 0;
ao = &i;
routetable->set(oi, &ao);
// XXX - Routing metrics?
subid[sublen + 2] = ipRouteMetric1;
i = -1;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteMetric2;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteMetric3;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteMetric4;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteMetric5;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteType;
i = routeTypeInvalid;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteProto;
i = routeProtoNetmgmt;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteAge;
i = 0;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteValid;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteNextHop;
ao = &p;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteMask;
routetable->set(oi, &ao);
subid[sublen + 2] = ipRouteInfo;
ao = &aoi;
routetable->set(oi, &ao);
subid[sublen + 2] = s;
ao = 0;
}
switch (subid[sublen + 2]) {
case ipRouteDest:
case ipRouteNextHop:
delete ao;
// Check for correct type
if ((*a)->getTag() != TAG_IPADDRESS)
return SNMP_ERR_badValue;
// Only allow setting an invalid route
s = subid[sublen + 2];
subid[sublen + 2] = ipRouteType;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = s;
return rc;
}
subid[sublen + 2] = s;
if (((asnInteger *) ao)->getValue() != routeTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Set it in the agent
delete ao;
return routetable->set(oi, a);
case ipRouteIfIndex:
case ipRouteMask:
// We don't allow this to be set
return SNMP_ERR_noSuchName;
case ipRouteMetric1:
case ipRouteMetric2:
case ipRouteMetric3:
case ipRouteMetric4:
case ipRouteMetric5:
case ipRouteAge:
delete ao;
// Check for correct type
if ((*a)->getTag() != TAG_INTEGER)
return SNMP_ERR_badValue;
// Only allow setting an invalid route
s = subid[sublen + 2];
subid[sublen + 2] = ipRouteType;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = s;
return rc;
}
subid[sublen + 2] = s;
if (((asnInteger *) ao)->getValue() != routeTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Set it in the agent
delete ao;
return routetable->set(oi, a);
case ipRouteType:
// Check for correct type
if ((*a)->getTag() != TAG_INTEGER) {
delete ao;
return SNMP_ERR_badValue;
}
if (((asnInteger *) ao)->getValue() == routeTypeInvalid) {
// Add a new route
#ifdef sgi
struct rtuentry rt;
#else
struct rtentry rt;
#endif
bzero(&rt, sizeof rt);
delete ao;
// Check that new value is legal
if (((asnInteger *) *a)->getValue() == routeTypeInvalid)
return SNMP_ERR_badValue;
// Fill in the rtentry
#ifdef sgi
rt.rtu_rtflags = RTF_UP;
rt.rtu_rtflags |= ((asnInteger *) *a)->getValue() ==
routeTypeIndirect ?
RTF_GATEWAY : RTF_HOST;
#else
rt.rt_flags = RTF_UP;
rt.rt_flags |= ((asnInteger *) *a)->getValue() ==
routeTypeIndirect ?
RTF_GATEWAY : RTF_HOST;
#endif
subid[sublen + 2] = ipRouteDest;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipRouteType;
return rc;
}
#ifdef sgi
SIN(rt.rtu_dst)->sin_family = AF_INET;
SIN(rt.rtu_dst)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#else
SIN(rt.rt_dst)->sin_family = AF_INET;
SIN(rt.rt_dst)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#endif
delete ao;
subid[sublen + 2] = ipRouteNextHop;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipRouteType;
return rc;
}
#ifdef sgi
SIN(rt.rtu_router)->sin_family = AF_INET;
SIN(rt.rtu_router)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#else
SIN(rt.rt_gateway)->sin_family = AF_INET;
SIN(rt.rt_gateway)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#endif
delete ao;
subid[sublen + 2] = ipRouteType;
// Add to kernel route table
#ifdef sgi
if(rtioctl(ADD, &rt) < 0) {
#else
int sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0 || ioctl(sock, SIOCADDRT, &rt) < 0) {
close(sock);
#endif
return SNMP_ERR_noSuchName;
}
#ifndef sgi
close(sock);
#endif
return routetable->set(oi, a);
} else {
#ifdef sgi
struct rtuentry rt;
#else
struct rtentry rt;
#endif
// Only allow deleting an existing route.
if (((asnInteger*)*a)->getValue() != routeTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Fill in the rtentry
bzero(&rt, sizeof rt);
#ifdef sgi
rt.rtu_rtflags = RTF_UP;
rt.rtu_rtflags |= ((asnInteger *) ao)->getValue() ==
routeTypeIndirect ?
RTF_GATEWAY : RTF_HOST;
#else
rt.rt_flags = RTF_UP;
rt.rt_flags |= ((asnInteger *) ao)->getValue() ==
routeTypeIndirect ?
RTF_GATEWAY : RTF_HOST;
#endif
delete ao;
subid[sublen + 2] = ipRouteDest;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipRouteType;
return rc;
}
#ifdef sgi
SIN(rt.rtu_dst)->sin_family = AF_INET;
SIN(rt.rtu_dst)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#else
SIN(rt.rt_dst)->sin_family = AF_INET;
SIN(rt.rt_dst)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#endif
delete ao;
subid[sublen + 2] = ipRouteNextHop;
rc = routetable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipRouteType;
return rc;
}
#ifdef sgi
SIN(rt.rtu_router)->sin_family = AF_INET;
SIN(rt.rtu_router)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#else
SIN(rt.rt_gateway)->sin_family = AF_INET;
SIN(rt.rt_gateway)->sin_addr.s_addr = (unsigned int)
((snmpIPaddress *) ao)->getValue();
#endif
delete ao;
// Delete from kernel route table
#ifdef sgi
if(rtioctl(DELETE, &rt) < 0) {
#else
int sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0 || ioctl(sock, SIOCDELRT, &rt) < 0) {
close(sock);
#endif
subid[sublen + 2] = ipRouteType;
return SNMP_ERR_noSuchName;
}
#ifndef sgi
close(sock);
#endif
// Delete from agent table
ao = 0;
for (s = ipRouteDest; s <= ipRouteValid; s++) {
subid[sublen + 2] = s;
routetable->set(oi, &ao);
}
subid[sublen + 2] = ipRouteType;
return SNMP_ERR_noError;
}
}
case ipNetToMediaTable:
if (len != sublen + 8
|| subid[sublen + 1] != 1
|| subid[sublen + 2] == 0
|| subid[sublen + 2] > ipNetToMediaType)
return SNMP_ERR_noSuchName;
// Update the table
updateNetToMediaTable();
// Check if the entry exists
rc = nettomediatable->get(oi, &ao);
if (rc == SNMP_ERR_noSuchName) {
// Add a new row
#if _MIPS_SZLONG == 64
unsigned int addr;
#else
unsigned long addr;
#endif
snmpIPaddress p;
asnInteger i;
asnObjectIdentifier aoi = "0.0";
asnOctetString physaddr = "0:0:0:0:0:0";
subID s = subid[sublen + 2];
// Set up new row
subid[sublen + 2] = ipNetToMediaPhysAddress;
ao = &physaddr;
nettomediatable->set(oi, &ao);
subid[sublen + 2] = ipNetToMediaNetAddress;
addr = (subid[sublen + 4] & 0xFF) << 24;
addr |= (subid[sublen + 5] & 0xFF) << 16;
addr |= (subid[sublen + 6] & 0xFF) << 8;
addr |= subid[sublen + 7] & 0xFF;
p = addr;
ao = &p;
nettomediatable->set(oi, &ao);
subid[sublen + 2] = ipNetToMediaIfIndex;
i = subid[sublen + 3];
ao = &i;
nettomediatable->set(oi, &ao);
subid[sublen + 2] = ipNetToMediaValid;
nettomediatable->set(oi, &ao);
subid[sublen + 2] = ipNetToMediaType;
i = mediaTypeInvalid;
nettomediatable->set(oi, &ao);
subid[sublen + 2] = s;
ao = 0;
}
switch (subid[sublen + 2]) {
case ipNetToMediaIfIndex: // We don't allow this to be set
delete ao;
return SNMP_ERR_badValue;
case ipNetToMediaPhysAddress:
delete ao;
// Check for correct type
if ((*a)->getTag() != TAG_OCTET_STRING)
return SNMP_ERR_badValue;
s = subid[sublen + 2];
subid[sublen + 2 ] = ipNetToMediaType;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = s;
return rc;
}
subid[sublen + 2] = s;
if (((asnInteger *) ao)->getValue() != mediaTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Set it in the agent
delete ao;
return nettomediatable->set(oi, a);
case ipNetToMediaNetAddress:
delete ao;
// Check for correct type
if ((*a)->getTag() != TAG_IPADDRESS)
return SNMP_ERR_badValue;
s = subid[sublen + 2];
subid[sublen + 2 ] = ipNetToMediaType;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = s;
return rc;
}
subid[sublen + 2] = s;
if (((asnInteger *) ao)->getValue() != mediaTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Set it in the agent
delete ao;
return nettomediatable->set(oi, a);
case ipNetToMediaType:
// Check for correct type
if ((*a)->getTag() != TAG_INTEGER) {
delete ao;
return SNMP_ERR_badValue;
}
if (((asnInteger *) ao)->getValue() == mediaTypeInvalid) {
// Add a new entry
struct arpreq arpreq;
bzero(&arpreq, sizeof arpreq);
delete ao;
// Check that new value is legal
if (((asnInteger *) *a)->getValue() == mediaTypeInvalid)
return SNMP_ERR_badValue;
// Fill in the arp table entry
struct sockaddr_in *sin;
subid[sublen + 2] = ipNetToMediaNetAddress;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipNetToMediaType;
return rc;
}
sin = (struct sockaddr_in *)&arpreq.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = (unsigned int)((snmpIPaddress *) ao)->getValue();
delete ao;
subid[sublen + 2] = ipNetToMediaPhysAddress;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipNetToMediaType;
return rc;
}
bcopy(((asnOctetString *) ao)->getValue(),
arpreq.arp_ha.sa_data,
((asnOctetString *) ao)->getLength());
delete ao;
subid[sublen + 2] = ipNetToMediaType;
// Add arp entry to kernel
int sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0 || ioctl(sock, SIOCSARP, &arpreq) < 0) {
close(sock);
return SNMP_ERR_noSuchName;
}
close(sock);
return SNMP_ERR_noError;
} else {
struct arpreq arpreq;
bzero (&arpreq, sizeof arpreq);
// Only allow deleting an existing entry
if (((asnInteger *) *a)->getValue() != mediaTypeInvalid) {
delete ao;
return SNMP_ERR_badValue;
}
// Fill in the arp table entry
struct sockaddr_in *sin;
subid[sublen + 2] = ipNetToMediaNetAddress;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipNetToMediaType;
return rc;
}
sin = (struct sockaddr_in *)&arpreq.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = (unsigned int)((snmpIPaddress *) ao)->getValue();
delete ao;
subid[sublen + 2] = ipNetToMediaPhysAddress;
rc = nettomediatable->get(oi, &ao);
if (rc != SNMP_ERR_noError) {
subid[sublen + 2] = ipNetToMediaType;
return rc;
}
bcopy(((asnOctetString *) ao)->getValue(),
arpreq.arp_ha.sa_data,
((asnOctetString *) ao)->getLength());
delete ao;
// Delete arp entry from kernel
int sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0 || ioctl(sock, SIOCDARP, &arpreq) < 0) {
close(sock);
subid[sublen + 2] = ipNetToMediaType;
return SNMP_ERR_noSuchName;
}
close(sock);
// Delete from the agent table
ao = 0;
for (s = ipNetToMediaIfIndex;
s <= ipNetToMediaValid; s++) {
subid[sublen + 2] = s;
nettomediatable->set(oi, &ao);
}
subid[sublen + 2] = ipNetToMediaType;
return SNMP_ERR_noError;
}
}
case ipForwarding:
// IRIX can't switch on the fly
// XXX - Can it?
return SNMP_ERR_noSuchName;
case ipDefaultTTL:
// This is a defined constant in IRIX
return SNMP_ERR_noSuchName;
}
return SNMP_ERR_noSuchName;
}
void
updateIpAddrTable(void)
{
// Only update once per packet
extern unsigned int packetCounter;
static unsigned int validCounter = 0;
if (validCounter == packetCounter) {
return;
}
validCounter = packetCounter;
char *buf, *next, *lim;
struct ifa_msghdr *ifam;
oid oi = "1.3.6.1.2.1.4.20.1.6.0.0.0.0"; // ipAddrTable
asnObject *a;
snmpIPaddress p;
asnInteger i;
int mib[6];
subID *subid;
unsigned int len;
struct sockaddr *sa;
char *cp;
size_t needed;
int rc;
oi.getValue(&subid, &len);
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
perror("sysctl");
return;
}
buf = (char *)alloca(needed);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
perror("sysctl");
return;
}
lim = buf + needed;
for (next = buf; next < lim; next += ifam->ifam_msglen) {
struct sockaddr_in *dest = 0, *mask = 0, *addr = 0;
ifam = (struct ifa_msghdr *)next;
if (ifam->ifam_type == RTM_IFINFO) {
continue;
}
if (ifam->ifam_addrs & RTA_NETMASK) {
mask = (struct sockaddr_in *)(ifam + 1);
}
if (ifam->ifam_addrs & RTA_IFA) {
#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
: sizeof(__uint64_t))
#ifdef _HAVE_SA_LEN
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
#else
#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
#endif
cp = (char *)mask;
sa = (struct sockaddr *)mask;
ADVANCE(cp, sa);
addr = (struct sockaddr_in *)cp;
}
if (ifam->ifam_addrs & RTA_BRD) {
dest = addr + 1;
}
subid[len - 4] = (subID)((addr->sin_addr.s_addr &
0xFF000000) >> 24);
subid[len - 3] = (subID)((addr->sin_addr.s_addr &
0x00FF0000) >> 16);
subid[len - 2] = (subID)((addr->sin_addr.s_addr &
0x0000FF00) >> 8);
subid[len - 1] = (subID)(addr->sin_addr.s_addr &
0x000000FF);
// Set the variables
subid[len - 5] = ipAdEntAddr;
p.setValue(addr->sin_addr.s_addr);
a = &p;
ipsa->addrtable->set(&oi, &a);
subid[len - 5] = ipAdEntNetMask;
p.setValue(mask->sin_addr.s_addr);
ipsa->addrtable->set(&oi, &a);
subid[len - 5] = ipAdEntBcastAddr;
p.setValue(dest->sin_addr.s_addr);
ipsa->addrtable->set(&oi, &a);
subid[len - 5] = ipAdEntIfIndex;
i = ifam->ifam_index;
a = &i;
ipsa->addrtable->set(&oi, &a);
subid[len - 5] = ipAdEntReasmMaxSize;
i = 65535;
ipsa->addrtable->set(&oi, &a);
subid[len - 5] = ipAdEntValid;
i = validCounter;
ipsa->addrtable->set(&oi, &a);
}
// Remove invalid entries
subid[len - 4] = subid[len - 3] = subid[len - 2] = subid[len - 1] = 0;
// subid[len - 5] equals ipAdEntValid
for ( ; ; ) {
rc = ipsa->addrtable->formNextOID(&oi);
if (rc != SNMP_ERR_noError) {
break;
}
rc = ipsa->addrtable->get(&oi, &a);
if (rc == SNMP_ERR_noError
&& ((asnInteger *) a)->getValue() == validCounter) {
delete a;
continue;
}
if (a != 0) {
delete a;
a = 0;
}
// Entries is invalid, delete it
for (subID s = ipAdEntAddr; s <= ipAdEntValid; s++) {
subid[len - 5] = s;
ipsa->addrtable->set(&oi, &a);
}
}
}
void
updateIpRouteTable(void)
{
size_t needed;
int mib[6];
char *buf, *next, *lim;
struct rt_msghdr *rtmsg;
struct sockaddr *sa;
struct k_rtentry {
struct sockaddr k_rt_dst; /* key */
struct sockaddr k_rt_gateway; /* value */
struct sockaddr k_rt_netmask; /* mask */
short k_rt_flags; /* up/down?, host/net */
} k_rt;
struct k_rtentry *rt = &k_rt;
// If packets are coming every fastRequestTime, hold off updating
// until mustUpdateTime.
const int mustUpdateTime = 30;
const int fastRequestTime = 5;
extern unsigned int packetCounter;
static unsigned int validCounter = 0;
static time_t lastRequestTime = 0;
static time_t lastUpdateTime = 0;
if (validCounter == packetCounter)
return;
validCounter = packetCounter;
time_t t = time(0);
if (t - lastUpdateTime < mustUpdateTime
&& t - lastRequestTime <= fastRequestTime) {
lastRequestTime = t;
return;
}
lastUpdateTime = lastRequestTime = t;
subID *subid, *sub;
unsigned int len, l;
unsigned int addr;
int rc;
asnObject *a;
asnInteger i;
snmpIPaddress p;
asnObjectIdentifier ao = "0.0";
oid oi = "1.3.6.1.2.1.4.21.1.1.0.0.0.0"; // ipRouteTable
oi.getValue(&subid, &len);
oid aoi = "1.3.6.1.2.1.2.2.1.24.0"; // if_addr
aoi.getValue(&sub, &l);
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
exc_errlog(LOG_ERR, 0, "route-sysctl-estimate =%d", errno);
return;
}
buf = (char *)alloca(needed);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
exc_errlog(LOG_ERR, 0, "sysctl of routing table =%d", errno);
return;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtmsg->rtm_msglen) {
rtmsg = (struct rt_msghdr *)next;
/* skip it if do not have both gateway and dst */
if ((rtmsg->rtm_addrs & (RTA_DST|RTA_GATEWAY)) ==
(RTA_DST|RTA_GATEWAY)) {
sa = (struct sockaddr*)(rtmsg + 1);
#ifdef _HAVE_SA_LEN
bcopy(sa, sa->sa_len, &rt->k_rt_dst);
sa = (struct sockaddr*)(sa->sa_len + (char*)sa);
bcopy(sa, sa->sa_len, &rt->k_rt_gateway);
if (rtmsg->rtm_addrs & RTA_NETMASK) {
sa = (struct sockaddr*)(sa->sa_len + (char*)sa);
bcopy(sa, sa->sa_len, &rt->k_rt_netmask);
}
#else
rt->k_rt_dst = sa[0];
rt->k_rt_gateway = sa[1];
if (rtmsg->rtm_addrs & RTA_NETMASK) {
rt->k_rt_netmask = sa[2];
}
#endif
rt->k_rt_flags =
rtmsg->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST);
if (rt->k_rt_gateway.sa_family != AF_INET)
continue;
}
// Form the oid
addr = SIN(rt->k_rt_dst)->sin_addr.s_addr;
subid[len - 4] = (subID) ((addr & 0xFF000000) >> 24);
subid[len - 3] = (subID) ((addr & 0x00FF0000) >> 16);
subid[len - 2] = (subID) ((addr & 0x0000FF00) >> 8);
subid[len - 1] = (subID) (addr & 0x000000FF);
// Set the variables
subid[len - 5] = ipRouteDest;
p = addr;
a = &p;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteIfIndex;
i = (unsigned)rtmsg->rtm_index;
a = &i;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMetric1;
i = -1;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMetric2;
i = -1;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMetric3;
i = -1;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMetric4;
i = -1;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMetric5;
i = -1;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteType;
i = (rt->k_rt_flags & RTF_GATEWAY) ?
routeTypeIndirect : routeTypeDirect;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteAge;
i = 0;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteValid;
i = validCounter;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteProto;
if (rt->k_rt_flags & RTF_DYNAMIC || rt->k_rt_flags & RTF_MODIFIED) {
i = routeProtoIcmp;
ipsa->routetable->set(&oi, &a);
} else {
rc = ipsa->routetable->get(&oi, &a);
if (rc != SNMP_ERR_noError) {
i = routeProtoOther;
ipsa->routetable->set(&oi, &a);
} else {
delete a;
// Just leave it what it is
}
}
subid[len - 5] = ipRouteNextHop;
p = SIN(rt->k_rt_gateway)->sin_addr.s_addr;
a = &p;
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteMask;
if (rtmsg->rtm_addrs & RTA_NETMASK) {
p = SIN(rt->k_rt_netmask)->sin_addr.s_addr;
} else {
addr = SIN(rt->k_rt_gateway)->sin_addr.s_addr;
if (addr == 0)
#if _MIPS_SZLONG == 64
p = (unsigned int) 0;
#else
p = (unsigned long) 0;
#endif
else if (IN_CLASSA(addr))
p = IN_CLASSA_NET;
else if (IN_CLASSB(addr))
p = IN_CLASSB_NET;
else if (IN_CLASSC(addr))
p = IN_CLASSC_NET;
else if (IN_CLASSD(addr))
p = IN_CLASSD_NET;
else
#if _MIPS_SZLONG == 64
p = (unsigned int) 0;
#else
p = (unsigned long) 0;
#endif
}
ipsa->routetable->set(&oi, &a);
subid[len - 5] = ipRouteInfo;
a = &ao;
ipsa->routetable->set(&oi, &a);
}
// Remove invalid entries
subid[len - 4] = subid[len - 3] = subid[len - 2] = subid[len - 1] = 0;
subid[len - 5] = ipRouteValid;
for ( ; ; ) {
rc = ipsa->routetable->formNextOID(&oi);
if (rc != SNMP_ERR_noError)
break;
rc = ipsa->routetable->get(&oi, &a);
if (rc == SNMP_ERR_noError
&& ((asnInteger *) a)->getValue() == validCounter) {
delete a;
continue;
}
delete a;
// Check if this is an entry under construction
subid[len - 5] = ipRouteType;
rc = ipsa->routetable->get(&oi, &a);
subid[len - 5] = ipRouteValid;
if (rc == SNMP_ERR_noError
&& ((asnInteger *) a)->getValue() == routeTypeInvalid) {
delete a;
continue;
}
delete a;
a = 0;
// Entry is invalid, delete it
for (subID s = ipRouteDest; s <= ipRouteValid; s++) {
subid[len - 5] = s;
ipsa->routetable->set(&oi, &a);
}
}
}
void
updateNetToMediaTable(void)
{
// If packets are coming every fastRequestTime, hold off updating
// until mustUpdateTime.
const int mustUpdateTime = 30;
const int fastRequestTime = 5;
extern unsigned int packetCounter;
static unsigned int validCounter = 0;
static time_t lastRequestTime = 0;
static time_t lastUpdateTime = 0;
if (validCounter == packetCounter)
return;
validCounter = packetCounter;
time_t t = time(0);
if (t - lastUpdateTime < mustUpdateTime
&& t - lastRequestTime <= fastRequestTime) {
lastRequestTime = t;
return;
}
lastUpdateTime = lastRequestTime = t;
snmpIPaddress ip;
asnOctetString o;
asnInteger ai;
asnObject *a;
subID *subid;
unsigned int len;
u_int i;
int rc, mib[6];
char *buf, *next, *lim;
size_t needed;
struct sockaddr_inarp *sarp;
struct sockaddr_dl *sdl;
struct rt_msghdr *msg;
oid oi = "1.3.6.1.2.1.4.22.1.1.1.0.0.0.0";
oi.getValue(&subid, &len);
// Read arp table
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return;
buf = (char *)alloca(needed * 2);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
return;
// Loop through entries
lim = buf + needed;
for (next = buf; next < lim; next += msg->rtm_msglen) {
msg = (struct rt_msghdr *)next;
sarp = (struct sockaddr_inarp *)(msg + 1);
#ifdef _HAVE_SA_LEN
sdl = (struct sockaddr_dl *)(sarp->sarp_len + (char *)sarp);
#else /* _HAVE_SA_LEN */
sdl = (struct sockaddr_dl *)(_FAKE_SA_LEN_DST((struct sockaddr *)sarp)
+ (char *)sarp);
#endif /* _HAVE_SA_LEN */
if (sdl->sdl_alen) {
subid[len - 4] = (subID)((sarp->sarp_addr.s_addr & 0xFF000000) >> 24);
subid[len - 3] = (subID)((sarp->sarp_addr.s_addr & 0x00FF0000) >> 16);
subid[len - 2] = (subID)((sarp->sarp_addr.s_addr & 0x0000FF00) >> 8);
subid[len - 1] = (subID)(sarp->sarp_addr.s_addr & 0x000000FF);
subid[len - 6] = ipNetToMediaIfIndex;
ai = 1;
a = &ai;
ipsa->nettomediatable->set(&oi, &a);
subid[len - 6] = ipNetToMediaType;
ai = (msg->rtm_rmx.rmx_expire == 0) ?
mediaTypeStatic : mediaTypeDynamic;
ipsa->nettomediatable->set(&oi, &a);
subid[len - 6] = ipNetToMediaValid;
ai = validCounter;
ipsa->nettomediatable->set(&oi, &a);
subid[len - 6] = ipNetToMediaPhysAddress;
o.setValue((char *)LLADDR(sdl), sdl->sdl_alen);
a = &o;
ipsa->nettomediatable->set(&oi, &a);
subid[len - 6] = ipNetToMediaNetAddress;
ip = sarp->sarp_addr.s_addr;
a = &ip;
ipsa->nettomediatable->set(&oi, &a);
}
}
// Remove invalid entries
for (i = 5; i != 0; i--)
subid[len - i] = 0;
subid[len - 6] = ipNetToMediaValid;
for ( ; ; ) {
rc = ipsa->nettomediatable->formNextOID(&oi);
if (rc != SNMP_ERR_noError)
break;
rc = ipsa->nettomediatable->get(&oi, &a);
if (rc == SNMP_ERR_noError
&& ((asnInteger *) a)->getValue() == validCounter) {
delete a;
continue;
}
delete a;
// Check if this is an entry under construction
subid[len - 6] = ipNetToMediaType;
rc = ipsa->nettomediatable->get(&oi, &a);
subid[len - 6] = ipNetToMediaValid;
if (rc == SNMP_ERR_noError
&& ((asnInteger *) a)->getValue() == mediaTypeInvalid) {
delete a;
continue;
}
delete a;
a = 0;
// Entry is invalid, delete it
for (subID s = ipNetToMediaIfIndex; s <= ipNetToMediaValid; s++) {
subid[len - 6] = s;
ipsa->nettomediatable->set(&oi, &a);
}
}
}