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] |