253 lines
6.3 KiB
C
Executable File
253 lines
6.3 KiB
C
Executable File
/* table.c - ATMARP table */
|
|
|
|
/* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/atm.h>
|
|
|
|
#include "atm.h"
|
|
#include "atmd.h"
|
|
#include "atmarpd.h"
|
|
|
|
#include "table.h"
|
|
|
|
|
|
#define COMPONENT "TABLE"
|
|
|
|
|
|
const char *entry_state_name[] = { "NONE","RESOLV","INVALID","VALID" };
|
|
|
|
|
|
ENTRY *alloc_entry(int svc)
|
|
{
|
|
ENTRY *entry;
|
|
|
|
entry = alloc_t(ENTRY);
|
|
entry->state = as_none;
|
|
entry->svc = svc;
|
|
entry->ip = 0;
|
|
entry->addr = NULL;
|
|
entry->flags = 0;
|
|
entry->timer = NULL;
|
|
entry->vccs = NULL;
|
|
entry->notify = NULL;
|
|
entry->itf = NULL;
|
|
return entry;
|
|
}
|
|
|
|
|
|
ENTRY *lookup_ip(const ITF *itf,uint32_t ip)
|
|
{
|
|
ENTRY *walk;
|
|
|
|
for (walk = itf->table; walk; walk = walk->next)
|
|
if (walk->ip == ip) break;
|
|
return walk;
|
|
}
|
|
|
|
|
|
ENTRY *lookup_addr(const ITF *itf,const struct sockaddr_atmsvc *addr)
|
|
{
|
|
ENTRY *walk;
|
|
|
|
for (walk = itf->table; walk; walk = walk->next)
|
|
if (walk->addr && atm_equal((struct sockaddr *) walk->addr,
|
|
(struct sockaddr *) addr,0,0)) break;
|
|
return walk;
|
|
}
|
|
|
|
|
|
ENTRY *lookup_incoming(const struct sockaddr_atmsvc *addr)
|
|
{
|
|
ENTRY *walk;
|
|
|
|
for (walk = unknown_incoming; walk; walk = walk->next)
|
|
if (walk->addr && atm_equal((struct sockaddr *) walk->addr,
|
|
(struct sockaddr *) addr,0,0)) break;
|
|
return walk;
|
|
}
|
|
|
|
|
|
static int table_uptodate = 0; /* ATMARP table file is up to date */
|
|
static FILE *out_file = NULL;
|
|
static int out_error = 0;
|
|
|
|
|
|
static void output(const char *fmt,...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap,fmt);
|
|
if (!out_file) vdiag(COMPONENT,DIAG_DEBUG,fmt,ap);
|
|
else if (vfprintf(out_file,fmt,ap) < 0 || putc('\n',out_file) < 0)
|
|
out_error = errno;
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
static void dump_vcc(VCC *vcc)
|
|
{
|
|
struct sockaddr_atmsvc addr;
|
|
char addr_buf[MAX_ATM_ADDR_LEN+1];
|
|
char qos_buf[MAX_ATM_QOS_LEN+1];
|
|
struct atm_qos qos;
|
|
int size,sndbuf;
|
|
|
|
size = sizeof(addr);
|
|
if (getpeername(vcc->fd,(struct sockaddr *) &addr,&size) < 0) {
|
|
diag(COMPONENT,DIAG_ERROR,"getpeername: %s",strerror(errno));
|
|
strcpy(addr_buf,"<getsocknam error>");
|
|
}
|
|
else {
|
|
#if 0
|
|
int i;
|
|
|
|
for (i = 0; i < size; i++)
|
|
printf("%02X ",((unsigned char *) &addr)[i]);
|
|
printf("\n");
|
|
#endif
|
|
if (atm2text(addr_buf,sizeof(addr_buf),(struct sockaddr *) &addr,
|
|
pretty) < 0) strcpy(addr_buf,"<atm2text error>");
|
|
}
|
|
output(" %s%s",addr_buf,vcc->connecting ? ", connecting" :
|
|
!vcc->entry || !vcc->entry->svc ? "" : vcc->active ? " (active)" :
|
|
" (passive)");
|
|
if (vcc->connecting) return;
|
|
size = sizeof(qos);
|
|
if (getsockopt(vcc->fd,SOL_ATM,SO_ATMQOS,&qos,&size) < 0)
|
|
output(" QOS: <unavailable: %s>",strerror(errno));
|
|
else if (!vcc->entry || !qos_equal(&vcc->entry->qos,&qos)) {
|
|
if (qos2text(qos_buf,sizeof(qos_buf),&qos,0) < 0)
|
|
strcpy(qos_buf,"<invalid qos>");
|
|
output(" QOS: %s",qos_buf);
|
|
}
|
|
size = sizeof(sndbuf);
|
|
if (getsockopt(vcc->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,&size) < 0)
|
|
output(" Send buffer: <unavailable: %s>",strerror(errno));
|
|
else if (!vcc->entry || vcc->entry->sndbuf != sndbuf)
|
|
output(" Send buffer: %d",sndbuf);
|
|
}
|
|
|
|
|
|
static void dump_vccs(VCC *vcc)
|
|
{
|
|
while (vcc) {
|
|
dump_vcc(vcc);
|
|
vcc = vcc->next;
|
|
}
|
|
}
|
|
|
|
|
|
static void dump_entries(ENTRY *list)
|
|
{
|
|
static const char *flag_name[] = {
|
|
"???", "com", "PERM", "PUBL", /* 0x0001-0x0008 */
|
|
"trailers", "netmask", "dontpub", "magic", /* 0x0010-0x0080 */
|
|
"???", "???", "???", "???", /* 0x0100-0x0800 */
|
|
"NULL", "ARPSRV", "NOVC", "???" }; /* 0x1000-0x8000 */
|
|
/* lower case flags are not used by ATMARP */
|
|
ENTRY *entry;
|
|
char addr_buf[MAX_ATM_ADDR_LEN+1];
|
|
char qos_buf[MAX_ATM_QOS_LEN+1];
|
|
char tmp[100]; /* large enough for all flags */
|
|
unsigned char *ipp;
|
|
int i;
|
|
|
|
for (entry = list; entry ; entry = entry->next) {
|
|
if (!entry->addr) strcpy(addr_buf,"<none>");
|
|
else if (atm2text(addr_buf,MAX_ATM_ADDR_LEN+1,
|
|
(struct sockaddr *) entry->addr,pretty) < 0)
|
|
strcpy(addr_buf,"<error>");
|
|
ipp = (unsigned char *) &entry->ip;
|
|
*tmp = 0;
|
|
for (i = 0; i < 16; i++)
|
|
if (entry->flags & (1 << i)) {
|
|
if (*tmp) strcat(tmp,",");
|
|
strcat(tmp,flag_name[i]);
|
|
}
|
|
output("IP %d.%d.%d.%d, state %s, addr %s, flags 0x%x<%s>",ipp[0],
|
|
ipp[1],ipp[2],ipp[3],entry_state_name[entry->state],addr_buf,
|
|
entry->flags,tmp);
|
|
if (entry->itf && !qos_equal(&entry->itf->qos,&entry->qos)) {
|
|
if (qos2text(qos_buf,sizeof(qos_buf),&entry->qos,0) < 0)
|
|
strcpy(qos_buf,"<error>");
|
|
output(" QOS: %s",qos_buf);
|
|
}
|
|
if (entry->itf && entry->sndbuf && entry->sndbuf != entry->itf->sndbuf)
|
|
output(" Send buffer: %d",entry->sndbuf);
|
|
if (entry->notify) {
|
|
NOTIFY *notify;
|
|
int count;
|
|
|
|
count = 0;
|
|
for (notify = entry->notify; notify; notify = notify->next) count++;
|
|
output(" %d quer%s pending",count,count == 1 ? "y" : "ies");
|
|
}
|
|
dump_vccs(entry->vccs);
|
|
}
|
|
}
|
|
|
|
|
|
static void dump_itf(ITF *itf)
|
|
{
|
|
unsigned char *ipp,*nmp;
|
|
char buf[MAX_ATM_QOS_LEN+1];
|
|
|
|
ipp = (unsigned char *) &itf->local_ip;
|
|
nmp = (unsigned char *) &itf->netmask;
|
|
output("----- Itf %d (%d.%d.%d.%d, netmask %d.%d.%d.%d) -----",itf->number,
|
|
ipp[0],ipp[1],ipp[2],ipp[3],nmp[0],nmp[1],nmp[2],nmp[3]);
|
|
if (qos2text(buf,sizeof(buf),&itf->qos,0) < 0) strcpy(buf,"<error>");
|
|
output("Default QOS: %s",buf);
|
|
if (itf->sndbuf) output("Default send buffer: %d",itf->sndbuf);
|
|
dump_entries(itf->table);
|
|
}
|
|
|
|
|
|
static void dump_all(void)
|
|
{
|
|
ITF *itf;
|
|
|
|
for (itf = itfs; itf; itf = itf->next) dump_itf(itf);
|
|
output("----- Unknown incoming connections -----");
|
|
dump_entries(unknown_incoming);
|
|
output("----- Incoming unidirectional connections -----");
|
|
dump_vccs(unidirectional_vccs);
|
|
output("----- End of dump -----");
|
|
}
|
|
|
|
|
|
void table_changed(void)
|
|
{
|
|
table_uptodate = 0;
|
|
table_update(); /* @@@ sigh, fix this later */
|
|
if (debug) {
|
|
out_file = 0;
|
|
dump_all();
|
|
}
|
|
}
|
|
|
|
|
|
int table_update(void)
|
|
{
|
|
if (table_uptodate) return 0;
|
|
out_file = fopen(ATMARP_TMP_DUMP_FILE,"w");
|
|
out_error = 0;
|
|
dump_all();
|
|
if (fclose(out_file) < 0) out_error = errno;
|
|
if (!out_error) {
|
|
if (rename(ATMARP_TMP_DUMP_FILE,ATMARP_DUMP_FILE) < 0)
|
|
out_error = errno;
|
|
else table_uptodate = 1;
|
|
}
|
|
unlink(ATMARP_TMP_DUMP_FILE);
|
|
return out_error;
|
|
}
|