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

403 lines
8.3 KiB
C

/*
* Copyright 1989,1990,1991 Silicon Graphics, Inc. All rights reserved.
*
* $Revision: 1.21 $
*/
#include <errno.h>
#include <string.h>
#include <bstring.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/ioctl.h>
#include <net/multi.h>
#include <netinet/in.h>
#include <cap_net.h>
#include <sm_types.h>
#include <sm_log.h>
#include <smt_asn1.h>
#include <smt_snmp.h>
#include <smtd.h>
#include <ma.h>
#include <smtd_svc.h>
#include <smtd_fs.h>
#include <smtd_nn.h>
/*
* Approximate upper bound on socket buffer space reservation.
*/
#define MAXBUFSPACE 60000
int
sm_multi(char *ifname, LFDDI_ADDR *maddr, int add, int s)
{
int bufspace;
struct ifreq ifr;
union mkey *key;
bzero(&ifr, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
key = (union mkey*)&ifr.ifr_addr;
key->mk_family = AF_RAW;
bcopy(maddr, key->mk_dhost, sizeof(*maddr));
if (ioctl(s, (add==1?SIOCADDMULTI:SIOCDELMULTI), (caddr_t)&ifr) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR, "sm_multi: %s",
add == 1 ? "SIOCADDMULTI" : "SIOCDELMULTI");
return(-1);
}
return(0);
}
int
sm_open(char *nam, int port, int *fd_ptr, fd_set *fdset_ptr)
{
int s, bufspace;
struct sockaddr_raw sr;
s = cap_socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN);
if (s < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR, "sm_open: socket");
return(-1);
}
bzero(&sr, sizeof(sr));
sr.sr_family = AF_RAW;
sr.sr_port = port;
strncpy(sr.sr_ifname, nam, sizeof(sr.sr_ifname));
if (cap_bind(s, (struct sockaddr *) &sr, sizeof(sr)) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"sm_open: bind port(%d, %s)", port, nam);
(void)close(s);
return(-1);
}
bufspace = 60000;
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
(char *) &bufspace, sizeof bufspace) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"sm_open: setsockopt (%s)", port, nam);
(void)close(s);
return(-1);
}
*fd_ptr = s;
FD_SET(s, fdset_ptr);
return(0);
}
void
sm_close(int *fd_ptr, fd_set *fdset_ptr)
{
(void)close(*fd_ptr);
FD_CLR(*fd_ptr, fdset_ptr);
*fd_ptr = -1;
}
/*
* cache an open socket for uncoupled functions
*/
int cached_soc = -1;
static fd_set cached_fds;
static struct sockaddr_raw cached_addr;
static int
cache_soc(char *name, char* logmsg)
{
if (cached_soc >= 0
&& bcmp(cached_addr.sr_ifname, name,
sizeof(cached_addr.sr_ifname)))
sm_close(&cached_soc, &cached_fds);
if (cached_soc < 0) {
if (sm_open(name, 0, &cached_soc, &cached_fds)) {
sm_log(LOG_EMERG, 0, logmsg);
return(-1);
}
strncpy(cached_addr.sr_ifname, name,
sizeof(cached_addr.sr_ifname));
}
return(0);
}
/*
* NOT coupled with smtd.
*/
static int
sm_conf(char *name, int phyidx, struct smt_conf *conf, int cmd)
{
SMT_SIOC sioc;
if (0 > cache_soc(name,"sm_conf: oport failed"))
return(SNMP_ERR_NOSUCHNAME);
sioc.smt_ptr_u.conf = conf;
sioc.len = sizeof(*conf);
sioc.phy = phyidx;
if (ioctl(cached_soc, cmd, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(%s)", name, phyidx,
cmd==SIOC_SMTGET_CONF?"SIOC_SMTGET_CONF":
"SIOC_SMTSET_CONF");
sm_close(&cached_soc, &cached_fds);
return(SNMP_ERR_NOSUCHNAME);
}
return(SNMP_ERR_NOERROR);
}
/*
* NOT coupled with smtd.
*/
int
sm_getconf(char *name, int phyidx, struct smt_conf *conf)
{
return(sm_conf(name, phyidx, conf, SIOC_SMTGET_CONF));
}
/*
* NOT coupled with smtd.
*/
int
sm_setconf(char *name, int phyidx, struct smt_conf *conf)
{
return(sm_conf(name, phyidx, conf, SIOC_SMTSET_CONF));
}
/*
* NOT coupled with smtd.
*/
int
sm_stat(char *name, int phyidx, struct smt_st *stat)
{
SMT_SIOC sioc;
if (0 > cache_soc(name,"SMT_STAT: oport failed"))
return(SNMP_ERR_NOSUCHNAME);
sioc.smt_ptr_u.st = stat;
sioc.len = sizeof(*stat);
sioc.phy = phyidx;
if (ioctl(cached_soc, SIOC_SMTGET_ST, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(SIOC_SMTGET_ST)", name, phyidx);
sm_close(&cached_soc, &cached_fds);
return(SNMP_ERR_NOSUCHNAME);
}
return(SNMP_ERR_NOERROR);
}
/*
* NOT coupled with smtd.
*/
int
sm_trace(char *name, int phyidx)
{
SMT_SIOC sioc;
sm_log(LOG_EMERG, 0, "%s.%d: TRACE", name, phyidx);
if (0 > cache_soc(name,"SMT_TRACE: oport failed"))
return(SNMP_ERR_NOSUCHNAME);
sioc.smt_ptr_u.st = 0;
sioc.len = 0;
sioc.phy = phyidx;
if (ioctl(cached_soc, SIOC_SMT_TRACE, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(TRACE)", name, phyidx);
sm_close(&cached_soc, &cached_fds);
return(SNMP_ERR_NOSUCHNAME);
}
return(SNMP_ERR_NOERROR);
}
/*
* NOT coupled with smtd.
*/
int
sm_maint(char *name, int phyidx, enum pcm_ls ls)
{
SMT_SIOC sioc;
if (0 > cache_soc(name,"SMT_MAINT: oport failed"))
return(SNMP_ERR_NOSUCHNAME);
sioc.smt_ptr_u.ls = ls;
sioc.len = sizeof(ls);
sioc.phy = phyidx;
if (ioctl(cached_soc, SIOC_SMT_MAINT, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(SIOC_SMT_MAINT)", name, phyidx);
sm_close(&cached_soc, &cached_fds);
return(SNMP_ERR_NOSUCHNAME);
}
return(SNMP_ERR_NOERROR);
}
/*
* coupled with smtd.
*/
int
sm_arm(char *name, int s, u_long *arm, int phyidx)
{
SMT_SIOC sioc;
sioc.len = sizeof(*arm);
sioc.phy = phyidx;
if (ioctl(s, SIOC_SMT_ARM, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(SIOC_SMT_ARM)", name, phyidx);
return(SNMP_ERR_NOSUCHNAME);
}
if (arm)
*arm = sioc.smt_ptr_u.alarm;
return(SNMP_ERR_NOERROR);
}
/*
* coupled with smtd.
*/
int
sm_lem_fail(char *name, int s, int phyidx)
{
SMT_SIOC sioc;
sm_log(LOG_EMERG, 0, "%s.%d: LEM_FAIL", name, phyidx);
sioc.len = 0;
sioc.phy = phyidx;
if (ioctl(s, SIOC_SMT_LEM_FAIL, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s.%d: ioctl(SIOC_SMT_LEM_FAIL)", name, phyidx);
return(SNMP_ERR_NOSUCHNAME);
}
return(SNMP_ERR_NOERROR);
}
/*
* coupled with smtd.
*/
void
sm_d_bec(char *name, void *frame, int len, int s)
{
SMT_SIOC sioc;
sioc.len = len;
sioc.smt_ptr_u.d_bec = frame;
sioc.phy = 0;
if (ioctl(s, SIOC_SMT_DIRECT_BEC, &sioc) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"%s: ioctl(SIOC_SMT_DIRECT_BEC)", name);
}
}
/*
* coupled with smtd.
*/
int
sm_reset(char *name, int up)
{
int s;
struct ifreq ifr;
sm_log(LOG_EMERG, 0, "Reset %s", name);
/* open socket and save if_flags */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR, "sm_reset: socket");
return(SNMP_ERR_NOSUCHNAME);
}
/* save flags */
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
sm_log(LOG_EMERG,SM_ISSYSERR,"sm_reset: ioctl(SIOCGIFFLAGS)");
(void)close(s);
return(SNMP_ERR_NOSUCHNAME);
}
/* down */
ifr.ifr_flags &= ~IFF_UP;
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR, "sm_reset: ioctl(~IFF_UP)");
(void)close(s);
return(SNMP_ERR_NOSUCHNAME);
}
/* finished if it is supposed to be left down */
if (!up) {
(void)close(s);
return(SNMP_ERR_NOERROR);
}
ifr.ifr_flags |= IFF_UP;
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
sm_log(LOG_EMERG,SM_ISSYSERR,"sm_reset: ioctl(IFF_UP)");
(void)close(s);
return(SNMP_ERR_NOSUCHNAME);
}
/* verify flags */
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR,
"sm_reset: ioctl(SIOCGIFFLAGS)");
(void)close(s);
return(SNMP_ERR_NOSUCHNAME);
}
if ((ifr.ifr_flags & IFF_UP) == 0) {
sm_log(LOG_EMERG,SM_ISSYSERR,
"sm_reset: ioctl(IFF_UP) failed");
(void)close(s);
return(SNMP_ERR_NOSUCHNAME);
}
(void)close(s);
return(SNMP_ERR_NOERROR);
}
/*
* NOT coupled with smtd.
* This can only work when the SMT daemon is not entirely alive,
* and when the interface is down.
*
* More code should be added to take the interface down, tell smtd
* that its station number should change, and so on and so forth.
*/
void
sm_set_macaddr(char *name, LFDDI_ADDR *addr)
{
int s;
struct ifreq ifr;
/* open socket and save if_flags */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
sm_log(LOG_EMERG, SM_ISSYSERR, "sm_set_macaddr: socket");
exit(1);
}
/*
* addr is Canonical.
*/
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_addr.sa_family = AF_RAW;
bitswapcopy(addr, &ifr.ifr_addr.sa_data[0], sizeof(*addr));
if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0)
sm_log(LOG_EMERG, SM_ISSYSERR,
"sm_set_macaddr: ioctl(SIOCSIFADDR)");
(void)close(s);
}