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

450 lines
9.6 KiB
C

/* isp.c - Internal Signaling Protocol test generator */
/* Written 1997-2000 by Werner Almesberger, EPFL-ICA */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <atm.h>
#include <atmd.h>
#include <linux/atmsvc.h>
#include "isp.h"
extern int yyparse(void);
int quiet = 0;
int verbose = 0;
VAR *variables = NULL;
static int sock;
void send_msg(const struct atmsvc_msg *msg)
{
int wrote;
wrote = write(sock,msg,sizeof(*msg));
if (wrote == sizeof(*msg)) return;
if (wrote < 0) perror("write");
else fprintf(stderr,"bad write: %d != %d\n",wrote,sizeof(*msg));
exit(1);
}
void recv_msg(struct atmsvc_msg *msg)
{
int got;
got = read(sock,msg,sizeof(*msg));
if (got == sizeof(*msg)) return;
if (got < 0) perror("read");
else fprintf(stderr,"bad read: %d != %d\n",got,sizeof(*msg));
exit(1);
}
static struct errno_table {
const char *name;
int value;
} table[] = {
#include "errnos.inc"
{ NULL, 0 }
};
static const char *errno2str(int code)
{
static char buf[30]; /* probably large enough :) */
const struct errno_table *walk;
for (walk = table; walk->name; walk++) {
if (walk->value == code) return walk->name;
if (walk->value == -code) {
sprintf(buf,"-%s",walk->name);
return buf;
}
}
sprintf(buf,"%d (0x%x)",code,code);
return buf;
}
/* Synchronized with include/linux/atmsvc.h:enum atmsvc_msg_type */
static struct {
const char *name;
int fields;
} types[] = {
{ "<invalid>", 0 },
{ "bind", F_VCC | F_SVC | F_SAP },
{ "connect", F_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP },
{ "accept", F_VCC | F_LISTEN_VCC },
{ "reject", F_VCC | F_LISTEN_VCC | F_REPLY },
{ "listen", F_VCC | F_QOS | F_SVC | F_SAP },
{ "okay", F_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP },
{ "error", F_VCC | F_REPLY },
{ "indicate", F_LISTEN_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP},
{ "close", F_VCC | F_REPLY },
{ "itf_notify", F_PVC },
{ "modify", F_VCC | F_REPLY | F_QOS },
{ "identify", F_VCC | F_LISTEN_VCC | F_PVC },
{ "terminate", 0 }};
#define MSG_TYPES (sizeof(types)/sizeof(*types))
void print_value(VALUE val)
{
char buf[1000]; /* bigger than any MAX_ATM_*_LEN */
switch (val.type) {
case vt_text:
printf("\"%s\"",val.u.text);
return;
case vt_vcc:
printf("%s",kptr_print(&val.u.id));
return;
case vt_error:
printf("%s",errno2str(val.u.num));
return;
case vt_pvc:
if (atm2text(buf,sizeof(buf),(struct sockaddr *) &val.u.pvc,
A2T_PRETTY | A2T_NAME) < 0) strcpy(buf,"<invalid>");
printf("%s",buf);
return;
case vt_svc:
if (atm2text(buf,sizeof(buf),(struct sockaddr *) &val.u.svc,
A2T_PRETTY | A2T_NAME) < 0) strcpy(buf,"<invalid>");
printf("%s",buf);
return;
case vt_qos:
if (qos2text(buf,sizeof(buf),&val.u.qos,0) < 0)
strcpy(buf,"<invalid>");
printf("%s",buf);
return;
case vt_sap:
if (sap2text(buf,sizeof(buf),&val.u.sap,S2T_NAME) < 0)
strcpy(buf,"<invalid>");
printf("%s",buf);
return;
default:
fprintf(stderr,"\ninvalid value type %d\n",val.type);
exit(1);
}
}
#define FIELD(FLD,MSG) \
if (fields & FLD) { \
printf("%s",MSG); \
print_value(pick(msg,FLD)); \
putchar('\n'); \
}
void dump_msg(const char *prefix,const struct atmsvc_msg *msg)
{
int fields;
if (msg->type >= MSG_TYPES) {
printf("%s: unknown message type %d\n",prefix,msg->type);
return;
}
fields = types[msg->type].fields;
printf("%s: %s\n",prefix,types[msg->type].name);
FIELD(F_VCC, " vcc = ");
FIELD(F_LISTEN_VCC, " listen_vcc = ");
FIELD(F_REPLY, " reply = ");
FIELD(F_PVC, " pvc = ");
FIELD(F_LOCAL, " local = ");
FIELD(F_QOS, " qos = ");
FIELD(F_SVC, " svc = ");
FIELD(F_SAP, " sap = ");
}
#undef FIELD
VAR *create_var(const char *name)
{
VAR *var,**walk;
var = malloc(sizeof(VAR));
if (!var) {
perror("malloc");
exit(1);
}
var->name = name; /* strdup'ed */
var->value.type = vt_none;
for (walk = &variables; *walk; walk = &(*walk)->next)
if (strcmp(name,(*walk)->name) > 0) break;
var->next = *walk;
*walk = var;
return var;
}
VAR *lookup(const char *name)
{
VAR *var;
for (var = variables; var; var = var->next)
if (!strcmp(var->name,name)) break;
return var;
}
static void destroy(VALUE value)
{
if (value.type == vt_text) free((char *) value.u.text);
}
void assign(VAR *var,VALUE value)
{
destroy(var->value);
var->value = value;
}
static int str2errno(const char *str)
{
const struct errno_table *walk;
for (walk = table; walk->name; walk++)
if (!strcmp(walk->name,str)) break;
return walk->value;
}
static VALUE convert(VALUE in,VALUE_TYPE type)
{
VALUE out;
char *end;
if (in.type == type) {
if (type == vt_text) {
in.u.text = strdup(in.u.text);
if (!in.u.text) {
perror("strdup");
exit(1);
}
}
return in;
}
if (in.type != vt_text) yyerror("type conflict");
out.type = type;
switch (type) {
case vt_vcc:
memset(&out.u.id,0,sizeof(out.u.id));
*(unsigned long *) &out.u.id = strtoul(in.u.text,&end,0);
if (*end) yyerror("invalid number");
break;
case vt_error:
out.u.num = strtoul(in.u.text,&end,0);
if (*end) {
out.u.num = str2errno(*in.u.text == '-' ? in.u.text+1 :
in.u.text);
if (!out.u.num) yyerror("invalid error code");
if (*in.u.text == '-') out.u.num = -out.u.num;
}
break;
case vt_svc:
if (text2atm(in.u.text,(struct sockaddr *) &out.u.svc,
sizeof(out.u.svc), T2A_SVC | T2A_NAME) < 0)
yyerror("invalid SVC address");
break;
case vt_pvc:
if (text2atm(in.u.text,(struct sockaddr *) &out.u.pvc,
sizeof(out.u.pvc),T2A_PVC | T2A_NNI | T2A_NAME) < 0)
yyerror("invalid PVC address");
break;
case vt_qos:
if (text2qos(in.u.text,&out.u.qos,0) < 0) yyerror("invalid QOS");
break;
case vt_sap:
if (text2sap(in.u.text,&out.u.sap,T2S_NAME) < 0)
yyerror("invalid SAP address");
break;
default:
fprintf(stderr,"unexpected conversion type %d\n",type);
exit(1);
}
return out;
}
void check(VALUE a,VALUE b)
{
if (a.type == vt_text) a = convert(a,b.type);
if (b.type == vt_text) b = convert(b,a.type);
if (a.type != b.type) yyerror("type conflict");
switch (a.type) {
case vt_vcc:
case vt_error:
if (kptr_eq(&a.u.id,&b.u.id)) return;
break;
case vt_svc:
if (atm_equal((struct sockaddr *) &a.u.svc,
(struct sockaddr *) &b.u.svc,0,0)) return;
break;
case vt_pvc:
if (atm_equal((struct sockaddr *) &a.u.pvc,
(struct sockaddr *) &b.u.pvc,0,0)) return;
break;
case vt_qos:
if (qos_equal(&a.u.qos,&b.u.qos)) return;
break;
case vt_sap:
if (sap_equal(&a.u.sap,&b.u.sap,0)) return;
break;
default:
fprintf(stderr,"unexpected conversion type %d\n",a.type);
exit(1);
}
printf("Expected ");
print_value(b);
printf(",\nbut message contains ");
print_value(a);
printf("\n");
exit(1);
}
#define COPY_MSG_VAL(V) \
switch (field) { \
case F_VCC: _COPY(V.u.id,msg->vcc); break; \
case F_LISTEN_VCC: _COPY(V.u.id,msg->listen_vcc); break; \
case F_REPLY: _COPY(V.u.num,msg->reply); break; \
case F_PVC: _COPY(V.u.pvc,msg->pvc); break; \
case F_LOCAL: _COPY(V.u.svc,msg->local); break; \
case F_QOS: _COPY(V.u.qos,msg->qos); break; \
case F_SVC: _COPY(V.u.svc,msg->svc); break; \
case F_SAP: _COPY(V.u.sap,msg->sap); break; \
default: fprintf(stderr,"unexpected field type 0x%x\n",field); \
exit(1); \
}
VALUE pick(const struct atmsvc_msg *msg,int field)
{
VALUE out;
if (msg->type >= MSG_TYPES) {
fprintf(stderr,"invalid message type %d",msg->type);
exit(1);
}
if (!(types[msg->type].fields & field)) yyerror("no such field in message");
out.type = type_of(field);
#define _COPY(V,M) V = M
COPY_MSG_VAL(out)
#undef _COPY
return out;
}
void store(struct atmsvc_msg *msg,int field,VALUE val)
{
if (msg->type >= MSG_TYPES) {
fprintf(stderr,"invalid message type %d",msg->type);
exit(1);
}
if (!(types[msg->type].fields & field)) yyerror("no such field in message");
if (val.type != type_of(field)) yyerror("type conflict");
#define _COPY(V,M) M = V
COPY_MSG_VAL(val)
#undef _COPY
}
#undef COPY_MSG_VAL
VALUE eval(VALUE_TYPE type,const char *str)
{
VALUE a,b;
a.type = vt_text;
a.u.text = strdup(str);
if (!a.u.text) {
perror("strdup");
exit(1);
}
b = convert(a,type);
destroy(a);
return b;
}
void cast(VAR *var,VALUE_TYPE type)
{
VALUE old;
if (var->value.type == type) return;
old = var->value;
var->value = convert(var->value,type);
destroy(old);
}
VALUE_TYPE type_of(int field)
{
switch (field) {
case F_VCC:
case F_LISTEN_VCC:
return vt_vcc;
case F_REPLY:
return vt_error;
case F_PVC:
return vt_pvc;
case F_LOCAL:
case F_SVC:
return vt_svc;
case F_QOS:
return vt_qos;
case F_SAP:
return vt_sap;
default:
fprintf(stderr,"unexpected field type 0x%x\n",field);
exit(1);
}
}
int main(int argc,char **argv)
{
const char *name;
name = *argv;
if (argc > 2 && !strcmp(argv[1],"-q")) {
quiet = 1;
argc--;
argv++;
}
if (argc > 2 && !strcmp(argv[1],"-v")) {
verbose = 1;
argc--;
argv++;
}
if (argc != 2 || (quiet && verbose)) {
fprintf(stderr,"usage: %s [-q | -v] socket\n",name);
return 1;
}
sock = un_attach(argv[1]);
if (sock < 0) {
perror(argv[1]);
return 1;
}
return yyparse();
}