1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Files
2024-07-22 01:58:46 -03:00

299 lines
7.7 KiB
C

/*
* io.c - Ilmi input/output routines
*
* Written by Scott W. Shumate
*
* Copyright (c) 1995-97 All Rights Reserved.
*
* Permission to use, copy, modify and distribute this
* software and its documentation is hereby granted,
* provided that both the copyright notice and this
* permission notice appear in all copies of the software,
* derivative works or modified versions, and any portions
* thereof, that both notices appear in supporting
* documentation, and that the use of this software is
* acknowledged in any publications resulting from using
* the software.
*
* I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS
* SOFTWARE.
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/if.h>
#include <atm.h>
#include <linux/atmdev.h>
#include "io.h"
#include "atmd.h"
#include "atmf_uni.h"
#define SNMP_VCI 16
#define COMPONENT "IO"
#define MAX_EXTRA_ADDRS 4 /* maximum number of additional addresses that can
be manually configured (after ilmid has
registered the "official" address) - HACK */
static short atm_itf = -1; /* bad value */
AsnOid *get_esi(int fd, int itf)
{
static AsnOid *name;
struct atmif_sioc req;
unsigned char esi[ESI_LEN];
int m, n, size;
req.number = itf;
req.arg = esi;
req.length = ESI_LEN;
if(ioctl(fd, ATM_GETESI, &req) < 0)
diag(COMPONENT, DIAG_FATAL, "ioctl ATM_GETESI: %s", strerror(errno));
/* save esi to atmfMySystemIdentifierValue */
if (!atmfMySystemIdentifierValue.octs) {
atmfMySystemIdentifierValue.octs = alloc(6);
memcpy(atmfMySystemIdentifierValue.octs, esi, 6);
}
/* Convert hex string to Object ID BER */
for(m = 0, size = 0; m < ESI_LEN; esi[m++] & 0x80 ? size += 2 : size++);
size++;
name = alloc_t(AsnOid);
name->octs = alloc(size);
name->octetLen = size;
for(m = 0, n = 0; m < ESI_LEN; m++, n++)
{
if(esi[m] & 0x80)
name->octs[n++] = '\201';
name->octs[n] = esi[m] & 0x7F;
}
/* Add the SEL */
name->octs[n] = '\0';
return name;
}
void update_nsap(int itf, AsnOid *netprefix, AsnOid *esi)
{
struct atmif_sioc req;
struct sockaddr_atmsvc addr, ouraddr[MAX_EXTRA_ADDRS+1];
char buffer[MAX_ATM_ADDR_LEN+1];
int fd, m, n;
addr.sas_family = AF_ATMSVC;
addr.sas_addr.pub[0] = 0;
/* Convert net prefix BER to hex */
for(m = 0, n = 0; m < netprefix->octetLen; m++, n++)
if(netprefix->octs[m] & 0x80)
addr.sas_addr.prv[n] = netprefix->octs[++m] | 0x80;
else
addr.sas_addr.prv[n] = netprefix->octs[m];
/* Convert esi BER to hex */
for(m = 0; m < esi->octetLen; m++, n++)
if(esi->octs[m] & 0x80)
addr.sas_addr.prv[n] = esi->octs[++m] | 0x80;
else
addr.sas_addr.prv[n] = esi->octs[m];
if ((fd = socket(AF_ATMSVC, SOCK_DGRAM, 0)) < 0)
diag(COMPONENT, DIAG_FATAL, "socket: %s", strerror(errno));
req.number = itf;
req.arg = &ouraddr;
req.length = sizeof(ouraddr);
/* Try to get our address on that interface */
if (ioctl(fd, ATM_GETADDR, &req) <0)
diag(COMPONENT, DIAG_FATAL, "ioctl ATM_GETADDR: %s", strerror(errno));
n = 0;
if (req.length && atm_equal((struct sockaddr *) &addr,
(struct sockaddr *) &ouraddr[0], ATM_ESA_LEN, 0)) {
diag(COMPONENT, DIAG_INFO, "Primary ATM Address did not change");
n = 1;
}
if ((!(m = req.length)) || (!n)) {
req.number = itf;
req.arg = NULL;
req.length = 0;
if (ioctl(fd, ATM_RSTADDR, &req) < 0)
diag(COMPONENT, DIAG_FATAL, "ioctl ATM_RSTADDR: %s", strerror(errno));
req.number = itf;
req.arg = &addr;
req.length = sizeof(addr);
if (ioctl(fd, ATM_ADDADDR, &req) < 0)
diag(COMPONENT, DIAG_FATAL, "ioctl ATM_ADDADDR: %s", strerror(errno));
atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &addr, A2T_PRETTY);
diag(COMPONENT, DIAG_INFO, "Primary ATM Address %s added local", buffer);
for (n = 0; n < m/sizeof(addr); n++) {
if(n > MAX_EXTRA_ADDRS-1) break; /* We have already registered "primary" NSAP */
req.number = itf;
req.arg = &ouraddr[n];
req.length = sizeof(*ouraddr);
atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &ouraddr[n], A2T_PRETTY);
if (ioctl(fd, ATM_ADDADDR, &req) < 0)
diag(COMPONENT, DIAG_ERROR, "ioctl ATM_ADDADDR: %s", strerror(errno));
else
diag(COMPONENT, DIAG_INFO, "Extra ATM Address %s added local", buffer);
}
}
close(fd);
}
int wait_for_message(int fd, struct timeval *timeout)
{
int numfds;
fd_set fdvar;
FD_ZERO(&fdvar);
FD_SET(fd, &fdvar);
if((numfds = select(fd + 1, &fdvar, 0, 0, timeout)) < 0)
diag(COMPONENT, DIAG_FATAL, "select: %s", strerror(errno));
return numfds;
}
int read_message(int fd, Message *message)
{
SBuf buffer;
char data[MAX_ILMI_MSG];
AsnLen length;
jmp_buf env;
if ((int) (length = read(fd, data, MAX_ILMI_MSG)) < 0)
diag(COMPONENT, DIAG_FATAL, "read: %s", strerror(errno));
SBufInstallData(&buffer, data, length);
if (setjmp(env) == 0)
{
BDecMessage(&buffer, message, &length, env);
}
else
{
diag(COMPONENT, DIAG_ERROR, "message decoding error");
return -1;
}
diag(COMPONENT, DIAG_DEBUG, "SNMP message received:");
if(get_verbosity(NULL) == DIAG_DEBUG)
PrintMessage(get_logfile(), message, 0);
if(message->version != VERSION_1)
{
diag(COMPONENT, DIAG_ERROR, "received message with wrong version number");
return -1;
}
if(message->community.octetLen != 4 ||
memcmp(message->community.octs, "ILMI", 4))
{
diag(COMPONENT, DIAG_ERROR, "received message with wrong community");
return -1;
}
return 0;
}
int send_message(int fd, Message *message)
{
SBuf buffer;
AsnLen length;
char data[MAX_ILMI_MSG];
SBufInit(&buffer, data, MAX_ILMI_MSG);
SBufResetInWriteRvsMode(&buffer);
if(!(length = BEncMessage(&buffer, message)))
{
diag(COMPONENT, DIAG_ERROR, "message encoding error");
return -1;
}
if(write(fd, SBufDataPtr(&buffer), length) != length)
diag(COMPONENT, DIAG_FATAL, "write: %s", strerror(errno));
diag(COMPONENT, DIAG_DEBUG, "SNMP message sent:");
if(get_verbosity(NULL) == DIAG_DEBUG)
PrintMessage(get_logfile(), message, 0);
return 0;
}
int open_ilmi(int itf,const char *qos_spec)
{
struct sockaddr_atmpvc addr;
struct atm_qos qos;
int fd;
if((fd = socket(PF_ATMPVC, SOCK_DGRAM, 0)) < 0)
diag(COMPONENT, DIAG_FATAL, "socket: %s", strerror(errno));
atm_itf = itf;
memset(&qos, 0, sizeof(qos));
qos.rxtp.max_sdu = MAX_ILMI_MSG;
qos.txtp.max_sdu = MAX_ILMI_MSG;
qos.aal = ATM_AAL5;
if (!qos_spec) qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_UBR;
else if (text2qos(qos_spec,&qos,T2Q_DEFAULTS) < 0)
diag(COMPONENT,DIAG_FATAL,"invalid qos: %s",qos_spec);
if (setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
diag(COMPONENT,DIAG_FATAL,"setsockopt SO_ATMQOS: %s",strerror(errno));
memset(&addr, 0, sizeof(addr));
addr.sap_family = AF_ATMPVC;
addr.sap_addr.itf = itf;
addr.sap_addr.vpi = 0;
addr.sap_addr.vci = SNMP_VCI;
if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
diag(COMPONENT, DIAG_FATAL, "bind: %s", strerror(errno));
return fd;
}
int get_ci_range(struct atm_cirange *ci)
{
struct atmif_sioc req;
int fd,error;
fd = socket(PF_ATMPVC,SOCK_DGRAM,0);
if (fd < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno));
req.number = atm_itf;
req.length = sizeof(*ci);
req.arg = ci;
error = ioctl(fd,ATM_GETCIRANGE,&req);
(void) close(fd);
if (error < 0) {
diag(COMPONENT,DIAG_ERROR,"ioctl ATM_GETCIRANGE: %s",strerror(errno));
return error;
}
}