You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(2) |
Sep
(164) |
Oct
(104) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
|
Feb
|
Mar
|
Apr
(3) |
May
(17) |
Jun
|
Jul
(11) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2004 |
Jan
|
Feb
(8) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(4) |
Oct
(1) |
Nov
|
Dec
(6) |
2005 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(7) |
Oct
(2) |
Nov
(6) |
Dec
|
2007 |
Jan
|
Feb
(3) |
Mar
|
Apr
(2) |
May
|
Jun
|
Jul
(6) |
Aug
(36) |
Sep
(3) |
Oct
(1) |
Nov
|
Dec
(23) |
2008 |
Jan
(33) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2009 |
Jan
|
Feb
|
Mar
(13) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(32) |
Sep
|
Oct
|
Nov
(14) |
Dec
|
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(13) |
2011 |
Jan
(16) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/maint In directory usw-pr-cvs1:/tmp/cvs-serv10656/maint Added Files: Tag: V2_4_0 atmdump.8 atmdump.c atmtcp.8 atmtcp.c atmloop.8 atmloop.c esi.8 esi.c README.nstune enitune.c zntune.c sonetdiag.c Makefile.am saaldump.c nstune.c atmaddr.8 atmaddr.c atmdiag.8 atmdiag.c Log Message: --- NEW FILE: atmdump.8 --- .TH ATMDUMP 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmdump \- capture or generate ATM cells .SH SYNOPSIS .B atmdump .RB [ \-i ] .RB [ .B \-t\ \fItype\fB .RB [ \-g\ \fIgfc\fB ] .RB [ \-c ] .RB ] .RB [\fIitf\fP.]\fIvpi\fP.\fIvci\fP .ad b .SH DESCRIPTION .B atmdump captures or generates single ATM cells ("AAL0"). When capturing cells, a time stamp, the cell header contents, and a hex dump of the cell payload are shown. When sending cells, the payload type, the generic flow control (GFC), and the cell loss priority (CLP) can be set. .P In both modes of operation, the interface number, the VPI, and the VCI have to be specified. .P When sending, \fBatmdump\fP expects the cell payload on standard input. If only less than 48 bytes can be read, the remaining space is padded with zero bytes. .SH OPTIONS .IP \fB\-i\fP displays timestamps as the interval since the last cell reception. By default, the absolute time is displayed. This options is ignored in transmit mode. .IP \fB\-t\ \fItype\fP selects transmit mode and specifies the payload type. A list of valid payload type numbers can be obtained by invoking .B atmdump without any arguments. .IP \fB\-g\ \fIgfc\fP specifies the value of the GFC field. \fIgfc\fP has to be in the range from 0 to 15, default is zero. .IP \fB\-c\fP sets the cell loss priority flag, indicating low priority. By default, CLP is not set. .SH RESTRICTIONS Some device drivers may not pass OAM cells transparently. .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" atmdiag(8), clip(8), sonetdiag(8) .\"{{{}}} --- NEW FILE: atmdump.c --- /* atmdump.c - ATM raw cell dumper */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> /* for htonl and ntohl */ #include <atm.h> static const char *pti[] = { "Data SDU 0","Data SDU 1","Data SDU 0, CE", "Data SDU 1, CE","Segment OAM F5","End-to-end OAM F5","Reserved (RM)", "Reserved" }; static int interval = 0; /* display absolute time by default */ #define GET(item) ((*cell & ATM_HDR_##item##_MASK) >> ATM_HDR_##item##_SHIFT) static void analyze(unsigned long *cell,struct timeval stamp) { static struct timeval last; static int first = 1; int i; if (first || !interval) { printf("%2d:%02d:%02d",(int) ((stamp.tv_sec/3600) % 24), (int) ((stamp.tv_sec/60) % 60),(int) (stamp.tv_sec % 60)); if (interval) { first = 0; last = stamp; } } else { struct timeval diff; diff.tv_sec = stamp.tv_sec-last.tv_sec; diff.tv_usec = stamp.tv_usec-last.tv_usec; while (diff.tv_usec < 0) { diff.tv_usec += 1000000; diff.tv_sec--; } last = stamp; printf("%8ld",(long) diff.tv_sec); } printf(".%06ld: VPI=%ld VCI=%ld, GFC=0x%lx, CLP=%ld, %s (PTI %ld)\n", (long) stamp.tv_usec,GET(VPI),GET(VCI),GET(GFC),*cell & ATM_HDR_CLP, pti[GET(PTI)],GET(PTI)); for (i = 0; i < ATM_CELL_PAYLOAD; i++) { if (!(i & 15)) printf(" "); printf("%02x ",((unsigned char *) cell)[i+4]); if ((i & 15) == 15) putchar('\n'); } } static void usage(const char *name) { int i; fprintf(stderr,"usage: %s [ -i ] [ -t type [ -g gfc ] [ -c ] ] " "[itf.]vpi.vci\n",name); for (i = 0; i < 8; i++) fprintf(stderr," %-6s %d %s\n",i ? "" : "type",i,pti[i]); fprintf(stderr," gfc 0-15, default 0\n"); exit(1); } int main(int argc,char **argv) { unsigned long buf[13]; /* ugly */ struct sockaddr_atmpvc addr; struct atm_qos qos; char *name,*end; int type,gfc,clp; int c,s,size; type = -1; gfc = clp = 0; /* for GCC */ name = argv[0]; while ((c = getopt(argc,argv,"t:g:c")) != EOF) switch (c) { case 'i': interval = 1; break; case 't': type = strtol(optarg,&end,0); if (*end || type < 0 || type > 7) usage(name); break; case 'g': gfc = strtol(optarg,&end,0); if (*end || gfc < 0 || gfc > 15) usage(name); break; case 'c': clp = 1; break; default: usage(name); } if (argc != optind+1) usage(name); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[optind],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(name); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL0; if (type == -1) { qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = 52; } else { qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 52; } if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } if (type == -1) { while ((size = read(s,buf,52)) == 52) { struct timeval stamp; if (ioctl(s,SIOCGSTAMP,&stamp) < 0) { perror("ioctl SIOCGSTAMP"); return 1; } analyze(buf,stamp); fflush(stdout); } if (size < 0) perror("read"); else fprintf(stderr,"short read (%d bytes)\n",size); return 1; } if ((size = read(0,buf+1,ATM_CELL_PAYLOAD)) < 0) { perror("read stdin"); return 1; } if (size < ATM_CELL_PAYLOAD) memset((unsigned char *) (buf+1)+size,0,ATM_CELL_PAYLOAD-size); *buf = (gfc << ATM_HDR_GFC_SHIFT) | (addr.sap_addr.vpi << ATM_HDR_VPI_SHIFT) | (addr.sap_addr.vci << ATM_HDR_VCI_SHIFT) | (type << ATM_HDR_PTI_SHIFT) | clp; if ((size = write(s,buf,ATM_CELL_SIZE-1)) < 0) { perror("write to network"); return 1; } if (size < ATM_CELL_SIZE-1) { fprintf(stderr,"short write (%d bytes)\n",size); return 1; } return 0; } --- NEW FILE: atmtcp.8 --- .TH ATMTCP 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmtcp \- set up ATM over TCP connections .SH SYNOPSIS .ad l .B atmtcp .RB [ \-d ] .RB [ \-v ] .I command .B ... .br .B atmtcp .B \-V .ad b .SH DESCRIPTION The main purpose of \fBatmtcp\fP is to establish TCP connections and to configure them as virtual ATM devices. Such pairs of "ATM over TCP" devices are connected as if they were real ATM adapters linked by a cable or fiber, i.e. SDUs sent on a given VPI/VCI are received at the other end on the same VPI/VCI. .PP Virtual interfaces and ATM over TCP connections are called \fIlinks\fP. Other link types supported by \fBatmtcp\fP are real interfaces, files for recording and playback of ATM traffic, and printing a hex dump of the PDU content on standard output. Any pair of such links can be connected with \fBatmtcp\fP. If additional links are attached to such a connection, they send to all other links, except to the first link and the respective sender, and they receive from all other links. .PP \fBatmtcp\fP can operate with two types of virtual interfaces: ephemeral or persistent. By default, \fBatmtcp\fP interfaces are ephemeral. When the \fBatmtcp\fP process that created an interface terminates, the virtual ATM device is removed as soon all VCs are closed. However, if the interface was previously created as a persistent interface, only the communication stops, but the interface and all VCs on it remain intact. Attempts to send data on an \fBatmtcp\fP interface in this state fail silently, i.e. the interface behaves just like a real ATM interface without a wire. A new \fBatmtcp\fP process can then attach to the interface and resume operation. Persistent interfaces need to be removed explicitly. .PP If \fBatmtcp\fP has any readable links after processing the command line, it enters a loop to perform the data forwarding. If no readable links have been specified, \fBatmtcp\fP terminates after processing the command line. If any setup operation fails, \fBatmtcp\fP terminates at this point and does not attempt to cancel previous operations (e.g. creation of permanent interfaces). .SH OPTIONS .IP \fB\-d\fP print detailed progress information on standard error. .IP \fB\-v\fP print some progress information on standard error. .IP \fB\-V\fP print version number of \fBatmtcp\fP on standard output and exit. .SH COMMANDS .IP \fBcreate\fP\ [\fIitf\fP] create a persistent interface. If no interface number is specified, \fBatmtcp\fP uses the default value 0. .IP \fBremove\fP\ [\fIitf\fP] remove a persistent interface. If the interface is still in use, it is marked as ephemeral and will be removed as soon as all VCs are closed. If no interface number is specified, \fBatmtcp\fP uses the default value 0. .IP \fBvirtual\fP\ [\fIitf\fP] link to the corresponding virtual (ATM over TCP) interface. If no interface number is specified, the kernel assigns the first available number. .IP \fBreal\fP\ [\fIitf\fP] link to the corresponding ATM interface. If no interface number is specified, \fBatmtcp\fP uses the default value 0. If a link requests that a VC be opened, \fBatmtcp\fP will attempt to open a VC with the specified QoS parameters on that interface. If the operation succeeds, data can be sent or received on that VC. If the operation fails, an error code is returned to the requester. Note that only data arriving on open VCs can be received and that a \fIreal\fP ATM interface never initiates a connection. \fBatmtcp\fP can share ATM interfaces with other applications. .IP \fBconnect\fP\ \fIhost\fP\ [\fIport\fP] connect to an instance of \fBatmtcp\fP running on the specified host. If the port argument is omitted, \fBatmtcp\fP uses the default port 2812. .IP \fBswitch\fP\ \fIhost\fP\ \fIline\fP\ [\fIport\fP] like \fBconnect\fP, but connects to an ATM over TCP "switch" and selects the specified virtual line. .IP \fBlisten\fP\ [\fIport\fP] listen for an incoming ATM over TCP connection. If the port argument is omitted, \fBatmtcp\fP uses the default port 2812. \fBatmtcp\fP waits until the connection is established. Only one connection is accepted per \fBlisten\fP command. .IP \fBlisten-bg\fP\ [\fIport\fP] like \fBlisten\fP, but run in background after beginning to listen. .IP \fBread\fP\ \fIfile\fP\ [\fIstream\fP] play back all streams from the specified file. If a stream number is specified, only that stream is played back. .IP \fBwrite\fP\ \fIfile\fP record the traffic of all links in the specified file. The PDUs from each link are stored in a stream with the same number as the link. .IP \fBprint\fP print a hex dump of the content of all received PDUs on standard output. .IP \fBbg\fP continue to run in background (i.e. in a forked child process). .IP \fBwait\fP\ [\fIseconds\fP] wait for the specified number of seconds. If no time is specified, \fBatmtcp\fP waits for a newline on standard input. .SH RESTRICTIONS Due to recent protocol changes, \fBatmtcp\fP is currently not compatible with the ATM over TCP "switch". .PP Only AAL SDUs are exchanged, no segmentation or reassembly is performed. That implies that using different AALs (e.g. AAL5 and AAL0) on either side will reveal limitations of this emulation. .PP The \fBatmtcp\fP process needs to run during the the whole lifetime of the connection. .SH EXAMPLES Create a pair of virtual ATM over TCP interfaces on the local host and connect them: .nf .sp # session A atmtcp virtual listen # session B atmtcp virtual connect localhost .sp .fi Create virtual interface 1, connect it to real ATM interface 0, then start \fBatmsigd\fP on the virtual interface, and log all the traffic in a file: .nf .sp atmtcp virtual 1 real 0 write /tmp/log atmsigd 1.0.5 .sp .fi Take the previously created file and examine the traffic sent from \fBatmsigd\fP using \fBsaaldump\fP: .nf .sp # session A atmtcp virtual 1 read /tmp/log 0 wait # session B saaldump 1.0.5 # press [Enter] in session A .sp .fi .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" atmdiag(8) .\"{{{}}} --- NEW FILE: atmtcp.c --- /* atmtcp.c - control ATM on TCP emulation */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <atm.h> #include <atmd.h> #include <linux/atm_tcp.h> #define DEFAULT_PORT 2812 /* IANA-assigned; old ATMTCP used 8401 & 8402 */ #define MAX_PACKET (ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_control)+ \ sizeof(int)) typedef struct _in { int fd; void (*recv)(struct _in *in); int link; unsigned char buf[MAX_PACKET]; int bytes; void *user; struct _in *next; } IN; typedef struct _out { const struct _out_ops *ops; int link; void *user; struct _out *next; } OUT; typedef struct _out_ops { int (*open)(struct _out *out,int in_link,struct atmtcp_control *msg); void (*send)(struct _out *out,int in_link,const struct atmtcp_hdr *hdr, int size); int (*close)(struct _out *out,int in_link,struct atmtcp_control *msg); } OUT_OPS; static OUT *outputs = NULL; static IN *inputs = NULL; static fd_set in_set; static int fds = 0; static int debug = 0; static int links = 0; /* misc. */ /* * Policy: * - first link sends to everybody except itself * - second link sends to everybody except itself * - all other links send to everybody except the first link the sender itself */ static int right_link(const OUT *out,int in_link) { if (out->link == in_link) return 0; return out != outputs || in_link == 1; } static void emit(int in_link,const struct atmtcp_hdr *hdr,int size) { OUT *out; if (debug) fprintf(stderr,"Emit: %d.%d, %d bytes\n",ntohs(hdr->vpi), ntohs(hdr->vci),(int) ntohl(hdr->length)); for (out = outputs; out; out = out->next) if (out->ops->send) out->ops->send(out,in_link,hdr,size); } static void control(int in_link,struct atmtcp_control *msg) { OUT *out; int changed = 0; if (debug) fprintf(stderr,"Control: (%d.%d) %s %d.%d, vcc %s\n", ntohs(msg->hdr.vpi),ntohs(msg->hdr.vci), msg->type == ATMTCP_CTRL_OPEN ? "OPEN" : msg->type == ATMTCP_CTRL_CLOSE ? "CLOSE" : "???", msg->addr.sap_addr.vpi,msg->addr.sap_addr.vci,kptr_print(&msg->vcc)); for (out = outputs; out; out = out->next) switch (msg->type) { case ATMTCP_CTRL_OPEN: if (out->ops->open) changed += out->ops->open(out,in_link,msg); break; case ATMTCP_CTRL_CLOSE: if (out->ops->close) changed += out->ops->close(out,in_link,msg); break; default: fprintf(stderr,"interval error\n"); exit(1); } if (changed > 1) fprintf(stderr,"WARNING: multiple changes on control()\n"); } /* ----- Registries -------------------------------------------------------- */ static IN *register_in(int fd,void (*receive)(IN *in),void *user) { IN *in = alloc_t(IN); IN **walk; in->fd = fd; in->recv = receive; in->link = links; in->bytes = 0; in->user = user; in->next = NULL; for (walk = &inputs; *walk; walk = &(*walk)->next); *walk = in; if (fd >= fds) fds = fd+1; FD_SET(fd,&in_set); return in; } static void unregister_in(IN *in) { IN **walk; for (walk = &inputs; *walk != in; walk = &(*walk)->next); FD_CLR(in->fd,&in_set); if (fds > in->fd+1) return; fds = 0; for (walk = &inputs; *walk; walk = &(*walk)->next) if ((*walk)->fd >= fds) fds = (*walk)->fd+1; } static void register_out(const OUT_OPS *ops,void *user) { OUT *out = alloc_t(OUT); OUT **walk; out->ops = ops; out->link = links; out->user = user; out->next = NULL; for (walk = &outputs; *walk; walk = &(*walk)->next); *walk = out; } /* ----- Virtual (ATMTCP) interface ---------------------------------------- */ static void virtual_do_send(int fd,const void *data,int size) { int wrote; wrote = write(fd,data,size); if (wrote < 0) perror("write to kernel"); else if (wrote != size) { fprintf(stderr,"bad write (%d != %d)\n",wrote,size); exit(1); } } static void virtual_in(IN *in) { const struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) in->buf; int got; got = read(in->fd,in->buf,MAX_PACKET); if (got < 0) { perror("virtual interface"); exit(1); } if (!got) exit(0); /* we don't use that yet */ if (got < sizeof(struct atmtcp_hdr)) { fprintf(stderr,"kernel message too small (%d)\n",got); exit(1); } if (ntohl(hdr->length) == ATMTCP_HDR_MAGIC) { if (got < sizeof(struct atmtcp_control)) { fprintf(stderr,"invalid control message\n"); exit(1); } control(in->link,(struct atmtcp_control *) in->buf); virtual_do_send(in->fd,hdr,sizeof(struct atmtcp_control)); return; } if (got != sizeof(struct atmtcp_hdr)+ntohl(hdr->length)) { fprintf(stderr,"invalid kernel message\n"); exit(1); } emit(in->link,hdr,got); } static void virtual_send(OUT *out,int in_link,const struct atmtcp_hdr *hdr, int size) { if (!right_link(out,in_link)) return; virtual_do_send(*(int *) out->user,hdr,size); } static OUT_OPS virtual_ops = { NULL, /* open */ virtual_send, /* send */ NULL /* close */ }; /* ----- Real ATM interface ------------------------------------------------ */ typedef struct _vcc { struct sockaddr_atmpvc addr; int fd; /* for output */ IN *in; /* NULL is output only */ struct _vcc *next; } VCC; typedef struct { int itf; VCC *vccs; } REAL_DATA; static VCC **real_lookup(REAL_DATA *data,const struct sockaddr_atmpvc *addr) { VCC **walk; for (walk = &data->vccs; *walk; walk = &(*walk)->next) if ((*walk)->addr.sap_addr.vpi == addr->sap_addr.vpi && (*walk)->addr.sap_addr.vci == addr->sap_addr.vci) break; return walk; } static void real_in(IN *in) { VCC *vcc = (VCC *) in->user; struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) in->buf; int got; got = read(in->fd,hdr+1,MAX_PACKET-sizeof(*hdr)); if (got < 0) { perror("real interface"); exit(1); } hdr->length = htonl(got); hdr->vpi = htons(vcc->addr.sap_addr.vpi); hdr->vci = htons(vcc->addr.sap_addr.vci); emit(in->link,hdr,got+sizeof(*hdr)); } static int real_open(OUT *out,int in_link,struct atmtcp_control *msg) { REAL_DATA *data = (REAL_DATA *) out->user; VCC **vcc; int s; if (!right_link(out,in_link)) return 0; vcc = real_lookup(data,&msg->addr); if (*vcc) { msg->result = -EADDRINUSE; return 1; } if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { msg->result = -errno; if (debug) perror("socket"); return 1; } if (setsockopt(s,SOL_ATM,SO_ATMQOS,&msg->qos,sizeof(msg->qos)) < 0) { msg->result = -errno; if (debug) perror("setsockopt SO_ATMQOS"); return 1; } msg->addr.sap_addr.itf = data->itf; if (connect(s,(struct sockaddr *) &msg->addr, sizeof(struct sockaddr_atmpvc)) < 0) { msg->result = -errno; if (debug) perror("connect"); return 1; } (*vcc) = alloc_t(VCC); (*vcc)->addr = msg->addr; (*vcc)->next = NULL; (*vcc)->fd = s; (*vcc)->in = msg->qos.rxtp.traffic_class == ATM_NONE ? NULL : register_in(s,real_in,*vcc); return 1; } static void real_send(OUT *out,int in_link,const struct atmtcp_hdr *hdr, int size) { REAL_DATA *data = (REAL_DATA *) out->user; struct sockaddr_atmpvc addr; VCC **vcc; int wrote; if (!right_link(out,in_link)) return; addr.sap_addr.vpi = ntohs(hdr->vpi); addr.sap_addr.vci = ntohs(hdr->vci); vcc = real_lookup(data,&addr); if (!*vcc) { if (debug) fprintf(stderr,"VCC %d.%d not found\n",addr.sap_addr.vpi, addr.sap_addr.vci); return; } wrote = write((*vcc)->fd,hdr+1,ntohl(hdr->length)); if (wrote < 0) { perror("real write"); exit(1); } if (!wrote) exit(0); /* EOF */ if (wrote != ntohl(hdr->length)) { fprintf(stderr,"bad write (%d != %d)\n",wrote,(int) ntohl(hdr->length)); exit(1); } } static int real_close(OUT *out,int in_link,struct atmtcp_control *msg) { REAL_DATA *data = (REAL_DATA *) out->user; VCC **vcc,*this; int fd; if (!right_link(out,in_link)) return 0; vcc = real_lookup(data,&msg->addr); if (!*vcc) { msg->result = -ENOENT; return 1; } this = *vcc; *vcc = this->next; if (this->in) unregister_in(this->in); fd = this->fd; free(this); if (close(fd) >= 0) return 0; msg->result = -errno; return 1; } static OUT_OPS real_ops = { real_open, /* open */ real_send, /* send */ real_close /* close */ }; /* ----- ATMTCP connection ------------------------------------------------- */ static void tcp_do_send(int fd,const void *data,int size) { int wrote; wrote = write(fd,data,size); if (wrote < 0) { perror("write to TCP"); exit(1); } if (!wrote) exit(0); /* EOF */ if (wrote != size) { fprintf(stderr,"bad write (%d != %d)\n",wrote,size); exit(1); } } static void tcp_in(IN *in) { struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) in->buf; char *msg = (char *) (hdr+1); int vpi,vci; char orig_addr[MAX_ATM_ADDR_LEN]; char qos[MAX_ATM_QOS_LEN]; struct atmtcp_control ctl; int size,got; size = sizeof(*hdr)-in->bytes; if (size <= 0) size += ntohl(hdr->length); got = read(in->fd,in->buf+in->bytes,size); if (got < 0) { perror("read from file"); exit(1); } if (!got) { fprintf(stderr,"TCP disconnected\n"); exit(0); } in->bytes += got; if (in->bytes < sizeof(*hdr)) return; if (ntohl(hdr->length) > ATM_MAX_AAL5_PDU) { fprintf(stderr,"giant PDU (length = %d) received\n", (unsigned int) ntohl(hdr->length)); exit(1); } if (in->bytes < sizeof(*hdr)+ntohl(hdr->length)) return; if (debug) fprintf(stderr,"TCP %d.%d, %d bytes\n",ntohs(hdr->vpi), ntohs(hdr->vci),(unsigned int) ntohl(hdr->length)); in->bytes = 0; if (hdr->vpi || hdr->vci) { emit(in->link,hdr,sizeof(*hdr)+ntohl(hdr->length)); return; } msg[ntohl(hdr->length)] = 0; memset(&ctl,0,sizeof(ctl)); if (sscanf(msg,"O %d.%d %s %s",&vpi,&vci,orig_addr,qos) == 4) ctl.type = ATMTCP_CTRL_OPEN; else if (sscanf(msg,"C %d.%d",&vpi,&vci) == 2) ctl.type = ATMTCP_CTRL_CLOSE; else { fprintf(stderr,"unrecognized control message \"%s\"\n",msg); return; } if (debug) fprintf(stderr,"received control \"%s\"\n",msg); ctl.hdr.vpi = htons(vpi); ctl.hdr.vci = htons(vci); ctl.hdr.length = htonl(ATMTCP_HDR_MAGIC); ctl.addr.sap_family = AF_ATMPVC; ctl.addr.sap_addr.itf = 0; ctl.addr.sap_addr.vpi = vpi; ctl.addr.sap_addr.vci = vci; if (ctl.type == ATMTCP_CTRL_OPEN) { if (text2atm(orig_addr,(struct sockaddr *) &ctl.addr,sizeof(ctl.addr), T2A_PVC) < 0) { fprintf(stderr,"invalid address \"%s\"\n",orig_addr); return; } if (text2qos(qos,&ctl.qos,0) < 0) { fprintf(stderr,"invalid QOS \"%s\"\n",qos); return; } } control(in->link,&ctl); } static void tcp_send(OUT *out,int in_link,const struct atmtcp_hdr *hdr,int size) { if (!right_link(out,in_link)) return; tcp_do_send(*(int *) out->user,hdr,size); } static int tcp_control(OUT *out,int in_link,struct atmtcp_control *msg) { char buf[MAX_ATM_NAME_LEN*2+MAX_ATM_NAME_LEN+5]; struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) buf; char *start = (char *) (hdr+1); char *pos = start; if (!right_link(out,in_link)) return 0; if (msg->type != ATMTCP_CTRL_OPEN && msg->type != ATMTCP_CTRL_CLOSE) { fprintf(stderr,"unrecognized control message %d\n",msg->type); return 0; } pos += sprintf(pos,"%c %d.%d",msg->type == ATMTCP_CTRL_OPEN ? 'O' : 'C', msg->addr.sap_addr.vpi,msg->addr.sap_addr.vci); if (msg->type == ATMTCP_CTRL_OPEN) { *pos++ = ' '; if (atm2text(pos,sizeof(buf)-(pos-buf),(struct sockaddr *) &msg->addr, 0) < 0) { fprintf(stderr,"invalid ATM address\n"); return 0; } pos = strchr(pos,0); *pos++ = ' '; if (qos2text(pos,sizeof(buf)-(pos-buf),&msg->qos,0) < 0) { fprintf(stderr,"invalid QOS\n"); return 0; } pos = strchr(pos,0); } hdr->vpi = hdr->vci = htons(0); hdr->length = htonl(pos-start); if (debug) fprintf(stderr,"sending control \"%s\"\n",start); tcp_do_send(*(int *) out->user,buf,pos-buf); return 0; } static OUT_OPS tcp_ops = { tcp_control, /* open */ tcp_send, /* send */ tcp_control /* close */ }; /* ----- File -------------------------------------------------------------- */ static void file_in(IN *in) { int *stream = (int *) in->buf; struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) (stream+1); int size,got; size = sizeof(int)+sizeof(*hdr)-in->bytes; if (size <= 0) size += ntohl(hdr->length) == ATMTCP_HDR_MAGIC ? sizeof(struct atmtcp_control)-sizeof(*hdr) : ntohl(hdr->length); got = read(in->fd,in->buf+in->bytes,size); if (got < 0) { perror("read from file"); exit(1); } if (!got) { fprintf(stderr,"EOF\n"); exit(0); } in->bytes += got; if (in->bytes < sizeof(int)+sizeof(*hdr)) return; if (ntohl(hdr->length) == ATMTCP_HDR_MAGIC) { if (in->bytes < sizeof(int)+sizeof(struct atmtcp_control)) return; } else { if (ntohl(hdr->length) > ATM_MAX_AAL5_PDU) { fprintf(stderr,"giant PDU (length = %d) received\n", (unsigned int) ntohl(hdr->length)); exit(1); } if (in->bytes < sizeof(int)+sizeof(*hdr)+ntohl(hdr->length)) return; if (debug) fprintf(stderr,"File %d.%d, %d bytes\n",ntohs(hdr->vpi), ntohs(hdr->vci),(unsigned int) ntohl(hdr->length)); } in->bytes = 0; if (*(int *) in->user != -1 && ntohl(*stream) != *(int *) in->user) return; if (ntohl(hdr->length) == ATMTCP_HDR_MAGIC) control(in->link,(struct atmtcp_control *) hdr); else emit(in->link,hdr,sizeof(*hdr)+ntohl(hdr->length)); } static void file_write(int fd,int stream,int is_control,const void *data, int size) { int wrote; stream = htonl(stream); wrote = write(fd,&stream,sizeof(stream)); if (wrote < 0) { perror("file write"); exit(1); } if (wrote != sizeof(stream)) { fprintf(stderr,"short write (%d < %d)\n",wrote,sizeof(stream)); exit(1); } wrote = write(fd,data,size); if (wrote < 0) { perror("file write"); exit(1); } if (wrote != size) { fprintf(stderr,"short write (%d < %d)\n",wrote,size); exit(1); } } static void file_send(OUT *out,int in_link,const struct atmtcp_hdr *hdr, int size) { file_write(*(int *) out->user,in_link,0,hdr,size); } static int file_control(OUT *out,int in_link,struct atmtcp_control *msg) { file_write(*(int *) out->user,in_link,1,msg,sizeof(*msg)); return 0; } static OUT_OPS file_ops = { file_control, /* open */ file_send, /* send */ file_control /* close */ }; /* ----- Print ------------------------------------------------------------- */ static void print_send(OUT *out,int in_link,const struct atmtcp_hdr *hdr, int size) { int length = ntohl(hdr->length); int i; printf("Link %d (from link %d), VPI %d, VCI %d, %d byte%s:",out->link, in_link,ntohs(hdr->vpi),ntohs(hdr->vci),length,length == 1 ? "" : "s"); for (i = 0; i < length; i++) { if (!(i & 15)) printf("\n "); printf(" %02x",((unsigned char *) (hdr+1))[i]); } putchar('\n'); fflush(stdout); } static OUT_OPS print_ops = { NULL, /* open */ print_send, /* send */ NULL /* close */ }; /* ----- Initialization ---------------------------------------------------- */ static void background(void) { static int backgrounding = 0; pid_t pid; if (backgrounding++) { fprintf(stderr,"\"bg\" only allowed once\n"); exit(1); } pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid) exit(0); } static void usage(const char *name) { fprintf(stderr,"usage: %s [ -d ] [ -v ] <cmd> ...\n",name); fprintf(stderr,"%6s %s -V\n\n","",name); fprintf(stderr," -d debug\n"); fprintf(stderr," -v verbose\n"); fprintf(stderr," -V version\n\n"); fprintf(stderr,"<cmd>: create [ <itf> ] (persistent; default itf: 0)\n"); fprintf(stderr," remove [ <itf> ] (persistent; default itf: 0)\n"); fprintf(stderr," virtual [ <itf> ] (default itf: assigned by " "kernel)\n"); fprintf(stderr," real [ <itf> ] (default itf: 0)\n"); fprintf(stderr," connect <host> [ <port> ]\n"); fprintf(stderr," switch <host> <line> [ <port> ] (to ATMTCP " "virtual switch)\n"); fprintf(stderr," listen [ <port> ]\n"); fprintf(stderr," read <file> [ <stream> ]\n"); fprintf(stderr," write <file>\n"); fprintf(stderr," print\n"); fprintf(stderr," bg (background)\n"); fprintf(stderr," wait [ <secs> ] (default: wait for [Enter])\n\n"); fprintf(stderr,"create, remove, bg, and wait don't create new links.\n"); exit(1); } #define NEXT (++optind < argc) #define HAS_MORE (optind < argc-1) #define NEED_NEXT { if (!NEXT) usage(*argv); } #define ARG argv[optind] #define NEXT_ARG argv[optind+1] int main(int argc,char **argv) { struct sockaddr_in addr; char *end; int verbose = 0; int do_create,do_background = 0,to_switch = 0; int c; FD_ZERO(&in_set); while ((c = getopt(argc,argv,"dvV")) != EOF) switch (c) { case 'd': debug = 1; break; case 'v': verbose = 1; break; case 'V': printf("%s\n",VERSION); return 0; default: usage(*argv); } optind--; if (!HAS_MORE) usage(*argv); while (NEXT) { if ((do_create = !strcmp(ARG,"create")) || !strcmp(ARG,"remove")) { int s; int itf = 0; if ((s = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } if (HAS_MORE) { itf = strtoul(NEXT_ARG,&end,10); if (*end) itf = 0; else (void) NEXT; } if (ioctl(s,do_create ? ATMTCP_CREATE : ATMTCP_REMOVE,itf) < 0) { perror(do_create ? "ioctl ATMTCP_CREATE" : "ioctl ATMTCP_REMOVE"); return 1; } (void) close(s); if (verbose) fprintf(stderr,"Persistent ATMTCP interface %d %s\n",itf, do_create ? "created" : "removed"); } else if (!strcmp(ARG,"virtual")) { int *fd = alloc_t(int); int itf = -1; if (HAS_MORE) { itf = strtoul(NEXT_ARG,&end,10); if (*end) itf = -1; else (void) NEXT; } if ((*fd = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } if ((itf = ioctl(*fd,SIOCSIFATMTCP,itf)) < 0) { perror("ioctl SIOCSIFATMTCP"); return 1; } (void) register_in(*fd,&virtual_in,NULL); register_out(&virtual_ops,fd); fprintf(stderr,"Link %d: virtual interface %d\n",links++,itf); } else if (!strcmp(ARG,"real")) { REAL_DATA *data = alloc_t(REAL_DATA); int itf = 0; if (HAS_MORE) { itf = strtoul(NEXT_ARG,&end,10); if (*end) itf = 0; else (void) NEXT; } data->itf = itf; data->vccs = NULL; register_out(&real_ops,data); fprintf(stderr,"Link %d: real interface %d\n",links++,itf); } else if (!strcmp(ARG,"connect") || (to_switch = !strcmp(ARG,"switch"))) { int *fd = alloc_t(int); const char *host,*line = NULL; int port; NEED_NEXT; host = ARG; if ((*fd = socket(PF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = text2ip(ARG,NULL,T2I_NAME | T2I_ERROR); if (addr.sin_addr.s_addr == INADDR_NONE) return 1; if (to_switch) { NEED_NEXT; line = ARG; } if (!HAS_MORE) port = DEFAULT_PORT; else { port = strtoul(NEXT_ARG,&end,10); if (*end) port = DEFAULT_PORT; else (void) NEXT; } addr.sin_port = htons(port); if (connect(*fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("connect"); return 1; } (void) register_in(*fd,&tcp_in,NULL); register_out(&tcp_ops,fd); fprintf(stderr,"Link %d: ATMTCP connection to %s\n",links++,host); if (to_switch) tcp_do_send(*fd,line,strlen(line)+1); } else if (!strcmp(ARG,"listen") || (do_background = !strcmp(ARG,"listen-bg"))) { int fd,port,addr_len; int *fd2 = alloc_t(int); if ((fd = socket(PF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); if (!HAS_MORE) port = DEFAULT_PORT; else { port = strtoul(NEXT_ARG,&end,10); if (*end) port = DEFAULT_PORT; else (void) NEXT; } addr.sin_port = htons(port); if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } if (listen(fd,5) < 0) { perror("listen"); return 1; } if (verbose) fprintf(stderr,"Listening on TCP port %d\n",port); if (do_background) background(); addr_len = sizeof(addr); if ((*fd2 = accept(fd,(struct sockaddr *) &addr,&addr_len)) < 0) { perror("accept"); return 1; } (void) close(fd); (void) register_in(*fd2,&tcp_in,NULL); register_out(&tcp_ops,fd2); fprintf(stderr,"Link %d: incoming ATMTCP connection from %s\n", links++,addr.sin_family == AF_INET ? inet_ntoa(addr.sin_addr) : "non-IPv4 host"); } else if (!strcmp(ARG,"read")) { int *stream = alloc_t(int); const char *name; int fd; NEED_NEXT; name = ARG; if ((fd = open(ARG,O_RDONLY)) < 0) { perror(ARG); return 1; } if (!HAS_MORE) *stream = -1; else { *stream = strtoul(NEXT_ARG,&end,10); if (*end) *stream = -1; else (void) NEXT; } (void) register_in(fd,&file_in,stream); fprintf(stderr,"Link %d: read-only file \"%s\"\n",links++,name); } else if (!strcmp(ARG,"write")) { int *fd = alloc_t(int); NEED_NEXT; if ((*fd = open(ARG,O_CREAT | O_WRONLY | O_TRUNC,0666)) < 0) { perror(ARG); return 1; } register_out(&file_ops,fd); fprintf(stderr,"Link %d: write-only file \"%s\"\n",links++,ARG); } else if (!strcmp(ARG,"print")) { register_out(&print_ops,0); fprintf(stderr,"Link %d: printing on standard output\n",links++); } else if (!strcmp(ARG,"bg")) background(); else if (!strcmp(ARG,"wait")) { int secs = -1; if (HAS_MORE) { secs = strtoul(NEXT_ARG,&end,10); if (*end) secs = -1; else (void) NEXT; } if (secs != -1) { sleep(secs); continue; } fprintf(stderr,"Press <Return> to continue\n"); do c = getchar(); while (c != EOF && c != '\n'); } else usage(*argv); } if (!fds) return 0; while (1) { IN *in; fd_set set; int ret; set = in_set; ret = select(fds,&set,NULL,NULL,NULL); if (ret < 0) { if (errno != EINTR) perror("select"); continue; } for (in = inputs; in; in = in->next) if (FD_ISSET(in->fd,&set)) in->recv(in); } } --- NEW FILE: atmloop.8 --- .TH ATMLOOP 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmloop \- get/set loopback mode of ATM interfaces .SH SYNOPSIS .ad l .B atmloop .B \-s .RB [ \-l\ \fIlevel\fP ] .RB [ \-r\ \fIlevel\fP ] .RB [ \fIitf\fP ] .br .B atmloop .RB [ \fIitf\fP ] .br .B atmloop .B \-q .RB [ \fIitf\fP ] .br .B atmloop .B \-V .ad b .SH DESCRIPTION .B atmloop sets or shows the current loopback settings of an ATM interface, and allows to query the loopback modes supported by the interface. .P Some ATM cards can be configured to echo data back to the driver (local loopback) or to the network (remote loopback). The echoing may be done at several different levels: .IP \fBaal\fP AAL PDUs .IP \fBatm\fP ATM cells .IP \fBdigital\fP bits sent to or received from the line interface .IP \fBanalog\fP the analog signal .P The levels supported by an interface can be queried with the \fB\-q\fP option. If invoked without options, \fBatmloop\fP displays the current loopback settings. .SH OPTIONS .IP \fB\-s\fP set loopback mode. Followed by either \fB\-l\fP or \fB\-r\fP, both options to set local and remote loopback at the same time (if supported by the driver), or none of them to turn off any loopback. .IP \fB\-l\ \fIlevel\fP enable local loopback. .IP \fB\-r\ \fIlevel\fP enable remote loopback. .IP \fB\-q\ \fIlevel\fP query loopback levels supported by the interface. .IP \fB\-V\fP print version number of \fBatmloop\fP on standard output and exit. .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" atmdiag(8), sonetdiag(8) .\"{{{}}} --- NEW FILE: atmloop.c --- /* atmloop.c - get/set loopback mode of ATM interfaces */ /* Written 2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <atm.h> #include <linux/atmdev.h> static void usage(const char *name) { fprintf(stderr,"usage: %s -s [ -l level ] [ -r level ] [ itf ]\n",name); fprintf(stderr,"%7s%s [ itf ]\n","",name); fprintf(stderr,"%7s%s -q [ itf ]\n","",name); fprintf(stderr,"%7s%s -V\n","",name); fprintf(stderr," levels: aal = AAL PDU, atm = ATM cell,\n"); fprintf(stderr,"%10sphy = line (digital), analog = line (analog)\n",""); exit(1); } static int text2level(const char *name,const char *s) { if (!strcmp(s,"aal")) return __ATM_LM_AAL; if (!strcmp(s,"atm")) return __ATM_LM_ATM; if (!strcmp(s,"phy")) return __ATM_LM_PHY; if (!strcmp(s,"analog")) return __ATM_LM_ANALOG; usage(name); return 0; /* uh ... */ } static const char *level2text(int level) { switch (level) { case __ATM_LM_AAL: return "aal"; case __ATM_LM_ATM: return "atm"; case __ATM_LM_PHY: return "phy"; case __ATM_LM_ANALOG: return "analog"; default: return "???"; } } static void print_levels(int levels,int show_none) { int mask; if (!levels) { if (show_none) printf(" (none)"); return; } for (mask = 1; levels; mask += mask) { if (!(mask & levels)) continue; printf(" %s",level2text(__ATM_LM_XTLOC(mask))); levels &= ~mask; } } int main(int argc,char **argv) { int local = ATM_LM_NONE,remote = ATM_LM_NONE,mode; int set = 0,query = 0; struct atmif_sioc req; int s,c; req.number = 0; while ((c = getopt(argc,argv,"l:qr:sV")) != EOF) switch (c) { case 'l': if (local) usage(*argv); local = text2level(*argv,optarg); break; case 'q': query = 1; break; case 'r': if (remote) usage(*argv); remote = text2level(*argv,optarg); break; case 's': set = 1; break; case 'V': printf("%s\n",VERSION); return 0; default: usage(*argv); } if (argc > optind+1) usage(*argv); if (argc == optind+1) { char *end; req.number = strtoul(argv[optind],&end,0); if (*end) usage(*argv); } mode = __ATM_LM_MKLOC(local) | __ATM_LM_MKRMT(remote); if ((mode && !set) || (set && query)) usage(*argv); s = socket(PF_ATMPVC,SOCK_DGRAM,0); if (s < 0) { perror("socket"); return 1; } if (set) { req.arg = (void *) mode; req.length = 0; if (ioctl(s,ATM_SETLOOP,&req) < 0) { perror("ioctl ATM_SETLOOP"); return 1; } return 0; } req.arg = &mode; req.length = sizeof(mode); if (ioctl(s,query ? ATM_QUERYLOOP : ATM_GETLOOP,&req) < 0) { perror(query ? "ioctl ATM_QUERYLOOP" : "ioctl ATM_GETLOOP"); return 1; } printf("local: "); print_levels(__ATM_LM_XTLOC(mode),query); printf("\nremote:"); print_levels(__ATM_LM_XTRMT(mode),query); printf("\n"); return 0; } --- NEW FILE: esi.8 --- .TH ESI 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME esi \- get or set the end system identifier (ESI) .SH SYNOPSIS .ad l .B esi .RB [ \fIitf\fP ] .br .B esi .RB [ \-f ]\ \fIesi\fP\ [ \fIitf\fP ] .br .B esi .B \-V .ad b .SH DESCRIPTION .B esi is used to show or set the end system identifier (ESI, a unique six-byte number corresponding to the MAC address of LAN technologies like Ethernet) of an ATM interface. If the interface number \fIitf\fP is omitted, interface 0 is used by default. The \fIesi\fP argument is a string of twelve hex digits. .P Only the ESI stored in the kernel is accessed; \fBesi\fP does not change the ESI stored on the NIC. If a non-zero ESI is already set on an interface, the \fB\-f\fP option has to be used to overwrite it. .P Note that ESI changes are not automatically propagated throughout the system, e.g. to \fBilmid\fP. \fBesi\fP should therefore be used early during system initialization. .SH OPTIONS .IP \fB\-f\fP force overwriting an existing ESI. .IP \fB\-V\fP print version number of \fBesi\fP on standard output and exit. .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" ilmid(8) .\"{{{}}} --- NEW FILE: esi.c --- /* esi.c - Get or set End System Identifier (ESI) */ /* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <linux/version.h> #if LINUX_VERSION_CODE < 0x20100 #include <stdio.h> int main(int argc,const char **argv) { fprintf(stderr,"%s: not supported in this version\n",*argv); return 1; } #else #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/ioctl.h> #include <atm.h> #include <linux/atmdev.h> static void usage(const char *name) { fprintf(stderr,"usage: %s [ [ -f ] esi ] [ itf ]\n",name); fprintf(stderr,"%6s %s -V\n","",name); exit(1); } int main(int argc,char **argv) { struct atmif_sioc req; const char *esi; unsigned char esi_buf[ESI_LEN]; char *end; int op,c,s; op = ATM_SETESI; memset(&req,0,sizeof(req)); esi = NULL; while ((c = getopt(argc,argv,"fV")) != EOF) switch (c) { case 'f': op = ATM_SETESIF; break; case 'V': printf("%s\n",VERSION); return 0; default: usage(*argv); } if (argc > optind+2) usage(*argv); if (argc == optind+2) { req.number = strtoul(argv[optind+1],&end,0); if (*end) usage(*argv); esi = argv[optind]; } if (argc == optind+1) { if (strlen(argv[optind]) == ESI_LEN*2) esi = argv[optind]; else { req.number = strtoul(argv[optind],&end,0); if (*end) usage(*argv); } } if (op == ATM_SETESIF && !esi) usage(*argv); if (esi) { int i,byte; for (i = 0; i < ESI_LEN; i++) { if (sscanf(esi,"%2x",&byte) != 1) usage(*argv); esi_buf[i] = byte; esi += 2; } } req.arg = esi_buf; req.length = ESI_LEN; if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } if (ioctl(s,esi ? op : ATM_GETESI,&req) < 0) { perror(esi ? op == ATM_SETESI ? "ioctl ATM_SETESI" : "ioctl ATM_SETESIF" : "ioctl ATM_GETESI"); return 1; } if (!esi) { int i; for (i = 0; i < ESI_LEN; i++) printf("%02X",esi_buf[i]); putchar('\n'); } return 0; } #endif --- NEW FILE: README.nstune --- [ Note: this is the original README. Since the patch is already included in atm.patch, only the instructions at the end of this file apply. - WA ] README file for release 7 of the nicstar device driver by Rui Prior. * * Make sure you read carefully the Installation section before proceeding * * This is the 7th release of my nicstar device driver. The driver is meant to work with the atm patch 0.38 applied to the 2.1.105 kernel. It supports AAL0 and AAL5. Supported traffic classes are UBR and CBR. Please note that this is not meant to be a final release, but a preliminary version. The code isn't optimized, doesn't look very nice, and probably still has some bugs, but at least it doesn't seem to freeze or crash the kernel. Hope it is useful. NOTE: the code for extracting the MAC address from the EPROM was not written by me (I didn't want to reinvent the weel :-). It was taken from the frle-0.22 device driver for the 2.0 series of kernels. Please read the nicstarmac.copyright file for the copyright notice included in the frle-0.22 device driver. Contact: -------- To send some feedback or bug reports, my e-mail address is rp...@in... My group's web page is at http://aramis.inescn.pt Installation: ------------- To use the driver, first you have to apply the atm patch to the kernel sources. Read the USAGE file in the atm distribution to learn how to do it. Then create a directory, cd to that directory, and extract the files with tar xvfz nicstar.tgz Now you have to go to the linux kernel source directory (usually /usr/src/linux) and apply the nicstar patch. cd /usr/src/linux patch -s -p1 < (nicstar_dir)/ns.patch where (nicstar_dir) is the directory where you extracted the files. Configure and compile the kernel the usual way, and you should have it working. To compile the nstune utility, cd (nicstar_dir) make If you compiled the driver as a module you can insert it with insmod nicstar and when you don't need it anymore you can remove it with rmmod nicstar Tuning: ------- You can tune the buffer level watermarks by doing nstune itf {s|l|h|i} min init max where: - itf is the atm interface number (most users only have one card, so this is 0. - s for small buffers, l for large buffers, h for huge buffers or i for iovec buffers. - min is the lower watermark, max the higher, and init is the initial level, and the level which is ideally sustained. For example: nstune 0 s 10 30 50 If you want to set the actual buffer level, not the watermarks, use nstune itf {s|l|h|i} which will set the corresponding buffer number to the init watermark level. Please note that small and large buffer numbers can't be decreased by using nstune. --- NEW FILE: enitune.c --- /* enitune.c - ENI buffer size tuning */ /* Written 2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include <linux/atm_eni.h> static void usage(const char *name) { fprintf(stderr,"usage: %s [ -t tx_mult ] [ -r rx_mult ] itf\n",name); fprintf(stderr," multipliers are in percent and must be > 100\n"); exit(1); } int main(int argc,char **argv) { char *name,*end; struct atmif_sioc sioc; struct eni_multipliers mult; int c,s; name = argv[0]; mult.tx = mult.rx = 0; while ((c = getopt(argc,argv,"t:r:")) != EOF) switch (c) { case 't': mult.tx = strtol(optarg,&end,0); if (*end || mult.tx <= 100) usage(name); break; case 'r': mult.rx = strtol(optarg,&end,0); if (*end || mult.rx <= 100) usage(name); break; default: } if (argc != optind+1) usage(name); sioc.number = strtol(argv[optind],&end,0); if (*end || sioc.number < 0) usage(name); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } sioc.arg = &mult; sioc.length = sizeof(mult); if (ioctl(s,ENI_SETMULT,&sioc) < 0) { perror("ioctl ENI_SETMULT"); return 1; } return 0; } --- NEW FILE: zntune.c --- /* zntune.c - ZN122x free buffer pool tuning */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <atm.h> #include <sys/time.h> /* for struct timeval, although it's not used */ #include <linux/atm_zatm.h> static void usage(const char *name) { fprintf(stderr,"%s: [-z] itf [pool]\n",name); fprintf(stderr,"%s: [-l low_water] [-h high_water] [-t threshold] itf " "[pool]\n",name); exit(1); } int main(int argc,char **argv) { char *name,*end; int low_water,high_water,next_thres,zero; int itf,pool,first,i; int c,s; low_water = high_water = next_thres = zero = 0; name = argv[0]; while ((c = getopt(argc,argv,"l:h:t:z")) != EOF) switch (c) { case 'l': low_water = strtol(optarg,&end,0); if (*end || low_water < 0) usage(name); break; case 'h': high_water = strtol(optarg,&end,0); if (*end || high_water < 0) usage(name); break; case 't': next_thres = strtol(optarg,&end,0); if (*end || next_thres < 0) usage(name); break; case 'z': zero = 1; default: usage(name); } if (zero && (low_water || high_water)) usage(name); if (argc < optind+1 || argc > optind+2) usage(name); itf = strtol(argv[optind],&end,0); if (*end || itf < 0) usage(name); if (argc < optind+2) pool = -1; else { pool = strtol(argv[optind+1],&end,0); if (*end || pool < 0 || pool > 31) usage(name); } s = socket(PF_ATMPVC,SOCK_DGRAM,0); if (s < 0) { perror("socket"); return 1; } first = 1; for (i = pool == -1 ? 0 : pool; i <= (pool == -1 ? ZATM_LAST_POOL : pool); i++) { struct atmif_sioc sioc; struct zatm_pool_req req; sioc.number = itf; sioc.arg = &req; sioc.length = sizeof(req); req.pool_num = i; if (low_water || high_water) { req.info.low_water = low_water; req.info.high_water = high_water; req.info.next_thres = next_thres; if (ioctl(s,ZATM_SETPOOL,&sioc) < 0) { perror("ioctl ZATM_SETPOOL"); return 1; } } else { int size; if (ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc) < 0) { perror(zero ? "ioctl ZATM_GETPOOLZ" : "ioctl ZATM_GETPOOL"); return 1; } if (first) printf("Pool Size Ref Low High Alarm Under Offs NxOf Count " "Thres\n"); printf(" %2d ",i); size = 64 << (i < 2 ? 0 : i-2); if (size < 1024) printf("%4d",size); else printf("%3dk",size >> 10); printf(" %3d %3d %4d%8d%6d %4d %4d%6d%6d\n", req.info.ref_count,req.info.low_water,req.info.high_water, req.info.rqa_count,req.info.rqu_count,req.info.offset, req.info.next_off,req.info.next_cnt,req.info.next_thres); } first = 0; } return 0; } --- NEW FILE: sonetdiag.c --- /* sonetdiag.c - SONET diagnostics */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/sonet.h> struct opts { const char *name; int value; } options[] = { { "sbip", SONET_INS_SBIP }, { "lbip", SONET_INS_LBIP }, { "pbip", SONET_INS_PBIP }, { "frame",SONET_INS_FRAME }, { "los", SONET_INS_LOS }, { "lais", SONET_INS_LAIS }, { "pais", SONET_INS_PAIS }, { "hcs", SONET_INS_HCS }, { NULL, 0 } }; static void usage(const char *name) { fprintf(stderr,"usage: %s [ -z ] [ itf ] [ [-]error ...]\n",name); fprintf(stderr," errors: sbip lbip pbip frame\n"); fprintf(stderr," los lais pais hcs\n"); exit(1); } int main(int argc,char **argv) { struct atmif_sioc req; struct sonet_stats stats; struct opts *walk; const char *name; char *opt,*end; int zero,s,set,clear,error,minus; zero = 0; name = argv[0]; if (argc > 1 && argv[1][0] == '-') { if (strcmp(argv[1],"-z")) usage(name); zero = 1; argc--; argv++; } if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } if (argc == 1) req.number = 0; else { req.number = strtol(argv[1],&end,10); if (*end) req.number = 0; else { if (req.number < 0) usage(name); argc--; argv++; } } argc--; argv++; set = clear = error = 0; while (argc--) { minus = *(opt = *argv++) == '-'; if (minus) opt++; for (walk = options; walk->name; walk++) if (!strcmp(walk->name,opt)) break; if (walk->name) if (minus) clear |= walk->value; else set |= walk->value; else { fprintf(stderr,"unrecognized option: %s\n",opt); error = 1; } } if (error) return 1; if (!set && !clear) { req.arg = &stats; req.length = sizeof(stats); if (ioctl(s,zero ? SONET_GETSTATZ : SONET_GETSTAT,&req) < 0) { perror(zero ? "ioctl SONET_GETSTATZ" : "ioctl SONET_GETSTAT"); return 1; } req.arg = &set; req.length = sizeof(set); if (ioctl(s,SONET_GETDIAG,&req) < 0) if (errno != EINVAL) perror("ioctl SONET_GETDIAG"); if (stats.section_bip != -1) printf("Section BIP errors: %10d\n",stats.section_bip); if (stats.line_bip != -1) printf("Line BIP errors: %10d\n",stats.line_bip); if (stats.path_bip != -1) printf("Path BIP errors: %10d\n",stats.path_bip); if (stats.line_febe != -1) printf("Line FEBE: %10d\n",stats.line_febe); if (stats.path_febe != -1) printf("Path FEBE: %10d\n",stats.path_febe); if (stats.corr_hcs != -1) printf("Correctable HCS: %10d\n",stats.corr_hcs); if (stats.uncorr_hcs != -1) printf("Uncorrectable HCS: %10d\n",stats.uncorr_hcs); if (stats.tx_cells != -1) printf("TX cells: %10d\n",stats.tx_cells); if (stats.rx_cells != -1) printf("RX cells: %10d\n",stats.rx_cells); if (set) { int i; printf("\nDiagnostics:"); for (i = 0; options[i].name; i++) if (set & options[i].value) printf(" %s",options[i].name); putchar('\n'); } } else { if (set) { req.arg = &set; req.length = sizeof(set); if (ioctl(s,SONET_SETDIAG,&req) < 0) perror("ioctl SONET_SETDIAG"); } if (clear) { req.arg = &clear; req.length = sizeof(clear); if (ioctl(s,SONET_CLRDIAG,&req) < 0) perror("ioctl SONET_SETDIAG"); } } return 0; } --- NEW FILE: Makefile.am --- BOOTPGMS=atmaddr esi SYSPGMS=atmloop atmtcp enitune zntune # nstune USRPGMS=atmdiag atmdump sonetdiag saaldump INCLUDES=-I$(top_builddir)/src/qgen -I$(top_builddir)/src/saal -I. LDADD = $(top_builddir)/src/lib/libatmd.la $(top_builddir)/src/lib/libatm.la sbin_PROGRAMS = $(BOOTPGMS) $(SYSPGMS) bin_PROGRAMS = $(USRPGMS) atmaddr_SOURCES = atmaddr.c esi_SOURCES = esi.c atmloop_SOURCES = atmloop.c atmtcp_SOURCES = atmtcp.c enitune_SOURCES = enitune.c zntune_SOURCES = zntune.c #nstune_SOURCES = nstune.c atmdiag_SOURCES = atmdiag.c atmdump_SOURCES = atmdump.c sonetdiag_SOURCES = sonetdiag.c saaldump_SOURCES = saaldump.c saaldump_LDADD = $(top_builddir)/src/qgen/qd.dump.o $(top_builddir)/src/saal/libsaal.a $(LDADD) saaldump_DEPENDENCIES = $(saaldump_LDADD) man_MANS = atmaddr.8 atmdiag.8 atmdump.8 atmloop.8 atmtcp.8 esi.8 #EXTRA_DIST = $(man_MANS) README.nstune EXTRA_DIST = $(man_MANS) README.nstune nstune.c --- NEW FILE: saaldump.c --- /* saaldump.c - ATM signaling message dumper */ /* Written 1997-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include "pdu.h" #define DUMP_MODE #include "qlib.h" #define MAX_ITEM 2048 /* longest string emitted by q.dump */ static int interval = 0; /* display absolute time by default */ static int quiet = 0; /* decode Q.2931 messages by default */ static int new_line = 1; static void sscop_pdu_diag(int severity,const char *fmt,...) { va_list ap; va_start(ap,fmt); printf(" %s",severity == SP_ERROR ? "ERROR: " : ""); vprintf(fmt,ap); putchar('\n'); va_end(ap); } void qd_dump(const char *msg,...) { char buf[MAX_ITEM]; va_list ap; int len; if (new_line) printf(" "); va_start(ap,msg); len = vsprintf(buf,msg,ap); va_end(ap); if (len > MAX_ITEM) { fprintf(stderr,"FATAL ERROR: buffer too small (%d < %d)\n",MAX_ITEM, len); exit(1); } printf("%s",buf); new_line = len ? buf[len-1] == '\n' : 0; } void qd_report(int severity,const char *msg,...) { va_list ap; if (severity > Q_ERROR) return; printf("%s ERROR: ",new_line ? "" : "\n"); va_start(ap,msg); vprintf(msg,ap); va_end(ap); putchar('\n'); new_line = 1; } static void analyze(unsigned char *pdu,int size,struct timeval stamp) { static struct timeval last; static int first = 1; PDU_VARS; if (first || !interval) { printf("%2d:%02d:%02d ",(int) ((stamp.tv_sec/3600) % 24), (int) ((stamp.tv_sec/60) % 60),(int) (stamp.tv_sec % 60)); if (interval) { first = 0; last = stamp; } } else { struct timeval diff; diff.tv_sec = stamp.tv_sec-last.tv_sec; diff.tv_usec = stamp.tv_usec-last.tv_usec; while (diff.tv_usec < 0) { diff.tv_usec += 1000000; diff.tv_sec--; } last = stamp; printf("%05u.%02u",(unsigned) diff.tv_sec, (unsigned) diff.tv_usec/10000); } if (!DECOMPOSE_PDU(NULL,pdu,size)) { PRINT_PDU("",pdu); if (type == SSCOP_SD && !quiet) { Q_DSC dsc; qd_open(&dsc,pdu,length); qd_close(&dsc); } } } static void usage(const char *name) { fprintf(stderr,"usage: %s [-i] [-q] [itf.]vpi.vci\n",name); exit(1); } int main(int argc,char **argv) { char buf[ATM_MAX_AAL5_PDU]; struct sockaddr_atmpvc addr; struct atm_qos qos; char *name; int c,s,size; name = argv[0]; while ((c = getopt(argc,argv,"iq")) != EOF) switch (c) { case 'i': interval = 1; break; case 'q': quiet = 1; break; default: usage(name); } if (argc != optind+1) usage(name); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[optind],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(name); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = ATM_MAX_AAL5_PDU; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } pdu_diag = sscop_pdu_diag; qd_start(); while ((size = read(s,buf,ATM_MAX_AAL5_PDU)) > 0) { struct timeval stamp; if (ioctl(s,SIOCGSTAMP,&stamp) < 0) { perror("ioctl SIOCGSTAMP"); return 1; } analyze(buf,size,stamp); fflush(stdout); } perror("read"); return 1; } --- NEW FILE: nstune.c --- /****************************************************************************** * * nstune.c * * User level utility to tune the NICStAR device driver. * * Author: Rui Prior * * (C) INESC 1998 * ******************************************************************************/ #if HAVE_CONFIG_H #include <config.h> #endif #include <sys/time.h> #include <linux/atm_nicstar.h> #include <linux/atm.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <sys/ioctl.h> static void usage(const char *name) { fprintf(stderr, "Set buffer level marks: \n"); fprintf(stderr, "%s itf {s|l|h|i} min init max \n", name); fprintf(stderr, "Set buffer level to init mark: \n"); fprintf(stderr, "%s itf {s|l|h|i} \n", name); fprintf(stderr, "\n"); exit(1); } int main(int argc, char **argv) { char *name, *end; int itf, min, init, max; int s; pool_levels pl; int btype; struct atmif_sioc sioc; name = argv[0]; if (argc != 6 && argc != 3) usage(name); itf = strtol(argv[1], &end, 0); if (end == argv[1] || itf < 0) usage(name); if (argc == 6) { min = strtol(argv[3], &end, 0); if (end == argv[3] || min <= 0) usage(name); init = strtol(argv[4], &end, 0); if (end == argv[4] || init <= 0) usage(name); max = strtol(argv[5], &end, 0); if (end == argv[5] || max <= 0) usage(name); if (min >= init || init >= max) usage(name); switch(*argv[2]) { case 's': pl.buftype = NS_BUFTYPE_SMALL; break; case 'l': pl.buftype = NS_BUFTYPE_LARGE; break; case 'h': pl.buftype = NS_BUFTYPE_HUGE;... [truncated message content] |
Update of /cvsroot/linux-atm/linux-atm/src/sigd In directory usw-pr-cvs1:/tmp/cvs-serv10656/sigd Added Files: Tag: V2_4_0 io.c io.h sap.c sap.h uni.c README atmsigd.8 atmsigd.c timeout.c timeout.h policy.c policy.h mkmess.pl Makefile.am trace.c trace.h atmsigd.conf kernel.c cfg_l.l cfg_y.y atmsigd.conf.4 proto.c proto.h Log Message: --- NEW FILE: io.c --- /* io.c - I/O operations */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/atmsvc.h> #include "atmd.h" #include "uni.h" #include "pdu.h" #include "proto.h" #include "io.h" #include "trace.h" #define COMPONENT "IO" struct timeval now; int stop = 0; static int kernel = -1; static int need_connect = 0; /* non-zero if connection to kernel isn't bi-directional yet */ /* ----- kernel interface -------------------------------------------------- */ static int open_kernel(void) { int s; if ((s = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return -1; } if (ioctl(s,ATMSIGD_CTRL,0) < 0) { perror("ioctl ATMSIGD_CTRL"); return -1; } return s; } void open_unix(const char *path) { kernel = un_create(path,0600); if (kernel < 0) diag(COMPONENT,DIAG_FATAL,"un_create %s: %s",path,strerror(errno)); need_connect = 1; } static void recv_kernel(void) { static unsigned char buffer[sizeof(struct atmsvc_msg)+1]; int size; if (!need_connect) size = read(kernel,buffer,sizeof(buffer)); else { size = un_recv_connect(kernel,buffer,sizeof(buffer)); need_connect = 0; } if (size < 0) { diag(COMPONENT,DIAG_ERROR,"read kernel: %s",strerror(errno)); return; } if (size != sizeof(struct atmsvc_msg)) diag(COMPONENT,DIAG_FATAL,"kernel message size %d != %d",size, sizeof(struct atmsvc_msg)); trace_kernel("FROM KERNEL",(struct atmsvc_msg *) buffer); from_kernel((struct atmsvc_msg *) buffer,size); } void to_kernel(struct atmsvc_msg *msg) { int wrote; diag("KERNEL",DIAG_DEBUG,"TO KERNEL: %s (%d) for %s/%s", as_name[msg->type],msg->reply,kptr_print(&msg->vcc), kptr_print(&msg->listen_vcc)); /* should be "IO" ... */ trace_kernel("TO KERNEL",msg); wrote = write(kernel,msg,sizeof(*msg)); if (wrote == sizeof(*msg)) return; if (wrote < 0) { perror("kernel write"); return; } diag(COMPONENT,DIAG_ERROR,"bad kernel write: wanted %d, wrote %d", sizeof(*msg),wrote); } static void close_kernel(void) { (void) close(kernel); /* may get major complaints from the kernel ... */ } /* ----- signaling interface ----------------------------------------------- */ static int open_signaling(SIG_ENTITY *sig) { struct atm_qos qos; int s; if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return -1; } memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.max_sdu = qos.txtp.max_sdu = MAX_Q_MSG; if (sig->sig_qos) { if (text2qos(sig->sig_qos,&qos,T2Q_DEFAULTS) < 0) { fprintf(stderr,"invalid qos: %s\n",sig->sig_qos); return -1; } } else { if (sig->sig_pcr == -1) qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_UBR; else { qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_CBR; qos.rxtp.min_pcr = qos.txtp.min_pcr = sig->sig_pcr; } } if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return -1; } sig->signaling_pvc.sap_family = AF_ATMPVC; if (bind(s,(struct sockaddr *) &sig->signaling_pvc, sizeof(sig->signaling_pvc)) < 0) { perror("bind"); return -1; } return s; } static void recv_signaling(SIG_ENTITY *sig) { static unsigned char buffer[MAX_Q_MSG]; int size; size = read(sig->signaling,buffer,MAX_Q_MSG); if (size < 1) { perror("read signaling"); return; } diag(COMPONENT,DIAG_DEBUG,"FROM NET (%d.%d.%d): %s PDU (%d bytes)", S_PVC(sig),pdu_name[size > 3 && !(size & 3) ? buffer[size-4] & 0xf : 0], size); if (debug) diag_dump(COMPONENT,DIAG_DEBUG,NULL,buffer,size); from_net(sig,buffer,size); } void to_net(SIG_ENTITY *sig,void *msg,int size) { int wrote; diag(COMPONENT,DIAG_DEBUG,"TO NET (%d.%d.%d): %s PDU (%d bytes)",S_PVC(sig), pdu_name[size > 3 && !(size & 3) ? ((unsigned char *) msg)[size-4] & 0xf : 0],size); if (debug) diag_dump(COMPONENT,DIAG_DEBUG,NULL,msg,size); wrote = write(sig->signaling,msg,size); if (wrote == size) return; if (wrote < 0) { perror("signaling write"); return; } diag(COMPONENT,DIAG_WARN,"bad signaling write: wanted %d, wrote %d",size, wrote); } static void close_signaling(SIG_ENTITY *sig) { (void) close(sig->signaling); } /* ----- addresses --------------------------------------------------------- */ int get_addr(int itf,LOCAL_ADDR *local_addr) { struct atmif_sioc req; struct sockaddr_atmsvc buffer[MAX_LOCAL_ADDRS]; LOCAL_ADDR *from,*to; int addrs,i; for (from = to = local_addr; from->state != ls_unused; from++) if (from->state != ls_removed) { from->state = ls_removed; *to++ = *from; } to->state = ls_unused; req.number = itf; req.arg = buffer; req.length = sizeof(buffer); if (ioctl(entities->signaling,ATM_GETADDR,&req) < 0) diag(COMPONENT,DIAG_FATAL,"ioctl ATM_GETADDR yields \"%s\"", strerror(errno)); addrs = req.length/sizeof(struct sockaddr_atmsvc); for (i = 0; i < addrs; i++) { for (from = local_addr; from->state != ls_unused; from++) if (atm_equal((struct sockaddr *) (buffer+i), (struct sockaddr *) &from->addr,0,0)) break; if (from->state != ls_unused) from->state = ls_same; else if (to == local_addr+MAX_LOCAL_ADDRS-1) diag(COMPONENT,DIAG_WARN,"local address table overflow"); else { to->state = ls_added; to->addr = buffer[i]; to++; to->state = ls_unused; } } return addrs; } /* ----- common part ------------------------------------------------------- */ int open_all(void) { SIG_ENTITY *sig,*purge; if (kernel == -1) kernel = open_kernel(); if (kernel < 0) return -1; for (sig = entities; sig; sig = sig->next) { sig->signaling = open_signaling(sig); if (sig->signaling < 0) { for (purge = entities; purge != sig; purge = purge->next) close_signaling(purge); close_kernel(); return -1; } } return 0; } void close_all(void) { SIG_ENTITY *sig; close_kernel(); for (sig = entities;sig; sig = sig->next) close_signaling(sig); } void init_current_time(void) { gettimeofday(&now,NULL); } void poll_loop(void) { SIG_ENTITY *sig; fd_set perm,set; int fds,ret; FD_ZERO(&perm); FD_SET(kernel,&perm); fds = kernel+1; for (sig = entities; sig; sig = sig->next) { FD_SET(sig->signaling,&perm); if (fds <= sig->signaling) fds = sig->signaling+1; } gettimeofday(&now,NULL); while (!stop) { set = perm; poll_signals(); /* * Here we have a small race condition: if a signal is delivered after * poll_signals tests for it but before select sleeps, we miss that * signal. If it is sent again, we're of course likely to get it. This * isn't worth fixing, because those signals are only used for * debugging anyway. */ ret = select(fds,&set,NULL,NULL,next_timer()); if (ret < 0) { if (errno != EINTR) perror("select"); } else { diag(COMPONENT,DIAG_DEBUG,"----------"); gettimeofday(&now,NULL); if (FD_ISSET(kernel,&set)) recv_kernel(); for (sig = entities; sig; sig = sig->next) if (FD_ISSET(sig->signaling,&set)) recv_signaling(sig); expire_timers(); /* expire timers after handling messges to make sure we don't time out unnecessarily because of scheduling delays */ } } } /* * The allocation strategy could be improved as follows: we should try * vci = prev_vci++ first and only resort to ATM_VCI_ANY if that fails several * times (and we should actually skip over those which are in use by SVCs. This * way we avoid using VCIs that just became available. Doing it "right" seems * to be getting complex, though. */ int get_pvc(int itf,int *vci) { struct sockaddr_atmpvc addr; struct atm_qos qos; int s,error; if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"get_pvc: %s",strerror(errno)); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = qos.txtp.max_sdu = 1; /* smallest possible SDU size */ if (setsockopt(s,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 = ATM_VCI_ANY; error = 0; if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) error = errno; else { int size; size = sizeof(addr); if (getsockname(s,(struct sockaddr *) &addr,&size) < 0) diag(COMPONENT,DIAG_FATAL,"get_pvc: %s",strerror(errno)); *vci = addr.sap_addr.vci; return s; } (void) close(s); return -error; } int get_link_rate(int itf) { struct atmif_sioc req; int rate; req.number = itf; req.arg = &rate; req.length = sizeof(rate); if (ioctl(entities->signaling,ATM_GETLINKRATE,&req) < 0) diag(COMPONENT,DIAG_FATAL,"ioctl ATM_GETLINKRATE yields \"%s\"", strerror(errno)); return rate; } --- NEW FILE: io.h --- /* io.h - I/O operations */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef IO_H #define IO_H #include <stdint.h> #include <atm.h> #include <linux/atmsvc.h> #include "proto.h" int open_all(void); void open_unix(const char *name); void init_current_time(void); void poll_loop(void); void close_all(void); void to_kernel(struct atmsvc_msg *msg); void to_net(SIG_ENTITY *sig,void *msg,int size); int get_addr(int itf,LOCAL_ADDR *local_addr); int get_pvc(int itf,int *vci); int get_link_rate(int itf); #endif --- NEW FILE: sap.c --- /* sap.c - SAP manipulations */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <string.h> #include <errno.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/atmsvc.h> #include "atmd.h" #include "uni.h" #include "qlib.h" #include <q.out.h> #include "common.h" #include "proto.h" #include "sap.h" #define COMPONENT "SAP" static int class_compat(const struct atm_trafprm *tx, const struct atm_trafprm *rx) { if (tx->traffic_class == ATM_NONE || tx->traffic_class == ATM_ANYCLASS) return 1; if (rx->traffic_class == ATM_UBR || rx->traffic_class == ATM_ANYCLASS) return 1; /* don't apply CAC to PCR */ if (tx->traffic_class != rx->traffic_class) return 0; /* ignore special cases like CBR to VBR for now */ switch (tx->traffic_class) { case ATM_CBR: if (!rx->max_pcr || rx->max_pcr == ATM_MAX_PCR) return 1; return tx->min_pcr <= rx->max_pcr; /* Actually, we shouldn't look at min_pcr, because there's no bandwidth negotiation anyway. */ default: diag(COMPONENT,DIAG_ERROR,"unsupported traffic class %d\n", tx->traffic_class); return 0; } } int sap_compat(const struct sockaddr_atmsvc *old_addr, const struct sockaddr_atmsvc *new_addr,struct sockaddr_atmsvc *res_addr, const struct atm_sap *old_sap,const struct atm_sap *new_sap, struct atm_sap *res_sap,const struct atm_qos *old_qos, const struct atm_qos *new_qos,struct atm_qos *res_qos) { if (atmsvc_addr_in_use(*old_addr) && !atm_equal((struct sockaddr *) old_addr,(struct sockaddr *) new_addr,0,0)) return 0; if (res_qos) *res_qos = *new_qos; if (old_qos->txtp.max_sdu && new_qos->rxtp.max_sdu && old_qos->txtp.max_sdu > new_qos->rxtp.max_sdu) return 0; if (new_qos->txtp.max_sdu && old_qos->rxtp.max_sdu && new_qos->txtp.max_sdu > old_qos->rxtp.max_sdu) return 0; if (!class_compat(&old_qos->txtp,&new_qos->rxtp) || !class_compat(&new_qos->txtp,&old_qos->rxtp)) return 0; if (!sap_equal(old_sap,new_sap, SXE_COMPATIBLE | SXE_NEGOTIATION | (res_sap ? SXE_RESULT : 0),res_sap)) return 0; return 1; } static int encode_blli(Q_DSC *dsc,const struct atm_blli *blli) { if (blli->l2_proto != ATM_L2_NONE) { q_assign(dsc,QF_uil2_proto,blli->l2_proto); switch (blli->l2_proto) { case ATM_L2_X25_LL: case ATM_L2_X25_ML: case ATM_L2_HDLC_ARM: case ATM_L2_HDLC_NRM: case ATM_L2_HDLC_ABM: case ATM_L2_Q922: case ATM_L2_ISO7776: if (blli->l2.itu.mode != ATM_IMD_NONE) q_assign(dsc,QF_l2_mode,blli->l2.itu.mode); if (blli->l2.itu.window) q_assign(dsc,QF_window_size,blli->l2.itu.window); break; case ATM_L2_USER: q_assign(dsc,QF_user_l2,blli->l2.user); break; default: break; } } if (blli->l3_proto != ATM_L3_NONE) { q_assign(dsc,QF_uil3_proto,blli->l3_proto); switch (blli->l3_proto) { case ATM_L3_X25: case ATM_L3_ISO8208: case ATM_L3_X223: if (blli->l3.itu.mode != ATM_IMD_NONE) q_assign(dsc,QF_l3_mode,blli->l3.itu.mode); if (blli->l3.itu.def_size) q_assign(dsc,QF_def_pck_size,blli->l3.itu.def_size); if (blli->l3.itu.window) q_assign(dsc,QF_pck_win_size,blli->l3.itu.window); break; case ATM_L3_TR9577: q_assign(dsc,QF_ipi_high,blli->l3.tr9577.ipi >> 1); q_assign(dsc,QF_ipi_low,blli->l3.tr9577.ipi & 1); if (blli->l3.tr9577.ipi == NLPID_IEEE802_1_SNAP) { q_write(dsc,QF_oui,blli->l3.tr9577.snap,3); q_write(dsc,QF_pid,blli->l3.tr9577.snap+3,2); } break; case ATM_L3_USER: q_assign(dsc,QF_user_l3,blli->l3.user); break; default: diag(COMPONENT,DIAG_ERROR,"bad l3_proto (%d)", blli->l3_proto); return -EINVAL; } } return 0; } int sap_encode(Q_DSC *dsc,const struct sockaddr_atmsvc *addr, const struct atm_sap *sap,const struct atm_qos *qos,int uni,int max_rate) { int error,pcr; if (*addr->sas_addr.pub) q_write(dsc,QF_cdpn_e164,(void *) addr->sas_addr.pub, strlen(addr->sas_addr.pub)); else if (*addr->sas_addr.prv) q_write(dsc,QF_cdpn_esa,(void *) addr->sas_addr.prv,ATM_ESA_LEN); else return -EDESTADDRREQ; if (qos->txtp.traffic_class == ATM_UBR || qos->rxtp.traffic_class == ATM_UBR) { q_assign(dsc,QF_best_effort,0); #if defined(UNI30) || defined(ALLOW_UNI30) || defined(DYNAMIC_UNI) if (uni & S_UNI30) q_assign(dsc,QF_trans_cap,ATM_TC_VBR_NRT_R00); /* force presence - UNI 3.0 wants this */ #endif } if (qos->txtp.traffic_class == ATM_CBR || qos->rxtp.traffic_class == ATM_CBR) q_assign(dsc,QF_trans_cap,ATM_TC_CBR); switch (qos->txtp.traffic_class) { case ATM_NONE: q_assign(dsc,QF_fw_pcr_01,0); break; case ATM_UBR: /* fall through */ case ATM_CBR: /* here's a bit of policy: send the highest value we have */ pcr = SELECT_TOP_PCR(qos->txtp); diag(COMPONENT,DIAG_DEBUG,"fwd %d (%d..%d)",pcr, qos->txtp.min_pcr,qos->txtp.max_pcr); if (pcr == ATM_MAX_PCR) pcr = max_rate; q_assign(dsc,QF_fw_pcr_01,pcr); break; default: diag(COMPONENT,DIAG_ERROR,"bad TX class (%d)", qos->txtp.traffic_class); return -EINVAL; } switch (qos->rxtp.traffic_class) { case ATM_NONE: q_assign(dsc,QF_bw_pcr_01,0); break; case ATM_UBR: /* fall through */ case ATM_CBR: pcr = SELECT_TOP_PCR(qos->rxtp); diag(COMPONENT,DIAG_DEBUG,"bwd %d (%d..%d)",pcr, qos->rxtp.min_pcr,qos->rxtp.max_pcr); if (pcr == ATM_MAX_PCR) pcr = max_rate; q_assign(dsc,QF_bw_pcr_01,pcr); break; default: diag(COMPONENT,DIAG_ERROR,"bad RX class (%d)", qos->rxtp.traffic_class); return -EINVAL; } if (qos->txtp.max_sdu || qos->rxtp.max_sdu) { q_assign(dsc,QF_fw_max_sdu,qos->txtp.max_sdu); q_assign(dsc,QF_bw_max_sdu,qos->rxtp.max_sdu); } /* @@@ bearer class ? */ /* @@@ QOS class ? */ if (sap->bhli.hl_type != ATM_HL_NONE) { q_assign(dsc,QF_hli_type,sap->bhli.hl_type-1); switch (sap->bhli.hl_type) { case ATM_HL_ISO: q_write(dsc,QF_iso_hli,sap->bhli.hl_info,sap->bhli.hl_length); break; case ATM_HL_USER: q_write(dsc,QF_user_hli,sap->bhli.hl_info,sap->bhli.hl_length); break; #if defined(UNI30) || defined(DYNAMIC_UNI) case ATM_HL_HLP: if (!(uni & S_UNI30)) return -EINVAL; q_write(dsc,QF_hlp,sap->bhli.hl_info,4); break; #endif case ATM_HL_VENDOR: q_write(dsc,QF_hli_oui,sap->bhli.hl_info,3); q_write(dsc,QF_app_id, sap->bhli.hl_info+3,4); break; default: diag(COMPONENT,DIAG_ERROR,"bad hl_type (%d)", sap->bhli.hl_type); return -EINVAL; } } if (!blli_in_use(sap->blli[0])) return 0; q_instance(dsc,QG_blli1); error = encode_blli(dsc,sap->blli); if (error) return 0; if (!blli_in_use(sap->blli[1])) return 0; q_instance(dsc,QG_blli2); error = encode_blli(dsc,sap->blli+1); if (error) return 0; if (!blli_in_use(sap->blli[2])) return 1; q_instance(dsc,QG_blli3); return encode_blli(dsc,sap->blli+2); } static void decode_blli(Q_DSC *dsc,struct atm_blli *blli) { #define GET(var,field) \ ({ if (q_present(dsc,field)) blli->var = q_fetch(dsc,field); }) if (q_present(dsc,QF_uil2_proto)) { blli->l2_proto = q_fetch(dsc,QF_uil2_proto); GET(l2.itu.mode,QF_l2_mode); GET(l2.itu.window,QF_window_size); GET(l2.user,QF_user_l2); } if (q_present(dsc,QF_uil3_proto)) { blli->l3_proto = q_fetch(dsc,QF_uil3_proto); GET(l3.itu.mode,QF_l3_mode); GET(l3.itu.def_size,QF_def_pck_size); GET(l3.itu.window,QF_pck_win_size); GET(l3.user,QF_user_l3); if (q_present(dsc,QF_ipi_high)) { blli->l3.tr9577.ipi = q_fetch(dsc,QF_ipi_high) << 1; if (blli->l3.tr9577.ipi != NLPID_IEEE802_1_SNAP) blli->l3.tr9577.ipi |= q_fetch(dsc,QF_ipi_low); else if (!q_present(dsc,QF_oui)) blli->l3.tr9577.ipi |= 1; else { q_read(dsc,QF_oui,blli->l3.tr9577.snap,3); q_read(dsc,QF_pid,blli->l3.tr9577.snap+3,2); } } } #undef GET } unsigned int sap_decode(Q_DSC *dsc,struct sockaddr_atmsvc *addr, struct atm_sap *sap,struct atm_qos *qos,int uni) { memset(addr,0,sizeof(*addr)); memset(sap,0,sizeof(*sap)); memset(qos,0,sizeof(*qos)); addr->sas_family = AF_ATMSVC; if (q_present(dsc,QF_cdpn_e164)) (void) q_read(dsc,QF_cdpn_e164,(void *) &addr->sas_addr.pub, ATM_E164_LEN); else if (q_present(dsc,QF_cdpn_esa)) (void) q_read(dsc,QF_cdpn_esa,(void *) &addr->sas_addr.prv, ATM_ESA_LEN); qos->aal = ATM_AAL5; /* default and only choice */ if (q_present(dsc,QF_aal_type)) if (q_fetch(dsc,QF_aal_type) != 5) { diag(COMPONENT,DIAG_ERROR,"AAL type %d requested", q_fetch(dsc,QF_aal_type)); #ifdef DYNAMIC_UNI return IE_PROBLEM( uni & S_UNI30 ? ATM_CV_AAL_UNSUPP_OLD : ATM_CV_AAL_UNSUPP_NEW,0); #else #ifdef UNI30 return IE_PROBLEM(ATM_CV_AAL_UNSUPP_OLD,0); #else return IE_PROBLEM(ATM_CV_AAL_UNSUPP_NEW,0); #endif /* UNI30 */ #endif /* DYNAMIC_UNI */ } if (q_present(dsc,QF_best_effort)) { qos->txtp.traffic_class = qos->rxtp.traffic_class = ATM_UBR; diag(COMPONENT,DIAG_DEBUG,"UBR"); } else { qos->txtp.traffic_class = qos->rxtp.traffic_class = ATM_CBR; diag(COMPONENT,DIAG_DEBUG,"CBR"); } qos->txtp.max_pcr = qos->rxtp.max_pcr = 0; /* unbalanced decoding - always sets upper bound */ if (q_present(dsc,QF_fw_pcr_01)) { qos->rxtp.min_pcr = 0; qos->rxtp.max_pcr = q_fetch(dsc,QF_fw_pcr_01); } if (q_present(dsc,QF_bw_pcr_01)) { qos->txtp.min_pcr = 0; qos->txtp.max_pcr = q_fetch(dsc,QF_bw_pcr_01); } if (!qos->txtp.max_pcr) qos->txtp.traffic_class = ATM_NONE; if (!qos->rxtp.max_pcr) qos->rxtp.traffic_class = ATM_NONE; diag(COMPONENT,DIAG_DEBUG,"fwd %d..%d bwd %d..%d", qos->rxtp.min_pcr,qos->rxtp.max_pcr,qos->txtp.min_pcr, qos->txtp.max_pcr); /* SHOULD ... fail call if anything is missing ... @@@ */ if (q_present(dsc,QF_bw_max_sdu)) qos->txtp.max_sdu = q_fetch(dsc,QF_bw_max_sdu); if (q_present(dsc,QF_fw_max_sdu)) qos->rxtp.max_sdu = q_fetch(dsc,QF_fw_max_sdu); if (q_present(dsc,QG_bhli)) { sap->bhli.hl_type = q_fetch(dsc,QF_hli_type)+1; switch (sap->bhli.hl_type) { case ATM_HL_ISO: sap->bhli.hl_length = q_length(dsc,QF_iso_hli); q_read(dsc,QF_iso_hli,sap->bhli.hl_info,sap->bhli.hl_length); break; case ATM_HL_USER: sap->bhli.hl_length = q_length(dsc,QF_user_hli); q_read(dsc,QF_user_hli,sap->bhli.hl_info,sap->bhli.hl_length); break; case ATM_HL_VENDOR: sap->bhli.hl_length = 7; q_read(dsc,QF_hli_oui,sap->bhli.hl_info,3); q_read(dsc,QF_app_id,sap->bhli.hl_info+3,4); break; #if defined(UNI30) || defined(DYNAMIC_UNI) case ATM_HL_HLP: if (!(uni & S_UNI30)) { sap->bhli.hl_length = 4; q_read(dsc,QF_hlp,sap->bhli.hl_info,4); break; } /* fall through */ #endif default: diag(COMPONENT,DIAG_ERROR,"unrecognized hl_type %d", sap->bhli.hl_type); return IE_PROBLEM(ATM_CV_INVALID_IE,ATM_IE_BHLI); } } if (!q_present(dsc,QG_blli1)) return 0; q_instance(dsc,QG_blli1); decode_blli(dsc,sap->blli); if (!q_present(dsc,QG_blli2)) return 0; q_instance(dsc,QG_blli2); decode_blli(dsc,sap->blli+1); if (!q_present(dsc,QG_blli3)) return 0; q_instance(dsc,QG_blli3); decode_blli(dsc,sap->blli+2); return 0; } --- NEW FILE: sap.h --- /* sap.h - SAP manipulations */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef SAP_H #define SAP_H #include <linux/atm.h> #include <linux/atmsvc.h> #include "atmsap.h" #define IE_PROBLEM(cause,ie) (((cause) << 8) | (ie)) #define IE_PB_CAUSE(problem) ((problem) >> 8) #define IE_PB_IE(problem) ((problem) & 0xff) int sap_compat(const struct sockaddr_atmsvc *old_addr, const struct sockaddr_atmsvc *new_addr,struct sockaddr_atmsvc *res_addr, const struct atm_sap *old_sap,const struct atm_sap *new_sap, struct atm_sap *res_sap,const struct atm_qos *old_qos, const struct atm_qos *new_qos,struct atm_qos *res_qos); int sap_encode(Q_DSC *dsc,const struct sockaddr_atmsvc *addr, const struct atm_sap *sap,const struct atm_qos *qos,int uni,int max_rate); /* * sap_encode returns zero on success, -errno on error. */ unsigned int sap_decode(Q_DSC *dsc,struct sockaddr_atmsvc *addr, struct atm_sap *sap,struct atm_qos *qos,int uni); /* * sap_decode returns zero on success, the problem report (encoded with * IE_PROBLEM) on error. */ #endif --- NEW FILE: uni.c --- /* uni.c - Processing of incoming UNI signaling messages */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <assert.h> #include <atm.h> #include <linux/atmdev.h> #include "atmd.h" #include "uni.h" #include "qlib.h" #include <q.out.h> #include "proto.h" #include "sap.h" #include "io.h" #include "policy.h" #include "timeout.h" #include "trace.h" #define COMPONENT "UNI" extern const char *cause_text[]; /* from mess.c */ static Q_DSC in_dsc; static TIMER *t309 = NULL; static unsigned short cvt_ep_ref(SIG_ENTITY *sig,unsigned short ep_ref) { return sig->uni == S_UNI30 ? ep_ref & 0x7fff : ep_ref ^ 0x8000; } int send_call_proceeding(SOCKET *sock) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_CALL_PROC); q_assign(&dsc,QF_call_ref,sock->call_ref); if (sock->sig->mode == sm_net) { int vpci,vci; sock->pvc.sap_family = AF_ATMPVC; vpci = sock->sig->signaling_pvc.sap_addr.itf; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; vci = get_vci(sock->pvc.sap_addr.itf); if (vci < 0) { (void) q_close(&dsc); return vci; } sock->pvc.sap_addr.vci = vci; } if (sock->sig->mode != sm_user) { q_assign(&dsc,QF_vpi,sock->pvc.sap_addr.vpi); q_assign(&dsc,QF_vci,sock->pvc.sap_addr.vci); } if (sock->ep_ref >= 0) q_assign(&dsc,QF_ep_ref,sock->ep_ref); if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size); return 0; } static void setup_call(SIG_ENTITY *sig,unsigned long call_ref) { SOCKET *sock,*this,**walk; struct sockaddr_atmsvc in_addr; struct atm_sap in_sap; struct atm_qos in_qos; unsigned int problem; int i; problem = sap_decode(&in_dsc,&in_addr,&in_sap,&in_qos,sig->uni); if (problem) { send_release_complete(sig,call_ref,IE_PB_CAUSE(problem), IE_PB_IE(problem)); return; } if (!atmsvc_addr_in_use(in_addr)) { send_release_complete(sig,call_ref,ATM_CV_UNALLOC); return; } if (!allow(&in_addr,ACL_IN)) { send_release_complete(sig,call_ref,ATM_CV_REJ_CLIR); return; } this = new_sock(kptr_null); this->sig = sig; sock = lookup_sap(&in_addr,&in_sap,&in_qos,&this->local,&this->sap, &this->qos,0); if (!sock) { free_sock(this); send_release_complete(sig,call_ref,ATM_CV_INCOMP_DEST); return; } this->state = sig->mode == sm_net ? ss_proceeding : ss_indicated; this->call_state = cs_in_proc; this->call_ref = call_ref; if (q_present(&in_dsc,QF_ep_ref)) this->ep_ref = cvt_ep_ref(sig,q_fetch(&in_dsc,QF_ep_ref)); #ifdef CISCO else #endif if (sig->mode == sm_net) { int error; error = send_call_proceeding(this); if (error) { free_sock(this); send_release_complete(sig,call_ref,ATM_CV_NO_CI); return; } } /* if (sock->local) *this->local->sas_addr = sock->local->sas_addr; ??? */ diag(COMPONENT,DIAG_DEBUG,"AAL type %ld",q_fetch(&in_dsc,QF_aal_type)); if (sig->mode == sm_user) { /* already set by send_call_proceeding */ int vpci; vpci = q_fetch(&in_dsc,QF_vpi); this->pvc.sap_family = AF_ATMPVC; this->pvc.sap_addr.itf = get_itf(sig,&vpci); this->pvc.sap_addr.vpi = vpci; this->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); } diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d",this->pvc.sap_addr.itf, this->pvc.sap_addr.vpi,this->pvc.sap_addr.vci); if (q_present(&in_dsc,QF_cgpn)) { /* should handle E.164 too */ char buffer[MAX_ATM_ADDR_LEN+1]; int plan; plan = q_fetch(&in_dsc,QF_cgpn_plan); switch (plan) { case ATM_NP_AEA: i = q_read(&in_dsc,QF_cgpn,(void *) this->remote.sas_addr.prv, ATM_ESA_LEN); break; case ATM_NP_E164: i = q_read(&in_dsc,QF_cgpn,(void *) this->remote.sas_addr.pub, ATM_E164_LEN); break; default: diag(COMPONENT,DIAG_WARN,"Ignoring cgpn with unrecognized " "numbering plan 0x%x\n",plan); i = 0; } if (i) { this->remote.sas_family = AF_ATMSVC; if (atm2text(buffer,MAX_ATM_ADDR_LEN+1, (struct sockaddr *) &this->remote,pretty) < 0) strcpy(buffer,"<invalid address>"); diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer); } } send_kernel(kptr_null,sock->id,as_indicate,0,&this->pvc,&this->remote, &in_addr,&this->sap,&this->qos); for (walk = &sock->listen; *walk; walk = &(*walk)->listen); *walk = this; diag(COMPONENT,DIAG_DEBUG,"SE vpi.vci=%d.%d",this->pvc.sap_addr.vpi, this->pvc.sap_addr.vci); } static void send_status(SIG_ENTITY *sig,SOCKET *sock,unsigned long call_ref, unsigned char cause,...) { va_list ap; Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_STATUS); if (sock) { q_assign(&dsc,QF_call_ref,sock->call_ref); q_assign(&dsc,QF_call_state,(int) sock->call_state); if (sock->ep_ref >= 0) { q_assign(&dsc,QF_ep_ref,sock->ep_ref); q_assign(&dsc,QF_ep_state,eps_map[sock->call_state]); } } else { q_assign(&dsc,QF_call_ref,call_ref); q_assign(&dsc,QF_call_state,0); /* U0 - Null / REST 0 - Null */ } q_assign(&dsc,QF_cause,cause); va_start(ap,cause); switch (cause) { case ATM_CV_UNKNOWN_MSG_TYPE: case ATM_CV_INCOMP_MSG: q_assign(&dsc,QF_bad_msg_type,va_arg(ap,unsigned int)); break; case ATM_CV_MAND_IE_MISSING: case ATM_CV_INVALID_IE: { unsigned char ie; ie = va_arg(ap,unsigned int); q_write(&dsc,QF_ie_id6,&ie,1); break; } default: ; } va_end(ap); if ((size = q_close(&dsc)) >= 0) to_signaling(sig,q_buffer,size); } static void send_status_enq(SOCKET *sock) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_STATUS_ENQ); q_assign(&dsc,QF_call_ref,sock->call_ref); if (sock->ep_ref >= 0) q_assign(&dsc,QF_ep_ref,sock->ep_ref); if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size); /* @@@ should start T322 */ } static void send_connect_ack(SOCKET *sock) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_CONN_ACK); q_assign(&dsc,QF_call_ref,sock->call_ref); if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size); } static void send_restart_ack(SIG_ENTITY *sig,unsigned long call_ref,int vpi, int vci) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_REST_ACK); q_assign(&dsc,QF_call_ref,call_ref); if (!vpi && !vci) q_assign(&dsc,QF_rst_class,ATM_RST_ALL_VC); else { q_assign(&dsc,QF_rst_class,ATM_RST_IND_VC); q_assign(&dsc,QF_vpi,vpi); q_assign(&dsc,QF_vci,vci); } if ((size = q_close(&dsc)) >= 0) to_signaling(sig,q_buffer,size); } static void send_drop_party_ack(SIG_ENTITY *sig,unsigned long call_ref, unsigned short ep_ref,unsigned char cause) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_DROP_PARTY_ACK); q_assign(&dsc,QF_call_ref,call_ref); q_assign(&dsc,QF_ep_ref,ep_ref); q_assign(&dsc,QF_cause,cause); if ((size = q_close(&dsc)) >= 0) to_signaling(sig,q_buffer,size); } #if defined(Q2963_1) || defined(DYNAMIC_UNI) static void send_conn_avail(SOCKET *sock) { Q_DSC dsc; int size; q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,ATM_MSG_CONN_AVAIL); q_assign(&dsc,QF_call_ref,sock->call_ref); if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size); } #endif static void uni_call(SOCKET *sock,unsigned char mid) { char buffer[MAX_ATM_ADDR_LEN+1]; int error; switch (mid) { case ATM_MSG_STATUS: /* 5.5.6.12 */ { CALL_STATE state; /* * NOTE: T322 isn't implemented yet, but when it is, make sure * to only stop it on STATUS iff the cause is * ATM_CV_RESP_STAT_ENQ. Supplementary services break if * you stop on any STATUS. */ state = q_fetch(&in_dsc,QF_call_state); if (state == cs_null) break; /* clear call */ if (sock->call_state == cs_rel_req || sock->call_state == cs_rel_ind) return; if (state != sock->call_state) diag(COMPONENT,DIAG_WARN,"STATUS %s received in state %s", cs_name[state],cs_name[sock->call_state]); } return; default: ; } switch (mid) { case ATM_MSG_CALL_PROC: /* CONNECTING, WAIT_REL, REL_REQ */ if (sock->state == ss_wait_rel || sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG, ATM_MSG_CALL_PROC); return; } if (sock->state != ss_connecting) break; /* check for 2nd CALL_PROC @@@ */ STOP_TIMER(sock); if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } START_TIMER(sock,T310); sock->call_state = cs_out_proc; return; case ATM_MSG_CONNECT: /* CONNECTING, REL_REQ */ if (sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,ATM_MSG_CONNECT); return; } if (sock->state != ss_connecting) break; STOP_TIMER(sock); if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d/%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } error = 0; if (!sock->pvc.sap_addr.vpi && !sock->pvc.sap_addr.vci) error = -EPROTO; /* more problems */ if (error) { set_error(sock,error); send_release(sock,0); /* @@@ cause follows reason ??? */ START_TIMER(sock,T308_1); new_state(sock,ss_rel_req); return; } send_connect_ack(sock); /* @@@ fill in sock->remote */ /* @@@ fill in traffic parameters */ send_kernel(sock->id,kptr_null,as_okay,0,&sock->pvc,NULL, &sock->local,&sock->sap,&sock->qos); new_state(sock,ss_connected); #if defined(Q2963_1) || defined(DYNAMIC_UNI) sock->owner = 1; #endif if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &sock->remote,0) < 0) strcpy(buffer,"<invalid>"); diag(COMPONENT,DIAG_INFO,"Active open succeeded (CR 0x%06X, " "ID %s, to %s)",sock->call_ref,kptr_print(&sock->id),buffer); return; case ATM_MSG_CONN_ACK: /* ACCEPTING, WAIT_REL, REL_REQ */ diag(COMPONENT,DIAG_DEBUG,"CA vpi.vci=%d.%d", sock->pvc.sap_addr.vpi,sock->pvc.sap_addr.vci); if (sock->state == ss_wait_rel || sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG, ATM_MSG_CONN_ACK); return; } if (sock->state != ss_accepting) break; STOP_TIMER(sock); send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,&sock->local, &sock->sap,NULL); new_state(sock,ss_connected); #if defined(Q2963_1) || defined(DYNAMIC_UNI) sock->owner = 0; #endif if (atm2text(buffer,MAX_ATM_ADDR_LEN+1, (struct sockaddr *) &sock->remote,0) < 0) strcpy(buffer,"<invalid>"); diag(COMPONENT,DIAG_INFO,"Passive open succeeded (CR 0x%06X, " "ID %s, from %s)",sock->call_ref,kptr_print(&sock->id),buffer); return; case ATM_MSG_RELEASE: /* all states */ { unsigned char cause; cause = q_fetch(&in_dsc,QF_cause); diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause,cause > 127 ? "invalid cause" : cause_text[cause]); } switch (sock->state) { case ss_connecting: set_error(sock,-ECONNREFUSED); /* fall through */ case ss_accepting: set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */ send_release_complete(sock->sig,sock->call_ref,0); SEND_ERROR(sock->id,sock->error); STOP_TIMER(sock); free_sock(sock); return; case ss_rel_req: send_close(sock); /* fall through */ case ss_wait_rel: STOP_TIMER(sock); free_sock(sock); return; #if defined(Q2963_1) || defined(DYNAMIC_UNI) case ss_mod_req: #endif STOP_TIMER(sock); /* fall through */ #if defined(Q2963_1) || defined(DYNAMIC_UNI) case ss_mod_lcl: case ss_mod_rcv: case ss_mod_fin_ok: case ss_mod_fin_fail: case ss_mod_fin_ack: #endif case ss_connected: diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)", sock->call_ref); #if defined(Q2963_1) || defined(DYNAMIC_UNI) if (timer_handler(sock->conn_timer) == on_T361) STOP_TIMER(sock); #endif send_close(sock); new_state(sock,ss_rel_ind); return; case ss_indicated: /* fall through */ case ss_proceeding: send_release_complete(sock->sig,sock->call_ref,0); new_state(sock,ss_zombie); /* fall through */ case ss_rel_ind: return; default: send_release_complete(sock->sig,sock->call_ref,0); /* @@@ should be ATM_CV_INCOMP_MSG */ break; } break; case ATM_MSG_RESTART: set_error(sock,-ENETRESET); /* fall through */ case ATM_MSG_STATUS: /* fall through when clearing */ case ATM_MSG_REL_COMP: /* basically any state (except LISTENING and ZOMBIE) */ { unsigned char cause; if (mid != ATM_MSG_REL_COMP || !q_present(&in_dsc,QF_cause)) cause = 0; else { cause = q_fetch(&in_dsc,QF_cause); diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause, cause > 127 ? "invalid cause" : cause_text[cause]); } switch (sock->state) { case ss_connecting: set_error(sock,cause == ATM_CV_UNALLOC ? -EADDRNOTAVAIL : cause == ATM_CV_RES_UNAVAIL || #if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI) cause == ATM_CV_UCR_UNAVAIL_NEW || #endif cause == ATM_CV_NO_ROUTE_DEST ? -EHOSTUNREACH : cause == ATM_CV_NUM_CHANGED ? -EREMCHG : cause == ATM_CV_DEST_OOO ? -EHOSTDOWN : -ECONNREFUSED); /* fall through */ case ss_accepting: set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */ SEND_ERROR(sock->id,sock->error); STOP_TIMER(sock); free_sock(sock); return; case ss_rel_req: send_close(sock); /* fall through */ case ss_wait_rel: STOP_TIMER(sock); free_sock(sock); return; #if defined(Q2963_1) || defined(DYNAMIC_UNI) case ss_mod_req: #endif STOP_TIMER(sock); /* fall through */ #if defined(Q2963_1) || defined(DYNAMIC_UNI) case ss_mod_lcl: case ss_mod_rcv: case ss_mod_fin_ok: case ss_mod_fin_fail: case ss_mod_fin_ack: #endif case ss_connected: diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)", sock->call_ref); #if defined(Q2963_1) || defined(DYNAMIC_UNI) if (timer_handler(sock->conn_timer) == on_T361) STOP_TIMER(sock); #endif send_close(sock); /* fall through */ case ss_rel_ind: new_state(sock,ss_wait_close); return; case ss_indicated: /* fall through */ case ss_proceeding: new_state(sock,ss_zombie); return; default: break; } break; /* fail */ } case ATM_MSG_ALERTING: /* * We basically ignore this junk message, except for the connection * identifier it may carry. */ if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } return; case ATM_MSG_NOTIFY: /* silently ignore this junk */ return; #if defined(Q2963_1) || defined(DYNAMIC_UNI) /* * Buglet ahead: should actually test "call_state" */ case ATM_MSG_MODIFY_REQ: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_connected || sock->owner) break; sock->new_qos = sock->qos; if (q_present(&in_dsc,QF_fw_pcr_01)) sock->new_qos.rxtp.max_pcr = q_fetch(&in_dsc,QF_fw_pcr_01); if (q_present(&in_dsc,QF_bw_pcr_01)) sock->new_qos.txtp.max_pcr = q_fetch(&in_dsc,QF_bw_pcr_01); send_kernel(sock->id,kptr_null,as_modify, ATM_MF_INC_RSV | ATM_MF_DEC_RSV | ATM_MF_DEC_SHP, NULL,NULL,NULL,NULL,&sock->new_qos); new_state(sock,ss_mod_rcv); return; case ATM_MSG_MODIFY_ACK: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_mod_req) break; STOP_TIMER(sock); sock->qos = sock->new_qos; if (q_present(&in_dsc,QG_bbrt)) send_conn_avail(sock); send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_ok); return; case ATM_MSG_MODIFY_REJ: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_mod_req) break; STOP_TIMER(sock); sock->error = -EAGAIN; send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_fail); return; case ATM_MSG_CONN_AVAIL: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_connected || sock->owner) break; STOP_TIMER(sock); send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_ack); return; _default: /* jump here if we don't want to understand a message */ #endif default: diag(COMPONENT,DIAG_WARN,"Bad signaling message %d",mid); send_status(sock->sig,sock,0,ATM_CV_UNKNOWN_MSG_TYPE,mid); return; } diag(COMPONENT,DIAG_WARN, "Signaling message %s is incompatible with state %s/%s (%d?%d)", mid2name(mid),state_name[sock->state],cs_name[sock->call_state], (int) sock->state,(int) sock->call_state); send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,mid); } void clear_all_calls(SIG_ENTITY *sig) { SOCKET *curr,*next; for (curr = sockets; curr; curr = next) { next = curr->next; if (curr->sig == sig && curr->call_state != cs_null) uni_call(curr,ATM_MSG_RESTART); } } void clear_all_calls_on_T309(SIG_ENTITY *sig) { clear_all_calls(sig); t309 = NULL; } void saal_failure(SIG_ENTITY *sig) { SOCKET *curr,*next; trace_msg("SAAL went down"); for (curr = sockets; curr; curr = next) { next = curr->next; if (curr->sig != sig || curr->call_state == cs_null) continue; if (curr->call_state != cs_active) uni_call(curr,ATM_MSG_RESTART); else if (!t309) t309 = start_timer(T309_TIME,on_T309,sig); } } void saal_okay(SIG_ENTITY *sig) { SOCKET *curr; trace_msg("SAAL came up"); #ifdef THOMFLEX /* * Some versions of the Thomson Thomflex 5000 won't do any signaling before * they get a RESTART. Whenever SAAL comes up, this may indicate that the * switch got booted, so we send that RESTART. We also have to clear all * pending connections, which isn't that nice ... Note that the rest of the * RESTART state machine is not implemented, so the RESTART ACKNOWLEDGE * will yield a warning. */ { Q_DSC dsc; int size; clear_all_calls(sig); q_create(&dsc,q_buffer,MAX_Q_MSG); q_assign(&dsc,QF_msg_type,QMSG_RESTART); q_assign(&dsc,QF_call_ref,0); q_assign(&dsc,QF_rst_class,ATM_RST_ALL_VC); if ((size = q_close(&dsc)) >= 0) to_signaling(sig,q_buffer,size); } #endif if (!t309) return; stop_timer(t309); t309 = NULL; for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->call_state != cs_null) send_status_enq(curr); } static void process_uni(SIG_ENTITY *sig,void *msg) { SOCKET *curr; unsigned long call_ref; unsigned char mid; call_ref = q_fetch(&in_dsc,QF_call_ref)^0x800000; mid = q_fetch(&in_dsc,QF_msg_type); if (mid == ATM_MSG_REST_ACK) return; if (mid == ATM_MSG_RESTART) { /* 5.5.5.2 */ int rst_class; rst_class = q_fetch(&in_dsc,QF_rst_class); switch (rst_class) { case ATM_RST_IND_VC: { int vpi,vci; if (!q_present(&in_dsc,QG_conn_id)) { send_status(sig,NULL,call_ref,ATM_CV_MAND_IE_MISSING, ATM_IE_CONN_ID); return; } vpi = q_fetch(&in_dsc,QF_vpi); vci = q_fetch(&in_dsc,QF_vci); for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->pvc.sap_addr.vpi == vpi && curr->pvc.sap_addr.vci == vci) break; if (!curr) { send_status(sig,NULL,call_ref,ATM_CV_INVALID_IE, ATM_IE_CONN_ID); return; } uni_call(curr,mid); send_restart_ack(sig,call_ref,vpi,vci); } break; case ATM_RST_ALL_VC: clear_all_calls(sig); send_restart_ack(sig,call_ref,0,0); break; default: send_status(sig,NULL,call_ref,ATM_CV_INVALID_IE,ATM_IE_RESTART); } return; } if (!(call_ref & 0x7fffff)) { diag(COMPONENT,DIAG_ERROR,"unrecognized global call ref"); return; } for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->call_ref == call_ref) break; diag(COMPONENT,DIAG_DEBUG,"FROM SAAL %d.%d.%d: %s (0x%02X) CR 0x%06lx for " "%s",S_PVC(sig),mid2name(((unsigned char *) msg)[5]), ((unsigned char *) msg)[5],call_ref,curr ? kptr_print(&curr->id) : "?"); if (mid == ATM_MSG_SETUP) { if (!curr) setup_call(sig,call_ref); return; } if (mid == ATM_MSG_STATUS_ENQ) { send_status(sig,curr,call_ref,ATM_CV_RESP_STAT_ENQ); return; } if (curr && q_present(&in_dsc,QF_ep_ref) && mid != ATM_MSG_ADD_PARTY && mid != ATM_MSG_DROP_PARTY_ACK) { unsigned short ep_ref; ep_ref = cvt_ep_ref(sig,q_fetch(&in_dsc,QF_ep_ref)); if (curr->ep_ref != ep_ref) { send_drop_party_ack(sig,call_ref,ep_ref,ATM_CV_INV_EPR); return; } } if (!curr || curr->call_state == cs_null) { if (mid == ATM_MSG_REL_COMP) return; if (mid != ATM_MSG_STATUS) send_release_complete(sig,call_ref,ATM_CV_INV_CR); else if (q_fetch(&in_dsc,QF_call_state) != (int) cs_null) send_release_complete(sig,call_ref,ATM_CV_INCOMP_MSG); return; } uni_call(curr,mid); } static void abort_call(SIG_ENTITY *sig,unsigned char *msg,int size) { SOCKET *curr; unsigned long call_ref; if (size < 6) { diag(COMPONENT,DIAG_ERROR,"message too short (%d bytes)",size); return; } /* hope that at least the call ref is okay ... */ call_ref = ((msg[3] << 16) | (msg[4] << 8) | msg[5])^0x800000; diag(COMPONENT,DIAG_ERROR,"can't parse message - aborting the call " "(CR 0x%06lx)",call_ref); for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->call_ref == call_ref) { uni_call(curr,ATM_MSG_RESTART); break; } send_release_complete(sig,call_ref,ATM_CV_PROTOCOL_ERROR); } void to_uni(SIG_ENTITY *sig,void *msg,int size) { if (q_open(&in_dsc,msg,size) < 0) { abort_call(sig,msg,size); return; } process_uni(sig,msg); if (q_close(&in_dsc) < 0) diag(COMPONENT,DIAG_ERROR,"q_close returned <0 in to_uni"); } --- NEW FILE: README --- This is a very early version of atmsigd that supports multiple signaling entities in the same process. Everything's still a bit buggy and ugly. To play with it, ... 1) Generate ATM interfaces 1 and 2: # atmtcp -b -i 1 -l # atmtcp -b -i 2 -c localhost 2) Create the following configuration file (name "config"): entity 1.0.5 { mode user route +1 } entity 2.0.5 { mode network default } 3) Launch atmsigd: # ./atmsigd.new -c config 4) Add local addresses: # atmaddr -a 1 +1 # atmaddr -a 2 +2 5) Test it: % ttcp_atm -r -a % ttcp_atm -t -a +1 Known bugs: - wildcard bind removes wildcard - selection of local address isn't consistent with signaling interface selection - everything else that's marked with @@@ --- NEW FILE: atmsigd.8 --- .TH ATMSIGD 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmsigd \- ATM signaling demon .SH SYNOPSIS .B atmsigd .RB [ \-b ] .RB [ \-c\ \fIconfig_file\fP ] .RB [ \-d ] .RB [ \-D\ \fIdump_dir\fP ] .RB [ \-l\ \fIlogfile\fP ] .RB [ \-m\ \fImode\fP ] .RB [ \-n ] .RB [ \-q\ \fIqos\fP ] .RB [ \-t\ \fItrace_length\fP ] .RB [ \-u\ \fIuni_version\fP ] .RB [ [\fIitf\fP.]\fIvpi\fP.\fIvci\fP .RB [ \fIinput\ output\fP ] ] .br .B atmsigd .B \-V .SH DESCRIPTION \fBatmsigd\fP implements the ATM UNI signaling protocol. Requests to establish, accept, or close ATM SVCs are sent from the kernel (using a comparably simple protocol) to the signaling demon, which then performs the dialog with the network. .P Note that \fBatmsigd\fP is not able to accept or establish connections until the local ATM address of the interface is configured by \fBilmid\fP or manually using \fBatmaddr\fP. .P The default signaling VC (interface 0, VPI 0, VCI 5) can be overridden on the command line by specifying a different PVC address. .P When overriding the default VC, optionally a pair of named pipes to use for communicating with the user of signaling can be specified. Normally, the kernel is the user of signaling and \fBatmsigd\fP opens a special socket for communication with it. .P If \fBatmsigd\fP is killed, all system calls requiring interaction with it will return with an error and set \fBerrno\fP to \fBEUNATCH\fP. .SH OPTIONS .IP \fB\-b\fP Run in background (i.e. in a forked child process) after initializing. .IP \fB\-c\ \fIconfig_file\fP Use the specified configuration file instead of \fB/etc/atmsigd.conf\fP If an option is specified in the configuration file and on the command line, the command line has priority. .IP \fB\-d\fP Enables (lots of) debugging output. By default, \fBatmsigd\fP is comparably quiet. .IP \fB\-D\ \fIdump_dir\fP Specifies the directory to which \fBatmsigd\fP will write status and trace dumps. If \fB\-D\fP is not specified, dumps are written to /var/tmp. .IP \fB\-l\ \fIlogfile\fP Write diagnostic messages to the specified file. The special name \fBsyslog\fP is used to send diagnostics to the system logger, \fBstderr\fP is used to send diagnostics to standard error. If \fB\-l\fP is absent, the setting in \fBatmsigd.conf\fP is used. If \fBatmsigd\fP doesn't specify a destination either, messages are written to standard error. .IP \fB\-m\ \fImode\fP Set the mode of operation. The following modes are available: \fBuser\fP for the user side (the default), \fBnetwork\fP for the network side (useful if you have two PCs but no switch), and \fBswitch\fP for operation with a signaling relay in a switch. .IP \fB\-n\fP Prints addresses in numeric format only, i.e. no address to name translation is attempted. .IP \fB\-q\ \fIqos\fP Configures the signaling VC to use the specified quality of service (see qos(7) for the syntax). By default, UBR at link speed is used on the signaling VC. .IP \fB\-t\ \fItrace_length\fP Sets the number of entries that should be kept in the trace buffer. \fB\-t 0\fP disables tracing. If \fB\-t\fP is not specified, \fBatmsigd\fP uses a default of 20 trace entries. .IP \fB\-u\ \fIuni_version\fP Sets the signaling mode. The following modes are supported: \fBuni30\fP for UNI 3.0, \fBuni31\fP for UNI 3.1, \fBuni31+uni30\fP for UNI 3.1 with 3.0 compatibility, \fBuni40\fP for UNI 4.0, and \fBuni40+q.2963.1\fP for UNI 4.0 with Q.2963.1 peak cell rate renegotiation. .IP \fB\-V\fP Prints the version number of \fBatmsigd\fP on standard output and exits. .SH FILES .PD 0 .TP 25 .B /etc/atmsigd.conf default configuration file .TP 25 .B /var/tmp/atmsigd.\fIpid\fB.status.\fIversion\fP default location of status dumps .TP 25 .B /var/tmp/atmsigd.\fIpid\fB.trace.\fIversion\fP default location of signaling trace dumps .PD .SH DEBUGGING When receiving a \fBSIGUSR1\fP signal, \fBatmsigd\fP dumps the list of all internal socket descriptors. With \fBSIGUSR2\fP, it dumps the contents of the trace buffer. If a dump directory was set, dumps are written to files called \fBatmsigd.\fP\fIpid\fP\fB.status.\fP\fInumber\fP and \fBatmsigd.\fP\fIpid\fP\fB.trace.\fP\fInumber\fP, respectively, with \fInumber\fP starting at zero and being incremented for every dump. If no dump directory is set, dumps are written to standard error. .P Dumps are also generated whenever \fBatmsigd\fP detects a fatal error and terminates. No attempt is made to catch signals like \fBSIGSEGV\fP. .SH BUGS The generation of traces is a comparably slow process which may already take several seconds for only 100 trace entries. To generate a trace dump, \fBatmsigd\fP therefore forks a child process that runs in parallel to the signaling demon. .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" atmaddr(8), atmsigd.conf(4), ilmid(8), qos(7) .\"{{{}}} --- NEW FILE: atmsigd.c --- /* atmsigd.c - ATM signaling demon */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <limits.h> #include <sys/types.h> #include "atm.h" #include "atmd.h" #include "qlib.h" #include "io.h" #include "proto.h" #include "saal.h" #include "trace.h" #define COMPONENT "SIGD" extern int yyparse(void); extern FILE *yyin; int debug = 0; int pretty = A2T_PRETTY | A2T_NAME | A2T_LOCAL; const char *dump_dir = DEFAULT_DUMP_DIR; /* A little hack until we have full support for multiple signaling entities */ SIG_ENTITY _entity = { 0, /* fd */ 0, /* unspecified UNI version */ sm_user, /* mode */ -1, /* sig_pcr; obsolete @@@ */ NULL, /* sig_qos */ -1 /* max_rate */ }; /* ------------------------------ SAAL relays ------------------------------ */ static void q_estab_conf(void *user_data,void *uu_data,int uu_length) { SIG_ENTITY *sig = user_data; saal_okay(sig); } static void q_rel_ind(void *user_data,void *uu_data,int uu_length) { SIG_ENTITY *sig = user_data; saal_failure(sig); saal_estab_req(&sig->saal,NULL,0); } static void q_restart(void *user_data,void *uu_data,int uu_length,int ind) { SIG_ENTITY *sig = user_data; saal_failure(sig); if (!ind) saal_okay(sig); /* actually, ind should probably never be zero */ } void from_net(SIG_ENTITY *sig,void *buffer,int size) { saal_pdu(&sig->saal,buffer,size); } void to_signaling(SIG_ENTITY *sig,void *msg,int size) { trace_uni("TO NETWORK",sig,msg,size); diag(COMPONENT,DIAG_DEBUG,"TO SAAL (%d.%d.%d): %s (0x%02x) CR 0x%06x " "(%d bytes)",S_PVC(sig), mid2name(((unsigned char *) msg)[5]),((unsigned char *) msg)[5], (((unsigned char *) msg)[2] << 16) | (((unsigned char *) msg)[3] << 8) | ((unsigned char *) msg)[4],size); saal_send(&sig->saal,msg,size); } static void q_data_ind(void *user_data,void *data,int length) { SIG_ENTITY *sig = user_data; trace_uni("FROM NETWORK",sig,data,length); to_uni(sig,data,length); } static void q_cpcs_send(void *user_data,void *data,int length) { SIG_ENTITY *sig = user_data; to_net(sig,data,length); } static SAAL_USER_OPS ops = { NULL, /* no q_estab_ind - 5.5.6.9 says 5.5.6.11 and 5.5.6.11 says "may" */ q_estab_conf, q_rel_ind, NULL, /* no q_rel_conf - what to do ? */ q_restart, q_data_ind, NULL, /* no q_unitdata */ q_cpcs_send }; /* -------------------------------- signals -------------------------------- */ static volatile int got_usr1 = 0,got_usr2 = 0; static void dump_addr(FILE *file,const char *label,struct sockaddr_atmsvc *addr) { char buffer[MAX_ATM_ADDR_LEN+1]; int i; if (!atmsvc_addr_in_use(*addr)) return; fprintf(file," %s ",label); if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) addr,A2T_NAME | A2T_PRETTY | A2T_LOCAL) >= 0) fprintf(file,"%s\n",buffer); else { fprintf(file,"<invalid:"); for (i = 0; i < sizeof(*addr); i++) fprintf(file," %02X",((unsigned char *) addr)[i]); fprintf(file,">\n"); } } static void dump_sap(FILE *file,const char *label,struct atm_sap *sap) { char buffer[MAX_ATM_SAP_LEN+1]; int i; fprintf(file," %s ",label); if (sap2text(buffer,MAX_ATM_SAP_LEN+1,sap,S2T_NAME | S2T_LOCAL) >= 0) fprintf(file,"%s\n",buffer); else { fprintf(file,"<invalid:"); for (i = 0; i < sizeof(*sap); i++) fprintf(file," %02X",((unsigned char *) sap)[i]); fprintf(file,">\n"); } } static void dump_status(FILE *file,const char *banner) { SIG_ENTITY *sig; SOCKET *walk; if (entities) fprintf(file,"%s\n\n",banner); for (sig = entities; sig; sig = sig->next) { fprintf(file,"--- Entity %d.%d.%d ---\n",S_PVC(sig)); for (walk = sockets; walk; walk = walk->next) { fprintf(file,"%s: %s, CR 0x%06lX, PVC %d.%d.%d\n", kptr_print(&walk->id), state_name[walk->state],walk->call_ref,walk->pvc.sap_addr.itf, walk->pvc.sap_addr.vpi,walk->pvc.sap_addr.vci); dump_addr(file,"local ",&walk->local); dump_addr(file,"remote",&walk->remote); dump_sap(file,"sap",&walk->sap); } } } static void dump_trace(FILE *file,const char *banner) { static int busy = 0; char *trace; if (busy++) abort(); trace = get_trace(); if (trace) { fprintf(file,"%s\n\n",banner); fprintf(file,"%s",trace); } busy--; } void poll_signals(void) { static int status_num = 0,trace_num = 0; char path[PATH_MAX+1]; FILE *file; if (got_usr1) { got_usr1 = 0; if (!dump_dir) file = stderr; else { sprintf(path,"atmsigd.%d.status.%d",getpid(),status_num++); if ((file = fopen(path,"w"))) diag(COMPONENT,DIAG_INFO,"Dumping to %s",path); else { perror(path); file = stderr; } } dump_status(file,"Status dump (on SIGUSR1)"); if (file != stderr) (void) fclose(file); } if (got_usr2) { pid_t pid; got_usr2 = 0; if (!dump_dir) file = stderr; else { sprintf(path,"atmsigd.%d.trace.%d",getpid(),trace_num++); if ((file = fopen(path,"w"))) diag(COMPONENT,DIAG_INFO,"Dumping to %s",path); else { perror(path); file = stderr; } } if (!(pid = fork())) dump_trace(file,"Message trace (on SIGUSR2)"); else if (pid < 0) perror("fork"); if (file != stderr) (void) fclose(file); if (!pid) exit(0); } } static void handle_signal(int sig) { switch (sig) { case SIGUSR1: got_usr1 = 1; break; case SIGUSR2: got_usr2 = 1; break; default: break; } } static void setup_signals(void) { struct sigaction act; (void) signal(SIGCHLD,SIG_IGN); /* reap children automatially */ act.sa_handler = handle_signal; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGUSR1,&act,NULL) < 0) { perror("sigaction"); exit(1); } if (sigaction(SIGUSR2,&act,NULL) < 0) { perror("sigaction"); exit(1); } } /* ------------------------------- main ... ------------------------------- */ static void trace_on_exit(int status,void *dummy) { char path[PATH_MAX+1]; FILE *file; if (!status) return; if (!dump_dir) file = stderr; else { sprintf(path,"atmsigd.%d.trace.exit",getpid()); if (!(file = fopen(path,"w"))) { perror(path); file = stderr; } } dump_trace(file,"Message trace (after error exit)"); if (file != stderr) (void) fclose(file); } static void manual_override(void) { /* * Gross hack to avoid changing the command-line parameters ... @@@ */ entities = &_entity; _entity.next = NULL; } static void usage(const char *name) { fprintf(stderr,"usage: %s [ -b ] [ -c config_file ] [ -d ] " "[ -D dump_dir ]\n" " [ -l logfile ] [ -n ] [ -m user|network|switch ] [ -q qos ]\n" " [ -t trace_length ] [ -u uni_version ] [ [itf.]vpi.vci " "[ socket_path ] ]\n",name); fprintf(stderr,"%6s %s -V\n","",name); exit(1); } int main(int argc,char **argv) { SIG_ENTITY *sig; const char *config_file; char *end; int c,background; int net = 0,allocate_ci = 1; set_application("atmsigd"); config_file = ATMSIGD_CONF; background = 0; memset(&_entity.signaling_pvc,0,sizeof(_entity.signaling_pvc)); /* 1st pass to get the -c option */ while ((c = getopt(argc,argv,"Abc:dD:l:m:nNP:q:t:u:V")) != EOF) if (c == 'c') config_file = optarg; else if (c == 'V') { printf("%s\n",VERSION); return 0; } if (!(yyin = fopen(config_file,"r"))) diag(COMPONENT,DIAG_WARN,"%s not found. - Using defaults.",config_file); else if (yyparse()) diag(COMPONENT,DIAG_FATAL,"Error in config file. - Aborting."); if (!atmpvc_addr_in_use(_entity.signaling_pvc)) _entity.signaling_pvc.sap_addr.vci = 5; if (!_entity.uni) _entity.uni = #ifdef UNI31 S_UNI31 #ifdef ALLOW_UNI30 | S_UNI30 #endif #elif defined(UNI40) S_UNI40 #ifdef Q2963_1 | S_Q2963_1 #endif #else S_UNI30 #endif ; /* process all other options but -c */ optind = 0; while ((c = getopt(argc,argv,"Abc:dD:l:m:nNP:q:t:u:")) != EOF) switch (c) { case 'A': manual_override(); allocate_ci = 0; break; case 'b': background = 1; break; case 'c': /* already handled */ break; case 'd': set_verbosity(NULL,DIAG_DEBUG); set_verbosity("QMSG",DIAG_INFO); set_verbosity("SSCOP",DIAG_INFO); debug = 1; /*q_dump = 1;*/ break; case ... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:09
|
Update of /cvsroot/linux-atm/linux-atm/src/debug In directory usw-pr-cvs1:/tmp/cvs-serv10656/debug Added Files: Tag: V2_4_0 ed.c svctor.c delay.c dnstest.c Makefile.am znth.c peek.pl Log Message: --- NEW FILE: ed.c --- /* ed.c - eni memory dump */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/sonet.h> #include <linux/atm_eni.h> static void usage(const char *name) { fprintf(stderr,"usage: %s itf\n",name); exit(1); } int main(int argc,char **argv) { struct atmif_sioc req; int s; if (argc != 2) usage(argv[0]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,ATM_AAL5)) < 0) { perror("socket"); return 1; } req.number = atoi(argv[1]); if (ioctl(s,ENI_MEMDUMP,&req) < 0) { perror("ioctl ENI_MEMDUMP"); return 1; } return 0; } --- NEW FILE: svctor.c --- /* svctor.c - SVC Torture */ /* Written 1998,1999 by Werner Almesberger, EPFL ICA */ /* * This program frantically tries to concurrently set up connections to * itself. Once it has obtained all the connections it was looking for, * it exits, leaving the system with a lot of things to clean up. */ #if HAVE_CONFIG_H #include <config.h> #endif #define ITF 0 /* interface we use - should be command-line arg */ #define MAX_PAR 4 /* maximum number of concurrent connect()s */ #define EXIT_LIM 3 /* exit after establishing that many connections */ #define MAX_ADDR 10 /* maximum number of local addresses */ #define SAP "bhli:oui=0x0060D7,id=0x010000ff" #define QOS "ubr,aal5:tx:max_sdu=100,rx:max_sdu=100" #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <errno.h> #include <atm.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <linux/atmdev.h> int main(void) { static int fd[MAX_PAR]; /* to force initialization */ struct sockaddr_atmsvc local[MAX_ADDR]; struct atmif_sioc req; struct atm_sap sap; struct atm_qos qos; int listen_fd; fd_set rset,wset; int fds,completed = 0,connects = 0,accepts = 0; FD_ZERO(&rset); FD_ZERO(&wset); if (text2sap(SAP,&sap,0) < 0) { fprintf(stderr,"text2sap\n"); return 1; } if (text2qos(QOS,&qos,0) < 0) { fprintf(stderr,"text2qos\n"); return 1; } listen_fd = socket(PF_ATMSVC,SOCK_DGRAM,0); if (listen_fd < 0) { perror("socket"); return 1; } req.number = ITF; req.arg = local; req.length = sizeof(local); if (ioctl(listen_fd,ATM_GETADDR,&req) < 0) { perror("ioctl"); return 1; } if (!req.length) { fprintf(stderr,"No local address\n"); return 1; } if (setsockopt(listen_fd,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { perror("setsockopt SO_ATMSAP"); return 1; } if (setsockopt(listen_fd,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(listen_fd,(struct sockaddr *) local,sizeof(*local)) < 0) { perror("bind"); return 1; } if (fcntl(listen_fd,F_SETFL,O_NONBLOCK) < 0) { perror("fnctl"); return 1; } if (listen(listen_fd,5) < 0) { perror("listen"); return 1; } FD_SET(listen_fd,&rset); fds = listen_fd+1; (void) signal(SIGCHLD,SIG_IGN); while (1) { static struct timeval no_delay; fd_set _rset = rset; fd_set _wset = wset; int ret,i,empty; no_delay.tv_sec = 0; no_delay.tv_usec = 100000; ret = select(fds,&_rset,&_wset,NULL,&no_delay); if (ret < 0) { perror("select"); return 1; } if (FD_ISSET(listen_fd,&_rset)) { pid_t pid; pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (!pid) { if (accept(listen_fd,NULL,NULL) >= 0) exit(0); perror("accept"); return 1; } accepts++; } empty = -1; for (i = 0; i < MAX_PAR; i++) if (!fd[i]) empty = i; else if (FD_ISSET(fd[i],&_wset)) { struct sockaddr_atmsvc dummy; if (connect(fd[i],(struct sockaddr *) &dummy,sizeof(dummy)) < 0) { perror("connect"); return 1; } FD_CLR(fd[i],&wset); fd[i] = 0; empty = i; if (++completed == EXIT_LIM) { printf("%d attempted, %d completed, %d accepts\n", connects,completed,accepts); return 0; } } if (empty != -1) { fd[empty] = socket(PF_ATMSVC,SOCK_DGRAM,0); if (fd[empty] < 0) { perror("socket"); return 1; } if (fcntl(fd[empty],F_SETFL,O_NONBLOCK) < 0) { perror("fnctl"); return 1; } if (setsockopt(fd[empty],SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { perror("setsockopt SO_ATMSAP"); return 1; } if (setsockopt(fd[empty],SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (connect(fd[empty],(struct sockaddr *) local,sizeof(*local)) < 0 && errno != EINPROGRESS) { perror("connect"); return 1; } FD_SET(fd[empty],&wset); if (fds <= fd[empty]) fds = fd[empty]+1; connects++; } } return 0; } --- NEW FILE: delay.c --- /* delay.c - Simplistic AAL5-level software delay line */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ /* * BUGS: * - delay increases with load * - processing delay is far too big (always measure with ping first) * - horrifying command-line syntax */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include "atm.h" typedef struct _packet { struct timeval due; int size; struct _packet *next; char data[1]; } PACKET; typedef struct _link { int in,out; struct timeval delay; PACKET *queue,*last; struct _link *next; } LINK; static LINK *links = NULL; static fd_set in; static int fds = 0; #define LESS(a,b) ((a).tv_sec < (b).tv_sec || ((a).tv_sec == (b).tv_sec && \ (a).tv_usec < (b).tv_usec)) static void loop(void) { LINK *lnk; PACKET *p; struct timeval now,next,delta,*to; fd_set curr; char *buffer; int ready,size; if (!(buffer = malloc(sizeof(PACKET)-1+ATM_MAX_AAL5_PDU+4095))) { perror("buffer"); exit(1); } buffer = (char *) (((unsigned long) buffer+4095-(sizeof(PACKET)-1)) & ~4095); if (gettimeofday(&now,NULL) < 0) { perror("gettimeofday"); exit(1); } while (1) { curr = in; for (lnk = links; lnk; lnk = lnk->next) if (lnk->queue) break; if (!lnk) to = NULL; else { for (next = lnk->queue->due; lnk; lnk = lnk->next) if (lnk->queue && LESS(lnk->queue->due,next)) next = lnk->queue->due; delta.tv_sec = next.tv_sec-now.tv_sec; delta.tv_usec = next.tv_usec-now.tv_usec; if (delta.tv_usec < 0) { delta.tv_sec--; delta.tv_usec += 1000000; } if (delta.tv_usec > 0) { delta.tv_sec++; delta.tv_usec -= 1000000; } if (delta.tv_sec < 0) delta.tv_sec = delta.tv_usec = 0; to = δ } if ((ready = select(fds,&curr,NULL,NULL,to)) < 0) { perror("select"); exit(1); } if (gettimeofday(&now,NULL) < 0) { perror("gettimeofday"); exit(1); } if (ready) for (lnk = links; lnk; lnk = lnk->next) while (1) { size = read(lnk->in,buffer,ATM_MAX_AAL5_PDU); if (size < 0) { if (errno == EAGAIN) break; else { perror("read"); exit(1); } } if (size > 0) { if (!(p = malloc(sizeof(PACKET)-1+size))) { perror("malloc"); exit(1); } memcpy(p->data,buffer,size); p->size = size; p->due.tv_sec = now.tv_sec+lnk->delay.tv_sec; p->due.tv_usec = now.tv_usec+lnk->delay.tv_usec; if (p->due.tv_usec > 1000000) { p->due.tv_sec++; p->due.tv_usec -= 1000000; } p->next = NULL; if (lnk->queue) lnk->last->next = p; else lnk->queue = p; lnk->last = p; } } for (lnk = links; lnk; lnk = lnk->next) while (lnk->queue && LESS(lnk->queue->due,now)) { p = lnk->queue; lnk->queue = p->next; if ((size = write(lnk->out,p->data,p->size)) < 0) { perror("write"); exit(1); } if (p->size != size) fprintf(stderr,"short write: %d < %d\n",size,p->size); free(p); } } } static int setup(char *spec,int tx) { struct sockaddr_atmpvc addr; struct atm_qos qos; char *here; int fd; if (!(here = strchr(spec,','))) { memset(&qos,0,sizeof(qos)); if (tx) qos.txtp.traffic_class = ATM_UBR; else qos.rxtp.traffic_class = ATM_UBR; } else { *here = 0; if (text2qos(here+1,&qos,0) < 0) { fprintf(stderr,"invalid QOS: %s\n",here+1); exit(1); } } if (tx) qos.rxtp.traffic_class = ATM_NONE; else qos.txtp.traffic_class = ATM_NONE; qos.aal = ATM_AAL5; if (text2atm(spec,(struct sockaddr *) &addr,sizeof(addr), T2A_PVC | T2A_NAME) < 0) { fprintf(stderr,"invalid PVC: %s\n",spec); exit(1); } if ((fd = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); exit(1); } if (setsockopt(fd,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); exit(1); } if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); exit(1); } return fd; } static void usage(const char *name) { fprintf(stderr,"usage: %s path ...\n",name); fprintf(stderr," path :== vc/vc/delay\n"); fprintf(stderr," vc :== [itf.]vpi.vci[,qos_spec]\n"); fprintf(stderr," delay :== timeunit\n"); fprintf(stderr," unit :== s | ms\n"); exit(1); } int main(int argc,char **argv) { LINK *dsc; const char *name; unsigned long delay; char *end,*here; name = argv[0]; FD_ZERO(&in); if (argc < 2) usage(name); while (argc > 1) { argc--; argv++; if (!(dsc = malloc(sizeof(LINK)))) { perror("malloc"); return 1; } if (!(here = strtok(*argv,"/"))) usage(name); dsc->in = setup(here,0); FD_SET(dsc->in,&in); if (dsc->in >= fds) fds = dsc->in+1; if (fcntl(dsc->in,F_SETFL,O_NONBLOCK) < 0) { perror("fcntl"); return 1; } if (!(here = strtok(NULL,"/"))) usage(name); dsc->out = setup(here,1); if (!(here = strtok(NULL,"/"))) usage(name); delay = strtoul(here,&end,10); switch (*end) { case 's': dsc->delay.tv_sec = delay; dsc->delay.tv_usec = 0; break; case 'm': dsc->delay.tv_sec = delay/1000; dsc->delay.tv_usec = (delay % 1000)*1000; if (*++end != 's') usage(name); break; default: usage(name); } if (end[1]) usage(name); dsc->queue = dsc->last = NULL; dsc->next = links; links = dsc; } loop(); return 0; } --- NEW FILE: dnstest.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <netdb.h> #include <resolv.h> #include <atm.h> int main(int argc, char **argv) { int i; unsigned char *pnsap; struct sockaddr_atmsvc addr; unsigned char buffer[1024]; if (argc != 2) { printf("Usage: %s <name> \n", argv[0]); exit(0); } if (text2atm(argv[1], (struct sockaddr *) &addr, sizeof(addr), T2A_NAME) < 0) { perror("text2atm()"); exit(1); } if (atm2text(buffer, 1024, (struct sockaddr *) &addr, A2T_NAME) < 0) { perror("atm2text()"); exit(2); } printf("Looking up %s \n", argv[1]); printf("Direct: "); pnsap = (unsigned char *) &(addr.sas_addr.prv); for (i = 0; i < 20; i++) { printf("%02X", pnsap[i]); } printf("\n"); printf("Reverse: %s \n", buffer); exit(0); } --- NEW FILE: Makefile.am --- # Remove the # for more hardware-specific debugging programs. # I'll need those only if you're fiddling with the guts of drivers. noinst_PROGRAMS = delay svctor # ed dnstest znth LDADD = $(top_builddir)/src/lib/libatm.la delay_SOURCES = delay.c svctor_SOURCES = svctor.c #ed_SOURCES = ed.c #dnstest_SOURCES = dnstest.c #znth_SOURCES = znth.c #EXTRA_DIST = peek.pl EXTRA_DIST = peek.pl ed.c dnstest.c znth.c --- NEW FILE: znth.c --- /* znth.c - ZN122x timestamp adjustments history */ /* Written 1996-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/time.h> #include <atm.h> #include <linux/atm_zatm.h> int main(int argc,char **argv) { struct atmif_sioc sioc; struct zatm_t_hist history[ZATM_TIMER_HISTORY_SIZE]; char *end; int s,i; if (argc != 2 || ((sioc.number = strtoul(argv[1],&end,0)), *end)) { fprintf(stderr,"usage: %s itf\n",*argv); return 1; } if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } sioc.arg = history; sioc.length = sizeof(history); if (ioctl(s,ZATM_GETTHIST,&sioc) < 0) { perror("ioctl ZATM_GETTHIST"); return 1; } for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) { struct timeval diff; if (!history[i].real.tv_sec) continue; printf("%2ld:%02ld:%02ld.%06ld: ", ((long) history[i].real.tv_sec/3600) % 24, ((long) history[i].real.tv_sec/60) % 60, (long) history[i].real.tv_sec % 60, (long) history[i].real.tv_usec); history[i].expected.tv_sec += history[i].expected.tv_usec/1000000; history[i].expected.tv_usec %= 1000000; diff.tv_sec = history[i].expected.tv_sec-history[i].real.tv_sec; diff.tv_usec = history[i].expected.tv_usec-history[i].real.tv_usec; if (diff.tv_sec < -2000 || diff.tv_sec > 2000) printf("%11ld SECONDS\n",(long) diff.tv_sec); else { diff.tv_usec += diff.tv_sec*1000000; printf("%11ld usec\n",(long) diff.tv_usec); } } return 0; } --- NEW FILE: peek.pl --- #!/usr/bin/perl $base = 0x220000; $off = $ARGV[0]; $dsc = $base+hex($off)*4; $start = ($dsc & ~15)-64; $| = 1; printf("Descriptor is at 0x%06x\n",$dsc); system("hexdump -e'\"%06.6_ax \" 16/1 \"%02x \" \"\\n\"' -s $start /var/tmp/all"); |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:09
|
Update of /cvsroot/linux-atm/linux-atm/src/saal In directory usw-pr-cvs1:/tmp/cvs-serv10656/saal Added Files: Tag: V2_4_0 pdu.c pdu.h queue.c queue.h sscop.c sscop.h Makefile.am saal.c saal.h sscf.c sscf.h Log Message: --- NEW FILE: pdu.c --- /* pdu.c - SSCOP (Q.2110) PDU reader */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdint.h> #include "pdu.h" #ifndef NULL #define NULL 0 #endif const char *pdu_name[] = { "???","BGN","BGAK","END","ENDAK","RS","RSAK", "BGREJ","SD","ER","POLL","STAT","USTAT","UD","MD","ERAK" }; void (*pdu_maa)(void *arg,char code,int count) = NULL; void (*pdu_diag)(int severity,const char *fmt,...) = NULL; void print_pdu(const char *label,unsigned char type,void *data, const int *length,const int *s,const int *ps,const int *r,const int *mr, const int *sq) { int len; char *list; switch (type) { case SSCOP_SD: pdu_diag(SP_DEBUG,"%s SD(S=%d,len=%d)",label,*s,*length); break; case SSCOP_POLL: pdu_diag(SP_DEBUG,"%s POLL(PS=%d,S=%d)",label,*ps,*s); break; case SSCOP_STAT: if (*length & 3) { pdu_diag(SP_WARN,"%s STAT PDU has wrong size (%d)",label, *length); break; } len = *length/4; pdu_diag(SP_DEBUG,"%s STAT(PS=%d,MR=%d,R=%d,items=%d:",label,*ps, *mr,*r,len); list = (char *) data; while (len > 1) { pdu_diag(SP_DEBUG,"%s %d..%d",label,read_netl(list), read_netl(list+4)); list += 8; len -= 2; } if (!len) pdu_diag(SP_DEBUG,"%s <last is absent>)",label); else pdu_diag(SP_DEBUG,"%s <next is> %d)",label,read_netl(list)); break; case SSCOP_USTAT: if (*length != 8) { pdu_diag(SP_WARN,"%s USTAT PDU has wrong size (%d)",label, *length); break; } list = (char *) data; pdu_diag(SP_DEBUG,"%s USTAT(MR=%d,R=%d,%d..%d)",label,*mr,*r, read_netl(list),read_netl(list+4)); break; case SSCOP_UD: pdu_diag(SP_DEBUG,"%s UD(len=%d)",label,*length); break; case SSCOP_MD: pdu_diag(SP_DEBUG,"%s MD(len=%d)",label,*length); break; case SSCOP_BGN: pdu_diag(SP_DEBUG,"%s BGN(SQ=%d,MR=%d,len=%d)",label,*sq,*mr, *length); break; case SSCOP_BGAK: pdu_diag(SP_DEBUG,"%s BGAK(MR=%d,len=%d)",label,*mr,*length); break; case SSCOP_BGREJ: pdu_diag(SP_DEBUG,"%s BGREJ(len=%d)",label,*length); break; case SSCOP_END: pdu_diag(SP_DEBUG,"%s END(S=%d,len=%d)",label,*s,*length); break; case SSCOP_ENDAK: pdu_diag(SP_DEBUG,"%s ENDAK()",label); break; case SSCOP_RS: pdu_diag(SP_DEBUG,"%s RS(SQ=%d,MR=%d,len=%d)",label,*sq,*mr, *length); break; case SSCOP_RSAK: pdu_diag(SP_DEBUG,"%s RSAK(MR=%d)",label,*mr); break; case SSCOP_ER: pdu_diag(SP_DEBUG,"%s ER(MR=%d)",label,*mr); break; case SSCOP_ERAK: pdu_diag(SP_DEBUG,"%s ERAK(MR=%d)",label,*mr); break; default: pdu_diag(SP_ERROR,"%s unknown PDU type %d\n",label,type); } } int decompose_pdu(void *maa_arg,void *msg,int size,unsigned char *type, int *length,int *s,int *ps,int *r,int *mr,int *sq) { void *last; unsigned char pad; int n; /* * *length is undefined if PDU has no variable-length data part */ if (size < 4 || (size & 3)) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"invalid message length (%d)", size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } last = (char *) msg+size-4; *type = SSCOP_TYPE(last); pad = SSCOP_PAD(last); n = SSCOP_N(last); *length = size-4-pad; switch (*type) { case SSCOP_SD: *s = n; break; case SSCOP_POLL: if (size != 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "POLL PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *s = n; *ps = SSCOP_N(msg); break; case SSCOP_STAT: if (size < 12) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "STAT PDU too short (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } if (*length & 3) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "STAT PDU has bad length (%d)",length); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *r = n; *mr = SSCOP_N((char *) last-4); *ps = SSCOP_N((char *) last-8); *length -= 8; break; case SSCOP_USTAT: if (size != 16) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "USTAT PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(pdu_maa,'U',0); return -1; } *r = n; *mr = SSCOP_N((char *) last-4); *length -= 4; break; case SSCOP_UD: case SSCOP_MD: break; case SSCOP_BGN: if (size < 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"BGN PDU too short (%d)", size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; *sq = SSCOP_SQ(last); *length -= 4; break; case SSCOP_BGAK: if (size < 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "BGAK PDU too short (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; *length -= 4; break; case SSCOP_BGREJ: if (size < 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "BGREJ PDU too short (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *length -= 4; break; case SSCOP_END: if (size < 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"END PDU too short (%d)", size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *s = !!SSCOP_S(last); *length -= 4; break; case SSCOP_ENDAK: if (size != 8) { pdu_diag(SP_DEBUG,"ENDAK PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); if (size < 4) return -1; /* make it work with Fore */ } break; case SSCOP_RS: if (size < 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"RS PDU too short (%d)", size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; *sq = SSCOP_SQ(last); *length -= 4; break; case SSCOP_RSAK: if (size != 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "RSAK PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; break; case SSCOP_ER: if (size != 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "ER PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; *sq = SSCOP_SQ(last); break; case SSCOP_ERAK: if (size != 8) { pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, "ERAK PDU has bad length (%d)",size); if (pdu_maa) pdu_maa(maa_arg,'U',0); return -1; } *mr = n; break; default: pdu_diag(SP_ERROR,"unknown PDU type %d (0x%x)",*type,*type); return -1; } return 0; } --- NEW FILE: pdu.h --- /* pdu.h - SSCOP (Q.2110) PDU reader */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef PDU_H #define PDU_H #include <stdint.h> #include <atmd.h> /* SSCOP PDU types, Q.2110 section 7.1 */ #define SSCOP_BGN 1 /* Request Initialization */ #define SSCOP_BGAK 2 /* Request Acknowledgement */ #define SSCOP_BGREJ 7 /* Connection Reject */ #define SSCOP_END 3 /* Disconnect Command */ #define SSCOP_ENDAK 4 /* Disconnect Acknowledgement */ #define SSCOP_RS 5 /* Resynchronization Command */ #define SSCOP_RSAK 6 /* Resynchronization Acknowledgement */ #define SSCOP_ER 9 /* Recovery Command */ #define SSCOP_ERAK 15 /* Recovery Acknowledgement */ #define SSCOP_SD 8 /* Sequence Connection-mode Data */ #define SSCOP_POLL 10 /* Transmitter State Information with request ... */ #define SSCOP_STAT 11 /* Solicited Receiver State Information */ #define SSCOP_USTAT 12 /* Unsolicited Receiver State Information */ #define SSCOP_UD 13 /* Unnumbered User Data */ #define SSCOP_MD 14 /* Unnumbered Management Data */ /* Trailer format macros */ #define SSCOP_TRAIL(type,pad,n) (htonl((n) | ((type) << 24) | ((pad) << 30))) #define SSCOP_S_BIT 0x10000000 #define SSCOP_TYPE(last) ((read_netl(last) >> 24) & 15) #define SSCOP_PAD(last) (read_netl(last) >> 30) #define SSCOP_N(last) (read_netl(last) & 0xffffff) #define SSCOP_S(last) (read_netl(last) & SSCOP_S_BIT) #define SSCOP_SQ(last) (read_netl((char *) last-4) & 0xff) extern const char *pdu_name[]; /* Helper macros for PDU construction and decomposition */ #define PDU_VARS \ unsigned char type; \ int length; \ int s,ps,r,mr,sq #define DECOMPOSE_PDU(maa_arg,msg,size) decompose_pdu(maa_arg,msg,size,&type, \ &length,&s,&ps,&r,&mr,&sq) #define PRINT_PDU(label,data) print_pdu(label,type,data,&length,&s,&ps,&r, \ &mr,&sq) /* * Severity codes for pdu_diag. Surprisingly, they happen to have the same * numerical values as their corresponding diag counterparts. */ #define SP_DEBUG 3 #define SP_WARN 1 #define SP_ERROR 0 extern void (*pdu_maa)(void *arg,char code,int count); extern void (*pdu_diag)(int severity,const char *fmt,...); void print_pdu(const char *label,unsigned char type,void *data, const int *length,const int *s,const int *ps,const int *r,const int *mr, const int *sq); int decompose_pdu(void *maa_arg,void *msg,int size,unsigned char *type, int *length,int *s,int *ps,int *r,int *mr,int *sq); #endif --- NEW FILE: queue.c --- /* queue.c - Quick and very very dirty buffer and queue handling */ /* Written 1995-1996 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <string.h> #include "atmd.h" #include "queue.h" BUFFER *buffer_create(int length,int key) { BUFFER *buf; buf = alloc_t(BUFFER); buf->data = alloc(length); buf->length = length; buf->key = key; return buf; } BUFFER *buffer_clone(BUFFER *b) { BUFFER *buf; buf = buffer_create(b->length,b->key); memcpy(buf->data,b->data,b->length); return buf; } void buffer_discard(BUFFER *b) { free(b->data); free(b); } void queue_init(QUEUE *q) { q->first = q->last = NULL; } void queue_put(QUEUE *q,BUFFER *b) { Q_INSERT_AFTER(q->first,b,q->last); q->last = b; } void queue_remove(QUEUE *q,BUFFER *b) { if (q->last == b) q->last = b->prev; Q_REMOVE(q->first,b); } BUFFER *queue_peek(QUEUE *q) { return q->first; } BUFFER *queue_get(QUEUE *q) { BUFFER *buf; buf = queue_peek(q); if (buf) queue_remove(q,buf); return buf; } BUFFER *queue_lookup(QUEUE *q,int key) { BUFFER *walk; for (walk = q->first; walk; walk = walk->next) if (walk->key == key) break; return walk; } void queue_clear(QUEUE *q) { BUFFER *next; while (q->first) { next = q->first->next; buffer_discard(q->first); q->first = next; } q->last = NULL; } --- NEW FILE: queue.h --- /* queue.h - Quick and very very dirty buffer and queue handling */ /* Written 1995-1996 by Werner Almesberger, EPFL-LRC */ #ifndef QUEUE_H #define QUEUE_H typedef struct _buffer { void *data; int length; /* TX buffer: of the entire PDU; RX buffer: of the data */ int key; /* SD.N(S) */ int extra; /* SD.N(PS) */ struct _buffer *next,*prev; } BUFFER; typedef struct { BUFFER *first,*last; } QUEUE; BUFFER *buffer_create(int length,int key); BUFFER *buffer_clone(BUFFER *b); void buffer_discard(BUFFER *b); void queue_init(QUEUE *q); void queue_put(QUEUE *q,BUFFER *b); void queue_remove(QUEUE *q,BUFFER *b); BUFFER *queue_peek(QUEUE *q); BUFFER *queue_get(QUEUE *q); BUFFER *queue_lookup(QUEUE *q,int key); void queue_clear(QUEUE *q); #endif --- NEW FILE: sscop.c --- /* sscop.c - SSCOP (Q.2110) protocol */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdint.h> #include <stdarg.h> #include <string.h> #include <netinet/in.h> /* for htonl */ #include "atmd.h" #include "sscop.h" #include "queue.h" #include "pdu.h" [...1690 lines suppressed...] { if (dsc->state != sscop_idle) diag(COMPONENT,DIAG_WARN,"stopping dsc in state %s", state_name[dsc->state]); dsc->state = sscop_idle; /* avoid send attempts */ STOP_TIMER(dsc->timer_cc); STOP_TIMER(dsc->timer_poll); STOP_TIMER(dsc->timer_noresp); STOP_TIMER(dsc->timer_keepalive); STOP_TIMER(dsc->timer_idle); queue_clear(&dsc->rx_buf); queue_clear(&dsc->tx_q); queue_clear(&dsc->tx_buf); queue_clear(&dsc->rt_q); if (dsc->last_bgn) buffer_discard(dsc->last_bgn); if (dsc->last_end) buffer_discard(dsc->last_end); if (dsc->last_rs) buffer_discard(dsc->last_rs); if (dsc->last_er) buffer_discard(dsc->last_er); if (dsc->list) free(dsc->list); } --- NEW FILE: sscop.h --- /* sscop.h - SSCOP (Q.2110) user interface */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef SSCOP_H #define SSCOP_H #include <stdint.h> #include "atmd.h" #include "queue.h" typedef enum { sscop_qsaal1, /* emulate some properties of Q.SAAL1 as specified for UNI 3.0 */ sscop_q2110 /* follow Q.2110 by the letter */ } SSCOP_MODE; typedef enum { sscop_idle,sscop_outconn,sscop_inconn,sscop_outdisc, sscop_outres,sscop_inres,sscop_outrec,sscop_recresp,sscop_inrec, sscop_ready } SSCOP_STATE; typedef struct { SSCOP_STATE state; struct _sscop_user_ops *ops; void *user; /* --- Configurable parameters ----------------------------------------- */ SSCOP_MODE mode; int cf_max_cc,cf_max_pd,cf_max_stat; int cf_timer_cc,cf_timer_poll,cf_timer_noresp,cf_timer_keepalive, cf_timer_idle; /* --- SSCOP information, TX part -------------------------------------- */ int vt_s; /* send sequence number */ int vt_ps; /* poll send sequence number */ int vt_a; /* acknowledge sequence number */ int vt_pa; /* poll sequence number */ int vt_ms; /* maximum send sequence */ int vt_pd; /* SD PDUs between POLL PDUs */ int vt_cc; /* number of unacknowledged BSG, END, ER or RS PDUs */ int vt_sq; /* connection number */ /* --- SSCOP information, RX part -------------------------------------- */ int vr_r; /* receiver sequence number */ int vr_h; /* highest expected SD PDU */ int vr_mr; /* maximum acceptable (receiver) */ int vr_sq; /* connection number */ int vr_ps; /* non-Q.2110: keeps N(PS) received in last POLL for STAT */ /* Other variables */ int clear_buffers; int credit; /* Timers */ TIMER *timer_cc,*timer_poll,*timer_noresp,*timer_keepalive,*timer_idle; /* Queues and buffers */ QUEUE tx_buf,tx_q,rx_buf,rt_q; BUFFER *last_bgn,*last_end,*last_rs,*last_er; /* for retransmission */ /* Misc items */ uint32_t *list; /* STAT construction list */ } SSCOP_DSC; /* * Note: UU data of primitives carrying such is only available if * - the "user" flag is set (if available) and * - uu_data is non-NULL, and * - uu_length is non-zero * in all other cases, uu_data must not be dereferenced. * * Note: the "ind" parameter in restart indicates whether the release primitive * is an AA-RELEASE.indication (ind = 1) or to an AA-RELEASE.confirm (ind = 0). */ typedef struct _sscop_user_ops { void (*estab_ind)(void *user_data,void *uu_data,int uu_length); /* AA-ESTABLISH.indication */ void (*estab_conf)(void *user_data,void *uu_data,int uu_length); /* AA-ESTABLISH.confirm */ void (*rel_ind)(void *user_data,void *uu_data,int uu_length,int user); /* AA-RELEASE.indication */ void (*rel_conf)(void *user_data); /* AA-RELEASE.confirm */ void (*restart)(void *user_data,void *uu_data,int uu_length,int ind); /* AA-RELEASE.indication or AA-RELEASE.confirm immediately followed by AA-ESTABLISH.indication */ void (*res_ind)(void *user_data,void *uu_data,int uu_length); /* AA-RESYNC.indication */ void (*res_conf)(void *user_data); /* AA-RESYNC.confirm */ void (*rec_ind)(void *user_data); /* AA-RECOVER.indication */ void (*data_ind)(void *user_data,void *data,int length,int sn); /* AA-DATA.indication */ void (*unitdata)(void *user_data,void *data,int length); /* AA-UNITDATA.indication */ void (*retr_ind)(void *user_data,void *data,int length); /* AA-RETRIEVE.indication */ void (*retr_comp)(void *user_data); /* AA-RETRIEVE_COMPLETE.indication */ void (*maa_data)(void *user_data,void *data,int length); /* MAA-UNITDATA.indication */ int (*maa_error)(void *user_data,char code,int count); /* MAA-ERROR.indication */ void (*cpcs_send)(void *user_data,void *data,int length); } SSCOP_USER_OPS; /* Attach/detach protocol */ void start_sscop(SSCOP_DSC *dsc,SSCOP_USER_OPS *ops,void *user_data, SSCOP_MODE _mode); /* gcc 2.7.2 firmly believes "mode" can shadow ... @%! */ void stop_sscop(SSCOP_DSC *dsc); /* Connection control */ void sscop_estab_req(SSCOP_DSC *dsc,void *uu_data,int uu_length,int buf_rel); /* AA-ESTABLISH.request */ void sscop_estab_resp(SSCOP_DSC *dsc,void *uu_data,int uu_length,int buf_rel); /* AA-ESTABLISH.response */ void sscop_rel_req(SSCOP_DSC *dsc,void *uu_data,int uu_length); /* AA-RELEASE.request */ void sscop_res_req(SSCOP_DSC *dsc,void *uu_data,int uu_length); /* AA-RESYNC.request */ void sscop_res_resp(SSCOP_DSC *dsc); /* AA-RESYNC.response */ void sscop_rec_resp(SSCOP_DSC *dsc); /* AA-RECOVER.response */ /* Incoming PDU from lower layer */ void sscop_pdu(SSCOP_DSC *dsc,void *msg,int size); /* CPCS-UNITDATA.request */ /* Send data */ void sscop_send(SSCOP_DSC *dsc,void *buffer,int size); /* AA-DATA.request, 20.38 */ void sscop_unitdata(SSCOP_DSC *dsc,void *buffer,int size); /* AA-UNIDATA.request, 20.47 */ void sscop_maa_data(SSCOP_DSC *dsc,void *buffer,int size); /* MAA-UNITDATA.request, 20.47 */ /* Retrieve unsent data */ #define SSCOP_RN_UNKNOWN -2 /* -1 is (theoretically) a valid rn ... */ #define SSCOP_RN_TOTAL -3 void sscop_retrieve(SSCOP_DSC *dsc,int rn); /* AA-RETRIEVE.request */ #endif --- NEW FILE: Makefile.am --- noinst_LIBRARIES = libsaal.a libsaal_a_SOURCES = pdu.h queue.h saal.h sscf.h sscop.h pdu.c queue.c saal.c \ sscf.c sscop.c --- NEW FILE: saal.c --- /* saal.c - SAAL = SSCF+SSCOP */ /* Written 1995 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include "sscop.h" #include "saal.h" void saal_pdu(SAAL_DSC *dsc,void *buffer,int length) { sscop_pdu(&dsc->sscop,buffer,length); } --- NEW FILE: saal.h --- /* saal.h - SAAL user interface */ /* Written 1995 by Werner Almesberger, EPFL-LRC */ #ifndef SAAL_H #define SAAL_H #include "sscf.h" #include "sscop.h" #define SAAL_DSC SSCF_DSC #define SAAL_USER_OPS SSCF_USER_OPS #define start_saal start_sscf #define stop_saal stop_sscf #define saal_estab_req sscf_estab_req #define saal_rel_req sscf_rel_req #define saal_send sscf_send #define saal_unitdata sscf_unitdata void saal_pdu(SAAL_DSC *dsc,void *buffer,int length); #endif --- NEW FILE: sscf.c --- /* sscf.c - SSCF (Q.2130) protocol */ /* Written 1995,1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include "atmd.h" #include "sscop.h" #include "sscf.h" #define COMPONENT "SSCF" /* --- SSCOP configuration ------------------------------------------------- */ #define SSCF_MaxCC 4 /* give up after 4 retries */ #define SSCF_MaxPD 25 /* POLL after 25 SDs */ #define SSCF_Timer_CC 1000000 /* 1 sec */ #define SSCF_Timer_KEEPALIVE 2000000 /* 2 sec */ #define SSCF_Timer_NORESP 7000000 /* 7 sec */ #define SSCF_Timer_POLL 750000 /* 750 ms */ #define SSCF_Timer_IDLE 15000000 /* 15 sec */ static const char *state_name[] = { "1/2","2/2","4/10","3/4","2/5" }; /* --- Helper function(s) -------------------------------------------------- */ static void next_state(SSCF_DSC *dsc,SSCF_STATE state) { diag(COMPONENT,DIAG_DEBUG,"entering state %s",state_name[state]); dsc->state = state; } /* --- Invocation from SSCOP ----------------------------------------------- */ static void sscf_estab_ind(void *user_data,void *uu_data,int uu_length) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_11) diag(COMPONENT,DIAG_FATAL,"sscf_estab_ind in state %s", state_name[dsc->state]); next_state(dsc,sscf_410); sscop_estab_resp(&dsc->sscop,NULL,0,1); if (dsc->ops->estab_ind) dsc->ops->estab_ind(dsc->user,uu_data,uu_length); } static void sscf_estab_conf(void *user_data, void *uu_data,int uu_length) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_22) diag(COMPONENT,DIAG_FATAL,"sscf_estab_conf in state %s", state_name[dsc->state]); next_state(dsc,sscf_410); if (dsc->ops->estab_conf) dsc->ops->estab_conf(dsc->user,uu_data,uu_length); } static void sscf_restart(void *user_data,void *uu_data,int uu_length,int ind) { SSCF_DSC *dsc = user_data; if ((!ind && dsc->state != sscf_34) || (ind && (dsc->state == sscf_11 || dsc->state == sscf_34))) diag(COMPONENT,DIAG_FATAL,"sscf_restart (ind = %d) in state %s", state_name[dsc->state],ind); sscop_estab_resp(&dsc->sscop,NULL,0,1); next_state(dsc,sscf_410); if (dsc->ops->restart) dsc->ops->restart(dsc->user,uu_data,uu_length,ind); } static void sscf_rec_ind(void *user_data) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_410) diag(COMPONENT,DIAG_FATAL,"sscf_rec_ind in state %s", state_name[dsc->state]); sscop_rec_resp(&dsc->sscop); if (dsc->ops->estab_ind) dsc->ops->estab_ind(dsc->user,NULL,0); } static void sscf_rel_ind(void *user_data,void *uu_data,int uu_length,int user) { SSCF_DSC *dsc = user_data; if (dsc->state == sscf_11 || dsc->state == sscf_34) diag(COMPONENT,DIAG_FATAL,"sscf_rel_ind in state %s", state_name[dsc->state]); next_state(dsc,sscf_11); if (dsc->ops->rel_ind) dsc->ops->rel_ind(dsc->user,user ? uu_data : NULL,uu_length); } static void sscf_rel_conf(void *user_data) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_34) diag(COMPONENT,DIAG_FATAL,"sscf_rel_conf in state %s", state_name[dsc->state]); next_state(dsc,sscf_11); if (dsc->ops->rel_conf) dsc->ops->rel_conf(dsc->user); } static void sscf_data_ind(void *user_data,void *data,int length,int sn) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_410) diag(COMPONENT,DIAG_FATAL,"sscf_data_ind in state %s", state_name[dsc->state]); if (dsc->ops->data_ind) dsc->ops->data_ind(dsc->user,data,length); } static void sscf_res_ind(void *user_data,void *uu_data,int uu_length) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_410) diag(COMPONENT,DIAG_FATAL,"sscf_res_ind in state %s", state_name[dsc->state]); sscop_res_resp(&dsc->sscop); if (dsc->ops->estab_ind) dsc->ops->estab_ind(dsc->user,uu_data,uu_length); } static void sscf_res_conf(void *user_data) { SSCF_DSC *dsc = user_data; if (dsc->state != sscf_25) diag(COMPONENT,DIAG_FATAL,"sscf_res_conf in state %s", state_name[dsc->state]); next_state(dsc,sscf_410); if (dsc->ops->estab_conf) dsc->ops->estab_conf(dsc->user,NULL,0); } static void sscf_unitdata_ind(void *user_data,void *data,int length) { SSCF_DSC *dsc = user_data; if (dsc->ops->unitdata) dsc->ops->unitdata(dsc->user,data,length); } static void sscf_cpcs_send(void *user_data,void *data,int length) { SSCF_DSC *dsc = user_data; if (dsc->ops->cpcs_send) dsc->ops->cpcs_send(dsc->user,data,length); } static SSCOP_USER_OPS sscf_ops = { sscf_estab_ind, * sscf_estab_conf, * sscf_rel_ind, * sscf_rel_conf, * sscf_restart, sscf_res_ind, sscf_res_conf, sscf_rec_ind, sscf_data_ind, sscf_unitdata_ind, NULL, /* no retr_ind */ NULL, /* no retr_comp */ NULL, /* no maa_data */ NULL, /* no maa_error */ sscf_cpcs_send }; /* --- Invocation from user ------------------------------------------------ */ void start_sscf(SSCF_DSC *dsc,SSCF_USER_OPS *ops,void *user_data, SSCOP_MODE mode) { dsc->state = sscf_11; dsc->ops = ops; dsc->user = user_data; start_sscop(&dsc->sscop,&sscf_ops,dsc,mode); dsc->sscop.cf_max_cc = SSCF_MaxCC; dsc->sscop.cf_max_pd = SSCF_MaxPD; dsc->sscop.cf_timer_cc = SSCF_Timer_CC; dsc->sscop.cf_timer_poll = SSCF_Timer_POLL; dsc->sscop.cf_timer_noresp = SSCF_Timer_NORESP; dsc->sscop.cf_timer_keepalive = SSCF_Timer_KEEPALIVE; dsc->sscop.cf_timer_idle = SSCF_Timer_IDLE; } void stop_sscf(SSCF_DSC *dsc) { stop_sscop(&dsc->sscop); } void sscf_estab_req(SSCF_DSC *dsc,void *uu_data,int uu_length) { switch (dsc->state) { case sscf_11: case sscf_34: next_state(dsc,sscf_22); sscop_estab_req(&dsc->sscop,uu_data,uu_length,1); return; case sscf_410: next_state(dsc,sscf_25); sscop_res_req(&dsc->sscop,uu_data,uu_length); return; default: break; } diag(COMPONENT,DIAG_FATAL,"sscf_estab_req invoked in state %s", state_name[dsc->state]); } void sscf_rel_req(SSCF_DSC *dsc,void *uu_data,int uu_length) { switch (dsc->state) { case sscf_11: if (dsc->ops->rel_conf) dsc->ops->rel_conf(dsc->user); return; case sscf_22: case sscf_410: case sscf_25: next_state(dsc,sscf_34); sscop_rel_req(&dsc->sscop,uu_data,uu_length); return; default: break; } diag(COMPONENT,DIAG_FATAL,"sscf_rel_req invoked in state %s", state_name[dsc->state]); } void sscf_send(SSCF_DSC *dsc,void *data,int length) { switch (dsc->state) { case sscf_11: return; case sscf_410: sscop_send(&dsc->sscop,data,length); return; default: break; } diag(COMPONENT,DIAG_WARN,"sscf_send invoked in state %s", state_name[dsc->state]); /* make fatal later @@@ */ } void sscf_unitdata(SSCF_DSC *dsc,void *data,int length) { sscop_unitdata(&dsc->sscop,data,length); } --- NEW FILE: sscf.h --- /* sscf.h - SSCF (Q.2130) user interface */ /* Written 1995,1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef SSCF_H #define SSCF_H #include "sscop.h" typedef enum { sscf_11,sscf_22,sscf_410,sscf_34,sscf_25 } SSCF_STATE; typedef struct { SSCF_STATE state; struct _sscf_user_ops *ops; void *user; SSCOP_DSC sscop; } SSCF_DSC; typedef struct _sscf_user_ops { void (*estab_ind)(void *user_data,void *uu_data,int uu_length); /* AAL-ESTABLISH.indication */ void (*estab_conf)(void *user_data,void *uu_data,int uu_length); /* AAL-ESTABLISH.confirm */ void (*rel_ind)(void *user_data,void *uu_data,int uu_length); /* AAL-RELEASE.indication */ void (*rel_conf)(void *user_data); /* AAL-RELEASE.confirm */ void (*restart)(void *user_data,void *uu_data,int uu_length,int ind); /* AAL-RELEASE.indication or AAL-RELEASE.confirm immediately followed by AAL-ESTABLISH.indication */ void (*data_ind)(void *user_data,void *data,int length); /* AAL-DATA.indication */ void (*unitdata)(void *user_data,void *data,int length); /* AAL-UNITDATA.indication */ void (*cpcs_send)(void *user_data,void *data,int length); } SSCF_USER_OPS; /* Attach/detach protocol */ void start_sscf(SSCF_DSC *dsc,SSCF_USER_OPS *ops,void *user_data, SSCOP_MODE _mode); /* gcc 2.7.2 firmly believes "mode" can shadow ... @%! */ void stop_sscf(SSCF_DSC *dsc); /* Connection control */ void sscf_estab_req(SSCF_DSC *dsc,void *uu_data,int uu_length); void sscf_rel_req(SSCF_DSC *dsc,void *uu_data,int uu_length); /* Send data */ void sscf_send(SSCF_DSC *dsc,void *data,int length); void sscf_unitdata(SSCF_DSC *dsc,void *data,int length); #endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:09
|
Update of /cvsroot/linux-atm/linux-atm/src/qgen In directory usw-pr-cvs1:/tmp/cvs-serv10656/qgen Added Files: Tag: V2_4_0 TODO op.h qtest.c uni.h first.c third.c mknl.pl common.c common.h file.c file.h Makefile.am msg.fmt second.c qgen.c qgen.h ql_l.l ql_y.y qlib.c qlib.h incl.pl Log Message: --- NEW FILE: TODO --- - handle repeated IEs - q_assign should remove old value (i.e. zero destination) - bit numbering is wrong; should be <size@high> - should be library (well, need at least more flexible name selection) - copies of adjacent fields should be merged - copies of partial bytes should be byte-wide if rest is only zeroes - should be able to have multiple selectors in one byte - case/default needs better compile-time check - parser shouldn't copy unnamed fields - optimize - code needs a lot of cleaning Restrictions ------------ - there's only very limited error checking - no support for arrays (repeated IEs) - copy operations are not optimized --- NEW FILE: op.h --- /* op.h - message processor opcodes */ /* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ #ifndef OP_H #define OP_H /* construction */ #define OP_INVALID 0 /* crash here */ #define OP_COPY 1 /* copy <jump>,<src>,<size> */ #define OP_COPYVAR 2 /* copy <index>,<src>,<maxsize(bytes)> */ #define OP_BEGIN_LEN 3 /* begin_length <jump>,<src>,<size> */ #define OP_END_LEN 4 /* end_length */ #if 0 #define OP_CASE 4 /* case <groups>, { <group>,<offset>,... { <op>,..., jump }, ... } */ #endif #define OP_JUMP 5 /* jump <addr> */ #define OP_END 6 /* end */ #define OP_IFGROUP 7 /* ifgroup <group>,<jump> */ /* parsing */ #define OP_MULTI 8 /* multi <size>,case,... */ #define OP_CASE 9 /* case <jump>,<src>,<size>,<groups>, { <pattern>, <group>,<offset>,... { <op>,...,jump }, ... } */ #define OP_IFEND 10 /* ifend <addr> */ #define OP_DUMP 11 /* dump <index>; dumper only */ #define OP_BEGIN_REC 12 /* begin_recovery <id>,<group>,<addr> */ #define OP_END_REC 13 /* end_recovery */ #define OP_ABORT 14 /* abort <id> */ #endif --- NEW FILE: qtest.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> int main(void) { int error,i,j,u; error = 0; for (i = 0; fields[i]; i++) for (j = i+1; fields[j]; j++) if (!strcmp(fields[i],fields[j])) { fprintf(stderr,"collision: field \"%s\"\n",fields[i]); error = 1; } for (i = 0; groups[i]; i++) for (j = i+1; groups[j]; j++) if (!strcmp(groups[i],groups[j])) { fprintf(stderr,"collision: group \"%s\"\n",groups[i]); error = 1; } for (u = 0; unique[u]; u++) for (i = 0; unique[u][i] != -1; i++) for (j = i+1; unique[u][j] != -1; j++) if (unique[u][i] == unique[u][j]) { fprintf(stderr,"collision: value %d in collection %d\n", unique[u][i],u); error = 1; } return error; } --- NEW FILE: uni.h --- /* uni.h - Various Q.2931/Q.2971/Q.2963.1/UNI 3.x/UNI 4.0 constants */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ /* * Note: some values don't appear in UNI 3.0 or 3.1 but are taken from Q.2931 * and related ITU documents. */ #ifndef UNI_H #define UNI_H /* Maximum message size */ #define MAX_Q_MSG 1000 /* Protocol discriminator */ #define Q2931_PROTO_DSC 9 /* Q.2931 user-network call/connection control message */ /* Coding Standards */ #define Q2931_CS_ITU 0 /* ITU-T standardized */ #define Q2931_CS_NET 3 /* Standard defined for the network */ /* Message types */ #define ATM_MSG_NATIONAL 0x00 /* National specific message escape */ #define ATM_MSG_SETUP 0x05 /* SETUP */ #define ATM_MSG_ALERTING 0x01 /* ALERTING */ #define ATM_MSG_CALL_PROC 0x02 /* CALL PROCEEDING */ #define ATM_MSG_CONNECT 0x07 /* CONNECT */ #define ATM_MSG_CONN_ACK 0x0f /* CONNECT ACKNOWLEDGE */ #define ATM_MSG_RESTART 0x46 /* RESTART */ #define ATM_MSG_RELEASE 0x4d /* RELEASE */ #define ATM_MSG_REST_ACK 0x4e /* RESTART ACKNOWLEDGE */ #define ATM_MSG_REL_COMP 0x5a /* RELEASE COMPLETE */ #define ATM_MSG_NOTIFY 0x6e /* NOTIFY */ #define ATM_MSG_STATUS_ENQ 0x75 /* STATUS ENQUIRY */ #define ATM_MSG_STATUS 0x7d /* STATUS */ #define ATM_MSG_ADD_PARTY 0x80 /* ADD PARTY */ #define ATM_MSG_ADD_PARTY_ACK 0x81 /* ADD PARTY ACKNOWLEDGE */ #define ATM_MSG_ADD_PARTY_REJ 0x82 /* ADD PART REJECT */ #define ATM_MSG_PARTY_ALERT 0x85 /* PARTY ALERTING */ #define ATM_MSG_DROP_PARTY 0x83 /* DROP PARTY */ #define ATM_MSG_DROP_PARTY_ACK 0x84 /* DROP PARTY ACKNOWLEDGE */ #define ATM_MSG_MODIFY_REQ 0x88 /* MODIFY REQUEST */ #define ATM_MSG_MODIFY_ACK 0x89 /* MODIFY ACKNOWLEDGE */ #define ATM_MSG_MODIFY_REJ 0x8a /* MODIFY REJECT */ #define ATM_MSG_CONN_AVAIL 0x8b /* CONNECTION AVAILABLE */ #define ATM_MSG_LEAF_FAILURE 0x90 /* LEAF SETUP FAILURE */ #define ATM_MSG_LEAF_REQUEST 0x91 /* LEAF SETUP REQUEST */ #define ATM_MSG_RESERVED 0xff /* reserved for EVEN MORE msg types */ /* Information element identifiers */ #define ATM_IE_CAUSE 0x08 /* Cause */ #define ATM_IE_CALL_STATE 0x14 /* Call state */ #define ATM_IE_NOTIFY 0x27 /* Notification indicator */ #define ATM_IE_E2E_TDL 0x42 /* End-to-end transit delay */ #define ATM_IE_EPR 0x54 /* Endpoint reference */ #define ATM_IE_EP_STATE 0x55 /* Endpoint state */ #define ATM_IE_AAL 0x58 /* ATM adaption layer parameters */ #define ATM_IE_TD 0x59 /* ATM traffic descriptor */ #define ATM_IE_CONN_ID 0x5a /* Connection identifier */ #define ATM_IE_OAM_TD 0x5b /* OAM traffic descriptor */ #define ATM_IE_QOS 0x5c /* Quality of service parameter */ #define ATM_IE_BHLI 0x5d /* Broadband high layer information */ #define ATM_IE_BBCAP 0x5e /* Broadband bearer capability */ #define ATM_IE_BLLI 0x5f /* Broadband low-layer information */ #define ATM_IE_BBS_COMP 0x62 /* Broadband sending complete */ #define ATM_IE_BBREP 0x63 /* Broadband repeat indicator */ #define ATM_IE_CGPN 0x6c /* Calling party number */ #define ATM_IE_CGPS 0x6d /* Calling party subaddress */ #define ATM_IE_CDPN 0x70 /* Called party number */ #define ATM_IE_CDPS 0x71 /* Called party subaddress */ #define ATM_IE_TNS 0x78 /* Transit network selection */ #define ATM_IE_RESTART 0x79 /* Restart indicator */ #define ATM_IE_GIT 0x7f /* Generic identifier transport */ #define ATM_IE_ALT_TD 0x81 /* Alternate ATM traffic descriptor */ #define ATM_IE_MIN_TD 0x80 /* Minimum acceptable ATM traffic desc. */ #define ATM_IE_ABR_SET_PRM 0x84 /* ABR setup parameters */ #define ATM_IE_BBRT 0x89 /* Broadband report type */ #define ATM_IE_ABR_ADD_PRM 0xe4 /* ABR additional parameters */ #define ATM_IE_LIJ_ID 0xe8 /* Leaf initiated join call identifer */ #define ATM_IE_LIJ_PRM 0xe9 /* Leaf initiated join parameters */ #define ATM_IE_LEAF_SN 0xea /* Leaf sequence number */ #define ATM_IE_SCOPE_SEL 0xeb /* Connection Scope Selection */ #define ATM_IE_EQOS 0xec /* Extended QOS parameters */ /* Cause: Location */ #define ATM_LOC_USER 0 /* user */ #define ATM_LOC_PRV_LOC 1 /* private network serving the local user */ #define ATM_LOC_PUB_LOC 2 /* public network serving the local user */ #define ATM_LOC_TRANS_NET 3 /* transit network */ #define ATM_LOC_PRV_RMT 4 /* public network serving the remote user */ #define ATM_LOC_PUB_RMT 5 /* private network serving the remote user */ #define ATM_LOC_INT_NET 7 /* international network */ #define ATM_LOC_BEYOND_IWP 10 /* network beyond interworking point */ /* Cause: Cause values */ /* ----------------------------------- normal event */ #define ATM_CV_UNALLOC 1 /* unallocated (unassigned) number */ #define ATM_CV_NO_ROUTE_TNS 2 /* no route to specified transit network */ #define ATM_CV_NO_ROUTE_DEST 3 /* no route to destination */ #if defined(UNI30) || defined(DYNAMIC_UNI) #define ATM_CV_CI_UNACC 10 /* VPCI/VCI unacceptable */ #endif #if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI) #define ATM_CV_NORMAL_CLEAR 16 /* normal call clearing */ #endif #define ATM_CV_USER_BUSY 17 /* user busy */ #define ATM_CV_NO_USER_RESP 18 /* no user responding */ #define ATM_CV_CALL_REJ 21 /* call rejected */ #define ATM_CV_NUM_CHANGED 22 /* number changed */ #define ATM_CV_REJ_CLIR 23 /* user rejects all calls with calling line identification restriction (CLIR)*/ #define ATM_CV_DEST_OOO 27 /* destination out of order */ #define ATM_CV_INV_NUM_FMT 28 /* invalid number format (address incomplete) */ #define ATM_CV_RESP_STAT_ENQ 30 /* response to STATUS ENQUIRY */ #define ATM_CV_NORMAL_UNSPEC 31 /* normal, unspecified */ /* ----------------------------------- resource unavailable */ #define ATM_CV_CI_UNAVAIL 35 /* requested VPCI/VCI unavailable */ #if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI) #define ATM_CV_CI_FAIL 36 /* VPCI/VCI assignment failure */ #define ATM_CV_UCR_UNAVAIL_NEW 37 /* user cell rate not available (>3.0)*/ #endif #define ATM_CV_NET_OOO 38 /* network out of order - unused */ #define ATM_CV_TEMP_FAIL 41 /* temporary failure */ #define ATM_CV_ACC_INF_DISC 43 /* access information discarded */ #define ATM_CV_NO_CI 45 /* no VPCI/VCI available */ #define ATM_CV_RES_UNAVAIL 47 /* resource unavailable, unspecified */ /* ----------------------------------- service or option not available */ #define ATM_CV_QOS_UNAVAIL 49 /* Quality of Service unavailable */ #if defined(UNI30) || defined(ALLOW_UNI30) || defined(DYNAMIC_UNI) #define ATM_CV_UCR_UNAVAIL_OLD 51 /* user cell rate not available (3.0) */ #endif #define ATM_CV_BBCAP_NOT_AUTH 57 /* bearer capability not authorized */ #define ATM_CV_BBCAP_UNAVAIL 58 /* bearer capability not presently available */ #define ATM_CV_UNAVAILABLE 63 /* service or option not available, unspecified */ /* ----------------------------------- service or option not implemented */ #define ATM_CV_BBCAP_NOT_IMPL 65 /* bearer capability not implemented */ #define ATM_CV_UNSUPP_TRAF_PRM 73 /* unsupported combination of traffic parameters */ #if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI) #define ATM_CV_AAL_UNSUPP_NEW 78 /* AAL param. cannot be supported (>3.0) */ #endif /* ----------------------------------- invalid message */ #define ATM_CV_INV_CR 81 /* invalid call reference value */ #define ATM_CV_NO_SUCH_CHAN 82 /* identified channel does not exist */ #define ATM_CV_INCOMP_DEST 88 /* incompatible destination */ #define ATM_CV_INV_EPR 89 /* invalid endpoint reference */ #define ATM_CV_INV_TNS 91 /* invalid transit network selection */ #define ATM_CV_TOO_MANY_APR 92 /* too many pending add party requests */ #if defined(UNI30) || defined(DYNAMIC_UNI) #define ATM_CV_AAL_UNSUPP_OLD 93 /* AAL param. cannot be supported (3.0) */ #endif /* ----------------------------------- protocol error */ #define ATM_CV_MAND_IE_MISSING 96 /* mandatory information element is missing */ #define ATM_CV_UNKNOWN_MSG_TYPE 97 /* message type non-existent or not implemented */ #define ATM_CV_UNKNOWN_IE 99 /* information element non-existent or not implemented */ #define ATM_CV_INVALID_IE 100 /* invalid information element contents */ #define ATM_CV_INCOMP_MSG 101 /* message not compatible with call state*/ #define ATM_CV_TIMER_EXP 102 /* recovery on timer expiry */ #define ATM_CV_BAD_MSG_LEN 104 /* incorrect message length */ #define ATM_CV_PROTOCOL_ERROR 111 /* protocol error, unspecified */ /* Cause: P-U values */ #define ATM_PU_PROVIDER 0 /* Network service - Provider */ #define ATM_PU_USER 1 /* Network service - User */ /* Cause: N-A values */ #define ATM_NA_NORMAL 0 /* Normal */ #define ATM_NA_ABNORMAL 1 /* Abnormal */ /* Cause: Condition */ #define ATM_COND_UNKNOWN 0 /* Unknown */ #define ATM_COND_PERMANENT 1 /* Permanent */ #define ATM_COND_TRANSIENT 2 /* Transient */ /* Cause: Reject reason */ #define ATM_RSN_USER 0 /* User specific */ #define ATM_RSN_IE_MISS 1 /* Information element missing */ #define ATM_RSN_IE_INSUFF 2 /* Information element contents are not sufficient */ /* Restart Indicator class values */ #define ATM_RST_IND_VC 0 /* Indicated virtual channel */ #define ATM_RST_ALL_VC 2 /* All virtual channels controlled by the Layer 3 entity which sends the RESTART message */ /* Action Indicator for messages */ #define ATM_AI_MSG_CLEAR 0 /* clear call */ #define ATM_AI_MSG_DSC_IGN 1 /* discard and ignore */ #define ATM_AI_MSG_DSC_STAT 2 /* discard and report status */ #define ATM_AI_MSG_RSV 3 /* reserved */ /* Action Indicator for IEs */ #define ATM_AI_IE_CLEAR 0 /* clear call */ #define ATM_AI_IE_DSCIE_PRC 1 /* discard IE and proceed */ #define ATM_AI_IE_DSCIE_STAT 2 /* discard IE, procees, and report status */ #define ATM_AI_IE_DSCMSG_IGN 5 /* discard message, and ignore */ #define ATM_AI_IE_DSCMSG_STAT 6 /* discard message, and report status */ /* Type of number */ #define ATM_TON_UNKNOWN 0 /* unknown */ #define ATM_TON_INTRNTNL 1 /* international number */ #define ATM_TON_NATIONAL 2 /* national number */ #define ATM_TON_NETWORK 3 /* network specific number */ #define ATM_TON_SUBSCRIBER 4 /* subscriber number */ #define ATM_TON_ABBRV 6 /* abbreviated number */ /* Numbering/addressing plan */ #define ATM_NP_UNKNOWN 0 /* unknown */ #define ATM_NP_E164 1 /* ISDN numbering plan (E.164) */ #define ATM_NP_AEA 2 /* ATM endsystem address */ #define ATM_NP_PRIVATE 9 /* private numbering plan */ /* Type of sub-address */ #define ATM_SAT_NSAP 0 /* NSAP (Rec. X.213 ISO/IEC 8348) */ #define ATM_SAT_AEA 1 /* ATM endsystem address */ #define ATM_SAT_USER 2 /* user-specified */ /* Presentation indicator */ #define ATM_PRS_ALLOW 0 /* presentation allowed */ #define ATM_PRS_RESTRICT 1 /* presentation restricted */ #define ATM_PRS_NOTAVL 2 /* number not available */ /* Screening indicator */ #define ATM_SCRN_UP_NS 0 /* user-provided, not screened */ #define ATM_SCRN_UP_VP 1 /* user-provided, verified and passed */ #define ATM_SCRN_UP_VF 2 /* user-provided, verified and failed */ #define ATM_SCRN_NP 3 /* network provided */ /* VP-associated signalling */ #define ATM_VPA_VPA 0 /* VP-associated signalling */ #define ATM_VPA_EXPL 1 /* explicit indication of VPCI */ /* Preferred/exclusive */ #define ATM_POE_EXC_EXC 0 /* exclusive VPCI; exclusive VCI */ #define ATM_POE_EXC_ANY 1 /* exclusive VPCI; any VCI */ #if defined(UNI40) || defined(DYNAMIC_UNI) #define ATM_POE_EXC_NO 2 /* exclusive VPCI; no VCI (used for VPCs) */ #endif /* Traffic descriptor tags */ #define ATM_TD_FW_PCR_0 0x82 /* Forward peak cell rate (CLP=0) */ #define ATM_TD_BW_PCR_0 0x83 /* Backward peak cell rate (CLP=0) */ #define ATM_TD_FW_PCR_01 0x84 /* Forward peak cell rate (CLP=0+1) */ #define ATM_TD_BW_PCR_01 0x85 /* Backward peak cell rate (CLP=0+1) */ #define ATM_TD_FW_SCR_0 0x88 /* Forward sustained cell rate (CLP=0) */ #define ATM_TD_BW_SCR_0 0x89 /* Backward sustained cell rate (CLP=0) */ #define ATM_TD_FW_SCR_01 0x90 /* Forward sustained cell rate (CLP=0+1) */ #define ATM_TD_BW_SCR_01 0x91 /* Backward sustained cell rate (CLP=0+1)*/ #define ATM_TD_FW_MCR_01 0x92 /* Forward ABR min. cell rate (CLP=0+1) */ #define ATM_TD_BW_MCR_01 0x93 /* Backward ABR min. cell rate (CLP=0+1) */ #define ATM_TD_FW_MBS_0 0xa0 /* Forward maximum burst size (CLP=0) */ #define ATM_TD_BW_MBS_0 0xa1 /* Backward maximum burst size (CLP=0) */ #define ATM_TD_FW_MBS_01 0xb0 /* Forward maximum burst size (CLP=0+1) */ #define ATM_TD_BW_MBS_01 0xb1 /* Backward maximum burst size (CLP=0+1) */ #define ATM_TD_BEST_EFFORT 0xbe /* Best effort indicator */ #define ATM_TD_TM_OPT 0xbf /* Traffic management options */ /* Frame discard forward/backward */ #define ATM_FD_NO 0 /* No Frame discard allowed */ #define ATM_FD_YES 1 /* Frame discard allowed */ /* Tagging forward/backward */ #define ATM_TAG_NO 0 /* Tagging not requested */ #define ATM_TAG_YES 1 /* Tagging requested */ /* Bearer class */ #define ATM_BC_BCOB_A 1 /* BCOB-A */ #define ATM_BC_BCOB_C 3 /* BCOB-C */ #define ATM_BC_BCOB_X 16 /* BCOB-X */ #define ATM_BC_TVP 24 /* Transparent VP service */ /* ATM Transfer Capability */ #define ATM_TC_CBR 0x05 /* CBR */ #define ATM_TC_CBR_CLR 0x07 /* CBR with CLR commitment on CLP=0+1 */ #define ATM_TC_VBR_RT 0x09 /* Real time VBR */ #define ATM_TC_VBR_RT_CLR 0x13 /* Real time VBR w/ CLR comm. on CLP=0+1 */ #define ATM_TC_VBR_NRT 0x0a /* Non-real time VBR */ #define ATM_TC_VBR_NRT_CLR 0x0b /* Non-real time VBR w/ CLR com. CLP=0+1 */ #define ATM_TC_ABR 0x0c /* ABR */ #define ATM_TC_VBR_NRT_R00 0x00 /* Non-real time VBR (reception only) */ #define ATM_TC_VBR_RT_R01 0x01 /* Real time VBR (reception only) */ #define ATM_TC_VBR_NRT_R02 0x02 /* Non-real time VBR (reception only) */ #define ATM_TC_CBR_R04 0x04 /* CBR (reception only) */ #define ATM_TC_CBR_R06 0x06 /* CBR (reception only) */ #define ATM_TC_VBR_NRT_R08 0x08 /* Non-real time VBR (reception only) */ #define ATM_TC_RSV_20 0x20 /* Reserved for backward compatibility */ #define ATM_TC_RSV_21 0x21 /* Reserved for backward compatibility */ #define ATM_TC_RSV_22 0x22 /* Reserved for backward compatibility */ #define ATM_TC_RSV_24 0x24 /* Reserved for backward compatibility */ #define ATM_TC_RSV_25 0x25 /* Reserved for backward compatibility */ #define ATM_TC_RSV_26 0x26 /* Reserved for backward compatibility */ #define ATM_TC_RSV_28 0x28 /* Reserved for backward compatibility */ #define ATM_TC_RSV_29 0x29 /* Reserved for backward compatibility */ #define ATM_TC_RSV_2A 0x2a /* Reserved for backward compatibility */ #define ATM_TC_RSV_40 0x40 /* Reserved for backward compatibility */ #define ATM_TC_RSV_41 0x41 /* Reserved for backward compatibility */ #define ATM_TC_RSV_42 0x42 /* Reserved for backward compatibility */ #define ATM_TC_RSV_44 0x44 /* Reserved for backward compatibility */ #define ATM_TC_RSV_45 0x45 /* Reserved for backward compatibility */ #define ATM_TC_RSV_46 0x46 /* Reserved for backward compatibility */ #define ATM_TC_RSV_48 0x48 /* Reserved for backward compatibility */ #define ATM_TC_RSV_49 0x49 /* Reserved for backward compatibility */ #define ATM_TC_RSV_4A 0x4a /* Reserved for backward compatibility */ #define ATM_TC_RSV_60 0x60 /* Reserved for backward compatibility */ #define ATM_TC_RSV_61 0x61 /* Reserved for backward compatibility */ #define ATM_TC_RSV_62 0x62 /* Reserved for backward compatibility */ #define ATM_TC_RSV_64 0x64 /* Reserved for backward compatibility */ #define ATM_TC_RSV_65 0x65 /* Reserved for backward compatibility */ #define ATM_TC_RSV_66 0x66 /* Reserved for backward compatibility */ #define ATM_TC_RSV_68 0x68 /* Reserved for backward compatibility */ #define ATM_TC_RSV_69 0x69 /* Reserved for backward compatibility */ #define ATM_TC_RSV_6A 0x6a /* Reserved for backward compatibility */ #ifdef OBSOLETE_DEFINITIONS_FOLLOW /* Traffic type */ ATM_TT_NO_IND 0 /* no indication */ ATM_TT_CBR 1 /* constant bit rate */ ATM_TT_VBR 2 /* variable bit rate */ /* Timing requirements */ ATM_TR_NO_IND 0 /* no indication */ ATM_TR_E2E_REQ 1 /* end-to-end timing required */ ATM_TR_E2E_NRQ 2 /* end-to-end timing not required */ #endif /* Susceptibility to clipping */ #define ATM_STC_NO 0 /* not susceptible to clipping */ #define ATM_STC_YES 1 /* susceptible to clipping */ /* User-plane connection configuration */ #define ATM_UPCC_P2P 0 /* point-to-point */ #define ATM_UPCC_P2M 1 /* point-to-multipoint */ /* Instruction field flags */ #define ATM_FLAG_NO 0 /* instruction field not significant */ #define ATM_FLAG_YES 1 /* follow explicit instructions */ /* AAL parameter tags */ #define ATM_AALP_FW_MAX_SDU 0x8c /* Forward maximum CPCS-SDU size */ #define ATM_AALP_BW_MAX_SDU 0x81 /* Backward maximum CPCS-SDU size */ #define ATM_AALP_AAL_MODE 0x83 /* AAL mode (UNI 3.0 only) */ #define ATM_AALP_SSCS 0x84 /* SSCS type */ /* Transit delay identifiers */ #define ATM_TDL_CUM 0x01 /* Cumulative transit delay value */ #define ATM_TDL_E2EMAX 0x03 /* Maximum end-to-end transit delay value*/ #define ATM_TDL_NGI 0x06 /* Network generated indicator */ /* Transit network identification */ #define ATM_TNI_USER 0x00 /* User-specified */ #define ATM_TNI_NNI 0x02 /* National network identification */ #define ATM_TNI_INI 0x04 /* International network identification */ /* Network identification plan */ #define ATM_NIP_UNKNOWN 0x00 /* Unknown */ #define ATM_NIP_CARRIER 0x01 /* Carrier identification code */ #define ATM_NIP_DATA 0x03 /* Data network id. code (X.121) */ /* Shaping indicator */ #define ATM_SHI_NONE 0x00 /* No user specified requirement */ #define ATM_SHI_NOAGG 0x01 /* Aggr. shaping of user & OAM not all. */ /* Compliance indicator */ #define ATM_OCI_OPT 0x00 /* Use of e2e OAM F5 flow is optional */ #define ATM_OCI_MAND 0x01 /* Use of e2e OAM F5 flow is mandatory */ /* User-network fault management indicator */ #define ATM_UNFM_NONE 0x00 /* No user-orig. fault mg. indications */ #define ATM_UNFM_1CPS 0x01 /* Use of u-o fm. ind. w/ rate 1 cps */ /* End-to-end OAM F5 flow indicator */ #define ATM_OFI_0_0 0x00 /* 0% of cell rate (CLP=0+1) in ATM TD */ #define ATM_OFI_0_1 0x01 /* 0.1% of cell rate (CLP=0+1) in ATM TD */ #define ATM_OFI_1_0 0x04 /* 1% of cell rate (CLP=0+1) in ATM TD */ /* Identifier related standard/application */ #define ATM_IRS_DSMCC 0x01 /* DSM-CC ISO/IEC 13818-6 */ #define ATM_IRS_H245 0x02 /* Recommendation H.245 */ /* Identifier type */ #define ATM_IT_SESSION 0x01 /* Session */ #define ATM_IT_RESOURCE 0x02 /* Resource */ /* Leaf call identifier type */ #define ATM_LIT_ROOT 0x00 /* Root assigned */ /* (LIJ) screening indication */ #define ATM_LSI_NJ_NR 0x00 /* Network Join Without Root Notif. */ /* Type of connection scope */ #define ATM_TCS_ORGANIZATIONAL 0x00 /* Organizational */ /* Connection scope selection */ #define ATM_CSS_RSV_00 0x00 /* Reserved */ #define ATM_CSS_LOCAL 0x01 /* Local network */ #define ATM_CSS_LOCAL_P1 0x02 /* Local network plus one */ #define ATM_CSS_LOCAL_P2 0x03 /* Local network plus two */ #define ATM_CSS_SITE_M1 0x04 /* Site minus one */ #define ATM_CSS_SITE 0x05 /* Intra-site */ #define ATM_CSS_SITE_P1 0x06 /* Site plus one */ #define ATM_CSS_ORG_M1 0x07 /* Organization minus one */ #define ATM_CSS_ORG 0x08 /* Intra-organization */ #define ATM_CSS_ORG_P1 0x09 /* Organization plus one */ #define ATM_CSS_COM_M1 0x0a /* Community minus one */ #define ATM_CSS_COM 0x0b /* Intra-community */ #define ATM_CSS_COM_P1 0x0c /* Community plus one */ #define ATM_CSS_REG 0x0d /* Regional */ #define ATM_CSS_INTER 0x0e /* Inter-regional */ #define ATM_CSS_GLOBAL 0x0f /* Global */ /* Origin (of extended QOS) */ #define ATM_EQO_USER 0x00 /* Originating user */ #define ATM_EQO_NET 0x01 /* Intermediate network */ /* Extended QOS parameters */ #define ATM_EQP_ACC_FW_CDV 0x94 /* Acceptable fwd peak-to-peak CDV */ #define ATM_EQP_ACC_BW_CDV 0x95 /* Acceptable bwd peak-to-peak CDV */ #define ATM_EQP_CUM_FW_CDV 0x96 /* Cumulative fwd peak-to-peak CDV */ #define ATM_EQP_CUM_BW_CDV 0x97 /* Cumulative bwd peak-to-peak CDV */ #define ATM_EQP_ACC_FW_CLR 0xa2 /* Acceptable fwd cell loss ratio */ #define ATM_EQP_ACC_BW_CLR 0xa3 /* Acceptable bwd cell loss ratio */ /* ABR additional parameters */ #define ATM_AAP_FW_REC 0xc2 /* Forward additional parameters record */ #define ATM_AAP_BW_REC 0xc3 /* Backward additional parameters record */ /* ABR setup parameters */ #define ATM_ASP_FW_ICR 0xc2 /* Forward ABR initial cell rate, CLP01 */ #define ATM_ASP_BW_ICR 0xc3 /* Backward ABR initial cell rate, CLP01 */ #define ATM_ASP_FW_TBE 0xc4 /* Fwd ABR transient buffer exposure */ #define ATM_ASP_BW_TBE 0xc5 /* Bwd ABR transient buffer exposure */ #define ATM_ASP_CRF_RTT 0xc6 /* Cumulative RM fixed round trip time */ #define ATM_ASP_FW_RIF 0xc8 /* Forward rate increase factor */ #define ATM_ASP_BW_RIF 0xc9 /* Backward rate increase factor */ #define ATM_ASP_FW_RDF 0xca /* Forward rate decrease factor */ #define ATM_ASP_BW_RDF 0xcb /* Backward rate decrease factor */ /* Type of report (Q.2963.1) */ #define ATM_TOR_MOD_CONF 0x01 /* Modification confirmation */ /* The following constants tag message parser errors. */ #define RECOV_IND_IE 1 /* IE problem */ /* The following constants tag application-specific errors. */ #define RECOV_ASE_UNKNOWN_IE 1 /* unknown IE */ #endif --- NEW FILE: first.c --- /* first.c - Phase I, input data preprocessing */ /* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include "common.h" #include "qgen.h" #include "file.h" int field = 0; int group = 0; int offset = 0; int varlen_fields = 0; static unsigned char mask = 0; static int seq = 0; #define ALLOC(field) ({ \ if (mask & beg_mask) \ die("bit collision (%s: 0x%02X+0x%02X)",walk->id,mask,beg_mask); \ field->pos += offset; \ if (next <= 8) { \ mask |= end_mask; \ walk->jump = 0; \ } \ else { \ mask = end_mask; \ walk->jump = (next-1) >> 3; \ } \ if (walk->flush && walk->size) { \ if (!mask) die("nothing to flush (%s)",walk->id); \ walk->jump++; \ mask = 0; \ } }) static void process(FIELD *start,int defines) { FIELD *walk; TAG *scan; unsigned char beg_mask,end_mask,orig_mask; int tmp,shift,next; for (walk = start; walk; walk = walk->next) { walk->field = field; /* record it even if this isn't a real field (we need to know the first field number later in second.c and this way we don't have to search for it) */ if (walk->structure) { int start_field,start_group; start_field = field; start_group = group; process(walk->my_block,walk->structure->instances > 0); if (walk->structure->instances > 1) { walk->structure->instances = -1; walk->structure->first_field = start_field; walk->structure->fields = field-start_field; walk->structure->groups = group-start_group; } continue; } walk->seq = seq++; /* number of fields, always increases */ if (*walk->id != '_') { if (defines) to_h("#define QF_%s %d\n",walk->id,field); to_test(" \"%s\",\n",walk->id); field++; } if (mask && walk->brk) die("mask 0x%02x at break (%s)\n",mask,walk->id); /* compute position and adjust masks */ tmp = walk->size > 7 ? 0xff : (1 << walk->size)-1; beg_mask = tmp << walk->pos; tmp = 0xff & ~((1 << (8-(walk->size & 7)))-1); if (walk->size && !tmp) tmp = 0xff; next = walk->pos+walk->size; shift = 8-(next & 7); if (shift == 8) shift = 0; end_mask = tmp >> shift; if (debug) printf("mask 0x%02X, beg 0x%02X, end 0x%02X, offset %d, flush %d, " "%s\n",mask,beg_mask,end_mask,offset,walk->flush,walk->id); /* handle values */ if (!walk->value) { if (walk->var_len == -2) walk->var_len = varlen_fields++; ALLOC(walk); offset += walk->jump*8; } else switch (walk->value->type) { case vt_id: ALLOC(walk); to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n",walk->pos, walk->size,walk->value->id,walk->id); offset += walk->jump*8; break; case vt_case: if (*walk->id != '_') { ALLOC(walk); offset += walk->jump*8; #if 0 /* bad idea */ for (scan = walk->value->tags; scan; scan = scan->next) if (scan->deflt) { to_c(" q_put(q_initial,%d,%d,%s); " "/* %s */\n",walk->pos,walk->size, scan->value,walk->id); } #endif } /* fall through */ #if 0 if (*walk->id != '_') { ALLOC(walk); offset += walk->jump*8; orig_mask = mask; for (scan = walk->value->tags; scan; scan = scan->next) { if (scan->id && defines) to_h("#define QG_%s %d\n",scan->id,-group-1); scan->group = group++; scan->pos = walk->pos; mask = orig_mask; to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n", walk->pos,walk->size,scan->value,walk->id); process(scan->block,defines); if (mask) offset += 8; } break; } #endif /* fall through */ case vt_multi: orig_mask = mask; for (scan = walk->value->tags; scan; scan = scan->next) { if (scan->id && defines) to_h("#define QG_%s %d\n",scan->id,-group-1); scan->group = group++; scan->pos = walk->pos; if (debug) printf("| %s/%s (walk->flush = %d)\n",walk->id, scan->value,walk->flush); if (*walk->id != '_') mask = orig_mask; else { ALLOC(scan); if (debug) printf("| jump = %d (mask 0x%02x)\n", walk->jump,mask); offset += walk->jump*8; to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n", scan->pos,walk->size,scan->value,walk->id); } process(scan->block,defines); if (*walk->id != '_' && mask) die("EF129"); } break; case vt_length: ALLOC(walk); offset += walk->jump*8; process(walk->value->block,defines); break; default: abort(); } } } void first(FIELD *def) { def->group = group++; to_h("/*\n * Identifiers to access numbers of fields and of named\n"); to_h(" * groups (unnamed groups don't need that). Field numbers are\n"); to_h(" * zero-based. Group numbers are negative and -1-based.\n */\n\n"); to_c("static unsigned char q_initial[Q_DATA_BYTES];\n\n"); to_c("/*\n * Initialization of constant data. Could also do this in\n"); to_c(" * the translator and output the resulting byte stream.\n */\n\n"); to_c("static void q_init_global(void)\n{\n"); to_c(" memset(q_initial,0,sizeof(q_initial));\n"); to_test("static const char *fields[] = {\n"); process(def,1); to_test(" NULL\n};\n\n"); to_c("}\n\n"); if (mask) offset += 8; to_h("\n/*\n * Sizes of various tables which are allocated at run-time.\n"); to_h(" */\n"); to_h("\n#define Q_DATA_BYTES %d\n",offset/8); to_h("#define Q_GROUPS %d\n",group); to_h("#define Q_FIELDS %d\n",field); to_h("#define Q_VARLEN_FIELDS %d\n\n",varlen_fields); } --- NEW FILE: third.c --- /* third.c - Phase III, code generation */ /* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include "common.h" #include "qgen.h" #include "file.h" typedef struct _break { int pc; struct _break *next; } BREAK; int constr_size,parser_size; static BREAK *brks = NULL; static void construct(FIELD *start) { FIELD *walk; TAG *scan; int patch_here; patch_here = 0; /* for gcc */ for (walk = start; walk; walk = walk->next) { if (walk->structure) { construct(walk->my_block); continue; } if (!walk->value) if (walk->var_len == -1) code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump,walk->pos, walk->size,walk->id); else code("%s%d%d%d/* %s */\n","OP_COPYVAR",walk->var_len, walk->pos,walk->size/8,walk->id); else switch (walk->value->type) { case vt_id: code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump,walk->pos, walk->size,walk->id); break; case vt_case: if (*walk->id != '_') code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump, walk->pos,walk->size,walk->id); for (scan = walk->value->tags; scan; scan = scan->next) { if (debug) printf("C %s/%s(%d): %d\n",walk->id,scan->value, scan->group,scan->deflt); if (!scan->deflt) { code("%s%d%s\n","OP_IFGROUP",scan->group,"?"); patch_here = pc-1; } if (*walk->id == '_') code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump, scan->pos,walk->size,scan->value); construct(scan->block); if (scan->next) { code("%s%s\n","OP_JUMP","?"); scan->patch = pc-1; } if (!scan->deflt) patch(patch_here,pc-patch_here-1); } for (scan = walk->value->tags; scan && scan->next; scan = scan->next) patch(scan->patch,pc-scan->patch-1); break; case vt_multi: for (scan = walk->value->tags; scan; scan = scan->next) { if (debug) printf("M %s/%s(%d)\n",walk->id,scan->value, scan->group); code("%s%d%s\n","OP_IFGROUP",scan->group,"?"); scan->patch = pc-1; code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump, scan->pos,walk->size,scan->value); construct(scan->block); patch(scan->patch,pc-scan->patch-1); } break; case vt_length: code("%s%d%d%d/* %s */\n","OP_BEGIN_LEN",walk->jump, walk->pos,walk->size,walk->id); construct(walk->value->block); code("%s\n","OP_END_LEN"); break; default: abort(); } } } static void parser(FIELD *start,int level,int group) { FIELD *walk; TAG *scan; VALUE_LIST *tag; int count,patch_here; BREAK *brk,*tmp_brks,*next; patch_here = 0; /* for gcc */ for (walk = start; walk; walk = walk->next) { if (walk->structure) { parser(walk->my_block,level,group); continue; } if (walk->brk) { code("%s%s\n","OP_IFEND","?"); brk = alloc_t(BREAK); brk->pc = pc-1; brk->next = brks; brks = brk; } if (dump) { if ((!walk->value || walk->value->type != vt_multi) && walk->size) code("%s%d\n","OP_DUMP",walk->seq); if (walk->value || walk->name_list) to_dump(" { %d, dump_sym_%d, \"%s\" },\n",level, walk->name_list ? walk->name_list->id : walk->seq,walk->id); else to_dump(" { %d, NULL, \"%s\" },\n",level,walk->id); } if (!walk->value) { if (walk->var_len != -1) code("%s%d%d%d/* %s */\n","OP_COPYVAR",walk->var_len,walk->pos, walk->size/8,walk->id); else if (*walk->id != '_' || walk->jump || dump) code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump,walk->pos, walk->size,walk->id); } else switch (walk->value->type) { case vt_id: if (*walk->id != '_' || walk->jump || dump) code("%s%d%d%d/* %s */\n","OP_COPY",walk->jump, walk->pos,walk->size,walk->id); break; case vt_multi: code("%s%s/* %s */\n","OP_IFEND","?",walk->id); walk->patch = pc-1; if (dump) code("%s%d\n","OP_DUMP",walk->seq); /* fall through */ case vt_case: if (*walk->id != '_' || dump) code("%s%d%d%d/* %s */\n","OP_COPY",0,walk->pos, walk->size,walk->id); /* don't move */ count = 0; for (scan = walk->value->tags; scan; scan = scan->next) { count++; for (tag = scan->more; tag; tag = tag->next) count++; } code("%s%d%d%d%d/* %s */\n","OP_CASE",walk->jump, walk->pos,walk->size,count,walk->id); for (scan = walk->value->tags; scan; scan = scan->next) { code("%s%d%s\n",scan->deflt ? "-1" : scan->value, scan->group,"?"); scan->patch = pc-1; for (tag = scan->more; tag; tag = tag->next) { code("%s%d%s\n",tag->value,scan->group,"?"); tag->patch = pc-1; } } for (scan = walk->value->tags; scan; scan = scan->next) { patch(scan->patch,pc-scan->patch-1); for (tag = scan->more; tag; tag = tag->next) patch(tag->patch,pc-tag->patch-1); if (!scan->block && scan->abort_id) code("%s%s\n","OP_ABORT",scan->abort_id); parser(scan->block,level+1,scan->group); if (scan->next) { code("%s%s\n","OP_JUMP","?"); scan->patch = pc-1; } } for (scan = walk->value->tags; scan && scan->next; scan = scan->next) patch(scan->patch,pc-scan->patch-1); if (walk->value->type == vt_multi) { code("%s%d\n","OP_JUMP",walk->patch-pc-3); patch(walk->patch,pc-walk->patch-1); } break; case vt_length: code("%s%d%d%d/* %s */\n","OP_BEGIN_LEN",walk->jump, walk->pos,walk->size,walk->id); if (walk->value->recovery) { code("%s%s%d%d\n","OP_BEGIN_REC",walk->value->recovery, group,"?"); patch_here = pc-1; } tmp_brks = brks; if (!walk->value->block && walk->value->abort_id) code("%s%s\n","OP_ABORT",walk->value->abort_id); parser(walk->value->block,level+1,group); if (walk->value->recovery) { code("%s\n","OP_END_REC"); patch(patch_here,pc); } for (brk = brks; brk; brk = next) { next = brk->next; patch(brk->pc,pc-brk->pc-1); free(brk); } brks = tmp_brks; code("%s /* %s */\n","OP_END_LEN",walk->id); break; default: abort(); } } } void third(FIELD *def) { if (dump) constr_size = 0; else { to_c("\n/*\n"); to_c(" * \"Microcode\" used to construct messages. It copies all\n"); to_c(" * fields from the construction area to the resulting message."); to_c("\n */\n\n"); to_c("static int construct[] = {\n"); begin_code(); construct(def); constr_size = end_code()+1; to_c(" OP_END\n};\n\n"); } to_c("\n/*\n * \"Microcode\" used to parse messages. It detects the\n"); to_c(" * presence of fields and copies them from the message to the\n"); to_c(" * construction area.\n */\n\n"); to_c("static int parse[] = {\n"); if (dump) { to_dump("typedef struct {\n int level;\n const SYM_NAME *sym;\n"); to_dump(" const char *name;\n"); to_dump("} DUMP_FIELD;\n\n"); to_dump("static DUMP_FIELD dump_fields[] = {\n"); } begin_code(); parser(def,0,0); parser_size = end_code()+1; to_c(" OP_END\n};\n\n"); if (dump) to_dump("};\n\n"); } --- NEW FILE: mknl.pl --- #!/usr/bin/perl print "# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT !\n" || die "write: $!"; while ($line = <STDIN>) { chop($line); next unless $line =~ /^#define\s/; while ($line =~ m|/\*| && $line !~ m|\*/|) { $line .= <STDIN>; } $line =~ s/\s+/ /g; if (!defined($curr) || $line !~ /^#define ${curr}_/) { undef $curr; for (@ARGV) { ($tmp = $_) =~ tr/a-z/A-Z/; next unless $line =~ /^#define ${tmp}_/; $curr = $tmp; print "\n:$_\n" || die "write: $!"; last; } } next unless defined $curr; next unless $line =~ m|^#define (\S+) (\S+)( (/\*\s*(.*\S)\s*\*/))?|; # if (defined $3) { # print "$2=$1 $4\n" || die "write: $!"; # } if (defined $3) { print "$2=$2 \\\"$5\\\"\n" || die "write: $!"; } else { print "$2=$1\n" || die "write: $!"; } } --- NEW FILE: common.c --- /* common.c - Common functions */ /* Written 1995 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include "common.h" void *alloc(size_t size) { void *n; n = malloc(size); if (n) return n; perror("malloc"); exit(1); } char *stralloc(const char *str) { char *n; n = strdup(str); if (n) return n; perror("malloc"); exit(1); } void die(const char *fmt,...) { va_list ap; fflush(stdout); va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fputc('\n',stderr); exit(1); } --- NEW FILE: common.h --- /* common.h - Common definitions */ /* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ #ifndef COMMON_H #define COMMON_H #include <sys/types.h> #define alloc_t(t) ((t *) alloc(sizeof(t))) extern int debug; extern int dump; void *alloc(size_t size); char *stralloc(const char *str); void die(const char *fmt,...); #endif --- NEW FILE: file.c --- /* file.c - (source) file IO */ /* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include "common.h" #include "file.h" #define DEFAULT_BUF_SIZE 256 typedef struct { const char *data; const char *extra; } CODE_ITEM; int pc; static FILE *h_file,*c_file,*test_file,*dump_file; static CODE_ITEM *buf; static int buf_size; void to_h(const char *fmt,...) { va_list ap; va_start(ap,fmt); if (vfprintf(h_file,fmt,ap) == EOF) { perror("write"); exit(1); } va_end(ap); } void to_c(const char *fmt,...) { va_list ap; va_start(ap,fmt); if (vfprintf(c_file,fmt,ap) == EOF) { perror("write"); exit(1); } va_end(ap); } void to_test(const char *fmt,...) { va_list ap; va_start(ap,fmt); if (vfprintf(test_file,fmt,ap) == EOF) { perror("write"); exit(1); } va_end(ap); } void to_dump(const char *fmt,...) { va_list ap; va_start(ap,fmt); if (vfprintf(dump_file,fmt,ap) == EOF) { perror("write"); exit(1); } va_end(ap); } void open_files(const char *prefix) { char name[100]; /* maximum name */ sprintf(name,"%s.out.h",prefix); h_file = fopen(name,"w"); if (!h_file) { perror("creat"); exit(1); } sprintf(name,"%s.out.c",prefix); c_file = fopen(name,"w"); if (!c_file) { perror("creat"); exit(1); } sprintf(name,"%s.test.c",prefix); test_file = fopen(name,"w"); if (!test_file) { perror("creat"); exit(1); } if (dump) { sprintf(name,"%s.dump.c",prefix); dump_file = fopen(name,"w"); if (!dump_file) { perror("creat"); exit(1); } } } void close_files(void) { if (fclose(h_file) == EOF) { perror("fclose"); exit(1); } if (fclose(c_file) == EOF) { perror("fclose"); exit(1); } if (fclose(test_file) == EOF) { perror("fclose"); exit(1); } if (dump) if (fclose(dump_file) == EOF) { perror("fclose"); exit(1); } } void begin_code(void) { pc = 0; buf_size = DEFAULT_BUF_SIZE; buf = alloc(sizeof(CODE_ITEM)*buf_size); } static void put_item(const char *item) { if (pc >= buf_size) { buf_size *= 2; buf = realloc(buf,sizeof(CODE_ITEM)*buf_size); if (!buf) die("out of memory"); } buf[pc].data = item; buf[pc++].extra = NULL; } static void append_last(const char *str) { buf[pc-1].extra = str; } static char *itos(int val) { char buffer[21]; /* enough for 64 bits ... */ sprintf(buffer,"%d",val); return stralloc(buffer); } void code(const char *fmt,...) { va_list ap; va_start(ap,fmt); while (*fmt) if (*fmt++ == '%') { switch (*fmt++) { case 'd': put_item(itos(va_arg(ap,int))); break; case 's': put_item(va_arg(ap,const char *)); break; default: die("invalid format character %c",fmt[-1]); } } else { const char *here; here = strchr(--fmt,'%'); if (!here) append_last(fmt); else { char buffer[200]; /* ugly */ if (here[1] != 's') die("bad format in extension"); strncpy(buffer,fmt,(size_t) (here-fmt)); strcpy(buffer+(here-fmt),va_arg(ap,const char *)); strcat(buffer,here+2); append_last(stralloc(buffer)); } break; } va_end(ap); } int end_code(void) { int indent,i; indent = 1; for (i = 0; i < pc; i++) { if (indent) { to_c(" "); indent = 0; } to_c(buf[i].data); if (buf[i].extra && *buf[i].extra == '\n') to_c(","); else to_c(", "); if (buf[i].extra) { to_c(buf[i].extra); indent = !!strchr(buf[i].extra,'\n'); if (indent) to_c("/*%4d*/",i+1); } } return pc; } void patch(int old_pc,int value) { /* may leak memory */ buf[old_pc].data = itos(value); } --- NEW FILE: file.h --- /* file.h - (source) file IO */ /* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ #ifndef FILE_H #define FILE_H extern int pc; void open_files(const char *prefix); void to_h(const char *fmt,...); void to_c(const char *fmt,...); void to_test(const char *fmt,...); void to_dump(const char *fmt,...); void close_files(void); void begin_code(void); void code(const char *fmt,...); int end_code(void); void patch(int old_pc,int value); #endif --- NEW FILE: Makefile.am --- noinst_PROGRAMS = qgen q.dump # q40.out.o check_PROGRAMS = q.test qgen_SOURCES = common.c common.h file.c file.h first.c ql_y.y ql_l.l qgen.c \ qgen.h second.c third.c qgen_LDADD = -lfl q_dump_SOURCES = common.c q_dump_LDADD = qd.dump.standalone.o # FIXME: paulsch: We don't really depend on qd.dump.o or q.out.o here, but this # trick will get it built with only a minor glitch in the dependency checking # for q.dump. q_dump_DEPENDENCIES = $(q_dump_LDADD) qd.dump.o q.out.o EXTRA_q_dump_SOURCES = op.h uni.h qlib.c qlib.h q_test_SOURCES = qtest.c uni.h q_test_DEPENDENCIES = q.test.c #TESTS = $(check_PROGRAMS) EXTRA_DIST = ql_y.h incl.pl mknl.pl msg.fmt TODO CLEANFILES = q.out.h q.out.c q.test.c qd.out.h qd.out.c qd.dump.c qd.test.c \ default.nl # q40.out.h q40.out.c q40.test.c NLS = atm_ai_msg atm_ai_ie atm_loc atm_cv atm_pu atm_na atm_cond atm_ie \ atm_msg atm_np atm_ton atm_sat atm_prs atm_scrn atm_vpa atm_poe \ q2931_cs atm_td atm_bc atm_tc atm_stc atm_upcc q2931_proto atm_flag \ atm_aalp atm_fd atm_tag atm_l2 atm_l3 atm_tt atm_mc atm_hl atm_imd \ atm_tdl atm_tni atm_nip atm_shi atm_oci atm_unfm atm_ofi atm_irs \ atm_it atm_lit atm_lsi atm_tcs atm_css atm_eqo atm_eqp atm_aap \ atm_asp atm_tor SYMFILES = uni.h $(shell @PERL@ incl.pl $(CFLAGS) linux/atmsap.h) default.nl: mknl.pl $(SYMFILES) cat $(SYMFILES) | @PERL@ mknl.pl $(NLS) >default.nl || \ { rm -f default.nl; echo 1; } q.out.h q.out.c q.test.c: qgen msg.fmt default.nl $(CPP) $(DEFS) - <msg.fmt | ./qgen #q40.out.h q40.out.c q40.test.c: qgen uni40 default.nl # $(CPP) $(DEFS) - <uni40 | PREFIX=q40 ./qgen qd.out.h qd.out.c qd.dump.c: qgen msg.fmt default.nl $(CPP) $(DEFS) - <msg.fmt | ./qgen -D q.out.o: q.out.c q.out.h qlib.c qlib.h $(CC) $(DEFS) $(CFLAGS) -c q.out.c #q40.out.o: q40.out.c q40.out.h qlib.c qlib.h # $(CC) -DUNI40 $(CFLAGS) -c q40.out.c qd.dump.o: qd.dump.c qd.out.c qlib.c qlib.h $(CC) $(DEFS) $(CFLAGS) -c qd.dump.c qd.dump.standalone.o: qd.dump.c qd.out.c qlib.c qlib.h $(CC) $(DEFS) -DSTANDALONE $(CFLAGS) -c qd.dump.c \ -o qd.dump.standalone.o --- NEW FILE: msg.fmt --- /* msg.fmt - Signaling message format decription for UNI 3.0, 3.1, and 4.0 */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #undef linux /* grr ... */ include "atmsap.h" include "uni.h" #define VAR_STD_HDR(name,defl) \ _ext <1@8,more> = 1 \ name##_cs "q2931_cs" <2@6,more> = defl \ _flag "atm_flag" <1@5,more> = ATM_FLAG_NO \ _action_ind "atm_ai_ie" <3@1> = 0 /* only 2 bits in UNI 3.0 */ \ _ie_len <16> = recover RECOV_IND_IE length #define ITU_STD_HDR VAR_STD_HDR(,Q2931_CS_ITU) #define NET_STD_HDR VAR_STD_HDR(,Q2931_CS_NET) def ie_aal = { ITU_STD_HDR { aal_type <8> = case { 5 { _id "atm_aalp" <8> = multi { ATM_AALP_FW_MAX_SDU { fw_max_sdu <16> } ATM_AALP_BW_MAX_SDU { bw_max_sdu <16> } #if defined(UNI30) || defined(ALLOW_UNI30) || defined(DYNAMIC_UNI) ATM_AALP_AAL_MODE { aal_mode <8> # UNI 3.0 only } #endif ATM_AALP_SSCS { sscs_type <8> } } } } } } #define TRAFFIC_DESCRIPTOR_PCR(p) \ ATM_TD_FW_PCR_0 { p##fw_pcr_0 <24> } \ ATM_TD_BW_PCR_0 { p##bw_pcr_0 <24> } \ ATM_TD_FW_PCR_01 { p##fw_pcr_01 <24> } \ ATM_TD_BW_PCR_01 { p##bw_pcr_01 <24> } \ #define TRAFFIC_DESCRIPTOR_VBR(p) \ ATM_TD_FW_SCR_0 { p##fw_scr_0 <24> } \ ATM_TD_BW_SCR_0 { p##bw_scr_0 <24> } \ ATM_TD_FW_SCR_01 { p##fw_scr_01 <24> } \ ATM_TD_BW_SCR_01 { p##bw_scr_01 <24> } \ ATM_TD_FW_MBS_0 { p##fw_mbs_0 <24> } \ ATM_TD_BW_MBS_0 { p##bw_mbs_0 <24> } \ ATM_TD_FW_MBS_01 { p##fw_mbs_01 <24> } \ ATM_TD_BW_MBS_01 { p##bw_mbs_01 <24> } \ #define TRAFFIC_DESCRIPTOR_BE(p) \ ATM_TD_BEST_EFFORT { p##best_effort <0> } \ #if defined(UNI40) || defined(DYNAMIC_UNI) #define TRAFFIC_DESCRIPTOR_ABR(p) \ ATM_TD_FW_MCR_01 { p##fw_mcr_01 <24> } \ ATM_TD_BW_MCR_01 { p##bw_mcr_01 <24> } \ #else #define TRAFFIC_DESCRIPTOR_ABR(p) /* not yet */ #endif #define TRAFFIC_DESCRIPTOR(p) \ TRAFFIC_DESCRIPTOR_PCR(p) \ TRAFFIC_DESCRIPTOR_VBR(p) \ TRAFFIC_DESCRIPTOR_BE(p) #ifdef NOT_YET TRAFFIC_DESCRIPTOR_ABR(p) #endif def ie_td = { # UNI 3.0 calls this "User Cell Rate" ITU_STD_HDR { _id "atm_td" <8> = multi { TRAFFIC_DESCRIPTOR(_dummy <0> = length {}) /* * Confused ? ;-) Here, we want no prefix at all, but cpp * insists in getting an argument. So we give it that funny * construct. This yields something like * ... { _dummy <0> = length {}field <24> } * with the rather useless "dummy" field. "= length {}" is * necessary to avoid the restriction that unnamed fields must * have values (which would then get concatenated with the name * of the field we're actually interested in). */ ATM_TD_TM_OPT { # @@@ should this also go into the TD macro ? #if defined(UNI40) || defined(DYNAMIC_UNI) fw_fdisc "atm_fd" <1@8,more> = ATM_FD_NO bw_fdisc "atm_fd" <1@7,more> = ATM_FD_NO #endif bw_tag "atm_tag" <1@2,more> = ATM_TAG_NO fw_tag "atm_tag" <1@1> = ATM_TAG_NO } } } } def ie_bbcap = { ITU_STD_HDR { bearer_class "atm_bc" <5@1,more> _ext <1@8> = case { 0 { _ext <1@8,more> = 1 trans_cap "atm_tc" <7@1> } default 1 {} } _ext <1@8,more> = 1 susc_clip "atm_stc" <2@6,more> = ATM_STC_NO upcc "atm_upcc" <2@1> = ATM_UPCC_P2P } } def ie_bhli = { ITU_STD_HDR { _ext <1@8,more> = 1 hli_type <7@1> = case { # Note: cannot use ATM_HL_* here, because those values are incremented by one # to keep zero available for ATM_HL_NONE 0 { # ISO iso_hli <-64> } 1 { # User Specific user_hli <-64> } #if defined(UNI30) || defined(ALLOW_UNI30) || defined(DYNAMIC_UNI) 2 { # High layer profile - UNI 3.0 only hlp <32> } #endif 3 { # Vendor-Specific Application identifier hli_oui <24> app_id <32> } #if defined(UNI40) || defined(DYNAMIC_UNI) 4 { # Reference to ITU-T SG 1 B-ISDN Teleservice Recommendation tobedefined <8> } #endif } } } def ie_blli = { ITU_STD_HDR { _lid <2@6,more> = multi { 1 { _ext <1@8,more> = 1 uil1_proto <5@1> } 2 { uil2_proto "atm_l2" <5@1,more> = case { ATM_L2_X25_LL,ATM_L2_X25_ML,ATM_L2_HDLC_ARM, ATM_L2_HDLC_NRM,ATM_L2_HDLC_ABM,ATM_L2_Q922, ATM_L2_ISO7776 { # CCITT encoding _ext <1@8> = case { 0 { l2_mode "atm_imd" <2@6,more> = ATM_IMD_NORMAL q933 <2@1,more> = 0 _ext <1@8> = case { 0 { window_size <7@1,more> _ext <1@8> = 1 } default 1 {} } } default 1 {} } } ATM_L2_USER { # User specified _ext <1@8> = 0 user_l2 <7@1,more> _ext <1@8> = 1 } default ATM_L2_ISO1745,ATM_L2_Q291,ATM_L2_LAPB, ATM_L2_ISO8802,ATM_L2_X75 { # No additional data _ext <1@8> = 1 } } } 3 { uil3_proto "atm_l3" <5@1,more> = case { ATM_L3_X25,ATM_L3_ISO8208,ATM_L3_X223 { # CCITT coding _ext <1@8> = case { 0 { l3_mode "atm_imd" <2@6,more> = ATM_IMD_NORMAL _ext <1@8> = case { 0 { def_pck_size <4@1,more> _ext <1@8> = case { 0 { _ext <1@8> = 1 pck_win_size <7@1> } default 1 {} } } default 1 {} } } default 1 {} } } #if defined(UNI40) || defined(DYNAMIC_UNI) ATM_L3_H310 { # ITU-T Rec. H.310 _ext <1@8> = case { 0 { term_type "atm_tt" <4@1,more> = ATM_TT_RXTX _ext <1@8> = case { 0 { _ext <1@8,more> = 1 fw_mpx_cap "atm_mc" <3@4,more> = ATM_MC_NONE bw_mpx_cap "atm_mc" <3@1> = ATM_MC_NONE } default 1 {} } } default 1 {} } } #endif ATM_L3_TR9577 { # ISO/IEC TR9577 _ext <1@8> = case { 0 { _ext <1@8,more> = 0 ipi_high <7@1> = case { 0x40 { # SNAP hack _ext <1@8,more> = 1 _ipi_low <1@7> = case { # ugly 0 { _ext <1@8,more> = 1 _snap_id <2@6> = 0 oui <24> pid <16> } default 1 {} } } default 0x0 { # ugly _ext <1@8,more> = 1 ipi_low <1@7> } } } default 1 {} } } ATM_L3_USER { # User specified _ext <1@8> = 0 user_l3 <7@1,more> _ext <1@8> = 1 } } } } } } def ie_call_state = { ITU_STD_HDR { call_state <6@1> } } def ie_cdpn = { ITU_STD_HDR { _ext <1@8,more> = 1 _plan "atm_np" <4@1,more> = case { ATM_NP_E164 { _type "atm_ton" <3@5> = ATM_TON_INTRNTNL cdpn_e164 <-96> } ATM_NP_AEA { # ATM Endsystem Address _type "atm_ton" <3@5> = ATM_TON_UNKNOWN cdpn_esa <-160> } } } } def ie_cdps = { ITU_STD_HDR { _ext <1@8,more> = 1 #ifdef UNI30 _type "atm_sat" <3@5,more> = ATM_SAT_AEA #endif #if defined(UNI31) || defined(DYNAMIC_UNI) cdps_type "atm_sat" <3@5,more> = ATM_SAT_AEA #endif _oddeven <1@4> = 0 cdps <-160> } } def ie_cgpn = { # @@@ extend language to allow same trick as for cdpn ITU_STD_HDR { cgpn_plan "atm_np" <4@1,more> cgpn_type "atm_ton" <3@5,more> _ext <1@8> = case { 0 { _ext <1@8,more> = 1 pres_ind "atm_prs" <2@6,more> = ATM_PRS_ALLOW scr_ind "atm_scrn" <2@1> = ATM_SCRN_UP_NS } default 1 {} } cgpn <-160> } } def ie_cgps = { ITU_STD_HDR { _ext <1@8,more> = 1 #ifdef UNI30 _type "atm_sat" <3@5,more> = ATM_SAT_AEA #endif #if defined(UNI31) || defined(DYNAMIC_UNI) cgps_type "atm_sat" <3@5,more> = ATM_SAT_AEA #endif _oddeven <1@4> = 0 cgps <-160> } } def ie_cause = { VAR_STD_HDR(cause,Q2931_CS_ITU) { _ext <1@8,more> = 1 location "atm_loc" <4@1> = ATM_LOC_USER _ext <1@8,more> = 1 cause "atm_cv" <7@1> = case { ATM_CV_UNALLOC,ATM_CV_NO_ROUTE_DEST,ATM_CV_QOS_UNAVAIL { # Note 2 break _ext <1@8,more> = 1 pu "atm_pu" <1@4,more> = ATM_PU_USER na "atm_na" <1@3,more> = ATM_NA_NORMAL cond2 "atm_cond" <2@1> = ATM_COND_UNKNOWN } ATM_CV_CALL_REJ { # Note 3 break _ext <1@8,more> = 1 cond3 "atm_cond" <2@1,more> = ATM_COND_UNKNOWN reason <5@3> = case { ATM_RSN_USER { user_diag <-216> } ATM_RSN_IE_MISS,ATM_RSN_IE_INSUFF { ie_id3 "atm_ie" <8> } } } ATM_CV_NUM_CHANGED { # Note 4 break new_dest <-224> # good luck ... } ATM_CV_REJ_CLIR { # Note 5 break invalid <8> # not supported } ATM_CV_ACC_INF_DISC,ATM_CV_INCOMP_DEST,ATM_CV_MAND_IE_MISSING, ATM_CV_UNKNOWN_IE,ATM_CV_INVALID_IE { # Note 6 break ie_id6 <-224> } #if defined(DYNAMIC_UNI) || defined(ALLOW_UNI30) ATM_CV_UCR_UNAVAIL_OLD,ATM_CV_UCR_UNAVAIL_NEW { # Note 8 #else #ifdef UNI30 ATM_CV_UCR_UNAVAIL_OLD { # Note 8 #else ATM_CV_UCR_UNAVAIL_NEW { # Note 8 #endif #endif break ucr_id <-224> } ATM_CV_NO_SUCH_CHAN { # Note 9 break unav_vpci <16> unav_vci <16> } ATM_CV_UNKNOWN_MSG_TYPE,ATM_CV_INCOMP_MSG { # Note 10 break bad_msg_type "atm_msg" <8> } ATM_CV_TIMER_EXP { # Note 11 break timer <24> } default 0 {} } } } def ie_conn_id = { ITU_STD_HDR { _ext <1@8,more> = 1 _vp_ass "atm_vpa" <2@4,more> = ATM_VPA_EXPL /* explicit */ _pref_exc "atm_poe" <3@1> = 0 vpi <16> vci <16> } } #if defined(UNI40) || defined(DYNAMIC_UNI) def ie_e2e_tdl = { ITU_STD_HDR { _id "atm_tdl" <8> = multi { ATM_TDL_CUM { cum_delay <16> } ATM_TDL_E2EMAX { max_delay <16> } ATM_TDL_NGI {} } } } #endif def ie_qos = { #if defined(UNI30) && !defined(DYNAMIC_UNI) NET_STD_HDR { #else /* * Depending on what values are put into qos_fw and qos_bw, this may * still be invalid. But at least the defaults should be okay. Note * that defining UNI30 and UNI31 together yields only the UNI30 * behaviour. We assume that everybody who implements UNI 3.1 today * has a similar kludge in their networking code, so we should get * away with that. */ VAR_STD_HDR(qos,Q2931_CS_NET) { #endif qos_fw <8> = 0 qos_bw <8> = 0 } } def ie_bbrep = { ITU_STD_HDR { _ext <1@8,more> = 1 rep_ind <4@1> = 2 } } def ie_restart = { ITU_STD_HDR { _ext <1@8,more> = 1 rst_class <3@1> } } def ie_bbs_comp = { ITU_STD_HDR { _ext <1@8,more> = 1 bbsc_ind <7@1> = 0x21 } } def ie_tns = { ITU_STD_HDR { _ext <1@8,more> = 1 _net_type "atm_tni" <3@5,more> = ATM_TNI_NNI /* @@@ default ? */ _carrier_id "atm_nip" <4@1> = ATM_NIP_CARRIER /* @@@ default ? */ net_id <-32> } } #if defined(UNI40) || defined(DYNAMIC_UNI) def ie_notify = { ITU_STD_HDR { notification <-32> # @@@ how many actually ? } } def ie_oam_td = { ITU_STD_HDR { _ext <1@8,more> = 1 shaping "atm_shi" <2@6,more> = ATM_SHI_NONE compliance "atm_oci" <1@5,more> = ATM_OCI_OPT fault "atm_unfm" <3@1> = ATM_UNFM_NONE _ext <1@8,more> = 1 fwd_ofi "atm_ofi" <3@5,more> = ATM_OFI_0_0 bwd_ofi "atm_ofi" <3@1> = ATM_OFI_0_0 } } def ie_git = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _dummy <1@8> = 0 # bit is "spare", although not indicated in spec id_std_app "atm_irs" <7@1> = case { ATM_IRS_DSMCC,ATM_IRS_H245 { _type "atm_it" <8> = ATM_IT_SESSION _length <8> = length { session_id <-160> } _type "atm_it" <8> = ATM_IT_RESOURCE _length <8> = length { resource_id <-32> } } default 0 { unrecognized_git_identifiers <-224> # 33-5 bytes } } } } def ie_lij_id = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _ext <1@8,more> = 1 lij_id_type "atm_lit" <7@1> = ATM_LIT_ROOT lij_id <32> } } def ie_lij_prm = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _ext <1@8,more> = 1 lij_scr_ind "atm_lsi" <2@1> } } def ie_leaf_sn = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding leaf_sn <32> } } def ie_scope_sel = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _ext <1@8,more> = 1 scope_type "atm_tcs" <4@1> = ATM_TCS_ORGANIZATIONAL scope_sel "atm_css" <8> } } def ie_alt_td = { ITU_STD_HDR { _id "atm_td" <8> = multi { TRAFFIC_DESCRIPTOR(alt) } } } def ie_min_td = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _id "atm_td" <8> = multi { TRAFFIC_DESCRIPTOR_PCR(min) TRAFFIC_DESCRIPTOR_ABR(min) } } } def ie_eqos = { NET_STD_HDR { eqos_origin "atm_eqo" <8> _id "atm_eqp" <8> = multi { ATM_EQP_ACC_FW_CDV { acc_fw_cdv <24> } ATM_EQP_ACC_BW_CDV { acc_bw_cdv <24> } ATM_EQP_CUM_FW_CDV { cum_fw_cdv <24> } ATM_EQP_CUM_BW_CDV { cum_bw_cdv <24> } ATM_EQP_ACC_FW_CLR { acc_fw_clr <8> } ATM_EQP_ACC_BW_CLR { acc_bw_clr <8> } } } } def ie_abr_add_prm = { NET_STD_HDR { _id "atm_aap" <8> = multi { ATM_AAP_FW_REC { abr_fw_add_rec <32> } ATM_AAP_BW_REC { abr_bw_add_rec <32> } } } } def ie_abr_set_prm = { NET_STD_HDR { # @@@ UNI 4.0 does not specify the coding _id "atm_asp" <8> = multi { ATM_ASP_FW_ICR { abr_fw_icr <24> } ATM_ASP_BW_ICR { abr_bw_icr <24> } ATM_ASP_FW_TBE { abr_fw_tbe <24> } ATM_ASP_BW_TBE { abr_bw_tbe <24> } ATM_ASP_CRF_RTT { atm_crf_rtt <24> } ATM_ASP_FW_RIF { atm_fw_rif <8> } ATM_ASP_BW_RIF { atm_bw_rif <8> } ATM_ASP_FW_RDF { atm_fw_rdf <8> } ATM_ASP_BW_RDF { atm_bw_rdf <8> } } } } #endif def ie_ep_ref = { ITU_STD_HDR { _ep_type <8> = 0 ep_ref <16> } } def ie_ep_state = { ITU_STD_HDR { ep_state <6@1> } } #if defined(Q2963_1) || defined(DYNAMIC_UNI) def ie_bbrt = { ITU_STD_HDR { type_of_report "atm_tor" <8> } } #endif { _pdsc "q2931_proto" <8> = Q2931_PROTO_DSC _cr_len <8> = 3 call_ref <24> msg_type "atm_msg" <8> _ext <1@8,more> = 1 _flag "atm_flag" <1@5,more> = ATM_FLAG_NO _action_ind "atm_ai_msg" <2@1> = 0 msg_len <16> = length { _ie_id "atm_ie" <8> = multi { aal: ATM_IE_AAL ie_aal td: ATM_IE_TD ie_td bbcap: ATM_IE_BBCAP ie_bbcap bhli: ATM_IE_BHLI ie_bhli blli1: ATM_IE_BLLI ie_blli blli2: ATM_IE_BLLI ie_blli blli3: ATM_IE_BLLI ie_blli call_state: ATM_IE_CALL_STATE ie_call_state cdpn: ATM_IE_CDPN ie_cdpn cdps: ATM_IE_CDPS ie_cdps cgpn: ATM_IE_CGPN ie_cgpn cgps: ATM_IE_CGPS ie_cgps cause: ATM_IE_CAUSE ie_cause cause2: ATM_IE_CAUSE ie_cause conn_id: ATM_IE_CONN_ID ie_conn_id #if defined(UNI40) || defined(DYNAMIC_UNI) e2e_tdl: ATM_IE_E2E_TDL ie_e2e_tdl #endif qos: ATM_IE_QOS ie_qos bbrep: ATM_IE_BBREP ie_bbrep restart: ATM_IE_RESTART ie_restart bbs_comp: ATM_IE_BBS_COMP ie_bbs_comp tns: ATM_IE_TNS ie_tns #if defined(UNI40) || defined(DYNAMIC_UNI) notify: ATM_IE_NOTIFY ie_notify oam_td: AT... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:08
|
Update of /cvsroot/linux-atm/linux-atm/src/man In directory usw-pr-cvs1:/tmp/cvs-serv10656/man Added Files: Tag: V2_4_0 qos.7 sap.7 Makefile.am Log Message: --- NEW FILE: qos.7 --- .TH QOS 7 "April 20, 2000" "Linux" "Miscellaneous" .SH NAME qos \- Quality of Service specification .SH DESCRIPTION The \fBtext2qos\fP and \fBqos2text\fP functions use the format described in this man page. Because all standard ATM tools on Linux use those functions to convert to or from the textual representation of QOS specifications, they expect them in the same format too. .P The most fundamental parameters are the \fItraffic class\fP and the \fIAAL (ATM Adaption Layer) type\fP. If the connection is bi-directional, both directions have the same traffic class and the same AAL type. The traffic class and the AAL type are the first elements (in any order) in a QOS specification. The traffic class is the only required element. If the AAL type is omitted, the application will provide a default value. The following traffic classes are recognized: .IP \fBubr\fP Unassigned Bit Rate .IP \fBcbr\fP Constant Bit Rate .IP \fBabr\fP Available Bit Rate .P The following AAL types are recognized: .IP \fBaal0\fP ("raw ATM") .IP \fBaal5\fP .P If both, the traffic class and the AAL type are specified, they are separated by a comma. .P If more parameters are supplied, the traffic class and AAL type must be followed by a colon. Traffic parameters can be specified independently for the transmit and the receive direction. Their parameter lists are prefixed with \fBtx:\fP and \fBrx:\fP, respectively. If both parameter lists are present, the \fBtx:\fP list must precede the \fBrx:\fP list. If a parameter is equal for both directions, it can be placed in a common parameter list (without prefix). The general format is as follows: .P \fIclass_and_aal\fB:\fIcommon_list\fP,tx:\fIlist\fB,rx:\fIlist\fP .P Each list consists of elements specifying a parameter. Elements can appear in any order and they are separated with commas. The following elements are recognized: .IP \fBpcr=\fIrate\fP is a synonym for \fBmax_pcr=\fIrate\fP .IP \fBmax_pcr=\fIrate\fP The upper limit for the peak cell rate to assign. If omitted, any rate up to link speed may be chosen. .IP \fBmin_pcr=\fIrate\fP The lower limit for the peak cell rate to assign. If omitted, any rate above zero can be chosen. .IP \fBsdu=\fIsize\fP is a synonym for \fBmax_sdu=\fIsize\fP .IP \fBmax_sdu=\fIsize\fP The size of the largest packet that may be sent or received. If omitted, a context-dependent default value is used. .P Values are specified as follows: .IP \fIrate\fP The (decimal) rate, optionally followed by a unit. The unit may be prefixed with one of the multipliers \fBk\fP, \fBM\fP, or \fBG\fP, meaning 1'000, 1'000'000, or 1'000'000'000, respectively. The units \fBcps\fP (cells per second) and \fBbps\fP (bits per second) are recognized. If multiplier and unit are omitted, cells per second are assumed. Note that the rate is always converted to cells per second, so rounding errors may occur when specifying the rate in bits per second. Rates measured in bits per second are considered to be user data rates, i.e. one cell corresponds to 384 bits. The rate can be a fractional value, e.g. \fB1.3Mbps\fP. It is an error to specify only a multiplier without a unit. Link speed can be indicated by using the keyword \fBmax\fP as the rate. .IP \fIsize\fP The (decimal) number of bytes. .P The \fBtx:\fP or \fBrx:\fP lists may also just contain the single element \fBnone\fP, which indicates that the corresponding direction is not used. It is an error to specify \fBnone\fP for both direction. .P Note that commas must never follow colons or other commas. Also, whitespace is not allowed inside a QOS specification. QOS specifications are case-insensitive. .SH EXAMPLES Each of the following lines contains a valid QOS specification: .nf .sp ubr ubr:pcr=100kbps cbr,aal0:pcr=64kbps CBR:max_pcr=11Mbps,min_pcr=10mbps,sdu=8192 aal5,ubr:tx:none cbr:tx:pcr=30000,rx:none .sp .fi The following specificiations are equivalent: .nf .sp CBR,AAL5:PCR=48Mbps cbr,aal5:max_pcr=125000 cbr,aal5:tx:pcr=125kcps,rx:pcr=125kcps .sp .fi .SH AUTHOR Werner Almesberger, EPFL LRC/ICA <wer...@ep...> .\" .SH "SEE ALSO" .\" atmsigd(8), syslogd(8) .\"{{{}}} --- NEW FILE: sap.7 --- .TH SAP 7 "November 6, 1997" "Linux" "Miscellaneous" .SH NAME sap \- Service Access Point specification .SH DESCRIPTION The \fBtext2sap\fP and \fBsap2text\fP functions use the format described in this man page. Because all standard ATM tools on Linux use those functions to convert to or from the textual representation of SAP specifications, they expect them in the same format too. .P The SAP is divided into two parts: the \fIbroadband high layer information\fP (BHLI) and the \fIbroadband low layer information\fP (BLLI). A SAP can contain one, both, or none of them. In the latter case, the SAP is usually considered as a wildcard SAP, i.e. a SAP that is compatible with any other SAP. .P Each part begins with its name (\fBbhli\fP or \fBblli\fP), followed by a colon and a (non-empty) list of attributes, which are of the form \fIattribute\fP\fB=\fP\fIvalue\fP. Some attributes have sub-attributes, which follow them. Everything that isn't separated by a colon or an equal sign is separated by a comma. .P Values which are a number of bytes are specified as the corresponding sequence of pairs of hex digits. The sequence can be optionally prefixed with \fB0x\fP. Values with are integers in a given range can be specified in decimal (no prefix), octal (\fB0\fP prefix), and hexadecimal (\fB0x\fP prefix). .P The following, mutually exclusive attributes are allowed in the \fBbhli\fP part (see the corresponding ATM Forum and ITU documents for the semantics): .IP \fBiso=\fI1\-8\ bytes\fP ISO .IP \fBuser=\fI1\-8\ bytes\fP User-specific .IP \fBhlp=\fI4\ bytes\fP High layer profile. Note that this attribute only exists on UNI 3.0. \fBtext2sap\fP only recognizes it if your system is configured to accept UNI 3.0 message formats. .IP \fBoui=\fI3\ bytes\fB,id=\fI4\ bytes\fP Vendor-specific application identifier .P The structure of the \fBbhli\fP part is more complex. It distinguishes three layers, \fBl1\fP, \fBl2\fP, and \fBl3\fP, of which the first one is presently unsupported. For layer two, the following (mutually exclusive) possibilities exist: .IP \fBl2=iso1745\fP Basic mode ISO 1745 .IP \fBl2=q291\fP ITU-T Q.291 (Rec. I.441) .IP \fBl2=lapb\fP Extended LAPB, half-duplex (Rec. T.71) .IP \fBl2=iso8802\fP LAN LLC (ISO/IEC 8802/2) .IP \fBl2=x75\fP ITU-T X.75, SLP .IP \fBl2=x25_ll\fP\ ... ITU-T X.25, link layer. This attribute and the following attributes through \fBl2=iso7776\fP can optionally be followed by one or more of the following sub-attributes: \fBmode=\fP\fImode\fP (mode of operation, either \fBnorm\fP or \fBext\fP), and \fBwindow=\fP\fIwindow size\fP (window size in k, 1\-127). .IP \fBl2=x25_ml\fP\ ... ITU-T X.25, multilink .IP \fBl2=hdlc_arm\fP\ ... HDLC ARM (ISO/IEC 4335) .IP \fBl2=hdlc_nrm\fP\ ... HDLC NRM (ISO/IEC 4335) .IP \fBl2=hdlc_abm\fP\ ... HDLC ABM (ISO/IEC 4335) .IP \fBl2=q992\fP\ ... ITU-T Q.922 .IP \fBl2=iso7776\fP\ ... ISO 7776 DTE-DTE .IP \fBl2=user,info=\fIinformation\fP User-specified. \fIinformation\fP is an integer in the range 0 to 255. .P For layer three, the following (again, mutually exclusive) possibilities exist: .IP \fBl3=iso8473\fP ITU-T X.233 | ISO/IEC 8473 .IP \fBl3=t70\fP ITU-T T.70 minimum network layer .IP \fBl3=h321\fP ITU-T Recommendation H.321 .IP \fBl3=x25\fP\ ... ITU-T X.25, packet layer. This attribute and the following attributes through \fBl3=x223\fP can optionally be followed by one or more of the following sub-attributes: \fBmode=\fP\fImode\fP (see above), \fBsize=\fP\fIdefault packet size\fP (4\-12, corresponding to 16\-4096), \fBwindow=\fP\fIwindow size\fP (see above). .IP \fBl3=iso8208\fP\ ... ISO/IEC 8208 .IP \fBl3=x223\fP\ ... ITU-T X.223 | ISO/IEC 8878 .IP \fBl3=tr9577,ipi=\fP\fIidentifier\fP\ ... ISO/IEC TR 9577. \fIidentifier\fP is the initial protocol identifier in the range 0\-255. For SNAP (0x80), the keyword \fBsnap\fP can be used, and the following sub-attributes have to be specified: \fBoui=\fP\fI3 bytes\fP, and \fBpid=\fP\fI2 bytes\fP. .IP \fBl2=user,info=\fIinformation\fP User-specified, see above. .IP \fBl3=h310\fP\ ... ITU-T Recommendation H.310. The sub-attribute \fBterm=\fP\fItype\fP (terminal type, \fBrx\fP, \fBtx\fP, or \fBrxtx\fP) is recognized. If present, it enables the two additional sub-attributes \fBfw_mpx=\fP\fIcapability\fP (forward multiplexing capability, \fBts\fP, \fBts_fec\fP, \fBps\fP, \fBps_fec\fP, or \fBh221\fP) and \fBbw_mpx=\fP\fIcapability\fP. Both are optional. .P Note that commas must never follow colons or other commas. Also, whitespace is not allowed inside a SAP specification. SAP specifications are case-insensitive. On input, items must be written in exactly the order used in this document. .P .SH EXAMPLES .IP \fBblli:l2=iso8802\fP Classical IP over ATM (RFC1577) .IP \fBbhli:oui=0x0060D7,id=0x01000001,blli:l2=iso8802\fP Arequipa (RFC2170) .IP \fBblli:l3=tr9577,ipi=snap,oui=0x00A03E,pid=0x0002\fP LAN Emulation .SH AUTHOR Werner Almesberger, EPFL LRC <wer...@lr...> .\"{{{}}} --- NEW FILE: Makefile.am --- man_MANS = qos.7 sap.7 EXTRA_DIST = $(man_MANS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:08
|
Update of /cvsroot/linux-atm/linux-atm/src/arpd In directory usw-pr-cvs1:/tmp/cvs-serv10656/arpd Added Files: Tag: V2_4_0 io.c io.h arp.c arp.h itf.c itf.h table.c table.h Makefile.am atmarpd.8 atmarpd.c atmarpd.h atmarp.8 atmarp.c atmarp.h Log Message: --- NEW FILE: io.c --- /* io.c - I/O operations */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/in.h> #include <atm.h> #include <linux/atmclip.h> /* for CLIP_DEFAULT_IDLETIMER */ #include <linux/atmarp.h> #define _LINUX_NETDEVICE_H /* glibc2 */ #include <linux/if_arp.h> #include "atmd.h" #include "atmarpd.h" #include "table.h" #include "arp.h" #include "itf.h" #include "io.h" #define COMPONENT "IO" struct timeval now; static int kernel,incoming,inet,unix_sock; /* ----- kernel interface -------------------------------------------------- */ static void open_kernel(void) { struct sockaddr_atmsvc addr; struct atm_qos qos; struct atm_sap sap; if ((kernel = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); if (ioctl(kernel,ATMARPD_CTRL,0) < 0) diag(COMPONENT,DIAG_FATAL,"ioctl ATMARPD_CTRL: %s",strerror(errno)); if ((incoming = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_ANYCLASS; if (setsockopt(incoming,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) diag(COMPONENT,DIAG_FATAL,"setsockopt SO_ATMQOS: %s",strerror(errno)); memset(&sap,0,sizeof(sap)); sap.blli[0].l2_proto = ATM_L2_ISO8802; sap.blli[0].l3_proto = ATM_L3_NONE; if (setsockopt(incoming,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) diag(COMPONENT,DIAG_FATAL,"setsockopt SO_ATMSAP: %s",strerror(errno)); memset(&addr,0,sizeof(addr)); addr.sas_family = AF_ATMSVC; if (bind(incoming,(struct sockaddr *) &addr,sizeof(addr)) >= 0) { if (listen(incoming,5) < 0) diag(COMPONENT,DIAG_FATAL,"listen: %s",strerror(errno)); } else { if (errno != EUNATCH) diag(COMPONENT,DIAG_FATAL,"bind: %s",strerror(errno)); diag(COMPONENT,DIAG_WARN,"SVCs are not available"); (void) close(incoming); incoming = -1; } if ((inet = socket(PF_INET,SOCK_DGRAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); } static void recv_kernel(void) { struct atmarp_ctrl ctrl; int size; size = read(kernel,&ctrl,sizeof(ctrl)); if (size < 0) { diag(COMPONENT,DIAG_ERROR,"read kernel: %s",strerror(errno)); return; } switch (ctrl.type) { case act_need: need_ip(ctrl.itf_num,ctrl.ip); break; case act_up: itf_up(ctrl.itf_num); break; case act_down: itf_down(ctrl.itf_num); break; case act_change: itf_change(ctrl.itf_num); break; default: diag(COMPONENT,DIAG_ERROR,"invalid control msg type 0x%x", ctrl.type); } } static void close_kernel(void) { if (incoming >= 0) (void) close(incoming); (void) close(kernel); /* may get major complaints from the kernel ... */ (void) close(inet); } /* ----- atmarp (maintenance) interface ------------------------------------ */ static void open_unix(void) { unix_sock = un_create(ATMARP_SOCKET_PATH,0600); if (unix_sock < 0) diag(COMPONENT,DIAG_FATAL,"un_create: %s",strerror(errno)); } void notify(const UN_CTX *ctx,uint32_t ip,const ENTRY *entry) { struct atmarp_req reply; memset(&reply,0,sizeof(reply)); reply.type = art_query; reply.ip = ip; if (entry && entry->addr) reply.addr = *entry->addr; if (un_send(ctx,&reply,sizeof(reply)) < 0) diag(COMPONENT,DIAG_WARN,"notify: %s",strerror(errno)); } static void recv_unix(void) { UN_CTX ctx; struct atmarp_req req; int len,reply; len = un_recv(&ctx,unix_sock,&req,sizeof(req)); if (len < 0) { diag(COMPONENT,DIAG_ERROR,"recv_unix: %s",strerror(errno)); return; } if (len != sizeof(req)) { diag(COMPONENT,DIAG_ERROR,"bad unix read: %d != %d",len,sizeof(req)); return; } switch (req.type) { case art_create: reply = ioctl(kernel,SIOCMKCLIP,req.itf); if (reply >= 0) itf_create(reply); break; case art_qos: case art_set: case art_delete: reply = arp_ioctl(&req); break; case art_table: reply = table_update(); break; case art_query: query_ip(&ctx,req.ip); return; default: diag(COMPONENT,DIAG_ERROR,"invalid request msg type 0x%x",req.type); reply = -EINVAL; } if (un_send(&ctx,&reply,sizeof(reply)) < 0) diag(COMPONENT,DIAG_ERROR,"un_send: %s",strerror(errno)); } static void close_unix(void) { (void) close(unix_sock); (void) unlink(ATMARP_SOCKET_PATH); } /* ----- common part ------------------------------------------------------- */ #define MAX_BUFFER 1024 static fd_set rset,cset; int do_close(int fd) { int result; result = close(fd); FD_CLR(fd,&rset); /* we might open a new fd with the same number, so ... */ FD_CLR(fd,&cset); return result; } static void recv_vcc(VCC *vcc) { unsigned char buffer[MAX_BUFFER]; int size; size = read(vcc->fd,buffer,MAX_BUFFER); if (!size) { disconnect_vcc(vcc); return; } if (size < 0) { diag(COMPONENT,DIAG_ERROR,"read vcc: %s",strerror(errno)); disconnect_vcc(vcc); return; } if (debug) { int i; for (i = 0; i < size; i++) printf("%02X ",buffer[i]); printf("\n"); } incoming_arp(vcc,(struct atmarphdr *) buffer,size); } static void drain_vcc(VCC *vcc) { unsigned char buffer[MAX_BUFFER]; char line[80]; /* actually, it's only 7+16*3+1 */ int size; int i; size = read(vcc->fd,buffer,MAX_BUFFER); if (!size) { disconnect_vcc(vcc); return; } if (size < 0) { diag(COMPONENT,DIAG_ERROR,"read vcc: %s",strerror(errno)); disconnect_vcc(vcc); return; } diag(COMPONENT,DIAG_WARN,"drain_vcc: unexpected message on " "unidirectional (RSVP?) VCC %p:",vcc); for (i = 0; i < size; i++) { if (!(i & 15)) { if (i) diag(COMPONENT,DIAG_WARN,"%s",line); sprintf(line," %04x:",i); *line = 0; } sprintf(strchr(line,0)," %02x",buffer[i]); } diag(COMPONENT,DIAG_WARN,"%s",line); } static void accept_new(void) { char buffer[MAX_ATM_ADDR_LEN+1]; struct sockaddr_atmsvc addr; struct atm_qos qos; ENTRY *entry; VCC *vcc; int fd,len,size,error; len = sizeof(addr); if ((fd = accept(incoming,(struct sockaddr *) &addr,&len)) < 0) { error = errno; diag(COMPONENT,DIAG_ERROR,"accept: %s",strerror(errno)); if (error == EUNATCH) { diag(COMPONENT,DIAG_WARN,"disabling SVCs"); (void) close(incoming); incoming = -1; } return; } /* the following code probably belongs to arp.c ... */ if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &addr,pretty) < 0) strcpy(buffer,"<atm2text error>"); diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer); size = sizeof(qos); if (getsockopt(fd,SOL_ATM,SO_ATMQOS,&qos,&size) < 0) diag(COMPONENT,DIAG_FATAL,"getsockopt SO_ATMQOS: %s",strerror(errno)); if (size != sizeof(qos)) diag(COMPONENT,DIAG_FATAL,"SO_ATMQOS: size %d != %d",size,sizeof(qos)); if (ioctl(fd,ATMARP_MKIP,qos.txtp.traffic_class == ATM_NONE ? 0 : CLIP_DEFAULT_IDLETIMER) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_MKIP: %s",strerror(errno)); (void) do_close(fd); return; } vcc = alloc_t(VCC); vcc->active = 0; vcc->connecting = 0; vcc->fd = fd; if (qos.txtp.traffic_class == ATM_NONE) { vcc->entry = NULL; incoming_unidirectional(vcc); Q_INSERT_HEAD(unidirectional_vccs,vcc); return; } if (merge) { ITF *itf; for (itf = itfs; itf; itf = itf->next) { entry = lookup_addr(itf,&addr); if (entry) { vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); if (entry->state == as_valid) { if (set_ip(vcc->fd,entry->ip) < 0) { diag(COMPONENT,DIAG_ERROR,"set_ip: %s", strerror(errno)); disconnect_vcc(vcc); } else set_sndbuf(vcc); } return; } } } entry = alloc_entry(1); entry->state = as_invalid; entry->addr = alloc_t(struct sockaddr_atmsvc); *entry->addr = addr; entry->flags = ATF_PUBL; Q_INSERT_HEAD(unknown_incoming,entry); vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); incoming_call(vcc); } int connect_vcc(struct sockaddr *remote,const struct atm_qos *qos,int sndbuf, int timeout) { int fd,error,flags; if (remote->sa_family == AF_ATMSVC && incoming < 0) return -EUNATCH; if ((fd = socket(remote->sa_family,SOCK_DGRAM,0)) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"socket: %s",strerror(errno)); return error; } if (setsockopt(fd,SOL_ATM,SO_ATMQOS,qos,sizeof(*qos)) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"setsockopt SO_ATMQOS: %s",strerror(errno)); return error; } if (sndbuf) if (setsockopt(fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"setsockopt SO_SNDBUF: %s", strerror(errno)); return error; } if ((flags = fcntl(fd,F_GETFL)) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"fcntl F_GETFL: %s",strerror(errno)); return error; } flags |= O_NONBLOCK; if (fcntl(fd,F_SETFL,flags) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"fcntl F_GETFL: %s",strerror(errno)); return error; } if (remote->sa_family == AF_ATMSVC) { /* @@@ that's cheating */ struct atm_sap sap; memset(&sap,0,sizeof(sap)); sap.blli[0].l2_proto = ATM_L2_ISO8802; sap.blli[0].l3_proto = ATM_L3_NONE; if (setsockopt(fd,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"setsockopt SO_ATMSAP: %s", strerror(errno)); return error; } } /* PVC connect never blocks */ if (connect(fd,remote,remote->sa_family == AF_ATMPVC ? sizeof(struct sockaddr_atmpvc) : sizeof(struct sockaddr_atmsvc)) < 0) { if (errno != EINPROGRESS) { error = -errno; diag(COMPONENT,DIAG_ERROR,"[1]connect: %s",strerror(errno)); return error; } return fd; } if (ioctl(fd,ATMARP_MKIP,timeout) < 0) { error = -errno; diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_MKIP: %s",strerror(errno)); (void) do_close(fd); return error; } return fd; } int set_ip(int fd,int ip) { int error; if (ioctl(fd,ATMARP_SETENTRY,ip) >= 0) return 0; error = -errno; diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_SETENTRY: %s",strerror(errno)); return error; } int set_encap(int fd,int mode) { int error; if (ioctl(fd,ATMARP_ENCAP,mode) >= 0) return 0; error = -errno; diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_ENCAP: %s",strerror(errno)); (void) do_close(fd); return error; } void set_sndbuf(VCC *vcc) { if (setsockopt(vcc->fd,SOL_SOCKET,SO_SNDBUF,&vcc->entry->sndbuf, sizeof(int)) >= 0) return; diag(COMPONENT,DIAG_ERROR,"setsockopt SO_SNDBUF: %s",strerror(errno)); } static void complete_connect(VCC *vcc) { struct sockaddr_atmsvc dummy; if (!vcc->connecting) diag(COMPONENT,DIAG_FATAL,"connecting non-connecting VCC 0x%p",vcc); memset(&dummy,0,sizeof(dummy)); if (!connect(vcc->fd,(struct sockaddr *) &dummy,sizeof(dummy))) { if (ioctl(vcc->fd,ATMARP_MKIP,CLIP_DEFAULT_IDLETIMER) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_MKIP: %s",strerror(errno)); (void) do_close(vcc->fd); vcc_failed(vcc); } vcc_connected(vcc); } else { diag(COMPONENT,DIAG_INFO,"[2]connect: %s",strerror(errno)); (void) do_close(vcc->fd); vcc_failed(vcc); } } void poll_loop(void) { ITF *itf,*next_itf; ENTRY *entry,*next_entry; VCC *vcc,*next_vcc; int fds,ret; gettimeofday(&now,NULL); while (1) { FD_ZERO(&rset); FD_ZERO(&cset); FD_SET(kernel,&rset); FD_SET(unix_sock,&rset); if (incoming >= 0) FD_SET(incoming,&rset); fds = incoming+1; if (kernel >= fds) fds = kernel+1; if (unix_sock >= fds) fds = unix_sock+1; for (itf = itfs; itf; itf = itf->next) for (entry = itf->table; entry; entry = entry->next) for (vcc = entry->vccs; vcc; vcc = vcc->next) { if (vcc->connecting) FD_SET(vcc->fd,&cset); else FD_SET(vcc->fd,&rset); if (vcc->fd >= fds) fds = vcc->fd+1; } for (entry = unknown_incoming; entry; entry = entry->next) { if (!entry->vccs || entry->vccs->next) { diag(COMPONENT,DIAG_ERROR,"internal error: bad unknown entry"); continue; } FD_SET(entry->vccs->fd,&rset); if (entry->vccs->fd >= fds) fds = entry->vccs->fd+1; } for (vcc = unidirectional_vccs; vcc; vcc = vcc->next) { FD_SET(vcc->fd,&rset); if (vcc->fd >= fds) fds = vcc->fd+1; } ret = select(fds,&rset,&cset,NULL,next_timer()); /* * Now here's something strange: < 0.32 needed the exception mask to be NULL * in order to work, due to a bug in atm_select. In 0.32, this has been fixed. * Also, 2.1 kernels use the poll mechanism and not select, so select is * emulated on top of poll. Now the funny bit is that, as soon as the exception * set is non-NULL, when a non-blocking connect finishes, select returns one * but has none if the possible bits set in either rset or cset. To make things * even stranger, no exception is actually found in sys_select, so this must be * some very odd side-effect ... The work-around for now is to simply pass NULL * for the exception mask (which is the right thing to do anyway, but it'd be * nice if doing a perfectly valid variation wouldn't blow up the system ...) */ #if 0 { int i; for (i = 0; i < sizeof(rset); i++) fprintf(stderr,"%02x:%02x ",((unsigned char *) &rset)[i], ((unsigned char *) &cset)[i]); fprintf(stderr,"\n"); } #endif if (ret < 0) { if (errno != EINTR) perror("select"); } else { diag(COMPONENT,DIAG_DEBUG,"----------"); gettimeofday(&now,NULL); if (FD_ISSET(kernel,&rset)) recv_kernel(); if (FD_ISSET(unix_sock,&rset)) recv_unix(); if (incoming >= 0 && FD_ISSET(incoming,&rset)) accept_new(); for (itf = itfs; itf; itf = next_itf) { next_itf = itf->next; for (entry = itf->table; entry; entry = next_entry) { next_entry = entry->next; for (vcc = entry->vccs; vcc; vcc = next_vcc) { next_vcc = vcc->next; if (FD_ISSET(vcc->fd,&rset)) recv_vcc(vcc); else if (FD_ISSET(vcc->fd,&cset)) complete_connect(vcc); } } } for (entry = unknown_incoming; entry; entry = next_entry) { next_entry = entry->next; if (FD_ISSET(entry->vccs->fd,&rset)) recv_vcc(entry->vccs); } for (vcc = unidirectional_vccs; vcc; vcc = next_vcc) { next_vcc = vcc->next; if (FD_ISSET(vcc->fd,&rset)) drain_vcc(vcc); } expire_timers(); /* expire timers after handling messages to make sure we don't time out unnecessarily because of scheduling delays */ } table_changed(); } } void send_packet(int fd,void *data,int length) { int wrote; if (debug) { int i; for (i = 0; i < length; i++) printf("%02X ",((unsigned char *) data)[i]); printf("\n"); } if ((wrote = write(fd,data,length)) == length) return; if (wrote < 0) diag(COMPONENT,DIAG_ERROR,"write: %s",strerror(errno)); else diag(COMPONENT,DIAG_ERROR,"short write: %d < %d",wrote,length); } int ip_itf_info(int number,uint32_t *ip,uint32_t *netmask,int *mtu) { struct ifreq req; unsigned char *p1,*p2; sprintf(req.ifr_ifrn.ifrn_name,"atm%d",number); if (ioctl(inet,SIOCGIFADDR,&req) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl SIOCGIFADDR: %s",strerror(errno)); return -1; } *ip = ((struct sockaddr_in *) &req.ifr_ifru.ifru_addr)->sin_addr.s_addr; if (ioctl(inet,SIOCGIFNETMASK,&req) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl SIOCGIFNETMASK: %s",strerror(errno)); return -1; } *netmask = ((struct sockaddr_in *) &req.ifr_ifru.ifru_netmask)-> sin_addr.s_addr; if (ioctl(inet,SIOCGIFMTU,&req) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl SIOCGIFMTU: %s",strerror(errno)); return -1; } *mtu = req.ifr_ifru.ifru_mtu; p1 = (unsigned char *) ip; p2 = (unsigned char *) netmask; diag(COMPONENT,DIAG_DEBUG,"ip %d.%d.%d.%d mask %d.%d.%d.%d mtu %d", p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3],*mtu); return 0; } int get_local(int fd,struct sockaddr_atmsvc *addr) { int length,result; length = sizeof(struct sockaddr_atmsvc); result = getsockname(fd,(struct sockaddr *) addr,&length); if (result < 0) diag(COMPONENT,DIAG_ERROR,"getsockname: %s",strerror(errno)); return result; } void open_all(void) { open_kernel(); open_unix(); } void close_all(void) { close_kernel(); close_unix(); } --- NEW FILE: io.h --- /* io.h - I/O operations */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef IO_H #define IO_H #include <stdint.h> #include <sys/socket.h> /* for struct sockaddr */ #include <atm.h> /* for struct sockaddr_atmsvc */ #include <atmd.h> #include "table.h" void open_all(void); void close_all(void); void notify(const UN_CTX *ctx,uint32_t ip,const ENTRY *entry); int do_close(int fd); void poll_loop(void); int connect_vcc(struct sockaddr *remote,const struct atm_qos *qos,int sndbuf, int timeout); int set_ip(int fd,int ip); int set_encap(int fd,int mode); void set_sndbuf(VCC *vcc); void send_packet(int fd,void *data,int length); int ip_itf_info(int number,uint32_t *ip,uint32_t *netmask,int *mtu); int get_local(int fd,struct sockaddr_atmsvc *addr); #endif --- NEW FILE: arp.c --- /* arp.c - ARP state machine */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <assert.h> #include <sys/types.h> #include <sys/socket.h> /* for linux/if_arp.h */ #include <netinet/in.h> /* for ntohs, etc. */ #define _LINUX_NETDEVICE_H /* very crude hack for glibc2 */ #include <linux/if_arp.h> [...1059 lines suppressed...] diag(COMPONENT,DIAG_DEBUG,"disconnected VCC 0x%p",vcc); entry = vcc->entry; discard_vcc(vcc); if (entry) vcc_detach(entry); } void incoming_call(VCC *vcc) { diag(COMPONENT,DIAG_DEBUG,"incoming VCC 0x%p",vcc); START_TIMER(vcc->entry,REPLY); inarp_request(vcc->entry); } void incoming_unidirectional(VCC *vcc) { diag(COMPONENT,DIAG_DEBUG,"incoming unidirectional VCC 0x%p",vcc); /* don't put it into ATMARP table */ } --- NEW FILE: arp.h --- /* arp.h - ARP state machine */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef ARP_H #define ARP_H #include <stdint.h> #include <linux/atmarp.h> #include "atmd.h" #include "atmarp.h" #include "atmarpd.h" #include "table.h" void discard_vccs(ENTRY *entry); void discard_entry(ENTRY *entry); void vcc_detach(ENTRY *entry); void need_ip(int itf_num,uint32_t ip); void query_ip(const UN_CTX *ctx,uint32_t ip); void incoming_arp(VCC *vcc,struct atmarphdr *hdr,int len); int arp_ioctl(struct atmarp_req *req); void vcc_connected(VCC *vcc); void vcc_failed(VCC *vcc); void disconnect_vcc(VCC *vcc); void incoming_call(VCC *vcc); void incoming_unidirectional(VCC *vcc); #endif --- NEW FILE: itf.c --- /* itf.c - IP interface registry */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdint.h> #include <string.h> #include <sys/types.h> #include <linux/atmclip.h> #include <sys/socket.h> #define _LINUX_NETDEVICE_H /* glibc2 */ #include <linux/if_arp.h> #include "atmd.h" #include "table.h" #include "io.h" #include "itf.h" #include "arp.h" #define COMPONENT "ITF" ITF *lookup_itf(int number) { ITF *itf; for (itf = itfs; itf; itf = itf->next) if (itf->number == number) break; return itf; } ITF *lookup_itf_by_ip(uint32_t ip) { ITF *itf; for (itf = itfs; itf; itf = itf->next) if (!((itf->local_ip ^ ip) & itf->netmask)) break; return itf; } void itf_create(int number) { diag(COMPONENT,DIAG_DEBUG,"ITF CREATE %d",number); } void itf_up(int number) { ITF *itf; diag(COMPONENT,DIAG_DEBUG,"ITF UP %d",number); if (lookup_itf(number)) { diag(COMPONENT,DIAG_ERROR,"interface is already active"); return; } itf = alloc_t(ITF); if (ip_itf_info(number,&itf->local_ip,&itf->netmask,&itf->mtu) < 0) { free(itf); return; } itf->number = number; memset(&itf->qos,0,sizeof(struct atm_qos)); itf->qos.aal = ATM_AAL5; itf->qos.txtp.traffic_class = ATM_UBR; itf->qos.txtp.max_sdu = RFC1483LLC_LEN+RFC1626_MTU; itf->qos.rxtp = itf->qos.txtp; itf->sndbuf = 0; /* use system default */ itf->table = itf->arp_srv = NULL; Q_INSERT_HEAD(itfs,itf); } static void itf_bring_down(ITF *itf) { ENTRY *entry,*next; for (entry = itf->table; entry; entry = next) { next = entry->next; discard_entry(entry); } Q_REMOVE(itfs,itf); free(itf); } void itf_down(int number) { ITF *itf; diag(COMPONENT,DIAG_DEBUG,"ITF DOWN %d",number); itf = lookup_itf(number); if (!itf) { diag(COMPONENT,DIAG_ERROR,"no such interface (%d)",number); return; } itf_bring_down(itf); } void itf_change(int number) { ITF *itf; ENTRY *entry,*next,*disconnected; uint32_t local_ip,netmask; int mtu; diag(COMPONENT,DIAG_DEBUG,"ITF CHANGE %d",number); itf = lookup_itf(number); if (!itf) { diag(COMPONENT,DIAG_DEBUG,"no interface to change (%d)",number); return; } if (ip_itf_info(number,&local_ip,&netmask,&mtu) < 0) { itf_bring_down(itf); return; } disconnected = NULL; for (entry = itf->table; entry; entry = next) { next = entry->next; if ((entry->flags & ATF_PERM) && !((entry->ip ^ local_ip) & (netmask | itf->netmask))) continue; if ((entry->flags & ATF_ARPSRV) && !((entry->ip ^ local_ip) & netmask)) { disconnected = entry; discard_vccs(entry); /* @@@ should adjust max_sdu if mtu changed */ continue; } discard_entry(entry); } itf->local_ip = local_ip; itf->netmask = netmask; itf->mtu = mtu; if (disconnected) vcc_detach(disconnected); } --- NEW FILE: itf.h --- /* itf.h - IP interface registry */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef ITF_H #define ITF_H #include <stdint.h> #include "table.h" ITF *lookup_itf(int number); ITF *lookup_itf_by_ip(uint32_t ip); void itf_create(int number); void itf_up(int number); void itf_down(int number); void itf_change(int number); #endif --- NEW FILE: table.c --- /* table.c - ATMARP table */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #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; } --- NEW FILE: table.h --- /* table.h - ATMARP table */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef TABLE_H #define TABLE_H #include <stdint.h> #include <stdio.h> #include <linux/atm.h> #include "atmd.h" typedef struct _vcc { int connecting; int active; /* indicate direction - for user entertainment only */ int fd; struct _entry *entry; struct _vcc *prev,*next; } VCC; typedef enum { as_none, /* invalid */ as_resolv, /* waiting for resolver response */ as_invalid, /* invalid, waiting for all VCs to be closed */ as_valid, /* valid */ } ADDR_STATE; typedef struct _notify { UN_CTX ctx; /* peer to send reply to */ struct _notify *next; } NOTIFY; typedef struct _entry { ADDR_STATE state; int svc; uint32_t ip; struct sockaddr_atmsvc *addr; /* NULL if none */ struct atm_qos qos; int sndbuf; int flags; TIMER *timer; /* currently active timer or NULL */ int timeout; /* current interval - only necessary if using retries */ int retries; VCC *vccs; NOTIFY *notify; struct _itf *itf; struct _entry *prev,*next; /* undefined if itf == NULL */ } ENTRY; typedef struct _itf { uint32_t local_ip; /* @@@ */ uint32_t netmask; int number; int mtu; struct atm_qos qos; /* default QOS */ int sndbuf; /* default send buffer */ ENTRY *table; ENTRY *arp_srv; /* NULL is none */ struct _itf *prev,*next; } ITF; /* * May want to consider using one big unified table instead of lots of small * tables (one per interface). */ extern const char *entry_state_name[]; extern const char *vcc_state_name[]; extern ITF *itfs; extern ENTRY *unknown_incoming; extern VCC *unidirectional_vccs; extern int pretty,merge; ENTRY *alloc_entry(int svc); ENTRY *lookup_ip(const ITF *itf,uint32_t ip); ENTRY *lookup_addr(const ITF *itf,const struct sockaddr_atmsvc *addr); ENTRY *lookup_incoming(const struct sockaddr_atmsvc *addr); void table_changed(void); int table_update(void); #endif --- NEW FILE: Makefile.am --- LDADD = $(top_builddir)/src/lib/libatmd.la $(top_builddir)/src/lib/libatm.la sbin_PROGRAMS = atmarp atmarpd atmarp_SOURCES = atmarp.c atmarp.h atmarpd.h atmarpd_SOURCES = atmarpd.c atmarpd.h arp.c arp.h io.c io.h itf.c itf.h \ table.c table.h atmarp.h include_HEADERS = atmarp.h atmarpd.h man_MANS = atmarp.8 atmarpd.8 EXTRA_DIST = $(man_MANS) --- NEW FILE: atmarpd.8 --- .TH ATMARPD 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmarpd \- ATMARP demon .SH SYNOPSIS .B atmarpd .RB [ \-b ] .RB [ \-d ] .RB [ \-D\ \fIdirectory\fP ] .RB [ \-l\ \fIlogfile\fP ] .RB [ \-m ] .RB [ \-n ] .br .B atmarpd .B \-V .SH DESCRIPTION \fBatmarpd\fP implements the ATMARP protocol as specified in RFC1577 and RFC1755. Address resolution requests are sent from the kernel (using a comparably simple protocol) to the ATMARP demon, which then performs the dialog with the network. .P \fBatmarpd\fP can operate as an ATMARP client and as an ATMARP server. If also supports the concurrent use of several IP over ATM interfaces. .P \fBatmarpd\fP is configured from the command line using the \fBatmarp\fP program. Unless debugging is enabled, the ATMARP table is written after every change to the file \fB/var/run/atmarpd.table\fP (or to a file with the same name in a different directory, if the \fB\-D\fP option is used). .P Note that \fBatmarpd\fP disables support for SVCs if signaling is not available at start time, i.e. if \fBatmsigd\fP is not running. .SH OPTIONS .IP \fB\-b\fP Run in background (i.e. in a forked child process) after initializing. .IP \fB\-d\fP Enables (lots of) debugging output. By default, \fBatmarpd\fP is comparably quiet. .IP \fB\-D\ \fIdump_dir\fP Changes the directory where \fBatmarpd\fP writes its table (\fBatmarpd.table\fP). By default, \fB/var/run\fP is used. .IP \fB\-l\ \fIlogfile\fP Write diagnostic messages to the specified file instead of to standard error. The special name \fBsyslog\fP is used to send diagnostics to the system logger. .IP \fB\-m\fP Enables merging of incoming calls if the address is known. An incoming connection on which no InARP reply has been received yet, but which originates from an ATM address for which an ATMARP entry already exists, is automatically added to that entry. This assumes that there is a 1:1 mapping between IP addresses and ATMARP addresses. By default, this assumption is not made, which frequently results in the setup of duplicate connections. Note that RFC1577 requires that an ATMARP server sends an InARP request on an incoming connection. Merging may therefore violate RFC1577 in this case. .IP \fB\-n\fP Prints addresses in numeric format only, i.e. no address to name translation is attempted. .IP \fB\-V\fP Prints the version number of \fBatmarpd\fP on standard output and exits. .SH FILES .PD 0 .TP 25 .B /var/run/atmarpd.table ATMARP table .TP 25 .B /proc/atm/arp table of currently active IP over ATM VCs .PD .SH BUGS \fBatmarpd\fP removes ATMARP entries from the kernel table while refreshing them. .SH AUTHOR Werner Almesberger, EPFL ICA <wer...@ep...> .SH "SEE ALSO" atmarp(8), atmsigd(8) .\"{{{}}} --- NEW FILE: atmarpd.c --- /* atmarpd.c - ATMARP demon */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include "atm.h" #include "atmd.h" #include "atmarpd.h" #include "io.h" #include "table.h" #ifndef NULL #define NULL ((void *) 0) #endif #define COMPONENT "ARPD" ITF *itfs = NULL; ENTRY *unknown_incoming = NULL; VCC *unidirectional_vccs = NULL; int debug; int pretty = A2T_PRETTY | A2T_NAME | A2T_LOCAL; int merge = 0; static void usage(const char *name) { fprintf(stderr,"usage: %s [ -b ] [ -d ] [ -l logfile ] [ -m [ -m ] ] " "[ -n ]\n",name); fprintf(stderr,"%6s %s -V\n","",name); exit(1); } int main(int argc,char **argv) { const char *dump_dir; int c,background; set_application("atmarpd"); set_verbosity(NULL,DIAG_INFO); dump_dir = ATMARP_DUMP_DIR; background = 0; while ((c = getopt(argc,argv,"bdD:l:mnpV")) != EOF) switch (c) { case 'b': background = 1; break; case 'd': set_verbosity(NULL,DIAG_DEBUG); debug = 1; break; case 'D': dump_dir = optarg; break; case 'l': set_logfile(optarg); break; case 'm': merge = 1; break; case 'n': /* @@@ was planned for NSAP matching */ pretty = A2T_PRETTY; break; case 'V': printf("%s\n",VERSION); return 0; case 'p': /* paranoid anti-firewall-tunneling mode @@@ */ default: usage(argv[0]); } if (argc != optind) usage(argv[0]); diag(COMPONENT,DIAG_INFO,"Linux ATM ARP, version " VERSION); if (chdir(dump_dir) < 0) diag(COMPONENT,DIAG_ERROR,"chdir %s: %s",dump_dir,strerror(errno)); if (debug) (void) unlink(ATMARP_TMP_DUMP_FILE); /* avoid confusion */ open_all(); if (background) { pid_t pid; pid = fork(); if (pid < 0) diag(COMPONENT,DIAG_FATAL,"fork: %s",strerror(errno)); if (pid) { diag(COMPONENT,DIAG_DEBUG,"Backgrounding (PID %d)",pid); exit(0); } } (void) table_update(); /* erase old table, if any */ poll_loop(); close_all(); return 0; } --- NEW FILE: atmarpd.h --- /* atmarpd.h - ATMARP demon command interface */ /* Written 1998,1999 by Werner Almesberger, EPFL ICA */ #ifndef _ATMARPD_H #define _ATMARPD_H #include <stdint.h> #include <atm.h> #define ATMARP_SOCKET_PATH "/dev/atmarp" /* it seems awfully silly to put this socket into /dev, but since that's what syslogd and lpd are doing too, ... */ #define ATMARP_DUMP_DIR "/var/run" /* ATMARP table file location */ #define ATMARP_DUMP_FILE "atmarpd.table" /* ATMARP table file name */ #define ATMARP_TMP_DUMP_FILE "~atmarpd.table"/* name during creation */ #define ATF_NULL 0x1000 /* use NULL encapsulation */ #define ATF_ARPSRV 0x2000 /* entry describes ARP server */ #define ATF_NOVC 0x4000 /* query only; do not create a VC */ enum atmarp_req_type { art_invalid, /* catch uninitialized structures */ art_create, /* create an interface */ art_qos, /* set the default QoS */ art_set, /* create or change an entry */ art_delete, /* delete an entry */ art_table, /* update the ATMARP table file */ art_query /* request resolution without VC setup */ }; struct atmarp_req { enum atmarp_req_type type; /* request type */ int itf; /* interface number; art_create only */ uint32_t ip; /* IP address */ struct sockaddr_atmsvc addr; /* PVC or SVC address */ int flags; /* ARP flags */ struct atm_qos qos; /* requested QOS */ int sndbuf; /* send buffer; 0 if default */ }; #endif --- NEW FILE: atmarp.8 --- .TH ATMARP 8 "April 26, 2000" "Linux" "Maintenance Commands" .SH NAME atmarp \- administer classical IP over ATM connections .SH SYNOPSIS .ad l .B atmarp .B \-a .br .B atmarp .B \-c .RB [[atm]\fInumber\fP] .br .B atmarp .B \-q .RB \fIip_addr\fP .RB [ qos\ \fIqos\fP ] .RB [ sndbuf\ \fIbytes\fP ] .br .B atmarp .B \-s .RB \fIip_addr\fP .RB [\fIitf\fP.]\fIvpi\fP.\fIvci\fP .RB [ qos\ \fIqos\fP ] .RB [ sndbuf\ \fIbytes\fP ] .RB [ temp ] .RB [ pub ] .RB [ null ] .br .B atmarp .B \-s .RB \fIip_addr\fP .RB \fIatm_addr\fP .RB [ qos\ \fIqos\fP ] .RB [ sndbuf\ \fIbytes\fP ] .RB [ temp ] .RB [ pub ] .RB [ arpsrv ] .br .B atmarp .B \-d .RB \fIip_addr\fP .RB [ arpsrv ] .br .B atmarp .B \-V .ad b .SH DESCRIPTION \fBatmarp\fP is used to maintain the ATMARP table of the ATMARP demon. The table can be listed, new PVC and SVC entries can be added, and existing entries can be deleted. In addition to that, \fBatmarp\fP is also used to create new IP over ATM interfaces. .P Note that the kernel has its own ATMARP table containing only entries for destinations to which a connection exists. The table of \fBatmarpd\fP can also contain currently unused entries. .SH OPTIONS .IP \fB\-a\fP list the current ATMARP table. .IP \fB\-c\fP create the specified IP interface. If the interface number is omitted, the operating system assigns the next free number and \fBatmarp\fP prints the resulting interface name (e.g. `atm0') on standard output. .IP \fB\-q\fP sets the QOS and the send buffer size to use as the default for all VCs generated for that IP network (\fIip_addr\fP must be the address of the network). .IP \fB\-s\fP set up a PVC or create an SVC entry. The following options are recognized: .RS .IP \fBqos\fP\ \fIqos\fP uses the specified quality of service (see qos(7) for the syntax). UBR at link speed is used by default. .IP \fBsndbuf\fP\ \fIbytes\fP tries to set the send buffer to the specified number of bytes. A system default value is used if \fBsndbuf\fP is not specified. .IP \fBtemp\fP does not mark the entry as permanent, i.e. it will time out and then be removed. .IP \fBpub\fP publishes the entry (only relevant for ATMARP server). ATMARP requests for entries not marked for publishing yield an ATMARP_NAK response. .IP \fBnull\fP uses NULL encapsulation instead of LLC/SNAP encapsulation on the PVC. This option is not available for SVCs, because the LLC/SNAP header is required to identify ATMARP packets. \fBnull\fP also implies that the entry is permanent. .IP \fBarpsrv\fP identifies the entry pointing to the ATMARP server. Note that the node acting as the ATMARP server must have no ATMARP server entry in its ATMARP table. .RE .IP \fB\-d\fP delete the specified ARP entry. In order to prevent accidental deletion of the ATMARP server entry, the \fBarpsrv\fP flag must be specified when deleting it. .RE .IP \fB\-V\fP print the version number of \fBatmarp\fP on standard output and exit. .SH FILES .PD 0 .TP 25 .B /var/run/atmarpd.table ATMARP table .SH AUTHOR Werner Almesberger, EPFL ICA <Wer...@ep...> .SH "SEE ALSO" atmarpd(8), clip(8), qos(7) .\"{{{}}} --- NEW FILE: atmarp.c --- /* atmarp.c - RFC1577 ATMARP control */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <net/if_arp.h> #include <stdint.h> #include <linux/atmarp.h> #include <linux/atmclip.h> #include "atm.h" #include "atmd.h" #include "atmarpd.h" #define BUF_SIZE 4096 static int query_result(struct atmarp_req *reply) { unsigned char *ipp = (unsigned char *) &reply->ip; char buf[MAX_ATM_ADDR_LEN+1]; int error; printf("IP: %d.%d.%d.%d\n",ipp[0],ipp[1],ipp[2],ipp[3]); if (!atmsvc_addr_in_use(reply->addr)) return 0; error = atm2text(buf,sizeof(buf),(struct sockaddr *) &reply->addr, A2T_PRETTY | A2T_NAME) < 0; if (error) strcpy(buf,"<invalid>"); printf("ATM: %s\n",buf); return error ? 1 : 0; } static int send_request(struct atmarp_req *req) { struct atmarp_req reply; int s,len; s = un_attach(ATMARP_SOCKET_PATH); if (s < 0) { perror("un_attach"); exit(1); } if (write(s,req,sizeof(*req)) < 0) { perror("write"); exit(1); } len = read(s,&reply,sizeof(reply)); if (len < 0) { perror("read"); exit(1); } if (req->type == art_query) return query_result(&reply); if (len != sizeof(int)) { fprintf(stderr,"bad read: %d != %d\n",len,sizeof(int)); exit(1); } if (*(int *) &reply < 0) { fprintf(stderr,"atmarp: %s\n",strerror(-*(int *) &reply)); exit(1); } return *(int *) &reply; } static int print_table(void) { char buffer[BUF_SIZE]; int fd,size; if ((fd = open(ATMARP_DUMP_DIR "/" ATMARP_DUMP_FILE,O_RDONLY)) < 0) { perror("open " ATMARP_DUMP_DIR "/" ATMARP_DUMP_FILE); return 1; } while ((size = read(fd,buffer,BUF_SIZE))) { if (size < 0) { perror("read " ATMARP_DUMP_DIR "/" ATMARP_DUMP_FILE); return 1; } if (write(0,buffer,size) < 0) { perror("write stdout"); return 1; } } return 0; } static void usage(const char *name) { fprintf(stderr,"usage: %s -a\n",name); fprintf(stderr,"%6s %s -c [[atm]N]\n","",name); fprintf(stderr,"%6s %s -q ip_addr [qos qos_spec] [sndbuf bytes]\n","",name); fprintf(stderr,"%6s %s -s ip_addr [itf.]vpi.vci [pcr value] [qos spec] " "[sndbuf bytes]\n%8s [temp] [pub] [null]\n","",name,""); fprintf(stderr,"%6s %s -s ip_addr atm_addr [pcr value] [qos spec] " "[sndbuf bytes] [temp]\n%8s [pub] [arpsrv]\n","",name,""); fprintf(stderr,"%6s %s -d ip_addr [arpsrv]\n","",name); #if 0 /* undocumented */ fprintf(stderr,"%6s %s -Q ip_addr\n","",name); #endif fprintf(stderr,"%6s %s -V\n","",name); exit(1); } int main(int argc,char **argv) { struct atmarp_req req; int c,i,num; char *here,*end; req.type = 0; while ((c = getopt(argc,argv,"acdqQsV")) != EOF) switch (c) { case 'a': if (argc != optind || req.type) usage(argv[0]); req.type = art_table; /* (void) send_request(&req); @@@ fix this later */ return print_table(); case 'c': if (req.type) usage(argv[0]); req.type = art_create; break; case 'd': if (req.type) usage(argv[0]); req.type = art_delete; break; case 'q': if (req.type) usage(argv[0]); req.type = art_qos; break; case 'Q': if (req.type) usage(argv[0]); req.type = art_query; break; case 's': if (req.type) usage(argv[0]); req.type = art_set; break; case 'V': printf("%s\n",VERSION); return 0; default: usage(argv[0]); } switch (req.type) { case art_create: if (argc == optind) req.itf = -1; else { if (argc != optind+1) usage(argv[0]); here = argv[optind]; if (strlen(here) > 3 && !strncmp(here,"atm",3)) here += 3; req.itf = strtoul(here,&end,10); if (*end || (here[0] == '0' && here[1])) { usage(argv[0]); return 1; } } num = send_request(&req); if (req.itf == -1) printf("atm%d\n",num); return 0; case art_qos: if (argc < optind+1) usage(argv[0]); /* fall through */ case art_set: if (argc < optind+2) usage(argv[0]); break; case art_query: if (argc != optind+1) usage(argv[0]); break; case art_delete: if (argc < optind+1) usage(argv[0]); break; default: usage(argv[0]); } req.ip = text2ip(argv[optind],NULL,T2I_NAME | T2I_ERROR); if (req.ip == INADDR_NONE) return 1; req.flags = ATF_PERM; if (req.type == art_qos) { memset(&req.qos,0,sizeof(req.qos)); req.sndbuf = 0; for (i = optind+1; i < argc; i++) if (!strcmp(argv[i],"qos")) { if (++i >= argc) usage(argv[0]); if (text2qos(argv[i],&req.qos,0)) usage(argv[0]); } else if (!strcmp(argv[i],"sndbuf")) { if (++i >= argc) usage(argv[0]); req.sndbuf = strtol(argv[i],&end,0); if (*end) usage(argv[0]); } else if (i != optind+1 || argc != optind+2 || text2qos(argv[optind+1],&req.qos,0)) usage(argv[0]); } if (req.type == art_set) { memset(&req.qos,0,sizeof(req.qos)); req.sndbuf = 0; for (i = optind+2; i < argc; i++) if (!strcmp(argv[i],"temp")) req.flags &= ~ATF_PERM; else if (!strcmp(argv[i],"pub")) req.flags |= ATF_PUBL; else if (!strcmp(argv[i],"null")) req.flags |= ATF_NULL; else if (!strcmp(argv[i],"arpsrv")) req.flags |= ATF_ARPSRV; else if (!strcmp(argv[i],"qos")) { if (++i >= argc) usage(argv[0]); if (text2qos(argv[i],&req.qos,0)) usage(argv[0]); } else if (!strcmp(argv[i],"sndbuf")) { if (++i >= argc) usage(argv[0]); req.sndbuf = strtol(argv[i],&end,0); if (*end) usage(argv[0]); } else if (!strcmp(argv[i],"pcr")) { if (++i >= argc) usage(argv[0]); req.qos.txtp.traffic_class = req.qos.rxtp.traffic_class = ATM_CBR; req.qos.txtp.max_pcr = req.qos.rxtp.max_pcr = strtol(argv[i],&end,0); if (*end) usage(argv[0]); } else usage(argv[0]); if (text2atm(argv[optind+1],(struct sockaddr *) &req.addr, sizeof(req.addr),T2A_NAME) < 0) { fprintf(stderr,"%s: invalid ATM address\n",argv[optind+1]); return 1; } } if (req.type == art_delete && optind+1 < argc) { if (optind+2 < argc || strcmp(argv[optind+1],"arpsrv")) usage(argv[0]); req.flags |= ATF_ARPSRV; } if (!req.qos.aal) req.qos.aal = ATM_AAL5; send_request(&req); return 0; } --- NEW FILE: atmarp.h --- /* atmarp.h - ATM ARP protocol definitions */ /* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ #ifndef _ATMARP_H #define _ATMARP_H #include <stdint.h> /* RFC 1577 ATM ARP header */ struct atmarphdr { uint16_t ar_hrd; /* Hardware type */ uint16_t ar_pro; /* Protocol type */ uint8_t ar_shtl;/* Type & length of source ATM number (q) */ uint8_t ar_sstl;/* Type & length of source ATM subaddress (r) */ uint16_t ar_op; /* Operation code (request, reply, or NAK) */ uint8_t ar_spln;/* Length of source protocol address (s) */ uint8_t ar_thtl;/* Type & length of target ATM number (x) */ uint8_t ar_tstl;/* Type & length of target ATM subaddress (y) */ uint8_t ar_tpln;/* Length of target protocol address (z) */ /* ar_sha, at_ssa, ar_spa, ar_tha, ar_tsa, ar_tpa */ unsigned char data[1]; }; #define TL_LEN 0x3f /* ATMARP Type/Length field structure */ #define TL_E164 0x40 #define MAX_ATMARP_SIZE (sizeof(struct atmarphdr)-1+2*(ATM_E164_LEN+ \ ATM_ESA_LEN+4)) #endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:08
|
Update of /cvsroot/linux-atm/linux-atm/src/led In directory usw-pr-cvs1:/tmp/cvs-serv10656/led Added Files: Tag: V2_4_0 display.c display.h lec.h address.c address.h zeppelin.8 COPYRIGHT.TUT conn.c conn.h Makefile.am frames.c frames.h join.c join.h main.c frame_defs.h kernel.c kernel.h Log Message: --- NEW FILE: display.c --- /* display.c - display frames, addresses, opcodes, etc. */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <atm.h> #include <atmd.h> #include "display.h" #include "frame_defs.h" #define COMPONENT "display.c" #define MAX_TEXT 1024 /* Buffer size for displaying LE control frames */ static int my_atm2text(unsigned char *atm_addr, char *dest); static const char *lan_dst2text(struct lan_dst *dst); static void display_ready(void *buff); /* Prints out more or less human readable summary of * LE Control Frame pointed by frame. */ void display_frame(void *frame) { struct frame_hdr *hdr; struct ctrl_frame *f; char text[MAX_TEXT]; char *p; hdr = (struct frame_hdr *)frame; if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) display_ready(frame); p = text; p += sprintf(p, "\n"); p += sprintf(p, "Marker 0x%x\n", ntohs(hdr->marker)); p += sprintf(p, "Protocol 0x%x\n", hdr->protocol); p += sprintf(p, "Version 0x%x\n", hdr->version); p += sprintf(p, "Op-Code 0x%x (%s)\n", ntohs(hdr->opcode), opcode2text(hdr->opcode)); p += sprintf(p, "Status %d (%s)\n", hdr->status, status2text(hdr->status)); p += sprintf(p, "Trans-ID %d\n", ntohl(hdr->tran_id)); p += sprintf(p, "Req Lec-ID %d\n", ntohs(hdr->lec_id)); p += sprintf(p, "Flags 0x%x", ntohs(hdr->flags)); if (hdr->flags & htons(REMOTE_ADDRESS)) p+= sprintf(p, " 'Remote Address'"); if (hdr->flags & htons(V2_CAPABLE)) p+= sprintf(p, " 'V2 Capable'"); if (hdr->flags & htons(V2_REQUIRED)) p+= sprintf(p, " 'V2 Required'"); if (hdr->flags & htons(PROXY_FLAG)) p+= sprintf(p, " 'Proxy Flag'"); if (hdr->flags & htons(TOPO_CHANGE)) p+= sprintf(p, " 'Topology Change'"); p += sprintf(p, "\n"); f = (struct ctrl_frame *)frame; p += sprintf(p, "Source Lan 0x%x (%s)\n", ntohs(f->src_lan_dst.tag), lan_dst2text(&f->src_lan_dst)); p += sprintf(p, "Target Lan 0x%x (%s)\n", ntohs(f->target_lan_dst.tag), lan_dst2text(&f->target_lan_dst)); p += sprintf(p, "Source ATM "); p += my_atm2text(f->src_atm_addr, p); p += sprintf(p, "\n"); p += sprintf(p, "Lan type 0x%x\n", f->lan_type); p += sprintf(p, "Lan MTU 0x%x\n", f->max_frame_size); p += sprintf(p, "# of TLVs 0x%x\n", f->num_tlvs); p += sprintf(p, "Elan Name size 0x%x\n", f->elan_name_size); p += sprintf(p, "Target ATM "); p += my_atm2text(f->target_atm_addr, p); p += sprintf(p, "\n"); p += sprintf(p, "Elan Name ("); memcpy(p, f->elan_name, f->elan_name_size); p += f->elan_name_size; p += sprintf(p, ")\n"); *p = '\0'; diag(COMPONENT, DIAG_DEBUG, "%s\n", text); return; } static void display_ready(void *ready_frame) { diag(COMPONENT, DIAG_DEBUG, "ready frame\n"); return; } /* Poor man's atm2text */ static int my_atm2text(unsigned char *atm_addr, char *dest) { int i, len; len = 0; for (i = 0; i < ATM_ESA_LEN; i++) len += sprintf(dest + len, "%2.2x ", *(atm_addr + i)); return len; } static const char *lan_dst2text(struct lan_dst *dst) { static char text[42]; /* big enough for text + MAC */ char *p = text; switch(ntohs(dst->tag)) { case LAN_DST_NOT_PRESENT: sprintf(text, "Not present"); break; case LAN_DST_MAC_ADDR: p += sprintf(p, "MAC address"); p += sprintf(p, " "); mac2text(p, dst->mac); break; case LAN_DST_ROUTE_DESC: p += sprintf(p, "Route Descriptor"); p += sprintf(p, " "); mac2text(p, dst->mac); break; default: sprintf(text, "<Unknown Lan destination>"); break; } return text; } void mac2text(char *buff, unsigned char *mac_addr) { sprintf(buff, "%02x-%02x-%02x-%02x-%02x-%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); return; } const char *opcode2text(uint16_t opcode) { switch (ntohs(opcode)) { case LE_CONFIG_REQ: return "LE_CONFIG_REQUEST"; break; case LE_CONFIG_RSP: return "LE_CONFIG_RESPONSE"; break; case LE_JOIN_REQ: return "LE_JOIN_REQUEST"; break; case LE_JOIN_RSP: return "LE_JOIN_RESPONSE"; break; case LE_REG_REQ: return "LE_REGISTER_REQUEST"; break; case LE_REG_RSP: return "LE_REGISTER_RESPONSE"; break; case LE_ARP_REQ: return "LE_ARP_REQUEST"; break; case LE_ARP_RSP: return "LE_ARP_RESPONSE"; break; case LE_FLUSH_REQ: return "LE_FLUSH_REQUEST"; break; case LE_FLUSH_RSP: return "LE_FLUSH_RESPONSE"; break; case READY_QUERY: return "READY_QUERY"; break; case READY_IND: return "READY_INDICATION"; break; case LE_TOPO_REQ: return "LE_TOPOLOGY_REQUEST"; break; case LE_NARP_REQ: return "LE_NARP_REQUEST"; break; default: break; } return "<Unknown OP-CODE>"; } const char *tlv2text(uint32_t type) { switch (type) { case MAX_CUM_CTRL_TIMEOUT: return "Max-Cumulative-Control-Time-out"; break; case MAX_UNKNOWN_FRAME_CNT: return "Max-Unknown-Frame-Count"; break; case MAX_UNKNOWN_FRAME_TIME: return "Max-Unknown-Frame-Time"; break; case VCC_TIMEOUT_PERIOD: return "VCC-Timeout-Period"; break; case MAX_RETRY_COUNT: return "Max-Retry-Count"; break; case AGING_TIME: return "Aging-Time"; break; case FORWARD_DELAY_TIME: return "Forward-Delay-Time"; break; case EXPECTED_LE_ARP_TIME: return "Expected-LE_ARP-Response-Time"; break; case FLUSH_TIMEOUT: return "Flush-Time-out"; break; case PATH_SWITCHING_DELAY: return "Path-Switching-Delay"; break; case LOCAL_SEGMENT_ID: return "Local-Segment-ID"; break; case DEF_MCAST_SND_VCC_TYPE: return "Default-Mcast-Send-VCC-Type"; break; case DEF_MCAST_SND_VCC_AVG: return "Default-Mcast-Send-VCC-AvgRate"; break; case DEF_MCAST_SEND_PEAK_RT: return "Default-Mcast-Send-VCC-PeakRate"; break; case CONN_COMPLETION_TIMER: return "Connection-Completion-Timer"; break; case CONFIG_FRAG_INFO: return "Config-Frag-Info"; break; case LAYER3_ADDRESS: return "Layer-3-Address"; break; case ELAN_ID: return "ELAN-ID"; break; case SERVICE_CATEGORY: return "Service-Category"; break; case LLC_MUXED_ATM_ADDR: return "LLC-Muxed-ATM-Address"; break; case X5_ADJUSTMENT: return "X5-Adjustment"; break; case PREFERRED_LES: return "Preferred-LES"; break; case FORE_NAME: return "Fore's LANE client name"; break; default: break; } return "<Unknown TLV type>"; } const char *status2text(uint16_t status) { switch (ntohs(status)) { case 0: return "Success"; break; case 1: return "Version Not Supported"; break; case 2: return "Invalid request parameters"; break; case 4: return "Duplicate LAN Destination registration"; break; case 5: return "Dupliate ATM address"; break; case 6: return "Insufficient resources to grant request"; break; case 7: return "Access denied"; break; case 8: return "Invalid REQUESTOR-ID"; break; case 9: return "Invalid LAN Destination"; break; case 10: return "Invalid ATM Address"; break; case 20: return "No Configuration"; break; case 21: return "LE_CONFIGURE Error"; break; case 22: return "Insufficient Information"; break; case 24: return "TLV Not Found"; break; default: break; } return "<Something not supported in LANEv2>"; } --- NEW FILE: display.h --- /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef DISPLAY_H #define DISPLAY_H void display_frame(void *frame); void mac2text(char *buff, unsigned char *mac_addr); const char *opcode2text(uint16_t opcode); const char *tlv2text(uint32_t type); const char *status2text(uint16_t status); #endif /* DISPLAY_H */ --- NEW FILE: lec.h --- /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef LEC_H #define LEC_H #include "conn.h" /* * LANE client configuration and operation values. * These are in host byte order since there are * some values coming from network and some values * which are used by the host only */ struct lec_params { unsigned char c1n_my_atm_addr[ATM_ESA_LEN]; uint8_t c2_lan_type; uint8_t c3_max_frame_size; int c4_proxy_flag; char c5_elan_name[32 + 1]; char c6_mac_addr[ETH_ALEN]; int c7_ctrl_timeout; int c7i_initial_ctrl_timeout; int c7x_timeout_multiplier; int c7c_current_timeout; /* sum of c7i and c7x, LANEv2 5.3.1.7 */ unsigned char c9_les_atm_addr[ATM_ESA_LEN]; int c10_max_unknown_frames; int c11_max_unknown_frame_time; int c12_vcc_timeout; int c13_max_retry_count; uint16_t c14_lec_id; int c17_aging_time; int c18_forward_delay_time; int c19_topology_change; int c20_le_arp_response_time; int c21_flush_timeout; int c22_path_switching_delay; /* LANE2 variables follow */ int c29_v2_capable; uint32_t c31_elan_id; unsigned char c35_preferred_les[ATM_ESA_LEN]; int c35_contains_address; int c37_min_reconfig_delay; /* milliseconds */ int c38_max_reconfig_delay; /* milliseconds */ /* other stuff */ int itf_num; /* 1 for lec1 and so forth */ int sizeoftlvs; /* total size of TLVs associated with this LEC */ int num_tlvs; /* number of the TLVs */ unsigned char *tlvs; /* the TLVs */ char foreId[255]; /* connections to and from LES/BUS plus listen sockets */ Conn_t *kernel; Conn_t *ctrl_direct; Conn_t *ctrl_listen; /* Closed when join phase is over */ Conn_t *ctrl_dist; Conn_t *mcast_send; /* LANEv2 calls this Default Mcast Send VCC */ Conn_t *mcast_listen; Conn_t *data_listen; }; extern struct lec_params lec_params; #define LAN_TYPE_UNSPEC 0x00 /* Implies Ethernet/IEEE 802.3 */ #define LAN_TYPE_8023 0x01 /* IEEE 802.3 */ #define LAN_TYPE_8025 0x02 /* IEEE 802.5 */ #endif /* LEC_H */ --- NEW FILE: address.c --- /* address.c - functions to query ESI and local ATM address from kernel */ /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * 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. * * TUT ALLOWS 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. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <sys/ioctl.h> #include <unistd.h> #include <errno.h> #include <atm.h> #include <linux/atmdev.h> #include <atmd.h> #include "address.h" #define COMPONENT "address.c" /* Gets End System Identifier (MAC address) from kernel * Returns < 0 for error */ int addr_getesi(unsigned char *mac_addr, int phys_itf) { int fd, retval; struct atmif_sioc req; fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "addr_getesi: socket: %s\n", strerror(errno)); return -1; } req.number = phys_itf; req.arg = mac_addr; req.length = ESI_LEN; retval = ioctl(fd, ATM_GETESI, &req); if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETESI: %s\n", strerror(errno)); close(fd); return retval; } /* Gets one of our ATM addresses from kernel. Useful for binding listen sockets. * Returns < 0 for error */ #define MAX_LOCAL_ADDRS 32 int get_listenaddr(unsigned char *atm_addr, int phys_itf) { int fd, retval; struct atmif_sioc req; struct sockaddr_atmsvc listen_addr[MAX_LOCAL_ADDRS]; fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "get_listenaddr: socket: %s\n", strerror(errno)); return -1; } req.number = phys_itf; req.arg = listen_addr; req.length = sizeof(listen_addr); retval = ioctl(fd, ATM_GETADDR, &req); if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETADDR: %s\n", strerror(errno)); close(fd); memcpy(atm_addr, listen_addr[0].sas_addr.prv, ATM_ESA_LEN); return retval; } --- NEW FILE: address.h --- /* * Marko Kiiskila ca...@cs... * * Tampere University of Technology - Telecommunications Laboratory * * 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. * * TUT ALLOWS 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. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef ADDRESS_H #define ADDRESS_H /* Get ESI for the physical ATM interface */ int addr_getesi(unsigned char *mac_addr, int phys_addr); /* Get the ATM address for the physical ATM interface */ int get_listenaddr(unsigned char *atm_addr, int phys_addr); #endif /* ADDRESS_H */ --- NEW FILE: zeppelin.8 --- .TH zeppelin 8 "Nov 29, 1999" "Linux" "Maintenance Commands" .SH NAME zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin .SH SYNOPSIS .B zeppelin .RB [ \-c\ \fILECS_address\fP\ |\ \-s\ \fILES_address\fP ] .RB [ \-e\ \fIesi\fP ] .RB [ \-n\ \fIVLAN_name\fP ] .RB [ \-m\ \fImesg_mask\fP ] .RB [ \-l\ \fIlisten_address\ | \ selector\fP ] .RB [ \-i\ \fIinterface_number\fP ] .RB [ \-I\ \fIphysical_interface_number\fP ] .RB [ \-t\ \fI1516|1580|4544|9234|18190\fP ] .RB [ \-1\ ] .RB [ \-2\ ] .RB [ \-p\ ] .RB [ \-F\ \fIlogfile\fP ] .RB [ \-f\ \fIFore_specific_name\fP ] .SH DESCRIPTION A LAN Emulation Client is an entity in an ATM endstation that performs data forwarding, address resolution and other control functions. It uses the LUNI interface when communicating with other components in emulated LANs. It provides upper protocol layers a MAC like interface similar to IEEE 802.3/Ethernet or IEEE 802.5/Token Ring LAN. .PP LAN Emulation client code is divided into two parts: user space application LAN Emulation Demon called (LED) \fBzeppelin(8)\fP, and the kernel component. \fBZeppelin\fP is responsible for control operations needed in LAN Emulation clienthood. It forms the necessary VCCs and receives all the LE control frames and acts accordingly. It also controls the operation of the LEC kernel component. .PP Linux LEC supports only Ethernet type of emulated LAN. .PP \fBSIGHUP\fP causes restart of the LEC. All resources are released and \fBzeppelin\fP is started. .SH OPTIONS .IP \fB\-c\ \fILECS_address\fP ATM address of \fBlecs(8)\fP (Lan Emulation Configuration Server), if not set, Well-Known server address is used. .IP \fB\-s\ \fILES_address\fP ATM address of \fBles(8)\fP (Lan Emulation Server), can be used in bypassing configuration phase in joining emulated Lan i.e \fBlecs\fP address is not used. .IP \fB\-e\ \fIesi\fP Mac address to use when communicating in Emulated LAN. E.g. 00:20:22:23:04:05 . .IP \fB\-n\ \fIVLAN_name\fP Name of the virtual LAN to which joining is requested. This is used in LE_CONFIGURE_REQUEST to LECS or LE_JOIN_RESPONSE to LES, if configuration phase is bypassed. .IP \fB\-m\ \fImesg_mask\fP Sometimes one wants to know more what is happening in LE daemon e.g. when nothing works. This is a hexadecimal long value setting global message mask. 0 = No messages, ffff = All messages. .IP \fB\-l\ \fIlisten_address\ |\ selector\fP Local ATM address that zeppelin uses as local binding point in signalling. Use this if you are running more than one client or a set of LE servers. The local ATM address can be specified by either giving the full ATM address or the desired selector byte. .IP \fB\-i\ \fIinterface_number\fP Linux LEC supports up to 40+8 network interfaces. The interface_number tells zeppelin to which of these to attach. Ethernet type network interfaces are numbered from "lec0" to "lec39" and Token Ring interfaces are from "lec40" to "lec47". These parameters are tweakable during the kernel compile, see <linux/atmlec.h>. .IP \fB\-I\ \fIphysical_interface_number\fP The physical interface this LANE client should bind to. If your host has multiple ATM network cards, you can use this option to choose which card this zeppelin will use. .IP \fB\-t\ \fIMTU\fP The MTU of ELAN to join. You need to also use \fBifconfig(8)\fP to set the MTU of the LANE interface. .IP \fB\-1\fP Run as LANEv1 client. This is the default. .IP \fB\-2\fP Run as LANEv2 client. This is required by MPOA. .IP \fB\-p\fP Enable proxy. When started with this option, it is possible to bridge packets between ATM and Ethernet. That is, you can use LANE interfaces with normal bridging. See the Bridging mini-Howto for more info. .IP \fB\-F\ \fIlogfile\fP Instead of writing debug messages to \fBstderr\fP, write the messages to the file \fBlogfile\fP. Use \fBsyslog\fP as the file name to use the \fBsyslog(3)\fP facility. .IP \fB\-f\ \fIFore\ specific\ name\fP The LANE servers on Fore ATM switches can display a special name if a client can supply one. This name shows with command \'conf lane les show advanced\'. .SH TOKEN RING CONSIDERATIONS A number of lec interfaces is reserved for Token Ring ELANs when the kernel is compiled with Token Ring (CONFIG_TR) support. See the discussion about interface_number command line option above. The Linux Token Ring LANE client does not support bridging between legacy Token Ring and ATM parts of the ELAN, so using the -p option is not recommended. Token Ring support has received less testing than its Ethernet counterpart. .SH BUGS John Bonham died 1980 and Led Zeppelin broke. .PP Please report any other bugs to Heikki Vatiainen <he...@cs...> .SH AUTHORS Marko Kiiskila, TUT <ca...@cs...> and Heikki Vatiainen, TUT <he...@cs...> .SH "SEE ALSO" lecs(8), mpcd(8), atmsigd(8), les(8), qos(7) .\"{{{}}} --- NEW FILE: COPYRIGHT.TUT --- /* * Marko Kiiskila ca...@cs... * * Tampere University of Technology - Telecommunications Laboratory * * 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. * * TUT ALLOWS 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. * */ --- NEW FILE: conn.c --- /* conn.c - functions for handling SVCs, create, accept, send, etc. */ /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * 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. * * TUT ALLOWS 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. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <atm.h> #include <atmsap.h> #include <linux/atmlec.h> #include <atmd.h> #include "conn.h" #include "display.h" #include "lec.h" #include "frames.h" #include "kernel.h" #define COMPONENT "conn.c" /* status */ #define CONNECTED 42 /* Operational socket */ #define CONNECTING 43 /* Non-blocking socket, not yet connected */ /* type */ #define WEMADE 7 #define THEYMADE 8 #define LISTENING 9 #define KERNEL_SOCK 10 static Conn_t *connlist = NULL; /* Local protos */ static void list_remove_conn(Conn_t *conn); static Conn_t *list_add_conn(unsigned char *dest_atm_addr); static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current); static const char *get_type_string(int type); static int maxmtu2maxsdu(uint8_t mtu); static uint16_t conn_type2codepoint(int conn_type); static void delete_addr(unsigned char *atm_addr) { struct atmlec_msg msg; msg.type = l_addr_delete; memcpy(msg.content.normal.atm_addr, atm_addr, ATM_ESA_LEN); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return; } /* Checks if connection to atm_addr already exists. Does not * check against current though. * Returns NULL for no connection, or Conn_t of existing connection. */ static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current) { Conn_t *conn; conn = connlist; while (conn) { if (conn != current && conn->type != LISTENING && conn->type != KERNEL_SOCK) { if (memcmp(conn->atm_address, atm_addr, ATM_ESA_LEN) == 0) return conn; } conn = conn->next; } return NULL; } /* Initializes and fills in *sap and *qos according to Blli * code point value specified in conn_type. */ void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, uint16_t conn_type) { unsigned int bllicode; int i, sdu; char qos_text[MAX_ATM_QOS_LEN + 1]; diag(COMPONENT, DIAG_DEBUG, "init_conn_params, conn_type %x\n", conn_type); memset(qos, 0, sizeof(struct atm_qos)); memset(sap, 0, sizeof(struct atm_sap)); qos->aal = ATM_AAL5; /* Set the forward and backward Max CPCS-SDU Size */ switch(conn_type) { case CONTROL_CONN: qos->rxtp.max_sdu = 1516; qos->txtp.max_sdu = 1516; break; case DATA_DIRECT_CONN: case MCAST_CONN: sdu = maxmtu2maxsdu(lec_params.c3_max_frame_size); qos->rxtp.max_sdu = sdu; qos->txtp.max_sdu = sdu; break; default: diag(COMPONENT, DIAG_ERROR, "unknown conn_type %x\n", conn_type); break; } /* ATM User Cell Rate/ATM Traffic Descriptor. */ qos->txtp.traffic_class = ATM_UBR; qos->rxtp.traffic_class = ATM_UBR; if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { if (qos2text(qos_text, sizeof(qos_text), qos, 0) < 0) sprintf(qos_text, "<bad qos>"); diag(COMPONENT, DIAG_DEBUG, "init_conn_params, QoS '%s'\n", qos_text); } /* No Broadband High Layer Information in LANE. */ sap->bhli.hl_type = ATM_HL_NONE; /* Broadband Lower Layer Information. */ sap->blli[0].l3_proto = ATM_L3_TR9577; sap->blli[0].l3.tr9577.ipi = NLPID_IEEE802_1_SNAP; sap->blli[0].l3.tr9577.snap[0] = 0x00; sap->blli[0].l3.tr9577.snap[1] = 0xa0; sap->blli[0].l3.tr9577.snap[2] = 0x3e; bllicode = conn_type2codepoint(conn_type); sap->blli[0].l3.tr9577.snap[3] = (unsigned char)(0xff&(bllicode>>8)); sap->blli[0].l3.tr9577.snap[4] = (unsigned char)(0xff&bllicode); if (get_verbosity(COMPONENT) == DIAG_DEBUG) { for(i=0; i < 5; i++) { diag(COMPONENT, DIAG_DEBUG, "snap[%d] = 0x%2.2x", i, sap->blli[0].l3.tr9577.snap[i]); } } return; } /* Returns != 0 if blli indicates Data Direct * connection */ static int is_data_direct(struct atm_blli *blli) { return (blli->l3.tr9577.snap[4] == DATA_DIRECT_8023 || blli->l3.tr9577.snap[4] == DATA_DIRECT_8025); } /* Creates a socket with the specified parameters. * If listen_addr is non NULL binds to it. * Returns < 0 for error or new socket descriptor. */ static int get_socket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { int s, ret; s = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (s < 0) { diag(COMPONENT, DIAG_ERROR, "socket creation failure: %s\n", strerror(errno)); return -1; } diag(COMPONENT, DIAG_DEBUG, "get_socket: got fd %d\n", s); if (setsockopt(s, SOL_ATM, SO_ATMQOS, qos, sizeof(struct atm_qos)) < 0) { diag(COMPONENT, DIAG_ERROR, "get_socket: setsockopt SO_ATMQOS: %s\n", strerror(errno)); close(s); return -1; } if (setsockopt(s, SOL_ATM, SO_ATMSAP, sap, sizeof(struct atm_sap)) < 0) { diag(COMPONENT, DIAG_ERROR, "setup_svc setsockop(SO_ATMSAP)\n"); close(s); return -1; } /* Bind the socket to our local address */ if (listen_addr == NULL) return s; ret = bind(s, (struct sockaddr *)listen_addr, sizeof(struct sockaddr_atmsvc)); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "bind error: %s\n", strerror(errno)); close(s); return -1; } return s; } /* * You need to check this if setup_svc() returns NULL */ #if 0 if (is_data_direct(&sap->blli[0])) { /* Try to remove possible entry in kernel */ delete_addr(conn->atm_address); } #endif /* Does an active open to dst_addr using pre-filled * parameters in sap and qos. * If listen_addr is non NULL, binds to it. * Data direct SVCs are non-blocking, others block * Returns NULL for error or new connections. */ Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { Conn_t *conn; int s, ret; char buff[MAX_ATM_ADDR_LEN+1]; diag(COMPONENT, DIAG_DEBUG, "Outgoing call setup\n"); /* The code below is commented out due to the following scenario: We have made a connection to another LEC and our address was numerically lower than theirs (LANEv2 8.1.13). The other end has also connected us, but we must not use that VCC. However, if the connection we made gets closed, we can not open it again since a connection to the destination LEC already exists. */ #if 0 /* We don't create connection to an entity where we already have a connection. */ if (conn_already_exists(dst_addr->sas_addr.prv, NULL) && is_data_direct(&sap->blli[0])) return NULL; #endif dst_addr->sas_family = AF_ATMSVC; listen_addr->sas_family = AF_ATMSVC; switch(sap->blli[0].l3.tr9577.snap[4]) { /* Kludge. Eh? */ case CONTROL_CONN: diag(COMPONENT, DIAG_DEBUG, "LE Control SVC setup\n"); break; case DATA_DIRECT_8023: diag(COMPONENT, DIAG_DEBUG, "Data direct 802.3\n"); break; case DATA_DIRECT_8025: diag(COMPONENT, DIAG_DEBUG, "Data direct 802.5\n"); break; case MCAST_CONN_8023: diag(COMPONENT, DIAG_DEBUG, "Multicast 802.3\n"); break; case MCAST_CONN_8025: diag(COMPONENT, DIAG_DEBUG, "Multicast 802.5\n"); break; default: diag(COMPONENT, DIAG_ERROR, "Unknown codepoint in svc setup\n"); } s = get_socket(listen_addr, sap, qos); if (s < 0) return NULL; if (atm2text(buff, sizeof(buff), (struct sockaddr *)dst_addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) sprintf(buff, "<Unknown ATM address>"); diag(COMPONENT, DIAG_DEBUG, "Call to %s", buff); /* Make data direct SVCs non-blocking */ if (is_data_direct(&sap->blli[0])) { ret = fcntl(s, F_GETFL); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_GETFL)\n"); close(s); } else if (fcntl(s, F_SETFL, ret|O_NONBLOCK) < 0) { diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_SETFL, x|O_NONBLOCK)\n"); close(s); return NULL; } } ret = connect(s, (struct sockaddr *)dst_addr, sizeof(struct sockaddr_atmsvc)); if (ret < 0 && errno != EINPROGRESS) { diag(COMPONENT, DIAG_ERROR, "connect error: %s\n", strerror(errno)); close(s); return NULL; } conn = list_add_conn(dst_addr->sas_addr.prv); diag(COMPONENT, DIAG_DEBUG, "Conn:%p\n", conn); if (conn == NULL) { close(s); return NULL; } conn->fd = s; conn->type = WEMADE; conn->codepoint = sap->blli[0].l3.tr9577.snap[4]; if (is_data_direct(&sap->blli[0])) conn->status = CONNECTING; else conn->status = CONNECTED; return conn; } /* Creates listen socket for incoming data direct connections. * Only for data direct, not for Control or Multicast listen sockets. * Returns < 0 for error */ int create_data_listen(void) { struct atm_sap sap; struct atm_qos qos; struct sockaddr_atmsvc addr; memset(&addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); addr.sas_family = AF_ATMSVC; init_conn_params(&sap, &qos, DATA_DIRECT_CONN); lec_params.data_listen = create_listensocket(&addr, &sap, &qos); if (lec_params.data_listen == NULL) { diag(COMPONENT, DIAG_FATAL, "Could not create listen socket for incoming Data Direct VCCs\n"); return -1; } return 0; } /* Opens a Multicast or non-blocking Data Direct VCC to atm_addr. * Not for Control connections. * Returns < 0 for error */ int create_data_svc(unsigned char *atm_addr, int codepoint) { struct atm_sap sap; struct atm_qos qos; struct sockaddr_atmsvc my_addr, dst_addr; Conn_t *conn; memset(&my_addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(my_addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); memset(&dst_addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(dst_addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); my_addr.sas_family = dst_addr.sas_family = AF_ATMSVC; init_conn_params(&sap, &qos, codepoint); conn = setup_svc(&dst_addr, &my_addr, &sap, &qos); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "Could not create Data Direct VCC\n"); delete_addr(dst_addr.sas_addr.prv); return -1; } return 0; } /* Creates a listen socket with parameters specified with * arguments. * Returns NULL for error or Conn_t for new listen socket. */ Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { int fd, ret; Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "conn_create_listensocket\n"); fd = get_socket(listen_addr, sap, qos); if (fd < 0) return NULL; ret = listen(fd, 5); if (ret != 0) { diag(COMPONENT, DIAG_DEBUG, "Listen failed: %s\n", strerror(errno)); close(fd); return NULL; } conn = list_add_conn(NULL); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "List_add_conn failed\n"); close(fd); return NULL; } conn->type = LISTENING; conn->fd = fd; diag(COMPONENT, DIAG_DEBUG, "Listen socket created blli:%2.2x %2.2x fd: %d\n", sap->blli[0].l3.tr9577.snap[3], sap->blli[0].l3.tr9577.snap[4], conn->fd); return conn; } /* Accepts a new connection from listen socket in conn. * Returns NULL for error */ Conn_t *accept_conn(Conn_t *conn) { Conn_t *new; struct sockaddr_atmsvc addr; size_t len; int fd; char buff[MAX_ATM_ADDR_LEN+1]; diag(COMPONENT, DIAG_DEBUG, "Accepting connection on fd %d\n", conn->fd); len = sizeof(addr); fd = accept(conn->fd, (struct sockaddr *)&addr, &len); diag(COMPONENT, DIAG_DEBUG, "accept returned %d\n", fd); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "accept: %s\n", strerror(errno)); return NULL; } if (atm2text(buff, sizeof(buff), (struct sockaddr *)&addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) sprintf(buff, "<Unknown ATM address>"); diag(COMPONENT, DIAG_DEBUG, "Call from %s", buff); new = list_add_conn(addr.sas_addr.prv); if (new == NULL) return NULL; new->fd = fd; new->status = CONNECTED; new->type = THEYMADE; if (conn == lec_params.ctrl_listen) new->codepoint = CONTROL_CONN; if (conn == lec_params.mcast_listen) new->codepoint = MCAST_CONN; if (conn == lec_params.data_listen) new->codepoint = DATA_DIRECT_CONN; return new; } /* Close all connections, important or not. */ void close_connections(void) { Conn_t *conn, *next; for(conn = connlist; conn; conn = next) { diag(COMPONENT, DIAG_DEBUG, "Destroying:%p fd:%d type:%d\n", conn, conn->fd, conn->type); next = conn->next; close(conn->fd); list_remove_conn(conn); free(conn); } return; } /* Closes a connection and checks its importance. * Important connections are kernel socket, LES connections, * BUS Default Multicast Send VCC, last Multicast Forward VCC from Bus * and any of the listen sockets. * Returns < 0 for important connection. */ int close_connection(Conn_t *conn) { int bad = 0; Conn_t *mcast; diag(COMPONENT, DIAG_DEBUG, "close_connection %p\n", conn); if (conn == lec_params.kernel || conn == lec_params.ctrl_direct || conn == lec_params.ctrl_dist || conn == lec_params.mcast_send || conn == lec_params.mcast_listen || conn == lec_params.data_listen) bad = -1; else { bad = -1; for (mcast = connlist; mcast; mcast = mcast->next) if (mcast != conn && mcast->type == THEYMADE && mcast->codepoint == MCAST_CONN) bad = 0; } close(conn->fd); list_remove_conn(conn); free(conn); return bad; } /* Accepts a new incoming Data Direct or Multicast Forward connection. * Control connections (LECS/LES) are accepted during configuration/join. * Returns < 0 for serious error such as broken listen socket. */ static int handle_accept(Conn_t *conn) { Conn_t *new; struct atmlec_ioc ioc; new = accept_conn(conn); if (new == NULL) return -1; if (conn == lec_params.mcast_listen) { diag(COMPONENT, DIAG_DEBUG, "Multicast Forward VCC accepted\n"); ioc.receive = 2; } else { diag(COMPONENT, DIAG_DEBUG, "Data Direct VCC accepted\n"); ioc.receive = 0; if (conn_already_exists(new->atm_address, new) && memcmp(lec_params.c1n_my_atm_addr, new->atm_address, ATM_ESA_LEN) < 0) { diag(COMPONENT, DIAG_DEBUG, "Using it only to receive, spec 8.1.1\n"); ioc.receive = 1; } } memcpy(ioc.atm_addr, new->atm_address, ATM_ESA_LEN); ioc.dev_num = lec_params.itf_num; diag(COMPONENT, DIAG_DEBUG, "Attaching a new VCC, fd %d\n", new->fd); if (ioctl(new->fd, ATMLEC_DATA, &ioc) < 0) { diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); return -1; } return 0; } /* Reads a LE control frame from conn, usually Data Direct or * Multicast Forward connection. Calls the incoming packet * handler function. * Returns < 0 for serious error such as broken LES connection */ static int handle_data(Conn_t *conn) { char buff[MAX_CTRL_FRAME]; int retval; retval = recv_frame(conn, buff, sizeof(buff)); if (retval < 0) { diag(COMPONENT, DIAG_ERROR, "handle_data: read: %s\n", strerror(errno)); return (close_connection(conn)); } if (retval == 0) { diag(COMPONENT, DIAG_DEBUG, "fd %d, Data or Multicast VCC closed\n", conn->fd); return (close_connection(conn)); } return handle_frame(conn, buff, retval); } /* Checks connections in *fds. The only allowed sockets * in *fds are listen sockets, data direct and control * sockets. * Returns < 0 for serious error such as broken LES connection */ int check_connections(fd_set *fds) { Conn_t *conn, *next; conn = connlist; while (conn != NULL) { next = conn->next; if (!FD_ISSET(conn->fd, fds)) { conn = next; continue; } switch (conn->type) { case LISTENING: if (handle_accept(conn) < 0) return -1; break; case WEMADE: case THEYMADE: if (handle_data(conn) < 0) return -1; break; default: diag(COMPONENT, DIAG_ERROR, "check_connections: bad_type '%s'\n", get_type_string(conn->type)); break; } conn = next; } return 0; } /* Completes a non-blocking connect. * Returns < 0 for serious error */ static int handle_connect(Conn_t *conn) { int retval; struct sockaddr_atmsvc dummy; struct atmlec_msg msg; struct atmlec_ioc ioc; diag(COMPONENT, DIAG_DEBUG, "handle_connect: completing fd %d\n", conn->fd); /* this seems to be common method in Linux-ATM * making sure that nonblocking connect was * completed successfully */ conn->status = CONNECTED; retval = connect(conn->fd, (struct sockaddr *)&dummy, sizeof(struct sockaddr_atmsvc)); if (retval < 0) { diag(COMPONENT, DIAG_DEBUG, "handle_connect: connect: %s\n", strerror(errno)); delete_addr(conn->atm_address); close_connection(conn); return 0; } send_ready_ind(conn); memcpy(ioc.atm_addr, conn->atm_address, ATM_ESA_LEN); ioc.dev_num = lec_params.itf_num; ioc.receive = 0; diag(COMPONENT, DIAG_DEBUG, "Attaching a new active VCC, fd %d\n", conn->fd); if (ioctl(conn->fd, ATMLEC_DATA, &ioc) < 0) { diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); return -1; } memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_flush_tran_id; memcpy(msg.content.normal.atm_addr, conn->atm_address, ATM_ESA_LEN); msg.content.normal.flag = send_flush_req(conn); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return 0; } /* Complete non-blocking connections in *fds. * Returns < 0 for serious error (problems with kernel). */ int complete_connections(fd_set *fds) { Conn_t *conn, *next; int retval; conn = connlist; while (conn) { next = conn->next; if (FD_ISSET(conn->fd, fds)) { retval = handle_connect(conn); if (retval < 0) return -1; } conn = next; } return 0; } /* Send a LE control frame using *conn. * Returns < 0 for serious error */ int send_frame(Conn_t *conn, void *frame, int length) { struct frame_hdr *hdr; int ret; diag(COMPONENT, DIAG_DEBUG, "send_frame: fd:%d len:%ld\n", conn->fd, length); hdr = (struct frame_hdr *)frame; if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) diag(COMPONENT, DIAG_DEBUG, "%s\n", opcode2text(hdr->opcode)); else display_frame(frame); ret = write(conn->fd, frame, length); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "send_frame: write: %s\n", strerror(errno)); return -1; } return ret; } /* Receive a LE control frame from *conn. * Returns < 0 for serious error. */ int recv_frame(Conn_t *conn, void *buff, int length) { int ret; diag(COMPONENT, DIAG_DEBUG, "recv_frame: fd:%d\n", conn->fd); ret = read(conn->fd, buff, length); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "Read failed: %s\n", strerror(errno)); return -1; } #if 0 diag(COMPONENT, DIAG_DEBUG, "recv_frame: read %d bytes\n", ret); if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { int i; for (i = 0; i < 11; i++) diag(COMPONENT, DIAG_DEBUG, "0x%2x", ((unsigned char *)buff)[i]); } #endif return ret; } /* * LANE2: 5.2.1.4 and others, sleep random time before trying to reconnect */ void random_delay(void) { struct timeval tv; int millis, interval; srand(time(NULL)); interval = lec_params.c38_max_reconfig_delay - lec_params.c37_min_reconfig_delay; millis = (rand() % interval) + lec_params.c37_min_reconfig_delay; tv.tv_sec = (millis - (millis % 1000)) / 1000; tv.tv_usec = (millis % 1000) * 1000; diag(COMPONENT, DIAG_DEBUG, "random_delay: sleeping %d.%d seconds\n", tv.tv_sec, tv.tv_usec); (void)select(0, NULL, NULL, NULL, &tv); return; } /* Collect already connected sockets in *fds */ void conn_get_fds(fd_set *fds) { Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "collecting ready fds "); conn = connlist; while (conn) { if (conn->status != CONNECTING) { FD_SET(conn->fd, fds); diag(COMPONENT, DIAG_DEBUG, "%d type %s", conn->fd, get_type_string(conn->type)); } conn = conn->next; } return; } /* Collect non-blocking connecting sockets in *fds */ void conn_get_connecting_fds(fd_set *fds) { Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "collecting connecting fds "); conn = connlist; while (conn) { if (conn->status == CONNECTING) { FD_SET(conn->fd, fds); diag(COMPONENT, DIAG_DEBUG, "%d", conn->fd); } conn = conn->next; } } /* Creates Conn_t for fd and marks it as kernel socket * Returns < 0 for error */ int conn_set_kernel_socket(int fd) { Conn_t *conn; conn = list_add_conn(NULL); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "conn_set_kernel_socket: list_add_conn failed\n"); return -1; } conn->type = KERNEL_SOCK; conn->status = CONNECTED; conn->fd = fd; lec_params.kernel = conn; return fd; } /* Creates new Conn_t object and allocates memory for it. * atm_addr should be the ATM address of the other end * or NULL if not applicable */ static Conn_t *list_add_conn(unsigned char *atm_addr) { Conn_t *conn; conn = (Conn_t *)malloc(sizeof(Conn_t)); if (!conn) return NULL; memset(conn, 0, sizeof(Conn_t)); if (atm_addr) memcpy(conn->atm_address, atm_addr, ATM_ESA_LEN); conn->next = connlist; conn->previous = NULL; if (connlist) connlist->previous = conn; connlist = conn; diag(COMPONENT, DIAG_DEBUG, "Added conn:%p\n", conn); return conn; } /* Helper for close_connection and close_connections */ static void list_remove_conn(Conn_t *conn) { if (conn->next == NULL && conn->previous == NULL && connlist != conn) return; diag(COMPONENT, DIAG_DEBUG, "Removing conn:%p fd:%d previous:%p next:%p ", conn, conn->fd, conn->previous, conn->next); if (conn->previous) diag(COMPONENT, DIAG_DEBUG, "Previous:%p, fd:%d, next:%p, previous:%p ", conn->previous, conn->previous->fd, conn->previous->next, conn->previous->previous); if (conn->next) diag(COMPONENT, DIAG_DEBUG, "Next:%p, fd:%d next:%p, previous:%p ", conn->next, conn->next->fd, conn->next->next, conn->next->previous); if (conn->previous) { conn->previous->next = conn->next; } else /* First in line */ connlist = conn->next; if (conn->next) conn->next->previous = conn->previous; diag(COMPONENT, DIAG_DEBUG, "Connlist: %p\n", connlist); conn->next=conn->previous= NULL; return; } static const char *get_type_string(int type) { switch(type) { case WEMADE: return "WEMADE"; break; case THEYMADE: return "THEYMADE"; break; case LISTENING: return "LISTENING"; break; case KERNEL_SOCK: return "KERNEL_SOCK"; break; default: break; } return "UNKNOWN"; } static int maxmtu2maxsdu(uint8_t mtu) { int sdu; switch (mtu) { case MTU_1516: sdu = 1516; break; case MTU_1580: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ sdu = 1580; break; case MTU_4544: sdu = 4544; break; case MTU_9234: sdu = 9234; break; case MTU_18190: sdu = 18190; break; default: sdu = 1516; break; } return sdu; } int maxmtu2itfmtu(uint8_t mtu) { int sdu; switch (mtu) { case MTU_1516: sdu = 1500; break; case MTU_1580: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ sdu = 1500; break; case MTU_4544: sdu = 4528; break; case MTU_9234: sdu = 9218; break; case MTU_18190: sdu = 18174; break; default: sdu = 1500; break; } return sdu; } /* Convert a type of connection (CONTROL_CONN, DATA_DIRECT and MCAST_CONN) * to a BLLI codepoint which depends on C2 LAN Type. */ static uint16_t conn_type2codepoint(int conn_type) { if (conn_type == CONTROL_CONN) return CONTROL_CONN; if (conn_type == DATA_DIRECT_CONN) { if (lec_params.c2_lan_type == LAN_TYPE_8023 || lec_params.c2_lan_type == LAN_TYPE_UNSPEC) return DATA_DIRECT_8023; else if (lec_params.c2_lan_type == LAN_TYPE_8025) return DATA_DIRECT_8025; diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, bad lan_type %d", lec_params.c2_lan_type); return DATA_DIRECT_8023; } else if (conn_type == MCAST_CONN) { if (lec_params.c2_lan_type == LAN_TYPE_8023 || lec_params.c2_lan_type == LAN_TYPE_UNSPEC) return MCAST_CONN_8023; else if (lec_params.c2_lan_type == LAN_TYPE_8025) return MCAST_CONN_8025; diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, bad lan_type %d", lec_params.c2_lan_type); return MCAST_CONN_8023; } diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, unknown type %d", conn_type); return DATA_DIRECT_8023; } --- NEW FILE: conn.h --- /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * 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. * * TUT ALLOWS 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. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef CONN_H #define CONN_H typedef struct _conn_t_ { int fd; /* Socket connected to this connection */ int status; /* Connection status */ int type; /* We made, they made, listen socket */ int codepoint; /* One of the below, MCAST_CONN etc. */ unsigned char atm_address[ATM_ESA_LEN]; /* Destination address, not in listen or kernel sockets */ struct _conn_t_ *next; struct _conn_t_ *previous; } Conn_t; void close_connections(void); void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, uint16_t blli_codepoint); int create_data_svc(unsigned char *atm_addr, int codepoint); Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos); int create_data_listen(void); Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos); Conn_t *accept_conn(Conn_t *conn); int close_connection(Conn_t *conn); int check_connections(fd_set *fds); int complete_connections(fd_set *fds); int send_frame(Conn_t *conn, void *frame, int length); int recv_frame(Conn_t *conn, void *buff, int length); void conn_get_fds(fd_set *fds); void conn_get_connecting_fds(fd_set *fds); int conn_set_kernel_socket(int fd); void random_delay(void); int maxmtu2itfmtu(uint8_t mtu); /* * Connection types for BLLI codepoints. */ #define CONTROL_CONN 1 #define DATA_DIRECT_CONN 2 #define MCAST_CONN 4 #define DATA_DIRECT_8023 2 #define DATA_DIRECT_8025 3 #define MCAST_CONN_8023 4 #define MCAST_CONN_8025 5 /* * MTU sizes */ #define MTU_UNSPEC 0 #define MTU_1516 1 #define MTU_1580 5 /* LANEv2 */ #define MTU_4544 2 #define MTU_9234 3 #define MTU_18190 4 #endif /* CONN_H */ --- NEW FILE: Makefile.am --- sbin_PROGRAMS = zeppelin zeppelin_SOURCES = join.c join.h conn.c conn.h main.c address.c address.h \ frames.c frames.h display.c display.h \ kernel.c kernel.h frame_defs.h lec.h zeppelin_LDADD = $(top_builddir)/src/lib/libatm.la \ $(top_builddir)/src/lib/libatmd.la zeppelin_DEPENDENCIES = $(zeppelin_LDADD) man_MANS = zeppelin.8 EXTRA_DIST = $(man_MANS) COPYRIGHT.TUT --- NEW FILE: frames.c --- /* frames.c - handle incoming frames, prefill outgoing frames, parse TLVs etc. */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ /* Functions for handling LANE control frames used when joining an * ELAN are in lec.c */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <atm.h> #include <linux/atmlec.h> #include <atmd.h> #include "conn.h" #include "lec.h" #include "frames.h" #include "display.h" #include "kernel.h" #define COMPONENT "frames.c" static uint32_t transaction_id = 0; static void extract_tlv_value(uint16_t opcode, uint32_t type, unsigned char *tlvp, int len); static void handle_x5(uint16_t opcode); /* Initializes LANE Control frame of type 'type' */ void prefill_frame(void *buff, uint16_t type) { struct frame_hdr *header; memset(buff, 0, sizeof(struct ctrl_frame)); header = (struct frame_hdr *)buff; header->marker = htons(0xff00); header->protocol = 0x01; header->version = 0x01; header->opcode = htons(type); header->status = htons(0x0000); header->tran_id = htonl(transaction_id); header->lec_id = htons(lec_params.c14_lec_id); header->flags = htons(0x0000); transaction_id++; return; } /* Validates incoming Control frames except READY_IND and * READY_QUERY which do not start with the common header. * Also calls display_frame() to print out conforming frames. * Returns < 0 for error */ int validate_frame(unsigned char *buff, int size) { struct ready_frame *hdr; /* Ready is the shortest possible */ if (size < sizeof(struct ready_frame)) { diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); return -1; } hdr = (struct ready_frame *)buff; if (hdr->marker != htons(0xff00) || hdr->protocol != 0x01 || hdr->version != 0x01) return -1; /* READY_* frames are shorter than others */ if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) { diag(COMPONENT, DIAG_DEBUG, "Received a %s\n", opcode2text(hdr->opcode)); return 0; } if (size < sizeof(struct ctrl_frame)) { diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); return -1; } display_frame(buff); return 0; } /* Handle incoming LE_FLUSH_REQUEST frames. */ static void handle_flush_req(struct ctrl_frame *f) { if (memcmp(lec_params.c1n_my_atm_addr, f->target_atm_addr, ATM_ESA_LEN) != 0) return; f->header.opcode = htons(LE_FLUSH_RSP); if (send_frame(lec_params.ctrl_direct, f, sizeof(struct ctrl_frame)) < 0) diag(COMPONENT, DIAG_DEBUG, "could not send LE_FLUSH_RESPONSE\n"); return; } /* Handle incoming LE_FLUSH_RESPONSE frames. */ static void handle_flush_rsp(struct ctrl_frame *f) { struct atmlec_msg msg; if (f->header.lec_id != htons(lec_params.c14_lec_id)) { diag(COMPONENT, DIAG_DEBUG, "Wrong lec_id, ignoring\n"); return; } memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_flush_complete; msg.content.normal.flag = ntohl(f->header.tran_id); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return; } /* Handle incoming READY_QUERY frames. */ static void handle_ready_query(Conn_t *conn, struct ready_frame *f) { f->opcode = htons(READY_IND); send_frame(conn, f, sizeof(struct ready_frame)); return; } /* Helper for handle_le_arp_req. * If the target_lan_dst was not our MAC address, try to * see if the bridging table in the kernel knows about it. * Returns < 0 for serious error */ static int check_bridge(struct ctrl_frame *frame, int size) { struct atmlec_msg msg; if (lec_params.c4_proxy_flag == 0) return 0; memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_should_bridge; memcpy(msg.content.proxy.mac_addr, frame->target_lan_dst.mac, ETH_ALEN); memcpy(msg.content.proxy.atm_addr, frame->src_atm... [truncated message content] |
Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv10656/lib Added Files: Tag: V2_4_0 atmres.h qosequal.c ans.c rtf2e164_cc.pl atmequal.c sap2text.c text2atm.c timer.c text2qos.c text2sap.c diag.c common.c Makefile.am kptr.c misc.c text2ip.c qos2text.c unix.c sapequal.c atm2text.c sdu2cell.c Log Message: --- NEW FILE: atmres.h --- /* atmres.h - Common definitions and prototypes for resolver functions */ /* Written 1996,1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef _ATMRES_H #define _ATMRES_H #include <arpa/nameser.h> #include <linux/atm.h> /* Some #defines that may be needed if ANS isn't installed on that system */ #ifndef T_ATMA #define T_ATMA 34 #endif #ifndef ATMA_AESA #define ATMA_AESA 0 #endif #ifndef ATMA_E164 #define ATMA_E164 1 #endif /* Return codes for text2atm and atm2text */ #define TRY_OTHER -2 #define FATAL -1 /* must be -1 */ int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length, int flags); int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags); #endif --- NEW FILE: qosequal.c --- /* qosequal.c - Compares QOS specifications for equality */ /* Written 1996,1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include "atm.h" static int tp_equal(int traffic_class,struct atm_trafprm a,struct atm_trafprm b) { switch (traffic_class) { case ATM_NONE: return 1; case ATM_UBR: break; case ATM_CBR: if (a.max_cdv != b.max_cdv) return 0; break; default: return -1; } if (!a.max_pcr && !a.min_pcr) a.max_pcr = ATM_MAX_PCR; if (!b.max_pcr && !b.min_pcr) b.max_pcr = ATM_MAX_PCR; if (a.max_pcr != b.max_pcr || a.pcr != b.pcr || a.min_pcr != b.min_pcr) return 0; return a.max_sdu == b.max_sdu; } int qos_equal(const struct atm_qos *a,const struct atm_qos *b) { if (a->txtp.traffic_class != b->txtp.traffic_class) return 0; if (a->txtp.traffic_class == ATM_NONE) { if (a->rxtp.traffic_class != b->rxtp.traffic_class) return 0; return tp_equal(a->rxtp.traffic_class,a->rxtp,b->rxtp); } else { if (!tp_equal(a->txtp.traffic_class,a->txtp,b->txtp)) return 0; return tp_equal(a->txtp.traffic_class,a->rxtp,b->rxtp); } } --- NEW FILE: ans.c --- /* ans.c - Interface for text2atm and atm2text to ANS */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ /* * This stuff is a temporary hack to avoid using gethostbyname_nsap and such * without doing the "full upgrade" to getaddrinfo/getnameinfo. This also * serves as an exercise for me to get all the details right before I propose * a patch that would eventually end up in libc (and that should therefore be * as stable as possible). */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <netdb.h> #include <resolv.h> #include "atm.h" #include "atmres.h" #define MAX_ANSWER 2048 #define MAX_NAME 1024 #define MAX_LINE 2048 /* in /etc/e164_cc */ #define E164_CC_DEFAULT_LEN 2 #define E164_CC_FILE "/etc/e164_cc" #define GET16(pos) (((pos)[0] << 8) | (pos)[1]) static int ans(const char *text,int wanted,void *result,int res_len) { unsigned char answer[MAX_ANSWER]; unsigned char name[MAX_NAME]; unsigned char *pos,*data,*found; int answer_len,name_len,data_len,found_len; int questions,answers; found_len = 0; /* gcc wants it */ if ((answer_len = res_search(text,C_IN,wanted,answer,MAX_ANSWER)) < 0) return TRY_OTHER; /* * Response header: id, flags, #queries, #answers, #authority, * #additional (all 16 bits) */ pos = answer+12; if (answer[3] & 15) return TRY_OTHER; /* rcode != 0 */ questions = GET16(answer+4); if (questions != 1) return TRY_OTHER; /* trouble ... */ answers = GET16(answer+6); if (answers < 1) return TRY_OTHER; /* * Query: name, type (16), class (16) */ if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0) return TRY_OTHER; pos += name_len; if (GET16(pos) != wanted || GET16(pos+2) != C_IN) return TRY_OTHER; pos += 4; /* * Iterate over answers until we find something we like, giving priority * to ATMA_AESA (until signaling is fixed to work with E.164 too) */ found = NULL; while (answers--) { /* * RR: name, type (16), class (16), TTL (32), resource_len (16), * resource_data ... */ if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0) return TRY_OTHER; pos += name_len; data_len = GET16(pos+8); data = pos+10; pos = data+data_len; if (GET16(data-10) != wanted || GET16(data-8) != C_IN || !--data_len) continue; switch (wanted) { case T_NSAP: data_len++; if (data_len != ATM_ESA_LEN) continue; memcpy(((struct sockaddr_atmsvc *) result)-> sas_addr.prv,data,ATM_ESA_LEN); return 0; case T_ATMA: switch (*data++) { case ATMA_AESA: if (data_len != ATM_ESA_LEN) continue; memcpy(((struct sockaddr_atmsvc *) result)-> sas_addr.prv,data,ATM_ESA_LEN); return 0; case ATMA_E164: if (data_len > ATM_E164_LEN) continue; if (!found) { found = data; found_len = data_len; } break; default: continue; } case T_PTR: if (dn_expand(answer,answer+answer_len,data,result, res_len) < 0) return FATAL; return 0; default: continue; } } if (!found) return TRY_OTHER; memcpy(((struct sockaddr_atmsvc *) result)->sas_addr.pub,found, found_len); ((struct sockaddr_atmsvc *) result)->sas_addr.pub[found_len] = 0; return 0; } int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length, int flags) { if (!(flags & T2A_SVC) || length != sizeof(*addr)) return TRY_OTHER; memset(addr,0,sizeof(*addr)); addr->sas_family = AF_ATMSVC; if (!ans(text,T_ATMA,addr,length)) return 0; return ans(text,T_NSAP,addr,length); } static int encode_nsap(char *buf,const unsigned char *addr) { static int fmt_dcc[] = { 2,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 4,2,0 }; static int fmt_e164[] = { 2,12,1,1,1,1,1,1,1,1,16,2,0 }; int *fmt; int pos,i,j; switch (*addr) { case ATM_AFI_DCC: case ATM_AFI_ICD: case ATM_AFI_LOCAL: case ATM_AFI_DCC_GROUP: case ATM_AFI_ICD_GROUP: case ATM_AFI_LOCAL_GROUP: fmt = fmt_dcc; break; case ATM_AFI_E164: case ATM_AFI_E164_GROUP: fmt = fmt_e164; break; default: return TRY_OTHER; } pos = 2*ATM_ESA_LEN; for (i = 0; fmt[i]; i++) { pos -= fmt[i]; for (j = 0; j < fmt[i]; j++) sprintf(buf++,"%x", (addr[(pos+j) >> 1] >> 4*(1-((pos+j) & 1))) & 0xf); *buf++ = '.'; } strcpy(buf,"AESA.ATMA.INT."); return 0; } static int encode_nsap_new(char *buf,const unsigned char *addr) { int i; int digit; for (i = 20; i; ) { i--; digit = addr[i] & 0x0F; *(buf++) = digit + (digit >= 10 ? '7' : '0'); *(buf++) = '.'; digit = ((unsigned char) (addr[i])) >> 4; *(buf++) = digit + (digit >= 10 ? '7' : '0'); *(buf++) = '.'; } strcpy (buf, "NSAP.INT."); return 0; } static int cc_len(int p0,int p1) { static char *cc_table = NULL; FILE *file; char buffer[MAX_LINE]; char *here; int cc; if (!cc_table) { if (!(cc_table = malloc(100))) { perror("malloc"); return E164_CC_DEFAULT_LEN; } memset(cc_table,E164_CC_DEFAULT_LEN,100); if (!(file = fopen(E164_CC_FILE,"r"))) perror(E164_CC_FILE); else { while (fgets(buffer,MAX_LINE,file)) { here = strchr(buffer,'#'); if (here) *here = 0; if (sscanf(buffer,"%d",&cc) == 1) { if (cc < 10) cc_table[cc] = 1; else if (cc < 100) cc_table[cc] = 2; else cc_table[cc/10] = 3; } } fclose(file); } } if (cc_table[p0] == 1) return 1; return cc_table[p0*10+p1]; } static int encode_e164(char *buf,const char *addr) { const char *prefix,*here; prefix = addr+cc_len(addr[0]-48,addr[1]-48); here = strchr(addr,0); while (here > prefix) { *buf++ = *--here; *buf++ = '.'; } while (here > addr) *buf++ = *addr++; strcpy(buf,".E164.ATMA.INT."); return 0; } int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags) { char tmp[MAX_NAME]; /* could be smaller ... */ int res; if (addr->sas_addr.prv) { res = encode_nsap(tmp,addr->sas_addr.prv); if (!res && !ans(tmp,T_PTR,buffer,length)) return 0; res = encode_nsap_new(tmp,addr->sas_addr.prv); if (res < 0) return res; return ans(tmp,T_PTR,buffer,length); } else { res = encode_e164(tmp,addr->sas_addr.pub); if (res < 0) return res; return ans(tmp,T_PTR,buffer,length); } } --- NEW FILE: rtf2e164_cc.pl --- #!/usr/bin/perl # # The E.164 country code listing can be obtained from # http://www.itu.ch/itudoc/itu-t/lists/tf_cc_e_*.rtf # # Usage of this program: # perl rtf2e164_cc.pl <tf_cc_e_xxx.rtf >/etc/e164_cc while (<>) { next unless /{\\fs18\\cf1\s(\d+)}{\\f7\\fs24\s\\tab\s}{\\fs18\\cf1\s([^}]+)}/; last if $1 == 999; } while (<>) { next unless /{\\fs18\\cf1\s(\d+)}{\\f7\\fs24\s\\tab\s}{\\fs18\\cf1\s([^}]+)}/; printf("%-3d %s\n",$1,$2) || die "printf: $!"; } --- NEW FILE: atmequal.c --- /* atmequal.c - Compares ATM addresses for equality */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <string.h> #include <assert.h> #include <sys/socket.h> #include "atm.h" static int atm_equal_pvc(const struct sockaddr_atmpvc *a, const struct sockaddr_atmpvc *b,int flags) { int wc = flags & AXE_WILDCARD; #define EQ(field,any) \ (a->sap_addr.field == b->sap_addr.field || \ (wc && (a->sap_addr.field == any || b->sap_addr.field == any))) return EQ(itf,ATM_ITF_ANY) && EQ(vpi,ATM_VPI_ANY) && EQ(vci,ATM_VCI_ANY); #undef EQ } static int atm_equal_svc(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b,int len,int flags) { const unsigned char *a_prv,*b_prv; int len_a,len_b; if (!(flags & AXE_WILDCARD)) len = ATM_ESA_LEN*8; assert(len >= 0 && len <= ATM_ESA_LEN*8); if (*a->sas_addr.prv && *b->sas_addr.prv) { a_prv = a->sas_addr.prv; b_prv = b->sas_addr.prv; if ((flags & AXE_WILDCARD) && len >= 8 && *a_prv == ATM_AFI_E164 && *b_prv == ATM_AFI_E164) { if (len < 68) return 0; /* no comparison possible */ else { int a_pos,b_pos; unsigned char a_val,b_val; for (a_pos = 2; !a_prv[a_pos/2]; a_pos += 2); if (!(a_prv[a_pos/2] & 0xf0)) a_pos++; for (b_pos = 2; !b_prv[b_pos/2]; b_pos += 2); if (!(b_prv[b_pos/2] & 0xf0)) b_pos++; while (1) { a_val = (a_prv[a_pos/2] >> (((~a_pos) & 1)*4)) & 0xf; b_val = (b_prv[b_pos/2] >> (((~b_pos) & 1)*4)) & 0xf; if (a_val == 15 || b_val == 15) break; if (a_val != b_val) return 0; a_pos++; b_pos++; } a_prv += 9; b_prv += 9; if ((len -= 72) < 0) len = 0; } } if (memcmp(a_prv,b_prv,len/8)) return 0; if ((len & 7) && (a_prv[len/8+1]^b_prv[len/8+1]) & (0xff00 >> (len & 7))) return 0; return 1; } if ((*a->sas_addr.prv || *b->sas_addr.prv) && !(flags & AXE_PRVOPT)) return 0; if (!*a->sas_addr.pub || !*b->sas_addr.pub) return 0; len_a = strlen(a->sas_addr.pub); len_b = strlen(b->sas_addr.pub); if (len_a != len_b && !(flags & AXE_WILDCARD)) return 0; return !strncmp(a->sas_addr.pub,b->sas_addr.pub,len_a < len_b ? len_a : len_b); } int atm_equal(const struct sockaddr *a,const struct sockaddr *b,int len, int flags) { assert((a->sa_family == AF_ATMPVC && b->sa_family == AF_ATMPVC) || (a->sa_family == AF_ATMSVC && b->sa_family == AF_ATMSVC)); if (a->sa_family == AF_ATMPVC) return atm_equal_pvc((const struct sockaddr_atmpvc *) a, (const struct sockaddr_atmpvc *) b,flags); return atm_equal_svc((const struct sockaddr_atmsvc *) a, (const struct sockaddr_atmsvc *) b,len,flags); } --- NEW FILE: sap2text.c --- /* sap2text.c - Converts binary encoding of a SAP (Service Access Point; BHLI and BLLI) to textual representation */ /* Written 1997 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdarg.h> #include <string.h> #include <atmsap.h> #include <linux/atmsap.h> #include "atm.h" /* * <a-b> = a-b bytes * * bhli: * iso=<1-8> * user=<1-8> * hlp=<4> * oui=<3>,id=<4> * blli: * l2=x25_ll | x25_ml | hdlc_arm | hdlc_nrm | hdlc_abm | q922 | iso7776 * l2=user,info=<1> * l2=iso1745 | q291 | lapb | iso8802 | x75 * * etc. */ static int put(char **pos,char **end,int *length,const char *fmt,...) { char scratch[40]; /* we don't put long strings anyway */ va_list ap; int len; va_start(ap,fmt); len = vsprintf(scratch,fmt,ap); va_end(ap); if (!len) return 0; if (!*end) return -1; *length -= *end-*pos; *pos = *end; if (len >= *length) return -1; strcpy(*pos,scratch); *pos += len; *end = *pos; return 0; } static int dump(char **pos,char **end,int *length,const unsigned char *start, int size) { int i; if (!size) return -1; put(pos,end,length,"0x"); for (i = 0; i < size; i++) if (put(pos,end,length,"%02X",start[i]) < 0) return -1; return 0; } static void maybe(char **pos,char **end,int *length,const char *str) { int len; if (!*end) return; len = strlen(str)+*end-*pos; if (len >= *length) { /* okay, but fail on the next PUT */ *end = NULL; return; } strcpy(*end,str); *end = *pos+len; } #define PUT(fmt,arg...) if (put(pos,end,length,fmt,##arg) < 0) return -1 #define DUMP(start,size) if (dump(pos,end,length,start,size) < 0) return -1 #define MAYBE(str) maybe(pos,end,length,str) static int bhli2text(char **pos,char **end,int *length, const struct atm_bhli *bhli) { if (!bhli->hl_type) return 0; PUT("bhli:"); switch (bhli->hl_type) { case ATM_HL_ISO: PUT("iso="); DUMP(bhli->hl_info,bhli->hl_length); break; case ATM_HL_USER: PUT("user="); DUMP(bhli->hl_info,bhli->hl_length); break; #if defined(UNI30) || defined(ALLOW_UNI30) case ATM_HL_HLP: if (bhli->hl_length != 4) return -1; PUT("hlp="); DUMP(bhli->hl_info,bhli->hl_length); break; #endif case ATM_HL_VENDOR: if (bhli->hl_length != 7) return -1; PUT("oui="); DUMP(bhli->hl_info,3); PUT(",id="); DUMP(bhli->hl_info+3,4); break; default: return -1; } MAYBE(","); return 0; } static int l2_proto2text(char **pos,char **end,int *length, const struct atm_blli *blli) { if (!blli->l2_proto) return 0; PUT("l2="); switch (blli->l2_proto) { #define X(u,l) case ATM_L2_##u: PUT(#l); MAYBE(","); return 0 X(ISO1745,iso1745); X(Q291,q291); X(LAPB,lapb); X(ISO8802,iso8802); X(X75,x75); #undef X #define X(u,l) case ATM_L2_##u: PUT(#l); break X(X25_LL,x25_ll); X(X25_ML,x25_ml); X(HDLC_ARM,hdlc_arm); X(HDLC_NRM,hdlc_nrm); X(HDLC_ABM,hdlc_abm); X(Q922,q992); X(ISO7776,iso7776); #undef X case ATM_L2_USER: PUT("user,info=%d",blli->l2.user); MAYBE(","); return 0; default: return -1; } MAYBE(","); if (blli->l2.itu.mode) { PUT("mode="); switch (blli->l2.itu.mode) { case ATM_IMD_NORMAL: PUT("norm"); break; case ATM_IMD_EXTENDED: PUT("ext"); break; default: return -1; } MAYBE(","); } if (blli->l2.itu.window) { PUT("window=%d",blli->l2.itu.window); MAYBE(","); } return 0; } static int mpx_cap(char **pos,char **end,int *length,const char *label, int cap) { if (!cap) return 0; PUT("%s=",label); switch (cap) { case ATM_MC_TS: PUT("ts"); break; case ATM_MC_TS_FEC: PUT("ts_fec"); break; case ATM_MC_PS: PUT("ps"); break; case ATM_MC_PS_FEC: PUT("ps_fec"); break; case ATM_MC_H221: PUT("h221"); break; default: return -1; } MAYBE(","); return 0; } static int l3_proto2text(char **pos,char **end,int *length, const struct atm_blli *blli) { if (!blli->l3_proto) return 0; PUT("l3="); switch (blli->l3_proto) { #define X(u,l) case ATM_L3_##u: PUT(#l); break X(X25,x25); X(ISO8208,iso8208); X(X223,x223); #undef X case ATM_L3_TR9577: PUT("tr9577,ipi="); if (blli->l3.tr9577.ipi != NLPID_IEEE802_1_SNAP) { PUT("0x%x",blli->l3.tr9577.ipi); } else { PUT("snap,oui="); DUMP(blli->l3.tr9577.snap,3); PUT(",pid="); DUMP(blli->l3.tr9577.snap+3,2); } MAYBE(","); return 0; case ATM_L3_USER: PUT("user,info=%d",blli->l3.user); MAYBE(","); return 0; #define X(u,l) case ATM_L3_##u: PUT(#l); MAYBE(","); return 0 X(ISO8473,iso8473); X(T70,t70); X(H321,h321); #undef X case ATM_L3_H310: PUT("h310"); MAYBE(","); switch (blli->l3.h310.term_type) { case ATM_TT_NONE: return 0; case ATM_TT_RX: PUT("term=rx"); break; case ATM_TT_TX: PUT("term=tx"); break; case ATM_TT_RXTX: PUT("term=rxtx"); break; default: return -1; } MAYBE(","); mpx_cap(pos,end,length,"fw_mpx",blli->l3.h310.fw_mpx_cap); mpx_cap(pos,end,length,"bw_mpx",blli->l3.h310.bw_mpx_cap); return 0; default: return -1; } MAYBE(","); if (blli->l3.itu.mode) { PUT("mode="); switch (blli->l3.itu.mode) { case ATM_IMD_NORMAL: PUT("norm"); break; case ATM_IMD_EXTENDED: PUT("ext"); break; default: return -1; } MAYBE(","); } if (blli->l3.itu.def_size) { PUT("size=%d",blli->l3.itu.def_size); MAYBE(","); } if (blli->l3.itu.window) { PUT("window=%d",blli->l3.itu.window); MAYBE(","); } return 0; } static int blli2text(char **pos,char **end,int *length, const struct atm_blli *blli) { MAYBE("blli:"); if (l2_proto2text(pos,end,length,blli)) return -1; return l3_proto2text(pos,end,length,blli); } int sap2text(char *buffer,int length,const struct atm_sap *sap,int flags) { char *pos,*end; int i; pos = end = buffer; if (bhli2text(&pos,&end,&length,&sap->bhli) < 0) return -1; for (i = 0; i < ATM_MAX_BLLI; i++) { if (!blli_in_use(sap->blli[i])) break; if (blli2text(&pos,&end,&length,sap->blli+i) < 0) return -1; } *pos = 0; return pos-buffer; } --- NEW FILE: text2atm.c --- /* text2atm.c - Converts textual representation of ATM address to binary encoding */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <ctype.h> #include <string.h> #include <limits.h> #include "atm.h" #include "atmsap.h" #include "atmres.h" static int try_pvc(const char *text,struct sockaddr_atmpvc *addr,int flags) { int part[3]; int i; part[0] = part[1] = part[2] = 0; i = 0; while (1) { if (!*text) return FATAL; /* empty or ends with a dot */ if (i == 3) return TRY_OTHER; /* too long */ if (isdigit(*text)) { if (*text == '0' && isdigit(text[1])) return TRY_OTHER; /* no leading zeroes */ do { if (part[i] > INT_MAX/10) return TRY_OTHER;/* number too big */ part[i] = part[i]*10+*text++-'0'; } while (isdigit(*text)); i++; if (!*text) break; if (*text++ != '.') return TRY_OTHER; /* non-PVC character */ continue; } if (*text == '*') { if (!(flags & T2A_WILDCARD)) return FATAL; /* not allowed */ part[i++] = ATM_ITF_ANY; /* all *_ANY have the same value */ } else { if (*text != '?') return TRY_OTHER; /* invalid character */ if (!(flags & T2A_UNSPEC)) return FATAL; /* not allowed */ part[i++] = ATM_VPI_UNSPEC; /* all *_UNSPEC have the same value */ } if (!*++text) break; if (*text++ != '.') return FATAL; /* dot required */ } if (i < 2) return TRY_OTHER; /* no dots */ if (i == 2) { part[2] = part[1]; part[1] = part[0]; part[0] = 0; /* default interface */ } if (part[0] > SHRT_MAX || part[2] > ATM_MAX_VCI) return TRY_OTHER; /* too big */ if (part[1] > (flags & T2A_NNI ? ATM_MAX_VPI_NNI : ATM_MAX_VPI)) return TRY_OTHER; /* too big */ if (part[0] == ATM_VPI_UNSPEC) return FATAL; /* bad */ addr->sap_family = AF_ATMPVC; addr->sap_addr.itf = part[0]; addr->sap_addr.vpi = part[1]; addr->sap_addr.vci = part[2]; return 0; } static int do_try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags) { const char *walk; int count,pos,dot; int offset,len; char value; count = dot = 0; for (walk = text; *walk; walk++) if (isdigit(*walk)) { if (count++ == 15) break; dot = 1; } else if (*text != '.') break; else if (!dot) return FATAL; /* two dots in a row */ else dot = 0; if (*walk != ':') { pos = 0; offset = 0; } else { if (!dot || *text == '0') return FATAL; addr->sas_addr.prv[0] = ATM_AFI_E164; addr->sas_addr.prv[1] = 0; memset(addr->sas_addr.prv+1,0,8); for (pos = 18-count-1; *text; text++) { if (*text == '.') continue; if (*text == ':') break; else { if (pos & 1) addr->sas_addr.prv[pos >> 1] |= *text-'0'; else addr->sas_addr.prv[pos >> 1] = (*text-'0') << 4; pos++; } } addr->sas_addr.prv[8] |= 0xf; text++; pos++; offset = 72; } for (dot = 0; *text; text++) if (isxdigit(*text)) { if (pos == ATM_ESA_LEN*2) return TRY_OTHER; /* too long */ value = isdigit(*text) ? *text-'0' : (islower(*text) ? toupper(*text) : *text)-'A'+10; if (pos & 1) addr->sas_addr.prv[pos >> 1] |= value; else addr->sas_addr.prv[pos >> 1] = value << 4; pos++; dot = 1; } else if (*text == '/' && (flags & T2A_WILDCARD)) break; else if (*text != '.') return TRY_OTHER; else { if (!dot) return FATAL; /* two dots in a row */ dot = 0; } if (!dot) return FATAL; if (pos > 1 && !*addr->sas_addr.prv) return TRY_OTHER; /* no leading zeroes */ if (!*text) return pos != ATM_ESA_LEN*2 ? TRY_OTHER : ATM_ESA_LEN*2; /* handle bad length */ len = 0; while (*++text) { if (!isdigit(*text)) return -1; /* non-digit in length */ if (len >= pos*4) return -1; /* too long */ len = len*10+*text-'0'; } if (len > 7 && addr->sas_addr.prv[0] != ATM_AFI_E164) offset = 72; if (len < offset) return FATAL; return len > pos*4 ? TRY_OTHER : len; } static int try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags) { int result; result = do_try_nsap(text,addr,flags); if (result < 0) return result; addr->sas_family = AF_ATMSVC; *addr->sas_addr.pub = 0; return result; } static int try_e164(const char *text,struct sockaddr_atmsvc *addr,int flags) { int i,dot,result; if (*text == ':' || *text == '+') text++; for (i = dot = 0; *text; text++) if (isdigit(*text)) { if (i == ATM_E164_LEN) return TRY_OTHER; /* too long */ addr->sas_addr.pub[i++] = *text; dot = 1; } else if (*text != '.') break; else { if (!dot) return TRY_OTHER; /* two dots in a row */ dot = 0; } if (!dot) return TRY_OTHER; addr->sas_addr.pub[i] = 0; *addr->sas_addr.prv = 0; result = 0; if (*text) { if (*text++ != '+') return TRY_OTHER; else { result = do_try_nsap(text,addr,flags); if (result < 0) return FATAL; } } addr->sas_family = AF_ATMSVC; return result; } static int search(FILE *file,const char *text,struct sockaddr *addr,int length, int flags) { char line[MAX_ATM_NAME_LEN+1]; const char *here; int result; while (fgets(line,MAX_ATM_NAME_LEN,file)) { if (!strtok(line,"\t\n ")) continue; while ((here = strtok(NULL,"\t\n "))) if (!strcasecmp(here,text)) { here = strtok(line,"\t\n "); result = text2atm(here,addr,length,flags); if (result >= 0) return result; } } return TRY_OTHER; } static int try_name(const char *text,struct sockaddr *addr,int length, int flags) { FILE *file; int result; if (!(file = fopen(HOSTS_ATM,"r"))) return TRY_OTHER; result = search(file,text,addr,length,flags); (void) fclose(file); return result; } int text2atm(const char *text,struct sockaddr *addr,int length,int flags) { int result; if (!*text) return -1; if (!(flags & (T2A_PVC | T2A_SVC))) flags |= T2A_PVC | T2A_SVC; if (length < sizeof(struct sockaddr_atmpvc)) return -1; if (flags & T2A_PVC) { result = try_pvc(text,(struct sockaddr_atmpvc *) addr,flags); if (result != TRY_OTHER) return result; } if ((flags & T2A_SVC) && length >= sizeof(struct sockaddr_atmsvc)) { result = try_nsap(text,(struct sockaddr_atmsvc *) addr,flags); if (result != TRY_OTHER) return result; result = try_e164(text,(struct sockaddr_atmsvc *) addr,flags); if (result != TRY_OTHER) return result; } if (!(flags & T2A_NAME)) return -1; result = try_name(text,addr,length,flags & ~T2A_NAME); if (result == TRY_OTHER && !(flags & T2A_LOCAL)) result = ans_byname(text,(struct sockaddr_atmsvc *) addr,length,flags); if (result != TRY_OTHER) return result; return -1; } --- NEW FILE: timer.c --- /* timer.c - Timer support */ /* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include "atmd.h" static TIMER *timers = NULL; static void dump_list(const char *label) { #ifdef DEBUG_TIMERS TIMER *walk; if (!debug) return; fprintf(stderr,"Timer list %s\n",label); for (walk = timers; walk; walk = walk->next) fprintf(stderr," 0x%p: Timer @0x%p, %ld.%06d (-> 0x%p)\n", walk,walk->callback,(unsigned long) walk->expiration.tv_sec, (int) walk->expiration.tv_usec,walk->next); #endif } TIMER *start_timer(long usec,void (*callback)(void *user),void *user) { TIMER *n,*walk,*last; n = alloc_t(TIMER); n->expiration.tv_usec = now.tv_usec+usec; n->expiration.tv_sec = now.tv_sec; n->callback = callback; n->user = user; while (n->expiration.tv_usec > 1000000) { n->expiration.tv_usec -= 1000000; n->expiration.tv_sec++; } last = NULL; for (walk = timers; walk; walk = walk->next) if (walk->expiration.tv_sec > n->expiration.tv_sec || (walk->expiration.tv_sec == n->expiration.tv_sec && walk->expiration.tv_usec > n->expiration.tv_usec)) break; else last = walk; if (walk) Q_INSERT_BEFORE(timers,n,walk); else Q_INSERT_AFTER(timers,n,last); dump_list("START_TIMER"); return n; } void stop_timer(TIMER *timer) { Q_REMOVE(timers,timer); free(timer); } void (*timer_handler(TIMER *timer))(void *user) { return timer ? timer->callback : NULL; } struct timeval *next_timer(void) { static struct timeval delta; if (!timers) return NULL; delta.tv_sec = timers->expiration.tv_sec-now.tv_sec; delta.tv_usec = timers->expiration.tv_usec-now.tv_usec; while (delta.tv_usec < 0) { delta.tv_usec += 1000000; delta.tv_sec--; } if (delta.tv_sec < 0) delta.tv_sec = delta.tv_usec = 0; return δ } void pop_timer(TIMER *timer) { dump_list("POP_TIMER"); Q_REMOVE(timers,timer); timer->callback(timer->user); free(timer); } void expire_timers(void) { while (timers && (timers->expiration.tv_sec < now.tv_sec || (timers->expiration.tv_sec == now.tv_sec && timers->expiration.tv_usec < now.tv_usec))) pop_timer(timers); } --- NEW FILE: text2qos.c --- /* text2qos.c - Converts textual representation of QOS parameters to binary encoding */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <ctype.h> #include <limits.h> #include "atm.h" #define fetch __atmlib_fetch #define RATE_ERROR -2 int __t2q_get_rate(const char **text,int up) { const char mult[] = "kKmMgGg"; const char *multiplier; char *end; unsigned int rate,fract; int power; if (!strncmp(*text,"max",3)) { *text += 3; return ATM_MAX_PCR; } rate = strtoul(*text,&end,10); power = fract = 0; if (*end == '.') for (end++; *end && isdigit(*end); end++) { fract = fract*10+*end-48; if (--power == -9) break; } multiplier = NULL; if (*end && (multiplier = strchr(mult,*end))) { while (multiplier >= mult) { if (rate > UINT_MAX/1000) return RATE_ERROR; rate *= 1000; power += 3; multiplier -= 2; } end++; } while (power && fract) if (power < 0) { fract /= 10; power++; } else { fract *= 10; power--; } rate += fract; if (strlen(end) < 3) { if (multiplier) return RATE_ERROR; } else if (!strncmp(end,"cps",3)) end += 3; else if (!strncmp(end,"bps",3)) { rate = (rate+(up ? 8*ATM_CELL_PAYLOAD-1 : 0))/8/ ATM_CELL_PAYLOAD; end += 3; } else if (multiplier) return RATE_ERROR; if (rate > INT_MAX) return RATE_ERROR; *text = end; return rate; } static int params(const char **text,struct atm_trafprm *a, struct atm_trafprm *b) { int value; char *end; if (*(*text)++ != ':') return -1; while (1) { if (!**text) return -1; switch (fetch(text,"max_pcr=","pcr=","min_pcr=","max_sdu=","sdu=", NULL)) { case 0: if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1; if (a) a->max_pcr = value; if (b) b->max_pcr = value; break; case 1: if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1; if (a) a->pcr = value; if (b) b->pcr = value; break; case 2: if ((value = __t2q_get_rate(text,1)) == RATE_ERROR) return -1; if (value == ATM_MAX_PCR) return -1; if (a) a->min_pcr = value; if (b) b->min_pcr = value; break; case 3: case 4: value = strtol(*text,&end,10); if (value < 0) return -1; *text = end; if (a) a->max_sdu = value; if (b) b->max_sdu = value; break; default: return 0; } if (!**text) break; if (*(*text)++ != ',') return -1; } return 0; } int text2qos(const char *text,struct atm_qos *qos,int flags) { int traffic_class,aal; traffic_class = ATM_NONE; aal = ATM_NO_AAL; do { static const unsigned char aal_number[] = { ATM_AAL0, ATM_AAL5 }; int item; item = fetch(&text,"!none","ubr","cbr","vbr","abr","aal0","aal5",NULL); switch (item) { case 1: case 2: /* we don't support VBR yet */ case 4: traffic_class = item; break; case 5: case 6: aal = aal_number[item-5]; break; default: return -1; } } while (*text == ',' ? text++ : 0); if (!traffic_class) return -1; if (qos && !(flags & T2Q_DEFAULTS)) memset(qos,0,sizeof(*qos)); if (qos) qos->txtp.traffic_class = qos->rxtp.traffic_class = traffic_class; if (qos && aal) qos->aal = aal; if (!*text) return 0; if (params(&text,qos ? &qos->txtp : NULL,qos ? &qos->rxtp : NULL)) return -1; if (!*text) return 0; switch (fetch(&text,"tx","rx",NULL)) { case 0: if (!fetch(&text,":none",NULL)) { if (qos) qos->txtp.traffic_class = ATM_NONE; if (*text == ',') text++; break; } if (params(&text,qos ? &qos->txtp : NULL,NULL)) return -1; break; case 1: text -= 2; break; default: return -1; } if (!*text) return 0; if (fetch(&text,"rx",NULL)) return -1; if (!fetch(&text,":none",NULL) && qos) qos->rxtp.traffic_class = ATM_NONE; else if (params(&text,qos ? &qos->rxtp : NULL,NULL)) return -1; return *text ? -1 : 0; } --- NEW FILE: text2sap.c --- /* text2sap.c - Converts textual representation of a SAP (Service Access Point; BHLI and BLLI) to binary encoding */ /* Written 1997 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <atmsap.h> #include <linux/atmsap.h> #include "atm.h" #define fetch __atmlib_fetch static int bytes(const char **text,unsigned char *buf,int *len,int min,int max) { int num,value; num = 0; if (**text == '0' && ((*text)[1] == 'x' || (*text)[1] == 'X')) *text += 2; while (sscanf(*text,"%2x",&value) == 1) { if (++num > max) return -1; *buf++ = value; *text += 2; } if (num < min) return -1; if (len) *len = num; return 0; } static int text2bhli(const char **text,struct atm_bhli *bhli) { int len; switch (fetch(text,"iso=","user=","hlp=","oui=",NULL)) { case 0: bhli->hl_type = ATM_HL_ISO; if (bytes(text,bhli->hl_info,&len,1,8) < 0) return -1; bhli->hl_length = len; break; case 1: bhli->hl_type = ATM_HL_USER; if (bytes(text,bhli->hl_info,&len,1,8) < 0) return -1; bhli->hl_length = len; break; #if defined(UNI30) || defined(ALLOW_UNI30) case 2: bhli->hl_type = ATM_HL_HLP; if (bytes(text,bhli->hl_info,NULL,4,4) < 0) return -1; bhli->hl_length = 4; break; #endif case 3: bhli->hl_type = ATM_HL_VENDOR; if (bytes(text,bhli->hl_info,NULL,3,3) < 0) return -1; if (fetch(text,",id=",NULL) < 0) return -1; if (bytes(text,bhli->hl_info+3,NULL,4,4) < 0) return -1; bhli->hl_length = 7; break; default: return -1; } return 0; } static int get_int(const char **text,int *value,int min,int max) { char *end; *value = strtoul(*text,&end,0); if (end == *text) return -1; if (*value < min || *value > max) return -1; *text = end; return 0; } static int text2l2_proto(const char **text,struct atm_blli *blli) { static int map[] = { /* No parameters */ ATM_L2_ISO1745, ATM_L2_Q291,ATM_L2_LAPB,ATM_L2_ISO8802,ATM_L2_X75, /* With ITU parameters */ ATM_L2_X25_LL, ATM_L2_X25_ML, ATM_L2_HDLC_ARM, ATM_L2_HDLC_NRM, ATM_L2_HDLC_ABM, ATM_L2_Q922, ATM_L2_ISO7776, /* Other parameter sets */ ATM_L2_USER }; int item,value; item = fetch(text,"iso1745","q291","lapb","iso8802","x75","x25_ll", "x25_ml","hdlc_arm","hdlc_nrm","hdlc_abm","q992","iso7776","user,info=", NULL); if (item < 0) return -1; blli->l2_proto = map[item]; if (blli->l2_proto < ATM_L2_X25_LL) return 0; if (blli->l2_proto == ATM_L2_USER) { if (get_int(text,&value,0,255) < 0) return -1; blli->l2.user = value; return 0; } if (!fetch(text,",mode=",NULL)) { switch (fetch(text,"norm","ext",NULL)) { case 0: blli->l2.itu.mode = ATM_IMD_NORMAL; break; case 1: blli->l2.itu.mode = ATM_IMD_EXTENDED; break; default: return -1; } } if (!fetch(text,",window=",NULL)) { if (get_int(text,&value,1,127) < 0) return -1; blli->l2.itu.window = value; } return 0; } static int text2l3_proto(const char **text,struct atm_blli *blli) { static int map[] = { /* No parameters */ ATM_L3_ISO8473,ATM_L3_T70,ATM_L3_H321, /* With ITU parameters */ ATM_L3_X25,ATM_L3_ISO8208,ATM_L3_X223, /* Other parameter sets */ ATM_L3_TR9577,ATM_L3_USER,ATM_L3_H310 }; int item,value; item = fetch(text,"iso8473","t70","h321","x25","iso8208","x223", "tr9577,ipi=","user,info=","h310",NULL); if (item < 0) return -1; blli->l3_proto = map[item]; if (blli->l3_proto < ATM_L3_X25) return 0; if (blli->l3_proto == ATM_L3_TR9577) { if (!fetch(text,"snap",NULL)) value = NLPID_IEEE802_1_SNAP; else if (get_int(text,&value,0,255) < 0) return -1; blli->l3.tr9577.ipi = value; if (value != NLPID_IEEE802_1_SNAP) return 0; if (fetch(text,",oui=",NULL) < 0) return -1; if (bytes(text,blli->l3.tr9577.snap,NULL,3,3) < 0) return -1; if (fetch(text,",pid=",NULL) < 0) return -1; if (bytes(text,blli->l3.tr9577.snap+3,NULL,2,2) < 0) return -1; return 0; } if (blli->l3_proto == ATM_L3_USER) { if (get_int(text,&value,0,255) < 0) return -1; blli->l3.user = value; return 0; } if (blli->l3_proto == ATM_L3_H310) { if (fetch(text,",term=",NULL)) return 0; item = fetch(text,"!none","rx","tx","rxtx",NULL); if (item == -1) return -1; blli->l3.h310.term_type = item; if (!fetch(text,",fw_mpx=",NULL)) { item = fetch(text,"!none","ts","ts_fec","ps","ps_fec","h221",NULL); if (item == -1) return -1; blli->l3.h310.fw_mpx_cap = item; } if (!fetch(text,",bw_mpx=",NULL)) { item = fetch(text,"!none","ts","ts_fec","ps","ps_fec","h221",NULL); if (item == -1) return -1; blli->l3.h310.bw_mpx_cap = item; } return 0; } if (!fetch(text,",mode=",NULL)) { switch (fetch(text,"norm","ext",NULL)) { case 0: blli->l3.itu.mode = ATM_IMD_NORMAL; break; case 1: blli->l3.itu.mode = ATM_IMD_EXTENDED; break; default: return -1; } } if (!fetch(text,",size=",NULL)) { if (get_int(text,&value,4,12) < 0) return -1; blli->l3.itu.def_size = value; } if (!fetch(text,",window=",NULL)) { if (get_int(text,&value,1,127) < 0) return -1; blli->l3.itu.window = value; } return 0; } static int text2blli(const char **text,struct atm_blli *blli) { switch (fetch(text,"l2=","l3=",NULL)) { case 0: if (text2l2_proto(text,blli) < 0) return -1; break; case 1: return text2l3_proto(text,blli); default: return -1; } if (!**text) return 0; if (fetch(text,",l3=",NULL) < 0) return 0; return text2l3_proto(text,blli); } int text2sap(const char *text,struct atm_sap *sap,int flags) { int bllis; memset(sap,0,sizeof(*sap)); if (!*text) return 0; switch (fetch(&text,"bhli:","blli:",NULL)) { case 0: if (text2bhli(&text,&sap->bhli) < 0) return -1; bllis = 0; break; case 1: if (text2blli(&text,sap->blli) < 0) return -1; bllis = 1; break; default: return -1; } while (1) { if (!*text) return 0; if (fetch(&text,",blli:",NULL) < 0) return -1; if (bllis == ATM_MAX_BLLI) return 0; /* ignore extra BLLIs */ if (text2blli(&text,sap->blli+bllis) < 0) return -1; bllis++; } } --- NEW FILE: diag.c --- /* diag.c - Diagnostic messages */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <syslog.h> #include "atmd.h" #define MAX_DIAG_MSG 8200 #define DUMP_LINE_WIDTH 75 typedef struct _component { const char *name; int verbosity; struct _component *next; } COMPONENT; static int sev2prio[] = { DIAG_DEBUG,LOG_DEBUG, DIAG_INFO,LOG_INFO, DIAG_WARN,LOG_WARNING, DIAG_ERROR,LOG_ERR, DIAG_FATAL,LOG_ALERT, -1,LOG_NOTICE }; static const char *app_name = NULL; static COMPONENT *components = NULL; static int default_verbosity = DIAG_INFO; static FILE *log_to = NULL; static int log_to_initialized = 0; void set_application(const char *name) { app_name = name; } void set_verbosity(const char *component,int level) { COMPONENT *walk; if (!component) { default_verbosity = level; return; } for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; if (!walk) { walk = alloc_t(COMPONENT); walk->name = component; walk->next = components; components = walk; } walk->verbosity = level; } int get_verbosity(const char *component) { COMPONENT *walk; if (!component) { return default_verbosity; } for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; return walk ? walk->verbosity : default_verbosity; } void set_logfile(const char *name) { log_to_initialized = 1; if (log_to && log_to != stderr) { (void) fclose(log_to); log_to = stderr; } if (!name || !strcmp(name,"stderr")) { log_to = stderr; return; } if (!strcmp(name,"syslog")) { if (app_name) openlog(app_name,LOG_CONS,LOG_DAEMON); log_to = NULL; } else if (!(log_to = fopen(name,"w"))) { perror(name); log_to = stderr; } } FILE *get_logfile(void) { if (!log_to_initialized) { log_to = stderr; log_to_initialized = 1; } return log_to; } void diag_fatal_debug_hook(void); /* GCC insists on a prototype */ void diag_fatal_debug_hook(void) { /* * Set a breakpoint here to catch fatal errors before they mess up the * stack. */ } void vdiag(const char *component,int severity,const char *fmt,va_list ap) { COMPONENT *walk; FILE *to; char buffer[MAX_DIAG_MSG+1]; int i; for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; if (severity > (walk ? walk->verbosity : default_verbosity)) return; fflush(stdout); to = get_logfile(); if (!to) { for (i = 0; sev2prio[i] == severity || sev2prio[i] == -1; i += 2); vsprintf(buffer,fmt,ap); syslog(sev2prio[i+1],"%s: %s",component,buffer); } else { if (app_name) fprintf(to,"%s:%s: ",app_name,component); else fprintf(to,"%s: ",component); vfprintf(to,fmt,ap); fputc('\n',to); fflush(to); } if (severity == DIAG_FATAL) { diag_fatal_debug_hook(); fprintf(stderr,"Fatal error - Terminating\n"); exit(1); } } void diag(const char *component,int severity,const char *fmt,...) { va_list ap; va_start(ap,fmt); vdiag(component,severity,fmt,ap); va_end(ap); } void diag_dump(const char *component,int severity,const char *title, const unsigned char *data,int len) { char buffer[DUMP_LINE_WIDTH+1]; char *curr; int data_line,left; if (title) diag(component,severity,"%s (%d bytes)\n",title,len); data_line = DUMP_LINE_WIDTH-(app_name ? strlen(app_name)+1 : 0)- strlen(component)-3; while (len) { left = data_line; curr = buffer; while (len && left >= 3) { sprintf(curr," %02x",*data++); len--; curr += 3; left -= 3; } diag(component,severity,"%s ",buffer); } } --- NEW FILE: common.c --- /* common.c - Common functions */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdint.h> #include <sys/types.h> #include "atmd.h" void *alloc(size_t size) { void *n; n = malloc(size); if (n) return n; perror("malloc"); exit(1); } uint32_t read_netl(void *p) { unsigned char *_p = p; return (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3]; } --- NEW FILE: Makefile.am --- lib_LTLIBRARIES = libatm.la libatmd.la LDFLAGS = -version-info @ATMLIBS_VERSION@ libatm_la_SOURCES = text2atm.c atm2text.c atmequal.c sdu2cell.c text2qos.c \ qos2text.c qosequal.c sap2text.c text2sap.c sapequal.c \ misc.c atmres.h ans.c libatm_la_LIBADD = -lresolv libatm_la_DEPENDENCIES = $(top_builddir)/src/include/atm.h \ $(top_builddir)/src/include/atmsap.h \ $(top_builddir)/src/include/stdint.h libatmd_la_SOURCES = common.c diag.c kptr.c text2ip.c timer.c unix.c libatmd_la_DEPENDENCIES = $(top_builddir)/src/include/atm.h \ $(top_builddir)/src/include/atmd.h \ $(top_builddir)/src/include/stdint.h EXTRA_DIST = rtf2e164_cc.pl --- NEW FILE: kptr.c --- /* kptr.c - Helper functions to use kernel pointer handles */ /* Written 2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <assert.h> #include <atm.h> #include "atmd.h" int kptr_eq(const atm_kptr_t *a,const atm_kptr_t *b) { unsigned long *_a = (unsigned long *) a,*_b = (unsigned long *) b; assert(sizeof(atm_kptr_t) == 8); switch (sizeof(unsigned long)) { case 2: /* Wow, ATM on ELKS ? :-) */ if (_a[2] != _b[2]) return 0; if (_a[3] != _b[3]) return 0; case 4: if (_a[1] != _b[1]) return 0; case 8: return *_a == *_b; default: abort(); } } const char *kptr_print(const atm_kptr_t *p) { static char buf[KPRT_PRINT_BUFS][sizeof(atm_kptr_t)*2+1]; static int curr_buf = 0; char *result; int i; result = buf[curr_buf]; curr_buf = (curr_buf+1) & (KPRT_PRINT_BUFS-1); for (i = 0; i < sizeof(atm_kptr_t); i++) sprintf(result+2*i,"%02x",((unsigned char *) p)[i]); return result; } --- NEW FILE: misc.c --- /* misc.c - Miscellaneous library functions */ /* Written 1997-2000 by Werner Almesberger, EPFL-ICA/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdint.h> #include <stdarg.h> #include <string.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> /* for htons */ #include <atm.h> #include <atmsap.h> int __atmlib_fetch(const char **pos,...) { const char *value; int ref_len,best_len,len; int i,best; va_list ap; va_start(ap,pos); ref_len = strlen(*pos); best_len = 0; best = -1; for (i = 0; (value = va_arg(ap,const char *)); i++) { len = strlen(value); if (*value != '!' && len <= ref_len && len > best_len && !strncasecmp(*pos,value,len)) { best = i; best_len = len; } } va_end(ap); if (best > -1) (*pos) += best_len; return best; } void atm_tcpip_port_mapping(char *vs_id,uint8_t protocol,uint16_t port) { memcpy(vs_id,ATM_FORUM_OUI "\x01",4); vs_id[4] = protocol; /* e.g. IP_TCP or IP_UDP; from netinet/protocols.h */ vs_id[5] = (htons(port) >> 8) & 255; vs_id[6] = htons(port) & 255; } --- NEW FILE: text2ip.c --- /* text2ip.c - Converts a text string to an IP address. */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdint.h> #include <stdio.h> #include <string.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "atm.h" #include "atmd.h" static void complain(const char *component,const char *item,const char *msg) { if (!component) fprintf(stderr,"%s: %s\n",item,msg); else diag(component,DIAG_ERROR,"%s: %s",item,msg); } uint32_t text2ip(const char *text,const char *component,int flags) { struct hostent *hostent; uint32_t ip; if (strspn(text,"0123456789.") == strlen(text)) { ip = inet_addr(text); if (ip != INADDR_NONE) return ip; if (flags & T2I_ERROR) complain(component,text,"invalid address"); return INADDR_NONE; } if (!(flags & T2I_NAME)) { if (flags & T2I_ERROR) complain(component,text,"numeric IP address expected"); return INADDR_NONE; } hostent = gethostbyname(text); if (!hostent) { if (flags & T2I_ERROR) complain(component,text,"no such host"); return INADDR_NONE; } if (hostent->h_addrtype != AF_INET) { if (flags & T2I_ERROR) complain(component,text,"unknown address family"); return INADDR_NONE; } memcpy(&ip,hostent->h_addr,hostent->h_length); return ip; } --- NEW FILE: qos2text.c --- /* qos2text.c - Converts binary encoding of QOS parameters to textual representation */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include "atm.h" #define FLD(F) \ if (curr->F && ((ref && (ref->F != curr->F || ref->traffic_class == \ ATM_NONE)) || (comp && comp->F == curr->F && comp->traffic_class != \ ATM_NONE))) { \ if (buffer != *pos && !strchr(":,",(*pos)[-1])) *(*pos)++ = ','; \ if (curr->F != ATM_MAX_PCR) *pos += sprintf(*pos,#F "=%d",curr->F); \ else { \ strcat(*pos,#F "=max"); \ *pos += strlen(#F)+4; \ } \ } static void params(char *buffer,char **pos,const struct atm_trafprm *ref, const struct atm_trafprm *curr,const struct atm_trafprm *comp) { FLD(max_pcr); FLD(pcr); FLD(min_pcr); FLD(max_sdu); } static void opt(const char *prefix,char *buffer,char **pos, const struct atm_trafprm *ref,const struct atm_trafprm *curr, const struct atm_trafprm *comp) { char *start; if (curr->traffic_class == ATM_NONE) { if (!comp) *pos += sprintf(*pos,"%snone",prefix); return; } start = *pos; params(buffer,pos,ref,curr,comp); if (start == *pos) return; *pos = start; strcpy(*pos,prefix); *pos += strlen(prefix); params(buffer,pos,ref,curr,comp); } int qos2text(char *buffer,int length,const struct atm_qos *qos,int flags) { char *pos,*start; if (length <= MAX_ATM_QOS_LEN) return -1; *(pos = buffer) = 0; switch (qos->txtp.traffic_class == ATM_NONE ? qos->rxtp.traffic_class : qos->txtp.traffic_class) { case ATM_UBR: strcpy(buffer,"ubr"); pos += 3; break; case ATM_CBR: strcpy(buffer,"cbr"); pos += 3; break; case ATM_ABR: strcpy(buffer,"abr"); pos += 3; break; default: return -1; } if (qos->aal != ATM_NO_AAL) { strcpy(pos,","); pos++; } switch (qos->aal) { case ATM_NO_AAL: break; case ATM_AAL0: strcpy(pos,"aal0"); pos += 4; break; case ATM_AAL5: strcpy(pos,"aal5"); pos += 4; break; default: return -1; } pos++; start = pos; if (qos->txtp.traffic_class != ATM_NONE && qos->rxtp.traffic_class != ATM_NONE) params(buffer,&pos,NULL,&qos->txtp,&qos->rxtp); opt(start == pos ? "tx:" : ",tx:",buffer,&pos,&qos->rxtp,&qos->txtp,NULL); opt(start == pos ? "rx:" : ",rx:",buffer,&pos,&qos->txtp,&qos->rxtp,NULL); if (pos != start) start[-1] = ':'; return 0; } --- NEW FILE: unix.c --- /* unix.c - Unix domain socket communication */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> #include "atmd.h" static int mkaddr(const char *path,struct sockaddr_un *addr) { addr->sun_family = AF_UNIX; strcpy(addr->sun_path,path); return (char *) &addr->sun_path[strlen(path)]-(char *) addr; } int un_create(const char *path,mode_t mode) { struct sockaddr_un addr; mode_t old_umask; int size; int s; s = socket(PF_UNIX,SOCK_DGRAM,0); if (s < 0) return s; (void) unlink(path); size = mkaddr(path,&addr); old_umask = umask(~mode); if (bind(s,(struct sockaddr *) &addr,size) < 0) return -1; (void) umask(old_umask); return s; } int un_attach(const char *path) { struct sockaddr_un addr; int size; int s; s = socket(PF_UNIX,SOCK_DGRAM,0); if (s < 0) return s; size = mkaddr("",&addr); if (bind(s,(struct sockaddr *) &addr,size) < 0) return -1; size = mkaddr(path,&addr); if (connect(s,(struct sockaddr *) &addr,size) < 0) return -1; return s; } int un_recv_connect(int s,void *buf,int size) { struct sockaddr_un addr; int addr_size; int len; addr_size = sizeof(addr); len = recvfrom(s,buf,size,0,(struct sockaddr *) &addr,&addr_size); if (len < 0) return len; if (connect(s,(struct sockaddr *) &addr,addr_size) < 0) return -1; return len; } int un_recv(UN_CTX *ctx,int s,void *buf,int size) { ctx->s = s; ctx->size = sizeof(ctx->addr); return recvfrom(s,buf,size,0,(struct sockaddr *) &ctx->addr,&ctx->size); } int un_send(const UN_CTX *ctx,void *buf,int len) { int sent; sent = sendto(ctx->s,buf,len,0,(struct sockaddr *) &ctx->addr,ctx->size); if (sent < 0 || sent == len) return sent; errno = EMSGSIZE; /* ugly */ return -1; } int un_reply(int s,void *buf,int size, int (*handler)(void *buf,int len,void *user),void *user) { UN_CTX ctx; int len; len = un_recv(&ctx,s,buf,size); if (len < 0) return len; len = handler(buf,len,user); if (len <= 0) return len; return un_send(&ctx,buf,len); } --- NEW FILE: sapequal.c --- /* sapequal.c - Compares SAP specifications for compatibility */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdarg.h> #include <string.h> #include "atm.h" #include "atmsap.h" static int bhli_compat(const struct atm_bhli a,const struct atm_bhli b, int flags) { int length; if (!a.hl_type && (flags & SXE_COMPATIBLE)) return 1; if (a.hl_type != b.hl_type) return 0; switch (a.hl_type) { case ATM_HL_ISO: case ATM_HL_USER: length = a.hl_length; if (length != b.hl_length) return 0; break; case ATM_HL_HLP: length = 4; break; case ATM_HL_VENDOR: length = 7; break; default: length = 0; } return !length || !memcmp(a.hl_info,b.hl_info,length); } #define CHECK(FIELD,CONSTRAINT) \ if (res && !res->FIELD) res->FIELD = a.FIELD; \ if (a.FIELD && b.FIELD && a.FIELD != b.FIELD) { \ if (!(flags & SXE_NEGOTIATION)) return 0; \ if (!CONSTRAINT) return 0; \ if (res) res->FIELD = a.FIELD < b.FIELD ? a.FIELD : b.FIELD; \ } static int match_blli(const struct atm_blli a,const struct atm_blli b, int flags,struct atm_blli *res) { if (res) *res = b; if (a.l2_proto != b.l2_proto || a.l3_proto != b.l3_proto) return 0; switch (a.l2_proto) { case ATM_L2_X25_LL: case ATM_L2_X25_ML: case ATM_L2_HDLC_ARM: case ATM_L2_HDLC_NRM: case ATM_L2_HDLC_ABM: case ATM_L2_Q922: case ATM_L2_ISO7776: CHECK(l2.itu.mode,1); CHECK(l2.itu.window,a.l2.itu.window > b.l2.itu.window); break; default: } switch (a.l3_proto) { case ATM_L3_X25: case ATM_L3_ISO8208: case ATM_L3_X223: CHECK(l3.itu.mode,1); CHECK(l3.itu.def_size,a.l3.itu.def_size > b.l3.itu.def_size); CHECK(l3.itu.window,a.l3.itu.window > b.l3.itu.window); break; case ATM_L3_TR9577: if (a.l3.tr9577.ipi != b.l3.tr9577.ipi) return 0; if (a.l3.tr9577.ipi == NLPID_IEEE802_1_SNAP) if (memcmp(a.l3.tr9577.snap,b.l3.tr9577.snap,5)) return 0; break; case ATM_L3_USER: if (a.l3.user != b.l3.user) return 0; break; default: } return 1; } #undef CHECK static int blli_compat(const struct atm_blli *a,const struct atm_blli *b, int flags,struct atm_blli *res) { int i,j; if (!(flags & SXE_COMPATIBLE)) { for (i = 0; i < ATM_MAX_BLLI; i++) if (blli_in_use(a[i])) if (!blli_in_use(b[i])) return 0; else { if (!match_blli(a[i],b[i],0,NULL)) return 0; } else if (blli_in_use(b[i])) return 0; else break; if (res) *res = *a; return 1; } if (!blli_in_use(*a)) { if (res) *res = *b; return 1; } for (i = 0; i < ATM_MAX_BLLI && blli_in_use(a[i]); i++) for (j = 0; j < ATM_MAX_BLLI && blli_in_use(b[j]); j++) if (match_blli(a[i],b[j],flags,res)) return 1; return 0; } int sap_equal(const struct atm_sap *a,const struct atm_sap *b,int flags,...) { va_list ap; struct atm_sap *res; va_start(ap,flags); res = flags & SXE_RESULT ? va_arg(ap,struct atm_sap *) : NULL; va_end(ap); if (!bhli_compat(a->bhli,b->bhli,flags)) return 0; if (!blli_compat(a->blli,b->blli,flags,res ? res->blli : NULL)) return 0; if (res) { res->bhli = b->bhli; memset(res->blli+1,0,sizeof(struct atm_blli)*(ATM_MAX_BLLI-1)); } return 1; } --- NEW FILE: atm2text.c --- /* atm2text.c - Converts binary encoding of ATM address to textual representation */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include "atm.h" #include "atmres.h" static int put_item(char **buffer,int *length,int value) { char *walk,*scan; char tmp; if (!*length) return FATAL; if (value <= 0) { if (!value) *(*buffer)++ = '0'; else if (value == ATM_VCI_ANY) *(*buffer)++ = '*'; else if (value == ATM_VCI_UNSPEC) *(*buffer)++ = '?'; else return FATAL; /* ATM_*_ANY and ATM_*_UNSPEC have all the same value, respectively */ (*length)--; return 0; } for (walk = *buffer; value; value /= 10) { if (!(*length)--) return FATAL; *walk++ = '0'+(value % 10); } for (scan = walk-1; scan > *buffer; (*buffer)++) { tmp = *scan; *scan-- = **buffer; **buffer = tmp; } *buffer = walk; return 0; } static int do_pvc(char *buffer,int length,const struct sockaddr_atmpvc *addr, int flags) { int orig_len; orig_len = length; if (put_item(&buffer,&length,addr->sap_addr.itf)) return FATAL; if (!length--) return FATAL; *buffer++ = '.'; if (put_item(&buffer,&length,addr->sap_addr.vpi)) return FATAL; if (!length--) return FATAL; *buffer++ = '.'; if (put_item(&buffer,&length,addr->sap_addr.vci)) return FATAL; if (!length) return FATAL; *buffer = 0; return orig_len-length; } static int do_svc(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags) { static int pure[] = { 20 }; static int bin[] = { 1,2,10,6,1 }; static int local[] = { 1,12,6,1 }; static int e164[] = { 4,6,1 }; int orig_len,len,i,left,value; int *fmt; orig_len = length; if (!*addr->sas_addr.pub && !*addr->sas_addr.prv) return FATAL; if (*addr->sas_addr.pub) { len = strlen(addr->sas_addr.pub); if (!*addr->sas_addr.prv && length >= len+2) { *buffer++ = '+'; length--; } if (length < len+1) return FATAL; strcpy(buffer,addr->sas_addr.pub); buffer += len; length -= len; if (*addr->sas_addr.prv) { if (!length--) return FATAL; *buffer++ = '+'; } } if (*addr->sas_addr.prv) { fmt = pure; i = 0; if (flags & A2T_PRETTY) switch (*addr->sas_addr.prv) { case ATM_AFI_DCC: case ATM_AFI_ICD: case ATM_AFI_DCC_GROUP: case ATM_AFI_ICD_GROUP: fmt = bin; break; case ATM_AFI_LOCAL: case ATM_AFI_LOCAL_GROUP: fmt = local; break; case ATM_AFI_E164: case ATM_AFI_E164_GROUP: for (i = 2; i < 17; i++) if (addr->sas_addr.prv[i >> 1] & (0xf0 >> 4*(i & 1))) break; while (i < 17) { value = (addr->sas_addr.prv[i >> 1] >> 4*(1-(i & 1))) & 0xf; if (value > 9) return FATAL; if (!length--) return FATAL; *buffer++ = '0'+value; i++; } if (!length--) return FATAL; *buffer++ = ':'; i = 9; fmt = e164; break; default: break; } for (left = *fmt++; i < ATM_ESA_LEN; i++) { if (!left--) { if (!length--) return FATAL; *buffer++ = '.'; left = *fmt++-1; } if (length < 2) return FATAL; sprintf(buffer,"%02X",addr->sas_addr.prv[i]); length -= 2; buffer += 2; } } if (!length) return FATAL; *buffer = 0; return orig_len-length; } static int search(FILE *file,char *buffer,int length, const struct sockaddr *addr,int flags) { struct sockaddr_atmsvc temp; char line[MAX_ATM_NAME_LEN+1]; const char *here; while (fgets(line,MAX_ATM_NAME_LEN,file)) { if (!(here = strtok(line,"\t\n "))) continue; if (text2atm(here,(struct sockaddr *) &temp,sizeof(temp),flags) < 0) continue; if (temp.sas_family != addr->sa_family) continue; if (temp.sas_family == AF_ATMPVC) { if (((const struct sockaddr_atmpvc *) addr)->sap_addr.itf != ((struct sockaddr_atmpvc *) &temp)->sap_addr.itf || ((const struct sockaddr_atmpvc *) addr)->sap_addr.vpi != ((struct sockaddr_atmpvc *) &temp)->sap_addr.vpi || ((const struct sockaddr_atmpvc *) addr)->sap_addr.vci != ((struct sockaddr_atmpvc *) &temp)->sap_addr.vci) continue; } else if (!atm_equal(addr,(struct sockaddr *) &temp,0,0)) continue; while ((here = strtok(NULL,"\t\n "))) if (strlen(here) < length) { strcpy(buffer,here); return 0; } return FATAL; } return TRY_OTHER; } static int try_name(char *buffer,int length,const struct sockaddr *addr) { FILE *file; int result; if (!(file = fopen(HOSTS_ATM,"r"))) return TRY_OTHER; result = search(file,buffer,length,addr,addr->sa_family == AF_ATMPVC ? T2A_PVC : T2A_SVC); (void) fclose(file); return result; } int atm2text(char *buffer,int length,const struct sockaddr *addr,int flags) { int result; if (addr->sa_family != AF_ATMPVC && addr->sa_family != AF_ATMSVC) return -1; if (!length) return -1; if (flags & A2T_NAME) { result = try_name(buffer,length,addr); if (result == TRY_OTHER && !(flags & A2T_LOCAL)) result = ans_byaddr(buffer,length, (const struct sockaddr_atmsvc *) addr,flags); if (result == FATAL) return FATAL; if (result != TRY_OTHER) return strlen(buffer); } if (addr->sa_family == AF_ATMPVC) return do_pvc(buffer,length,(const struct sockaddr_atmpvc *) addr, flags); else return do_svc(buffer,length,(const struct sockaddr_atmsvc *) addr, flags); return -1; } --- NEW FILE: sdu2cell.c --- /* sdu2cr.c... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:35
|
Update of /cvsroot/linux-atm/linux-atm/src/switch/debug In directory usw-pr-cvs1:/tmp/cvs-serv8631/switch/debug Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-lsw -latmd -L.. LIBDEPS=../../lib/libatmd.a ../libsw.a INCLUDES=-I../../qgen OBJS=debug.o PGMS=sw_debug include ../Rules.make sw_debug: $(OBJS) $(CC) $(LDFLAGS) -o sw_debug $(OBJS) $(LIBS) $(LDLIBS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:35
|
Update of /cvsroot/linux-atm/linux-atm/src/switch/tcp In directory usw-pr-cvs1:/tmp/cvs-serv8631/switch/tcp Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-lsw -latmd -L.. LIBDEPS=../../lib/libatmd.a ../libsw.a INCLUDES=-I../../qgen OBJS=tcpsw.o PGMS=sw_tcp include ../Rules.make sw_tcp: $(OBJS) $(CC) $(LDFLAGS) -o sw_tcp $(OBJS) $(LIBS) $(LDLIBS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/maint In directory usw-pr-cvs1:/tmp/cvs-serv8631/maint Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LDLIBS=-latmd INCLUDES=-I../qgen -I../saal BOOTPGMS=atmaddr esi SYSPGMS=atmloop atmtcp enitune zntune # nstune USRPGMS=atmdiag atmdump sonetdiag saaldump MAN8=atmaddr.8 atmdiag.8 atmdump.8 atmloop.8 atmtcp.8 esi.8 include ../Rules.make saaldump: saaldump.o $(CC) $(LDFLAGS) -o saaldump saaldump.o ../qgen/qd.dump.o \ -L../saal -lsaal -L../lib -latm -latmd |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/lane In directory usw-pr-cvs1:/tmp/cvs-serv8631/lane Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- # # Makefile # $Id: Makefile-0.79,v 1.1.2.1 2001/09/03 18:32:30 paulsch Exp $ # # Compilation options # CFLAGS = -ansi -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs # # # The rules # # SYSPGMS = les bus lecs MAN8 = les.8 lecs.8 bus.8 LESBUSOBJS = mem.o load.o units.o load_lex.o timers.o dump.o atm.o \ events.o lane.o LESOBJS = $(LESBUSOBJS) packet.o connect.o db.o BUSOBJS = $(LESBUSOBJS) connect_bus.o LECSOBJS = lecs_db.o lecs_load.o lecs.o ldb.o mem_lecs.o atm_lecs.o OBJS = $(LESOBJS) $(BUSOBJS) $(LECSOBJS) CLEAN = clean_lane include ../Rules.make load_lex.c : load_lex.l $(LEX) -oload_lex.c load_lex.l lecs_db.c: lecs_db.l $(LEX) -olecs_db.c lecs_db.l les: $(LESOBJS) @echo "Linking $@" @$(CC) $(LDFLAGS) -o $@ $(LESOBJS) bus: $(BUSOBJS) @echo "Linking $@" @$(CC) $(LDFLAGS) -o $@ $(BUSOBJS) lecs: $(LECSOBJS) @echo "Linking $@" $(CC) $(LDFLAGS) -o $@ $(LECSOBJS) $(LDLIBS) clean_lane: rm -f $(SYSPGMS) *.o *.d *~ .*~ core *.bak *.tar* *.errs load_lex.c \ lecs_db.c *~ |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/switch In directory usw-pr-cvs1:/tmp/cvs-serv8631/switch Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LDLIBS=-latmd LIBDEPS=../lib/libatmd.a SW_OBJS=control.o dispatch.o proto.o relay.o route.o sig.o lex.yy.o y.tab.o SUBDIRS=debug tcp PGMS=swc all: do_all: libsw.a include ../Rules.make lex.yy.c: cfg.l y.tab.h ../lib/atm.h $(LEX) cfg.l y.tab.c y.tab.h: cfg.y ../lib/atmd.h route.h sig.h $(YACC) -d cfg.y libsw.a: $(SW_OBJS) ar rcs libsw.a $(SW_OBJS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/ilmid In directory usw-pr-cvs1:/tmp/cvs-serv8631/ilmid Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS = -L../lib -latmd -latm -Lasn1 -lasn1 LIBDEPS=../lib/libatmd.a ../lib/libatm.a INCLUDES = -I../lib -Iasn1 SRCS = rfc1157_snmp.c rfc1155_smi.c util.c io.c message.c \ atmf_uni.c mib.c sysgroup.c ilmid.c OBJS = $(SRCS:%.c=%.o) BOOTPGMS=ilmid CLEAN = clean_ilmid include ../Rules.make CFLAGS = $(CFLAGS_NOWARN) $(CFLAGS_OPT) $(CFLAGS_PRIVATE) $(STANDARDS) default: all do_all: ilmid asn1/libasn1.a: @cd asn1; make ilmid: asn1/libasn1.a $(OBJS) $(CC) $(OBJS) $(LIBS) -o ilmid clean_ilmid: @cd asn1; make clean rm -rf ilmid $(OBJS) *~ |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/mpoad In directory usw-pr-cvs1:/tmp/cvs-serv8631/mpoad Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-latm OBJS=get_vars.o io.o k_interf.o main.o p_factory.o p_recogn.o id_list.o tag_list.o poll2select.o lecs.o BOOTPGMS=mpcd MAN8= mpcd.8 # MPOA specific flags # -DDBROKEN_POLL use select() instead of poll() # -DMPOA_1_1 use proposed MPOA 1.1 features CFLAGS_PRIVATE=-DBROKEN_POLL include ../Rules.make mpcd: $(OBJS) $(CC) $(LDFLAGS) -o mpcd $(OBJS) $(LIBD) $(LDLIBS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/debug In directory usw-pr-cvs1:/tmp/cvs-serv8631/debug Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- PGMS=delay svctor # ed encopy endump zndump znth # Remove the # for more hardware-specific debugging programs. # I'll need those only if you're fiddling with the guts of drivers. MAN8= include ../Rules.make zndump.o: zndump.c $(CC) -c $(CFLAGS) -w -O zndump.c |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:34
|
Update of /cvsroot/linux-atm/linux-atm/src/ilmid/asn1 In directory usw-pr-cvs1:/tmp/cvs-serv8631/ilmid/asn1 Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- CC = cc CFLAGS = -O LIBS = SRCS = asn_len.c asn_tag.c asn_int.c asn_octs.c asn_bits.c str_stk.c \ asn_oid.c asn_null.c asn_list.c nibble_alloc.c print.c \ OBJS = $(SRCS:%.c=%.o) default: all all: libasn1.a .c.o: $(CC) $(CFLAGS) -c $< libasn1.a: $(OBJS) ar cr libasn1.a $(OBJS) depend: # makedepend $(INCLUDES) $(SRCS) $(CPP) -M $(SRCS) >.tmpdepend mv .tmpdepend .depend clean: rm -rf libasn1.a $(OBJS) ifeq (.depend,$(wildcard .depend)) include .depend endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/test In directory usw-pr-cvs1:/tmp/cvs-serv8631/test Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- ISP_OBJS=isp.o lex.yy.o y.tab.o USRPGMS=aread awrite ttcp_atm PGMS=align aping br bw isp window MAN1= TRASH=errnos.inc include ../Rules.make ttcp_atm.o: ttcp.c ttcp.o gcc -c -w -O2 -o ttcp_atm.o ttcp.c -I../lib ttcp.o: # dummy touch ttcp.o isp: $(ISP_OBJS) ../lib/libatm.a ../lib/libatmd.a $(CC) $(LDFLAGS) -o isp $(ISP_OBJS) $(LDLIBS) -latmd \ -lfl lex.yy.c: ispl.l y.tab.h $(LEX) ispl.l y.tab.c y.tab.h: ispl.y isp.h ../lib/atm.h $(YACC) -d ispl.y isp.o: errnos.inc errnos.inc: mkerrnos.pl perl ./mkerrnos.pl </usr/include/asm/errno.h \ >errnos.inc || { rm -f errnos.inc; exit 1; } # # During "make depend", we need to have something that keeps the #include from # failing. The "touch" at the end makes sure that errnos.inc gets rebuilt in # time. The sleep 1 makes sure that mkerrnos.pl is really more recent than # errnos.inc # $(DEPEND): fake_errnos.inc fake_errnos.inc: echo "! This must not compile" >errnos.inc sleep 1 touch mkerrnos.pl |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/saal In directory usw-pr-cvs1:/tmp/cvs-serv8631/saal Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS= OBJS=pdu.o saal.o sscf.o sscop.o queue.o do_all: libsaal.a include ../Rules.make ../saal/libsaal.a: libsaal.a libsaal.a: $(OBJS) ar rcs libsaal.a $(OBJS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/man In directory usw-pr-cvs1:/tmp/cvs-serv8631/man Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- MAN7=qos.7 sap.7 DEPEND = depend_man include ../Rules.make all: depend_man: @ |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/qgen In directory usw-pr-cvs1:/tmp/cvs-serv8631/qgen Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-lfl # lex may want -ll here OBJS=common.o file.o first.o lex.yy.o qgen.o second.o third.o y.tab.o TRASH=q.out.h q.out.c q.test.c qd.out.h qd.out.c qd.test.c qd.dump.c default.nl # q40.out.h q40.out.c q40.test.c PGMS=qgen q.out.o qd.dump.o q.dump #qtest # q40.out.o NLS=atm_ai_msg atm_ai_ie atm_loc atm_cv atm_pu atm_na atm_cond atm_ie atm_msg \ atm_np atm_ton atm_sat atm_prs atm_scrn atm_vpa atm_poe q2931_cs atm_td \ atm_bc atm_tc atm_stc atm_upcc q2931_proto atm_flag atm_aalp atm_fd atm_tag \ atm_l2 atm_l3 atm_tt atm_mc atm_hl atm_imd atm_tdl atm_tni atm_nip atm_shi \ atm_oci atm_unfm atm_ofi atm_irs atm_it atm_lit atm_lsi atm_tcs atm_css \ atm_eqo atm_eqp atm_aap atm_asp atm_tor SYMFILES=uni.h $(shell perl incl.pl $(CFLAGS) linux/atmsap.h) NOLIBATMDEP=yes include ../Rules.make qgen: $(OBJS) $(CC) $(LDFLAGS) -o qgen $(OBJS) $(LIBS) q.out.h q.out.c q.test.c: qgen msg.fmt default.nl $(CC) $(STANDARDS) -E - <msg.fmt | ./qgen #q40.out.o: q40.out.c q40.out.h qlib.c qlib.h # $(CC) $(CFLAGS) -DUNI40 -c q40.out.c # #q40.out.h q40.out.c q40.test.c: qgen uni40 default.nl # $(CC) $(STANDARDS) -E - <uni40 | \ # PREFIX=q40 ./qgen qd.out.h qd.out.c qd.dump.c: qgen msg.fmt default.nl $(CC) $(STANDARDS) -E - <msg.fmt | ./qgen -D lex.yy.c: ql.l qgen.h y.tab.h $(LEX) ql.l y.tab.c y.tab.h: ql.y qgen.h $(YACC) -d ql.y default.nl: mknl.pl $(SYMFILES) cat $(SYMFILES) | \ perl mknl.pl $(NLS) >default.nl || \ { rm -f default.nl; echo 1; } q.out.o: q.out.c q.out.h qlib.c qlib.h $(CC) $(CFLAGS) -c $(STANDARDS) q.out.c q.test: q.test.c qtest.c $(CC) $(CFLAGS) -o q.test $(STANDARDS) q.test.c q.dump: qd.dump.c q.out.h qd.out.c qlib.h qlib.c $(CC) $(CFLAGS) -DSTANDALONE -o q.dump \ $(STANDARDS) qd.dump.c common.o qd.dump.o: qd.dump.c qd.out.c qlib.h qlib.c $(CC) $(CFLAGS) -c $(STANDARDS) qd.dump.c qtest: q.test ./q.test |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/sigd In directory usw-pr-cvs1:/tmp/cvs-serv8631/sigd Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-L../saal -lsaal -latmd -lfl # lex may want -ll here LIBDEPS=../saal/libsaal.a ../lib/libatmd.a INCLUDES=-I../qgen -I../saal -I. OBJS=atmsigd.o io.o kernel.o mess.o proto.o uni.o sap.o timeout.o trace.o \ policy.o lex.yy.o y.tab.o EXTOBJS=../qgen/q.out.o ../qgen/qd.dump.o BOOTPGMS=atmsigd TRASH=mess.c TRASH_SPOTLESS=q.out.h MAN4=atmsigd.conf.4 MAN8=atmsigd.8 include ../Rules.make CFLAGS_NOWARN += $(STANDARDS) atmsigd: $(OBJS) $(EXTOBJS) $(CC) $(LDFLAGS) -o atmsigd $(OBJS) $(EXTOBJS) \ $(LDLIBS) $(LIBS) lex.yy.c: cfg.l y.tab.h ../lib/atm.h $(LEX) cfg.l y.tab.c y.tab.h: cfg.y ../lib/atmd.h proto.h io.h $(YACC) -d cfg.y mess.c: ../qgen/uni.h mkmess.pl perl ./mkmess.pl <../qgen/uni.h >mess.c # # The following hack makes sure that "make depend" finds q.out.h and is # happy with it. Once qgen has been built, there will be ../qgen/q.out.h, # which is first in the include file search path and therefore gets # included. An second "make depend" will also use the right file. # $(DEPEND): fake_q.out.h fake_q.out.h: echo "! This must not compile" >q.out.h |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/led In directory usw-pr-cvs1:/tmp/cvs-serv8631/led Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- LIBS=-latm -latmd OBJS=join.o conn.o main.o address.o frames.o display.o kernel.o BOOTPGMS=zeppelin MAN8=zeppelin.8 CFLAGS_PRIVATE= include ../Rules.make zeppelin:$(OBJS) $(CC) $(LDFLAGS) -o $(BOOTPGMS) $(OBJS) $(LIBD) $(LDLIBS) $(LIBS) |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:32:33
|
Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv8631/lib Added Files: Tag: V2_4_0 Makefile-0.79 Log Message: --- NEW FILE: Makefile-0.79 --- ATM_OBJS=text2atm.o atm2text.o atmequal.o sdu2cell.o text2qos.o qos2text.o \ qosequal.o sap2text.o text2sap.o sapequal.o misc.o ifeq (/usr/lib/libresolv.a,$(wildcard /usr/lib/libresolv.a)) ATM_OBJS += ans_l.o else ATM_OBJS += ans.o endif ATMD_OBJS=common.o diag.o kptr.o text2ip.o timer.o unix.o PGMS=#test GENLIBS=libatm.a libatmd.a SYSHDR=atm.h atmd.h atmsap.h OPTSYSHDR=stdint.h do_all: libatm.a libatmd.a include ../Rules.make ../lib/libatm.a: libatm.a libatm.a: $(ATM_OBJS) ar rcs libatm.a $(ATM_OBJS) ../lib/libatmd.a: libatmd.a libatmd.a: $(ATMD_OBJS) ar rcs libatmd.a $(ATMD_OBJS) ans_l.o: ans.o ld -r -o ans_l.o ans.o -L/usr/lib -lresolv |