diff options
Diffstat (limited to 'sbin/atm/atmconfig')
-rw-r--r-- | sbin/atm/atmconfig/Makefile | 44 | ||||
-rw-r--r-- | sbin/atm/atmconfig/Makefile.depend | 22 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atm_oid.list | 20 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig.8 | 323 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig.h | 102 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig.help | 223 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig_device.c | 444 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig_device.h | 75 | ||||
-rw-r--r-- | sbin/atm/atmconfig/atmconfig_device.help | 62 | ||||
-rw-r--r-- | sbin/atm/atmconfig/diag.c | 1122 | ||||
-rw-r--r-- | sbin/atm/atmconfig/diag.h | 49 | ||||
-rw-r--r-- | sbin/atm/atmconfig/main.c | 880 | ||||
-rw-r--r-- | sbin/atm/atmconfig/natm.c | 680 | ||||
-rw-r--r-- | sbin/atm/atmconfig/private.h | 62 |
14 files changed, 4108 insertions, 0 deletions
diff --git a/sbin/atm/atmconfig/Makefile b/sbin/atm/atmconfig/Makefile new file mode 100644 index 000000000000..9e8196f76465 --- /dev/null +++ b/sbin/atm/atmconfig/Makefile @@ -0,0 +1,44 @@ +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# Author: Harti Brandt <brandt@fokus.gmd.de> +# +# $FreeBSD$ + +.include <src.opts.mk> + +PACKAGE=atm +PROG= atmconfig +SRCS= main.c diag.c natm.c +MAN= atmconfig.8 +# CFLAGS+= -DPATH_HELP='".:${SHAREDIR}/doc/atm:/usr/local/share/doc/atm"' + +CFLAGS+= -I${.OBJDIR} + +.if !defined(RESCUE) && ${MK_BSNMP} != "no" +CFLAGS+= -DWITH_BSNMP +SRCS+= oid.h atmconfig_device.c +LIBADD+= bsnmp +. if ${MK_DYNAMICROOT} == "no" && ${MK_OPENSSL} != "no" +LIBADD+= crypto +. endif +.endif + +CLEANFILES+= oid.h + +# XXX - this is verboten +.if ${MACHINE_CPUARCH} == "arm" +WARNS?= 3 +.endif + +FILES= atmconfig.help atmconfig_device.help +FILESDIR= ${SHAREDIR}/doc/atm + +SNMP_ATM_DEF= ${SRCTOP}/contrib/ngatm/snmp_atm/atm_tree.def \ + ${SRCTOP}/usr.sbin/bsnmpd/modules/snmp_atm/atm_freebsd.def + +oid.h: atm_oid.list ${SNMP_ATM_DEF} + cat ${SNMP_ATM_DEF} | gensnmptree -e `tail -n +2 ${.CURDIR}/atm_oid.list` \ + > ${.TARGET} + +.include <bsd.prog.mk> diff --git a/sbin/atm/atmconfig/Makefile.depend b/sbin/atm/atmconfig/Makefile.depend new file mode 100644 index 000000000000..6c9b39660895 --- /dev/null +++ b/sbin/atm/atmconfig/Makefile.depend @@ -0,0 +1,22 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + include/arpa \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libbsnmp/libbsnmp \ + lib/libc \ + lib/libcompiler_rt \ + lib/libnetgraph \ + secure/lib/libcrypto \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/sbin/atm/atmconfig/atm_oid.list b/sbin/atm/atmconfig/atm_oid.list new file mode 100644 index 000000000000..ca64afa44267 --- /dev/null +++ b/sbin/atm/atmconfig/atm_oid.list @@ -0,0 +1,20 @@ +# $FreeBSD$ +begemotAtmIfTable +begemotAtmIfName +begemotAtmIfNodeId +begemotAtmIfPcr +begemotAtmIfMedia +begemotAtmIfVpiBits +begemotAtmIfVciBits +begemotAtmIfMaxVpcs +begemotAtmIfMaxVccs +begemotAtmIfEsi +begemotAtmIfCarrierStatus +begemotAtmIfMode +begemotAtmIfTableLastChange +begemotAtmHWTable +begemotAtmHWVendor +begemotAtmHWDevice +begemotAtmHWSerial +begemotAtmHWVersion +begemotAtmHWSoftVersion diff --git a/sbin/atm/atmconfig/atmconfig.8 b/sbin/atm/atmconfig/atmconfig.8 new file mode 100644 index 000000000000..0cb04e86120f --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig.8 @@ -0,0 +1,323 @@ +.\" +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Author: Hartmut Brandt <harti@FreeBSD.org> +.\" +.\" $FreeBSD$ +.\" +.Dd October 5, 2016 +.Dt ATMCONFIG 8 +.Os +.Sh NAME +.Nm atmconfig +.Nd "ATM configuration tool" +.Sh SYNOPSIS +.Nm +.Op Fl htv +.Op Ar command Op Ar sub-command Op ... +.Op Ar options +.Op Ar arg ... +.Sh DESCRIPTION +The +.Nm +tool is used to configure the Netgraph ATM network sub-system. +.Pp +The command line of +.Nm +generally consists of common options followed by a command string, optionally +followed by sub-command strings, optional command specific options and +command specific arguments. +Commands and sub-commands as well as command +specific options may be abbreviated as +long as there is only one match possible. +.Ss Common Options +The following common options change the overall behaviour of +.Nm : +.Bl -tag -width indent +.It Fl h +Print a very short usage info and exit. +.It Fl t +Several show-type commands output a header and then several lines +of information. +If this option is given, the header is omitted, simplifying the parsing +of the output. +.It Fl v +Be more verbose. +.El +.Ss Obtaining Help +The +.Ic help +command has a number of useful sub-commands. +.Pp +To get general help use: +.D1 Nm Ic help +.Pp +To get a list of available commands use: +.D1 Nm Ic help Cm commands +.Pp +To get a list of available sub-commands use: +.D1 Nm Ic help Ar command +.Pp +or (if there are deeper levels of sub-commands): +.D1 Nm Ic help Ar command sub-command ... +.Pp +To get a list of options and arguments for a command use: +.D1 Nm Ic help Ar command sub-command ... +(given that there are no further sub-command levels). +.Pp +To get a list of common options use: +.D1 Nm Ic help Cm options +.Ss The Ic diag Command +The +.Ic diag +command allows the inspection of the ATM interfaces on the local host +and the modification of device parameters. +Sub-commands are: +.Cm list +(print a list of interfaces), +.Cm config +(print hardware configuration), +.Cm phy +(access PHY chip), +.Cm stats +(print statistics) and +.Cm vcc +(print list of VCCs). +.Bl -tag -width indent +.\"---------------------------------------- +.It Nm Ic diag Cm list +This sub-command lists all ATM interfaces in the system. +It takes no options or arguments. +.\"---------------------------------------- +.It Xo +.Nm Ic diag Cm config +.Op Fl atm +.Op Fl hardware +.Op Ar device ... +.Xc +This command prints the configuration of ATM interfaces. +If no +.Ar device +is given, all devices are listed, otherwise only the specified devices. +The option +.Fl atm +instructs the command to print ATM layer configuration parameters like +the number of VCI and VPI bits, whereas the +.Fl hardware +option requests card specific information like the vendor or the serial +number. +If none of the options is given, the defaults is to assume +.Fl atm . +.\"---------------------------------------- +.It Xo +.Nm Ic diag Cm phy print +.Op Fl numeric +.Ar device +.Xc +This command prints the PHY registers in a (potential) +human comprehensible format. +If +.Fl numeric +is given, the format is hex bytes. +Otherwise, textual representation will be printed. +.\"---------------------------------------- +.It Nm Ic diag Cm phy show Op Ar device ... +This sub-command prints static information about the PHY device used +in the ATM card like the type of the PHY and the media. +.\"---------------------------------------- +.It Xo +.Nm Ic diag Cm phy set +.Ar device +.Ar reg +.Ar mask +.Ar val +.Xc +This sub-command allows one to change bits in PHY registers. +This should be used with great care. +The bits of the given PHY chip register for which the corresponding bit in +.Ar mask +is one are set to the values of the corresponding bits in +.Ar val . +All register bits that have a zero in +.Ar mask +are written back with their original value. +.\"---------------------------------------- +.It Xo +.Nm Ic diag Cm phy stats +.Op Fl clear +.Ar device +.Xc +Print the PHY statistics for the given +.Ar device . +When the optional +.Fl clear +is given, the statistics are cleared atomically. +.\"---------------------------------------- +.It Xo +.Nm Ic diag Cm vcc +.Op Fl abr +.Op Fl channel +.Op Fl traffic +.Op Ar device +.Xc +Retrieve the list of currently active channels on either all +or the specified interfaces. +For each channel, the following information is printed depending +on the options (default is +.Fl channel ) . +.Bl -tag -width ".Fl traffic" +.It Fl abr +Print ABR specific traffic parameters: ICR, TBE, NRM, TRM, ADTF, RIF, RDF, +CDF. +.It Fl channel +Print basic information: VPI, VCI, AAL, traffic type, MTU and flags. +.It Fl traffic +Print traffic parameters: PCR, SCR, MBS, MCR. +.El +.\"---------------------------------------- +.It Nm Ic diag Cm stats Ar device +Print driver specific statistics. +.El +.Ss The Ic natm Command +The +.Ic natm +command is used to change +.Xr natmip 4 +routes on the local host. +The sub-commands for the routing table are: +.Cm add +(to add a new route), +.Cm delete +(to delete an existing route) and +.Cm show +(to print the currently installed NATM routes). +.Pp +.Bl -tag -width indent -compact +.\"---------------------------------------- +.It Xo +.Nm Ic natm Cm add +.Ar dest +.Ar device +.Ar vpi +.Ar vci +.Ar encaps +.Xc +.It Xo +.Nm Ic natm Cm add +.Ar dest +.Ar device +.Ar vpi +.Ar vci +.Ar encaps +.Cm ubr Op Ar pcr +.Xc +.It Xo +.Nm Ic natm Cm add +.Ar dest +.Ar device +.Ar vpi +.Ar vci +.Ar encaps +.Cm cbr Ar pcr +.Xc +.It Xo +.Nm Ic natm Cm add +.Ar dest +.Ar device +.Ar vpi +.Ar vci +.Ar encaps +.Cm vbr Ar pcr scr mbs +.Xc +.It Xo +.Nm Ic natm Cm add +.Ar dest +.Ar device +.Ar vpi +.Ar vci +.Ar encaps +.Cm abr Ar pcr mcr icr tbe nrm trm adtf rif rdf cdf +.Xc +Add a new route to the routing table. +The destination address (the address +on the other end of the link) is given in +.Ar dest . +The +.Ar device , +.Ar vpi +and +.Ar vci +arguments +are the name of the ATM device and the VPI and VCI values for the link. +The +.Ar encaps +argument +may be either +.Cm AAL5 +or +.Cm LLC/SNAP +both of which specify AAL5 encapsulation, the first one without additional +encapsulation, the second one with LLC/SNAP headers. +The first two forms of the command add an UBR (unspecified bit rate) channel, +where the second form allows the optional specification of a peak cell +rate (PCR). +The third form adds a CBR (constant bit rate) channel where a PCR +must be given. +The fourth form adds a VBR (variable bit rate) channel. +The arguments are the peak cell rate, the sustainable cell rate and the +maximum bursts size. +The last form of the command adds an ABR (available bit rate) channel. +.\"---------------------------------------- +.Pp +.It Nm Ic natm Cm delete Ar dest +.It Xo +.Nm Ic natm Cm delete +.Ar device +.Ar vpi +.Ar vci +.Xc +This commands deletes an NATM route. +The route may be specified either by the destination address or +by the +.Ar device , vpi +and +.Ar vci +triple. +.\"---------------------------------------- +.Pp +.It Nm Ic natm Cm show +List all NATM routes. +.El +.Sh SEE ALSO +.Xr natm 4 , +.Xr natmip 4 +.Sh HISTORY +An +.Nm +command appeared in +.Fx 3.0 . +.Sh AUTHORS +.An Hartmut Brandt Aq Mt harti@FreeBSD.org diff --git a/sbin/atm/atmconfig/atmconfig.h b/sbin/atm/atmconfig/atmconfig.h new file mode 100644 index 000000000000..5e5b04172cb0 --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $FreeBSD$ + */ +#ifndef _ATMCONFIG_H +#define _ATMCONFIG_H + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <netgraph/ng_message.h> + +#define DEFAULT_INTERFACE "hatm0" + +struct cmdtab { + const char *string; + const struct cmdtab *sub; + void (*func)(int, char *[]); +}; + +/* + * client configuration info + */ +struct amodule { + const struct cmdtab *cmd; +}; + +#define DEF_MODULE(CMDTAB) \ +struct amodule amodule_1 = { CMDTAB } + +/* for compiled-in modules */ +void register_module(const struct amodule *); + +/* print a message if we are verbose */ +void verb(const char *, ...) __printflike(1, 2); + +/* print heading */ +void heading(const char *, ...) __printflike(1, 2); + +/* before starting output */ +void heading_init(void); + +/* stringify an enumerated value */ +struct penum { + int32_t value; + const char *str; +}; +const char *penum(int32_t value, const struct penum *strtab, char *buf); +int pparse(int32_t *, const struct penum *, const char *); + +enum { + OPT_NONE, + OPT_UINT, + OPT_INT, + OPT_UINT32, + OPT_INT32, + OPT_UINT64, + OPT_INT64, + OPT_FLAG, + OPT_VCI, + OPT_STRING, + OPT_SIMPLE, +}; +struct option { + const char *optstr; + int opttype; + void *optarg; +}; + +int parse_options(int *_pargc, char ***_pargv, + const struct option *_opts); + +/* XXX while this is compiled in */ +void device_register(void); + +#endif /* _ATMCONFIG_H */ diff --git a/sbin/atm/atmconfig/atmconfig.help b/sbin/atm/atmconfig/atmconfig.help new file mode 100644 index 000000000000..8c6e7cec7f2f --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig.help @@ -0,0 +1,223 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# Copyright (c) 2004 +# Hartmut Brandt. +# All rights reserved. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Help file for the atmconfig utility +# +# $FreeBSD$ +# +^0 intro +ATM configuration utility. +usage: + atmconfig [common-options] command [subcommand] [options] + +Use 'atmconfig help' for general help or 'atmconfig help <command>' for +help on 'command' or 'atmconfig help commands' for a list of commands. + +^0 help +^^ help show help information +Use one of the following commands to get help on atmconfig: + + atmconfig help options + gives you help on common command line options + atmconfig help commands + prints a list of available commands (and help items) + atmconfig help <command> + prints help on the given command (including a list of subcommands) + atmconfig help <command> <subcommand> + gives help on the given subcommand + +^0 options +^^ help options list common options +Common command line options can be specified for all commands. They +are written immediately before the command. The following options are +available: + + -h print short help + -t don't print headings for 'show'-type commands + -v be verbose about all actions. + +^0 commands +^^ help commands show available commands +The following commands are available: + +$MAIN + +^0 diag +^^ diag show/modify ATM hardware interfaces +This command shows information about the ATM hardware interfaces in the +system. A list of ATM devices is obtained by: + + atmconfig [common-options] diag list + +Information about the hardware configuration of the ATM interfaces is +reported by: + + atmconfig [common-options] diag config [options] [<device> ...] + +The phy chip can be access with: + + atmconfig [common-options] diag phy print [options] <device> + atmconfig [common-options] diag phy show <device> + atmconfig [common-options] diag phy set <device> <reg> <msk> <val> + atmconfig [common-options] diag phy set stats [options] <device> + +A list of open VCCs can be obtained with: + + atmconfig [common-options] diag vcc [<device> ...] + +Driver internal statistics are printed with + + atmconfig [common-options] diag stats <device> + +^1 list +usage: atmconfig [common-options] diag list + +List all known ATM devices in the system. + +^1 config +usage: atmconfig [common-options] diag config [-hardware] [-atm] [device ...] +options: + -hardware print hardware related information + -atm print ATM related information + +If now device is given as argument information about all devices is shown. +The default is to print only ATM related information. + +^1 phy +To show the type of the PHY and its state: + + atmconfig [common-options] diag phy show <device> + +Change a PHY register (use with care): + + atmconfig [common-options] diag phy set <device> <reg> <msk> <val> + +Print the PHY registers in a human readable form: + + atmconfig [common-options] diag phy print [-numeric] <device> + +The PHY statistics can be printed with: + + atmconfig [common-options] diag phy stats [-clear] <device> + +^2 show +usage: atmconfig [common-options] diag phy show <device> + +Show configuration and state information about the PHY chip on the given +ATM interface. + +^2 set +usage: atmconfig [common-options] diag phy set <device> <reg> <msk> <val> + +Set the bits of given PHY chip register for which the corresponding bit in +<msk> is one to the value of the corresponding bit in <val>. All register +bits that have a zero in <msk> are written back with there original value. + +^2 print +usage: atmconfig [common-options] diag phy print [-numeric] <device> +options: + -numeric print registers in hex + +Print the registers of the PHY chip in a human readable format. + +^2 stats +usage: atmconfig [common-options] diag phy stats [-clear] <device> +options: + -clear clear the statistics atomically after reading them + +Prints the PHY layer statistics of the PHY chip and optionally clears them. + +^1 vcc +usage: atmconfig [common-options] diag vcc [-abr] [-channel] [-traffic] + [<device> ...] +options: + -abr print ABR specific traffic parameters + -channel print VPI, VCI, AAL, traffic type and flags (default) + -traffic print traffic parameters + +Prints a list of all open vccs. The default output is -channel. + +^1 stats +usage: atmconfig [common-options] diag stats <device> + +Prints the driver-internal statistics. + +^0 natm +^^ natm simple IP over ATM management (see natmip(4)) +The group of CLIP commands is used to manage classical IP over ATM +networking via NATM (see natm(4) and natmip(4)). A new PVC is added +to a CLIP via: + + atmconfig [common-options] natm add <dest> <device> <vpi> <vci> + <encaps> [<traffic> [<params> ...]] + +The PVC can be deleted with: + + atmconfig [common-options] natm del <device> <vpi> <vci> + +The list of PVC that are currently active is retrieved with: + + atmconfig [common-options] natm show + +^1 add +usage: atmconfig [common-options] natm add [-printonly] <dest> <device> + <vpi> <vci> <encaps> [<traffic> [<params> ...]] +options: + -printonly don't execute, print the route(8) command + +This subcommand adds a new CLIP PVC on the ATM interface <device>. The +host on the other end of the PVC has IP address <addr>. <encaps> is one +of llc/snap (LLC/SNAP encapsulated frames in AAL5) or aal5 (AAL5 frames +without LLC/SNAP). <traffic> specifies the traffic type of the PVC +and is one of UBR, CBR, VBR or ABR. If not given UBR is assumed. Depending +on the traffic type none or more parameters can follow: + + ubr [<pcr>] + cbr <pcr> + vbr <pcr> <scr> <mbs> + abr <pcr> <mcr> <icr> <tbe> <nrm> <trm> <adtf> <rif> <rdf> <cdf> + +^1 delete +usage: atmconfig [common-options] natm delete [-printonly] <dest> + or: atmconfig [common-options] natm delete [-printonly] <device> <vpi> <vci> +options: + -printonly don't execute, print the route(8) command + +This subcommand deletes and existing CLIP PVC that can bei either identified +by the destination address or by the <device><vpi><vci> triple. + +^1 show +usage: atmconfig [common-options] natm show [-abr] [-numeric] +options: + -abr show ABR parameters for ABR connections + -numeric print IP addresses numerically + +This subcommand prints all ATM routes. diff --git a/sbin/atm/atmconfig/atmconfig_device.c b/sbin/atm/atmconfig/atmconfig_device.c new file mode 100644 index 000000000000..f2f08380dcdf --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig_device.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2003-2004 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "atmconfig.h" +#include "atmconfig_device.h" +#include "private.h" +#include "oid.h" + +#include <bsnmp/asn1.h> +#include <bsnmp/snmp.h> +#include <bsnmp/snmpclient.h> + +/* + * Description of the begemotAtmIfTable + */ +static const struct snmp_table atmif_table = { + OIDX_begemotAtmIfTable, + OIDX_begemotAtmIfTableLastChange, 2, + sizeof(struct atmif), + 1, 0x7ffULL, + { + { 0, + SNMP_SYNTAX_INTEGER, offsetof(struct atmif, index) }, + { OID_begemotAtmIfName, + SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, ifname) }, + { OID_begemotAtmIfPcr, + SNMP_SYNTAX_GAUGE, offsetof(struct atmif, pcr) }, + { OID_begemotAtmIfMedia, + SNMP_SYNTAX_INTEGER, offsetof(struct atmif, media) }, + { OID_begemotAtmIfVpiBits, + SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vpi_bits) }, + { OID_begemotAtmIfVciBits, + SNMP_SYNTAX_GAUGE, offsetof(struct atmif, vci_bits) }, + { OID_begemotAtmIfMaxVpcs, + SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vpcs) }, + { OID_begemotAtmIfMaxVccs, + SNMP_SYNTAX_GAUGE, offsetof(struct atmif, max_vccs) }, + { OID_begemotAtmIfEsi, + SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmif, esi) }, + { OID_begemotAtmIfCarrierStatus, + SNMP_SYNTAX_INTEGER, offsetof(struct atmif, carrier) }, + { OID_begemotAtmIfMode, + SNMP_SYNTAX_INTEGER, offsetof(struct atmif, mode) }, + { 0, SNMP_SYNTAX_NULL, 0 } + } +}; + +/* List of all ATM interfaces */ +struct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list); + +/* + * ATM hardware table + */ +struct atmhw { + TAILQ_ENTRY(atmhw) link; + uint64_t found; + int32_t index; + u_char *vendor; + size_t vendorlen; + u_char *device; + size_t devicelen; + uint32_t serial; + uint32_t version; + uint32_t soft_version; +}; +TAILQ_HEAD(atmhw_list, atmhw); + +/* list of ATM hardware */ +static struct atmhw_list atmhw_list; + +/* + * Read ATM hardware table + */ +static const struct snmp_table atmhw_table = { + OIDX_begemotAtmHWTable, + OIDX_begemotAtmIfTableLastChange, 2, + sizeof(struct atmhw), + 1, 0x3fULL, + { + { 0, + SNMP_SYNTAX_INTEGER, offsetof(struct atmhw, index) }, + { OID_begemotAtmHWVendor, + SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, vendor) }, + { OID_begemotAtmHWDevice, + SNMP_SYNTAX_OCTETSTRING, offsetof(struct atmhw, device) }, + { OID_begemotAtmHWSerial, + SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, serial) }, + { OID_begemotAtmHWVersion, + SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, version) }, + { OID_begemotAtmHWSoftVersion, + SNMP_SYNTAX_GAUGE, offsetof(struct atmhw, soft_version) }, + { 0, SNMP_SYNTAX_NULL, 0 } + } +}; + +static void device_status(int, char *[]); +static void device_hardware(int, char *[]); +static void device_modify(int, char *[]); + +static const struct cmdtab device_tab[] = { + { "hardware", NULL, device_hardware }, + { "status", NULL, device_status }, + { "modify", NULL, device_modify }, + { NULL, NULL, NULL } +}; + +static const struct cmdtab entry = + { "device", device_tab, NULL }; + +static DEF_MODULE(&entry); + +/* + * Carrier state to string + */ +static const struct penum strcarrier[] = { + { 1, "on" }, + { 2, "off" }, + { 3, "unknown" }, + { 4, "none" }, + { 0, NULL } +}; +/* + * SUNI mode to string + */ +static const struct penum strsunimode[] = { + { 1, "sonet" }, + { 2, "sdh" }, + { 3, "unknown" }, + { 0, NULL } +}; + +/* + * OIDs + */ +static const struct asn_oid + oid_begemotAtmIfMode = OIDX_begemotAtmIfMode; + +/* + * Print 1st status line + */ +static void +dev_status1(const struct atmif *aif) +{ + char buf[100]; + + printf("%-5u %-8s %-6u %-4u %-5u %-4u %-5u " + "%02x:%02x:%02x:%02x:%02x:%02x %s\n", aif->index, + aif->ifname, aif->pcr, + (1 << aif->vpi_bits) - 1, (1 << aif->vci_bits) - 1, + aif->max_vpcs, aif->max_vccs, aif->esi[0], + aif->esi[1], aif->esi[2], aif->esi[3], aif->esi[4], aif->esi[5], + penum(aif->carrier, strcarrier, buf)); +} + +/* + * Print 2nd status line + */ +static void +dev_status2(const struct atmif *aif) +{ + char buf[100]; + + printf("%-5u %-8s %s\n", aif->index, aif->ifname, + penum(aif->mode, strsunimode, buf)); +} + +/* + * Implement the 'device status' command + */ +static void +device_status(int argc, char *argv[]) +{ + int opt, i; + struct atmif *aif; + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + const char dev1[] = + "Interface Max Max\n" + "Index Name PCR VPI VCI VPCs VCCs ESI Carrier\n"; + const char dev2[] = + "Interface\n" + "Index Name Mode\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + snmp_open(NULL, NULL, NULL, NULL); + atexit(snmp_close); + + atmif_fetchtable(); + + if (TAILQ_EMPTY(&atmif_list)) + errx(1, "no ATM interfaces found"); + + if (argc > 0) { + heading_init(); + for (i = 0; i < argc; i++) { + if ((aif = atmif_find_name(argv[i])) == NULL) { + warnx("%s: no such ATM interface", argv[i]); + continue; + } + heading(dev1); + dev_status1(aif); + } + heading_init(); + for (i = 0; i < argc; i++) { + if ((aif = atmif_find_name(argv[i])) == NULL) + continue; + heading(dev2); + dev_status2(aif); + } + } else { + heading_init(); + TAILQ_FOREACH(aif, &atmif_list, link) { + heading(dev1); + dev_status1(aif); + } + heading_init(); + TAILQ_FOREACH(aif, &atmif_list, link) { + heading(dev2); + dev_status2(aif); + } + } +} + +/* + * Print hardware info line + */ +static void +dev_hardware(const struct atmif *aif) +{ + const struct atmhw *hw; + + TAILQ_FOREACH(hw, &atmhw_list, link) + if (aif->index == hw->index) + break; + if (hw == NULL) { + warnx("hardware info not found for '%s'", aif->ifname); + return; + } + + printf("%-5u %-8s %-16s%-10s %-10u %-10u %u\n", aif->index, + aif->ifname, hw->vendor, hw->device, hw->serial, + hw->version, hw->soft_version); +} + +/* + * Show hardware configuration + */ +static void +device_hardware(int argc, char *argv[]) +{ + int opt, i; + struct atmif *aif; + + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + static const char headline[] = + "Interface \n" + "Index Name Vendor Card Serial HW SW\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + snmp_open(NULL, NULL, NULL, NULL); + atexit(snmp_close); + + atmif_fetchtable(); + + if (snmp_table_fetch(&atmhw_table, &atmhw_list) != 0) + errx(1, "AtmHW table: %s", snmp_client.error); + + if (argc > 0) { + heading_init(); + for (i = 0; i < argc; i++) { + if ((aif = atmif_find_name(argv[i])) == NULL) { + warnx("interface not found '%s'", argv[i]); + continue; + } + heading(headline); + dev_hardware(aif); + } + } else { + heading_init(); + TAILQ_FOREACH(aif, &atmif_list, link) { + heading(headline); + dev_hardware(aif); + } + } +} + +/* + * Change device parameters + */ +static void +device_modify(int argc, char *argv[]) +{ + int opt; + struct atmif *aif; + int mode = 0; + int n; + struct snmp_pdu pdu, resp; + + static const struct option opts[] = { +#define MODIFY_MODE 0 + { "mode", OPT_STRING, NULL }, + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + + case MODIFY_MODE: + if (pparse(&mode, strsunimode, optarg) == -1 || + mode == 3) + errx(1, "illegal mode for -m '%s'", optarg); + break; + } + + if (argc != 1) + errx(1, "device modify needs one argument"); + + snmp_open(NULL, NULL, NULL, NULL); + + atexit(snmp_close); + atmif_fetchtable(); + + if ((aif = atmif_find_name(argv[0])) == NULL) + errx(1, "%s: no such ATM interface", argv[0]); + + snmp_pdu_create(&pdu, SNMP_PDU_SET); + if (mode != 0) { + n = snmp_add_binding(&pdu, + &oid_begemotAtmIfMode, SNMP_SYNTAX_INTEGER, + NULL); + snmp_oid_append(&pdu.bindings[n + 0].var, "i", + (asn_subid_t)aif->index); + pdu.bindings[n + 0].v.integer = mode; + } + + if (pdu.nbindings == 0) + errx(1, "must specify something to modify"); + + if (snmp_dialog(&pdu, &resp)) + errx(1, "No response from '%s': %s", snmp_client.chost, + snmp_client.error); + + if (snmp_pdu_check(&pdu, &resp) <= 0) + errx(1, "Error modifying device"); + + snmp_pdu_free(&resp); + snmp_pdu_free(&pdu); +} + +/* XXX while this is compiled in */ +void +device_register(void) +{ + register_module(&amodule_1); +} + +/* + * Fetch the ATM interface table + */ +void +atmif_fetchtable(void) +{ + struct atmif *aif; + + while ((aif = TAILQ_FIRST(&atmif_list)) != NULL) { + free(aif->ifname); + free(aif->esi); + TAILQ_REMOVE(&atmif_list, aif, link); + free(aif); + } + + if (snmp_table_fetch(&atmif_table, &atmif_list) != 0) + errx(1, "AtmIf table: %s", snmp_client.error); +} + +/* + * Find a named ATM interface + */ +struct atmif * +atmif_find_name(const char *ifname) +{ + struct atmif *atmif; + + TAILQ_FOREACH(atmif, &atmif_list, link) + if (strcmp(atmif->ifname, ifname) == 0) + return (atmif); + return (NULL); +} +/* + * find an ATM interface by index + */ +struct atmif * +atmif_find(u_int idx) +{ + struct atmif *atmif; + + TAILQ_FOREACH(atmif, &atmif_list, link) + if (atmif->index == (int32_t)idx) + return (atmif); + return (NULL); +} diff --git a/sbin/atm/atmconfig/atmconfig_device.h b/sbin/atm/atmconfig/atmconfig_device.h new file mode 100644 index 000000000000..1c099fcdc79a --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig_device.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2003-2004 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef ATMCONFIG_DEVICE_H_ +#define ATMCONFIG_DEVICE_H_ + +#include <sys/types.h> +#include <sys/queue.h> +#include <stdint.h> + +/* + * ATM interface table + */ +struct atmif { + TAILQ_ENTRY(atmif) link; + uint64_t found; + int32_t index; + char *ifname; + size_t ifnamelen; + uint32_t pcr; + int32_t media; + uint32_t vpi_bits; + uint32_t vci_bits; + uint32_t max_vpcs; + uint32_t max_vccs; + u_char *esi; + size_t esilen; + int32_t carrier; + int32_t mode; +}; +TAILQ_HEAD(atmif_list, atmif); + +/* list of all ATM interfaces */ +extern struct atmif_list atmif_list; + +/* fetch this table */ +void atmif_fetchtable(void); + +/* find an ATM interface by name */ +struct atmif *atmif_find_name(const char *); + +/* find an ATM interface by index */ +struct atmif *atmif_find(u_int); + +#endif diff --git a/sbin/atm/atmconfig/atmconfig_device.help b/sbin/atm/atmconfig/atmconfig_device.help new file mode 100644 index 000000000000..27237c8cb7b9 --- /dev/null +++ b/sbin/atm/atmconfig/atmconfig_device.help @@ -0,0 +1,62 @@ +# Copyright (c) 2003-2004 +# Hartmut Brandt. +# All rights reserved. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Help file for the atmconfig utility +# +# $FreeBSD$ +# +^0 device +^^ device show information about ATM hardware interfaces +This command shows information about the ATM hardware interfaces on the +system. Status information can be obtained by: + + atmconfig [common-options] device status [options] [device ...] + +Information about the hardware of the ATM interfaces is reported by: + + atmconfig [common-options] device hardware [options] [device ...] + +The parameters of the a device can be changed by: + + atmconfig [common-options] device modify [options] <device> + +^1 status +usage: atmconfig [common-options] device status [device ...] + +If no device is given as argument information about all devices is shown. + +^1 hardware +usage: atmconfig [common-options] device hardware [device ...] + +If now device is given as argument information about all devices is shown. + +^1 modify +usage: atmconfig [common-options] device modify [-mode mode] <device> + +options: + -mode switch the SUNI mode to either 'sonet' or 'sdh'. + diff --git a/sbin/atm/atmconfig/diag.c b/sbin/atm/atmconfig/diag.c new file mode 100644 index 000000000000..3225e107e2b6 --- /dev/null +++ b/sbin/atm/atmconfig/diag.c @@ -0,0 +1,1122 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <net/if.h> +#include <net/if_mib.h> +#include <net/if_types.h> +#include <net/if_atm.h> +#include <net/if_media.h> +#include <netnatm/natm.h> +#include <dev/utopia/utopia.h> +#include <dev/utopia/suni.h> +#include <dev/utopia/idtphy.h> + +#include "atmconfig.h" +#include "private.h" +#include "diag.h" + +static void diag_list(int, char *[]); +static void diag_config(int, char *[]); +static void diag_vcc(int, char *[]); +static void diag_phy_show(int, char *[]); +static void diag_phy_set(int, char *[]); +static void diag_phy_print(int, char *[]); +static void diag_phy_stats(int, char *[]); +static void diag_stats(int, char *[]); + +static const struct cmdtab diag_phy_tab[] = { + { "show", NULL, diag_phy_show }, + { "set", NULL, diag_phy_set }, + { "stats", NULL, diag_phy_stats }, + { "print", NULL, diag_phy_print }, + { NULL, NULL, NULL }, +}; + +const struct cmdtab diag_tab[] = { + { "list", NULL, diag_list }, + { "config", NULL, diag_config }, + { "phy", diag_phy_tab, NULL }, + { "stats", NULL, diag_stats }, + { "vcc", NULL, diag_vcc }, + { NULL, NULL, NULL } +}; + +static const struct utopia_print suni_lite[] = { SUNI_PRINT_LITE }; +static const struct utopia_print suni_ultra[] = { SUNI_PRINT_ULTRA }; +static const struct utopia_print suni_622[] = { SUNI_PRINT_622 }; +static const struct utopia_print idt77105[] = { IDTPHY_PRINT_77105 }; +static const struct utopia_print idt77155[] = { IDTPHY_PRINT_77155 }; + +static const struct { + const struct utopia_print *tab; + u_int len; + u_int type; +} phy_print[] = { + { suni_lite, sizeof(suni_lite) / sizeof(suni_lite[0]), + UTP_TYPE_SUNI_LITE }, + { suni_ultra, sizeof(suni_ultra) / sizeof(suni_ultra[0]), + UTP_TYPE_SUNI_ULTRA }, + { suni_622, sizeof(suni_622) / sizeof(suni_622[0]), + UTP_TYPE_SUNI_622 }, + { idt77105, sizeof(idt77105) / sizeof(idt77105[0]), + UTP_TYPE_IDT77105 }, + { idt77155, sizeof(idt77155) / sizeof(idt77155[0]), + UTP_TYPE_IDT77155 }, +}; + +static const u_int utopia_addreg[] = { UTP_REG_ADD }; + +/* + * Driver statistics printing + */ +static const char *const print_stats_pca200e[] = { + "cmd_queue_full:", + "get_stat_errors:", + "clr_stat_errors:", + "get_prom_errors:", + "suni_reg_errors:", + "tx_queue_full:", + "tx_queue_almost_full:", + "tx_pdu2big:", + "tx_too_many_segs:", + "tx_retry:", + "fix_empty:", + "fix_addr_copy:", + "fix_addr_noext:", + "fix_addr_ext:", + "fix_len_noext:", + "fix_len_copy:", + "fix_len:", + "rx_badvc:", + "rx_closed:", + NULL +}; +static const char *const print_stats_he[] = { + "tdprq_full:", + "hbuf_error:", + "crc_error:", + "len_error:", + "flow_closed:", + "flow_drop:", + "tpd_no_mem:", + "rx_seg:", + "empty_hbuf:", + "short_aal5:", + "badlen_aal5:", + "bug_bad_isw:", + "bug_no_irq_upd:", + "itype_tbrq:", + "itype_tpd:", + "itype_rbps:", + "itype_rbpl:", + "itype_rbrq:", + "itype_rbrqt:", + "itype_unknown:", + "itype_phys:", + "itype_err:", + "defrag:", + "mcc:", + "oec:", + "dcc:", + "cec:", + "no_rcv_mbuf:", + NULL +}; +static const char *const print_stats_eni[] = { + "ttrash:", + "mfixaddr:", + "mfixlen:", + "mfixfail:", + "txmbovr:", + "dmaovr:", + "txoutspace:", + "txdtqout:", + "launch:", + "hwpull:", + "swadd:", + "rxqnotus:", + "rxqus:", + "rxdrqout:", + "rxmbufout:", + "txnomap:", + "vtrash:", + "otrash:", + NULL +}; + +static const char *const print_stats_idt77211[] = { + "need_copy:", + "copy_failed:", + "out_of_tbds:", + "no_txmaps:", + "tx_load_err:", + "tx_qfull:", + NULL +}; +static const char *const print_stats_idt77252[] = { + "raw_cells:", + "raw_no_vcc:", + "raw_no_buf:", + "tx_qfull:", + "tx_out_of_tbds:", + "tx_out_of_maps:", + "tx_load_err:", + NULL +}; +static const char *const print_stats_virtual[] = { + "dummy:", + NULL +}; +static const char *const *const print_stats[] = { + [ATM_DEVICE_UNKNOWN] = NULL, + [ATM_DEVICE_PCA200E] = print_stats_pca200e, + [ATM_DEVICE_HE155] = print_stats_he, + [ATM_DEVICE_HE622] = print_stats_he, + [ATM_DEVICE_ENI155P] = print_stats_eni, + [ATM_DEVICE_ADP155P] = print_stats_eni, + [ATM_DEVICE_FORELE25] = print_stats_idt77211, + [ATM_DEVICE_FORELE155] = print_stats_idt77211, + [ATM_DEVICE_NICSTAR25] = print_stats_idt77211, + [ATM_DEVICE_NICSTAR155] = print_stats_idt77211, + [ATM_DEVICE_IDTABR25] = print_stats_idt77252, + [ATM_DEVICE_IDTABR155] = print_stats_idt77252, + [ATM_DEVICE_PROATM25] = print_stats_idt77252, + [ATM_DEVICE_PROATM155] = print_stats_idt77252, + [ATM_DEVICE_VIRTUAL] = print_stats_virtual, +}; + +struct diagif_list diagif_list = TAILQ_HEAD_INITIALIZER(diagif_list); + +/* + * Fetch a phy sysctl + */ +static int +phy_fetch(const char *ifname, const char *var, void *val, size_t len, + int err_fatal) +{ + char *str; + + if (asprintf(&str, "hw.atm.%s.phy_%s", ifname, var) == -1) + err(1, NULL); + if (sysctlbyname(str, val, &len, NULL, 0) == -1) { + if (err_fatal || errno != ENOENT) + err(1, "%s", str); + free(str); + return (-1); + } + free(str); + return (0); +} + +/* + * Fetch the list of all ATM network interfaces and their MIBs. + */ +void +diagif_fetch(void) +{ + size_t len; + int count; + int name[6]; + struct ifmibdata mib; + struct ifatm_mib atm; + int idx; + struct diagif *d; + + while ((d = TAILQ_FIRST(&diagif_list)) != NULL) { + if (d->vtab != NULL) + free(d->vtab); + TAILQ_REMOVE(&diagif_list, d, link); + free(d); + } + + len = sizeof(count); + if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, + NULL, 0) == -1) + err(1, "ifcount"); + + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + + for (idx = 1; idx <= count; idx++) { + name[4] = idx; + name[5] = IFDATA_GENERAL; + len = sizeof(mib); + if (sysctl(name, 6, &mib, &len, NULL, 0) == -1) + err(1, "interface %d: general mib", idx); + if (mib.ifmd_data.ifi_type == IFT_ATM) { + name[5] = IFDATA_LINKSPECIFIC; + len = sizeof(atm); + if (sysctl(name, 6, &atm, &len, NULL, 0) == -1) + err(1, "interface %d: ATM mib", idx); + + d = malloc(sizeof(*d)); + if (d == NULL) + err(1, NULL); + bzero(d, sizeof(*d)); + d->mib = atm; + d->index = idx; + strcpy(d->ifname, mib.ifmd_name); + TAILQ_INSERT_TAIL(&diagif_list, d, link); + + if (phy_fetch(d->ifname, "type", &d->phy_type, + sizeof(d->phy_type), 0) == 0) { + d->phy_present = 1; + phy_fetch(d->ifname, "loopback", + &d->phy_loopback, + sizeof(d->phy_loopback), 1); + phy_fetch(d->ifname, "name", &d->phy_name, + sizeof(d->phy_name), 1); + phy_fetch(d->ifname, "state", &d->phy_state, + sizeof(d->phy_state), 1); + phy_fetch(d->ifname, "carrier", &d->phy_carrier, + sizeof(d->phy_carrier), 1); + } + } + } +} + +/* + * "<radix><bit>STRING\011<mask><pattern>STRING\012<mask><radix>STRING" + */ +static char * +printb8(uint32_t val, const char *descr) +{ + static char buffer[1000]; + char *ptr; + int tmp = 0; + u_char mask, pattern; + + if (*descr++ == '\010') + sprintf(buffer, "%#o", val); + else + sprintf(buffer, "%#x", val); + ptr = buffer + strlen(buffer); + + *ptr++ = '<'; + while (*descr) { + if (*descr == '\11') { + descr++; + mask = *descr++; + pattern = *descr++; + if ((val & mask) == pattern) { + if (tmp++) + *ptr++ = ','; + while (*descr >= ' ') + *ptr++ = *descr++; + } else { + while (*descr >= ' ') + descr++; + } + } else if (*descr == '\12') { + descr++; + mask = *descr++; + pattern = *descr++; + if (tmp++) + *ptr++ = ','; + while (*descr >= ' ') + *ptr++ = *descr++; + *ptr++ = '='; + if (pattern == 8) + sprintf(ptr, "%#o", + (val & mask) >> (ffs(mask)-1)); + else if (pattern == 10) + sprintf(ptr, "%u", + (val & mask) >> (ffs(mask)-1)); + else + sprintf(ptr, "%#x", + (val & mask) >> (ffs(mask)-1)); + ptr += strlen(ptr); + } else { + if (val & (1 << (*descr++ - 1))) { + if (tmp++) + *ptr++ = ','; + while (*descr >= ' ') + *ptr++ = *descr++; + } else { + while (*descr >= ' ') + descr++; + } + } + } + *ptr++ = '>'; + *ptr++ = '\0'; + + return (buffer); +} + +/* + * "<radix><bit>STRING<bit>STRING" + */ +static char * +printb(uint32_t val, const char *descr) +{ + static char buffer[1000]; + char *ptr; + int tmp = 0; + + if (*descr++ == '\010') + sprintf(buffer, "%#o", val); + else + sprintf(buffer, "%#x", val); + ptr = buffer + strlen(buffer); + + *ptr++ = '<'; + while (*descr) { + if (val & (1 << (*descr++ - 1))) { + if (tmp++) + *ptr++ = ','; + while (*descr > ' ') + *ptr++ = *descr++; + } else { + while (*descr > ' ') + descr++; + } + } + *ptr++ = '>'; + *ptr++ = '\0'; + + return (buffer); +} + + +static void +diag_loop(int argc, char *argv[], const char *text, + void (*func)(const struct diagif *)) +{ + int i; + struct diagif *aif; + + heading_init(); + if (argc > 0) { + for (i = 0; i < argc; i++) { + TAILQ_FOREACH(aif, &diagif_list, link) { + if (strcmp(argv[i], aif->ifname) == 0) { + heading("%s", text); + (*func)(aif); + break; + } + } + if (aif == NULL) + warnx("%s: no such ATM interface", argv[i]); + } + } else { + TAILQ_FOREACH(aif, &diagif_list, link) { + heading("%s", text); + (*func)(aif); + } + } +} + +/* + * Print the config line for the given interface + */ +static void +config_line1(const struct diagif *aif) +{ + printf("%-6u%-9s%-8u%-5u%-6u%-5u%-6u%02x:%02x:%02x:%02x:%02x:%02x\n", + aif->index, aif->ifname, aif->mib.pcr, (1 << aif->mib.vpi_bits) - 1, + (1 << aif->mib.vci_bits) - 1, aif->mib.max_vpcs, aif->mib.max_vccs, + aif->mib.esi[0], aif->mib.esi[1], aif->mib.esi[2], + aif->mib.esi[3], aif->mib.esi[4], aif->mib.esi[5]); +} + +static void +config_line2(const struct diagif *aif) +{ + u_int d, i; + + static const struct { + const char *dev; + const char *vendor; + } devs[] = { + ATM_DEVICE_NAMES + }; + static const struct { + u_int media; + const char *const name; + } medias[] = IFM_SUBTYPE_ATM_DESCRIPTIONS; + + for (i = 0; medias[i].name; i++) + if (aif->mib.media == medias[i].media) + break; + + if ((d = aif->mib.device) >= sizeof(devs) / sizeof(devs[0])) + d = 0; + + printf("%-6u%-9s%-12.11s%-13.12s%-8u%-6x%-6x %s\n", aif->index, + aif->ifname, devs[d].vendor, devs[d].dev, aif->mib.serial, + aif->mib.hw_version, aif->mib.sw_version, + medias[i].name ? medias[i].name : "unknown"); +} + +static void +diag_config(int argc, char *argv[]) +{ + int opt; + + static int hardware; + static int atm; + + static const struct option opts[] = { + { "hardware", OPT_SIMPLE, &hardware }, + { "atm", OPT_SIMPLE, &atm }, + { NULL, 0, NULL } + }; + + static const char config_text1[] = + "Interface Max Max\n" + "Index Name PCR VPI VCI VPCs VCCs ESI\n"; + static const char config_text2[] = + "Interface Version\n" + "Index Name Vendor Card " + "Serial HW SW Media\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + diagif_fetch(); + if (TAILQ_EMPTY(&diagif_list)) + errx(1, "no ATM interfaces found"); + + if (!atm && !hardware) + atm = 1; + + if (atm) + diag_loop(argc, argv, config_text1, config_line1); + if (hardware) + diag_loop(argc, argv, config_text2, config_line2); + +} + +static void +diag_list(int argc, char *argv[]) +{ + int opt; + struct diagif *aif; + + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc > 0) + errx(1, "no arguments required for 'diag list'"); + + diagif_fetch(); + if (TAILQ_EMPTY(&diagif_list)) + errx(1, "no ATM interfaces found"); + + TAILQ_FOREACH(aif, &diagif_list, link) + printf("%s ", aif->ifname); + printf("\n"); +} + +/* + * Print the config line for the given interface + */ +static void +phy_show_line(const struct diagif *aif) +{ + printf("%-6u%-9s", aif->index, aif->ifname); + if (aif->phy_present) + printf("%-5u%-25s0x%-9x", aif->phy_type, + aif->phy_name, aif->phy_loopback); + printf("\n"); +} + +static void +diag_phy_show(int argc, char *argv[]) +{ + int opt; + + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + static const char phy_show_text[] = + "Interface Phy\n" + "Index Name Type Name Loopback State\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + diagif_fetch(); + if (TAILQ_EMPTY(&diagif_list)) + errx(1, "no ATM interfaces found"); + + diag_loop(argc, argv, phy_show_text, phy_show_line); +} + +/* + * Make sure the interface exists and has a phy + */ +static struct diagif * +diagif_get_phy(const char *arg) +{ + struct diagif *aif; + + diagif_fetch(); + TAILQ_FOREACH(aif, &diagif_list, link) + if (strcmp(aif->ifname, arg) == 0) + break; + if (aif == NULL) + errx(1, "no such interface: %s", arg); + if (!aif->phy_present) + errx(1, "interface %s has no phy", arg); + + return (aif); +} + +static void +diag_phy_set(int argc, char *argv[]) +{ + int opt; + uint8_t reg[3]; + u_long res; + char *end; + char *str; + + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc != 4) + errx(1, "missing arguments for 'diag phy set'"); + + errno = 0; + res = strtoul(argv[1], &end, 0); + if (errno != 0) + err(1, "register number"); + if (*end != '\0') + errx(1, "malformed register number '%s'", argv[1]); + if (res > 0xff) + errx(1, "register number too large"); + reg[0] = res; + + errno = 0; + res = strtoul(argv[2], &end, 0); + if (errno != 0) + err(1, "mask"); + if (*end != '\0') + errx(1, "malformed mask '%s'", argv[1]); + if (res > 0xff) + errx(1, "mask too large"); + reg[1] = res; + + errno = 0; + res = strtoul(argv[3], &end, 0); + if (errno != 0) + err(1, "value"); + if (*end != '\0') + errx(1, "malformed value '%s'", argv[1]); + if (res > 0xff) + errx(1, "value too large"); + reg[2] = res; + + (void)diagif_get_phy(argv[0]); + + if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1) + err(1, NULL); + + if (sysctlbyname(str, NULL, NULL, reg, 3 * sizeof(uint8_t))) + err(1, "%s", str); + + free(str); +} + +static void +diag_phy_print(int argc, char *argv[]) +{ + int opt; + char *str; + size_t len, len1; + uint8_t *regs; + u_int type, i; + const struct utopia_print *p; + + static int numeric; + + static const struct option opts[] = { + { "numeric", OPT_SIMPLE, &numeric }, + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc != 1) + errx(1, "need device name for 'diag phy print'"); + + (void)diagif_get_phy(argv[0]); + + if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1) + err(1, NULL); + len = 0; + if (sysctlbyname(str, NULL, &len, NULL, 0)) + err(1, "'%s' not found", str); + + regs = malloc(len); + if (regs == NULL) + err(1, NULL); + + if (sysctlbyname(str, regs, &len, NULL, 0)) + err(1, "'%s' not found", str); + free(str); + + if (numeric) { + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("%02x: ", i); + if (i % 16 == 8) + printf(" "); + printf(" %02x", regs[i]); + if (i % 16 == 15) + printf("\n"); + } + if (i % 16 != 0) + printf("\n"); + } else { + if (asprintf(&str, "hw.atm.%s.phy_type", argv[0]) == -1) + err(1, NULL); + len1 = sizeof(type); + if (sysctlbyname(str, &type, &len1, NULL, 0)) + err(1, "'%s' not found", str); + free(str); + + for (i = 0; i < sizeof(phy_print) / sizeof(phy_print[0]); i++) + if (type == phy_print[i].type) + break; + if (i == sizeof(phy_print) / sizeof(phy_print[0])) + errx(1, "unknown PHY chip type %u\n", type); + + for (p = phy_print[i].tab; + p < phy_print[i].tab + phy_print[i].len; + p++) { + if (p->reg + utopia_addreg[p->type] > len) + /* don't have this register */ + continue; + + printf("%s:%*s", p->name, 40 - (int)strlen(p->name),""); + + switch (p->type) { + + case UTP_REGT_BITS: + printf("%s\n", printb8(regs[p->reg], p->fmt)); + break; + + case UTP_REGT_INT8: + printf("%#x\n", regs[p->reg]); + break; + + case UTP_REGT_INT10BITS: + printf("%#x %s\n", regs[p->reg] | + ((regs[p->reg + 1] & 0x3) << 8), + printb8(regs[p->reg + 1], p->fmt)); + break; + + case UTP_REGT_INT12: + printf("%#x\n", regs[p->reg] | + ((regs[p->reg + 1] & 0xf) << 8)); + break; + + case UTP_REGT_INT16: + printf("%#x\n", regs[p->reg] | + (regs[p->reg + 1] << 8)); + break; + + case UTP_REGT_INT19: + printf("%#x\n", regs[p->reg] | + (regs[p->reg + 1] << 8) | + ((regs[p->reg + 2] & 0x7) << 16)); + break; + + case UTP_REGT_INT20: + printf("%#x\n", regs[p->reg] | + (regs[p->reg + 1] << 8) | + ((regs[p->reg + 2] & 0xf) << 16)); + break; + + case UTP_REGT_INT21: + printf("%#x\n", regs[p->reg] | + (regs[p->reg + 1] << 8) | + ((regs[p->reg + 2] & 0x1f) << 16)); + break; + + default: + abort(); + } + } + } + free(regs); +} + +static void +diag_phy_stats(int argc, char *argv[]) +{ + int opt; + size_t len; + char *str; + struct utopia_stats1 stats1; + u_int foo; + + static int clear; + + static const struct option opts[] = { + { "clear", OPT_SIMPLE, &clear }, + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc != 1) + errx(1, "need device name for 'diag phy stats'"); + + (void)diagif_get_phy(argv[0]); + + if (asprintf(&str, "hw.atm.%s.phy_stats", argv[0]) == -1) + err(1, NULL); + + len = sizeof(stats1); + if (sysctlbyname(str, &stats1, &len, + clear ? &foo : NULL, clear ? sizeof(foo) : 0)) + err(1, "'%s' not found", str); + if (len < sizeof(stats1.version)) + errx(1, "phy statistics too short %zu", len); + + switch (stats1.version) { + + case 1: + if (len != sizeof(stats1)) + errx(1, "bad phy stats length %zu (expecting %zu)", + len, sizeof(stats1)); + break; + + default: + errx(1, "unknown phy stats version %u", stats1.version); + } + + free(str); + + printf("rx_sbip: %llu\n", (unsigned long long)stats1.rx_sbip); + printf("rx_lbip: %llu\n", (unsigned long long)stats1.rx_lbip); + printf("rx_lfebe: %llu\n", (unsigned long long)stats1.rx_lfebe); + printf("rx_pbip: %llu\n", (unsigned long long)stats1.rx_pbip); + printf("rx_pfebe: %llu\n", (unsigned long long)stats1.rx_pfebe); + printf("rx_cells: %llu\n", (unsigned long long)stats1.rx_cells); + printf("rx_corr: %llu\n", (unsigned long long)stats1.rx_corr); + printf("rx_uncorr: %llu\n", (unsigned long long)stats1.rx_uncorr); + printf("rx_symerr: %llu\n", (unsigned long long)stats1.rx_symerr); + printf("tx_cells: %llu\n", (unsigned long long)stats1.tx_cells); +} + +/* + * Fetch the table of open vccs + */ +void +diagif_fetch_vcc(struct diagif *aif, int fd) +{ + struct ifreq ifr; + + if (aif->vtab != NULL) + return; + + strncpy(ifr.ifr_name, aif->ifname, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + aif->vtab = malloc(sizeof(*aif->vtab) + sizeof(aif->vtab->vccs[0]) * + aif->mib.max_vccs); + if (aif->vtab == NULL) + err(1, NULL); + ifr.ifr_data = (caddr_t)aif->vtab; + + if (ioctl(fd, SIOCATMGVCCS, &ifr) == -1) + err(1, "SIOCATMGVCCS"); +} + +/* + * Print the VCC table for this interface. + */ +static void +print_channel(const struct diagif *aif) +{ + const struct atmio_vcc *v; + + static const char *const aal_tab[] = { + [ATMIO_AAL_0] = "0", + [ATMIO_AAL_34] = "3/4", + [ATMIO_AAL_5] = "5", + [ATMIO_AAL_RAW] = "raw", + }; + static const char *const traffic_tab[] = { + [ATMIO_TRAFFIC_UBR] = "ubr", + [ATMIO_TRAFFIC_CBR] = "cbr", + [ATMIO_TRAFFIC_ABR] = "abr", + [ATMIO_TRAFFIC_VBR] = "vbr", + }; + + for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) { + printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname, + v->vpi, v->vci); + + if (v->aal >= sizeof(aal_tab)/sizeof(aal_tab[0]) || + aal_tab[v->aal] == NULL) + printf("bad "); + else + printf("%-4s", aal_tab[v->aal]); + + if (v->traffic >= sizeof(traffic_tab)/sizeof(traffic_tab[0]) || + traffic_tab[v->traffic] == NULL) + printf("bad "); + else + printf("%-8s", traffic_tab[v->traffic]); + + printf("%-6u%-6u%s\n", v->rmtu, v->tmtu, + printb(v->flags, ATMIO_FLAGS)); + } +} + +/* + * Print the VCC table for this interface, traffic parameters. + */ +static void +print_traffic(const struct diagif *aif) +{ + const struct atmio_vcc *v; + + for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) { + printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname, + v->vpi, v->vci); + + switch (v->traffic) { + + case ATMIO_TRAFFIC_CBR: + printf("%u", v->tparam.pcr); + break; + + case ATMIO_TRAFFIC_UBR: + printf("%-8u %u", v->tparam.pcr, + v->tparam.mcr); + break; + + case ATMIO_TRAFFIC_VBR: + printf("%-8u%-8u%-8u", v->tparam.pcr, v->tparam.scr, + v->tparam.mbs); + break; + + case ATMIO_TRAFFIC_ABR: + printf("%-8u %-8u", + v->tparam.pcr, v->tparam.mcr); + break; + } + printf("\n"); + } +} + +/* + * Print the VCC table for this interface, ABR traffic parameters. + */ +static void +print_abr(const struct diagif *aif) +{ + const struct atmio_vcc *v; + + for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) { + printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname, + v->vpi, v->vci); + + if (v->traffic == ATMIO_TRAFFIC_ABR) { + printf("%-8u%-8u%-4u%-4u%-5u%-5u%-5u%u", + v->tparam.icr, v->tparam.tbe, v->tparam.nrm, + v->tparam.trm, v->tparam.adtf, v->tparam.rif, + v->tparam.rdf, v->tparam.cdf); + } + printf("\n"); + } +} + +static void +diag_vcc_loop(void (*func)(const struct diagif *), const char *text, + int argc, char *argv[], int fd) +{ + struct diagif *aif; + + heading_init(); + if (argc == 0) { + TAILQ_FOREACH(aif, &diagif_list, link) { + diagif_fetch_vcc(aif, fd); + if (aif->vtab->count != 0) { + heading("%s", text); + (*func)(aif); + } + } + + } else { + for (optind = 0; optind < argc; optind++) { + TAILQ_FOREACH(aif, &diagif_list, link) + if (strcmp(aif->ifname, argv[optind]) == 0) { + diagif_fetch_vcc(aif, fd); + if (aif->vtab->count != 0) { + heading("%s", text); + (*func)(aif); + } + break; + } + if (aif == NULL) + warnx("no such interface '%s'", argv[optind]); + } + } +} + +static void +diag_vcc(int argc, char *argv[]) +{ + int opt, fd; + + static int channel, traffic, abr; + static const struct option opts[] = { + { "abr", OPT_SIMPLE, &abr }, + { "channel", OPT_SIMPLE, &channel }, + { "traffic", OPT_SIMPLE, &traffic }, + { NULL, 0, NULL } + }; + static const char head_channel[] = + "Interface\n" + "Index Name VPI VCI AAL Traffic RxMTU TxMTU Flags\n"; + static const char head_traffic[] = + "Interface Traffic parameters\n" + "Index Name VPI VCI PCR SCR MBS MCR\n"; + static const char head_abr[] = + "Interface ABR traffic parameters\n" + "Index Name VPI VCI ICR TBE NRM TRM ADTF RIF RDF " + "CDF\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + fd = socket(PF_NATM, SOCK_STREAM, PROTO_NATMAAL5); + if (fd < 0) + err(1, "socket"); + + diagif_fetch(); + if (TAILQ_EMPTY(&diagif_list)) + errx(1, "no ATM interfaces found"); + + if (!channel && !traffic && !abr) + channel = 1; + + if (channel) + diag_vcc_loop(print_channel, head_channel, argc, argv, fd); + if (traffic) + diag_vcc_loop(print_traffic, head_traffic, argc, argv, fd); + if (abr) + diag_vcc_loop(print_abr, head_abr, argc, argv, fd); +} + +/* + * Print driver-internal statistics + */ +static void +diag_stats(int argc, char *argv[]) +{ + int opt; + char *str; + size_t len; + uint32_t *stats; + struct diagif *aif; + u_int i; + + static const struct option opts[] = { + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc != 1) + errx(1, "need one arg for 'diag stats'"); + + diagif_fetch(); + TAILQ_FOREACH(aif, &diagif_list, link) + if (strcmp(aif->ifname, argv[0]) == 0) + break; + + if (aif == NULL) + errx(1, "interface '%s' not found", argv[0]); + + if (asprintf(&str, "hw.atm.%s.istats", argv[0]) == -1) + err(1, NULL); + len = 0; + if (sysctlbyname(str, NULL, &len, NULL, 0)) + err(1, "'%s' not found", str); + + stats = malloc(len); + if (stats == NULL) + err(1, NULL); + + if (sysctlbyname(str, stats, &len, NULL, 0)) + err(1, "'%s' not found", str); + free(str); + + if (aif->mib.device >= sizeof(print_stats) / sizeof(print_stats[0]) || + print_stats[aif->mib.device] == NULL) + errx(1, "unknown stats format (%u)", aif->mib.device); + + for (i = 0; print_stats[aif->mib.device][i] != NULL; i++) { + if (i * sizeof(uint32_t) >= len) + errx(1, "debug info too short (version mismatch?)"); + printf("%-22s%u\n", print_stats[aif->mib.device][i], stats[i]); + } + free(stats); + + if (i != len / sizeof(uint32_t)) + errx(1, "debug info too long (version mismatch?)"); +} diff --git a/sbin/atm/atmconfig/diag.h b/sbin/atm/atmconfig/diag.h new file mode 100644 index 000000000000..8b36cd44e1f5 --- /dev/null +++ b/sbin/atm/atmconfig/diag.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $FreeBSD$ + */ + +struct diagif { + TAILQ_ENTRY(diagif) link; + char ifname[IFNAMSIZ]; + u_int index; + struct ifatm_mib mib; + int phy_present : 1; + u_int phy_type; + u_int phy_loopback; + char phy_name[100]; + u_int phy_state; + u_int phy_carrier; + struct atmio_vcctable *vtab; +}; +TAILQ_HEAD(diagif_list, diagif); +extern struct diagif_list diagif_list; + +void diagif_fetch(void); +void diagif_fetch_vcc(struct diagif *aif, int fd); diff --git a/sbin/atm/atmconfig/main.c b/sbin/atm/atmconfig/main.c new file mode 100644 index 000000000000..137421830a50 --- /dev/null +++ b/sbin/atm/atmconfig/main.c @@ -0,0 +1,880 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <netdb.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> +#include <stdint.h> +#include <fnmatch.h> +#include <dirent.h> +#ifdef WITH_BSNMP +#include <bsnmp/asn1.h> +#include <bsnmp/snmp.h> +#include <bsnmp/snmpclient.h> +#endif + +#include "atmconfig.h" +#include "private.h" + +/* verbosity level */ +static int verbose; + +/* notitle option */ +static int notitle; + +/* need to put heading before next output */ +static int need_heading; + +/* + * TOP LEVEL commands + */ +static void help_func(int argc, char *argv[]) __dead2; + +static const struct cmdtab static_main_tab[] = { + { "help", NULL, help_func }, + { "options", NULL, NULL }, + { "commands", NULL, NULL }, + { "diag", diag_tab, NULL }, + { "natm", natm_tab, NULL }, + { NULL, NULL, NULL } +}; + +static struct cmdtab *main_tab = NULL; +static size_t main_tab_size = sizeof(static_main_tab) / + sizeof(static_main_tab[0]); + +static int +substr(const char *s1, const char *s2) +{ + return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); +} + +/* + * Current help file state + */ +struct help_file { + int file_state; /* 0:looking for main file, 1:found, 2:other */ + const char *p_start; /* current path pointer */ + const char *p_end; /* end of current path in path */ + char *dirname; /* directory name */ + DIR *dir; /* open directory */ + char *fname; /* current filename */ + FILE *fp; /* open file */ + char line[LINE_MAX]; /* current line */ + u_int fcnt; /* count of files found */ +}; + +struct help_pos { + off_t pos; /* file position */ + u_int fcnt; /* number of file */ + char *fname; /* name of file */ + const char *p_start; /* current path pointer */ + const char *p_end; /* end of current path in path */ +}; + +static int +help_next_file(struct help_file *hp) +{ + const char *fpat; + struct dirent *ent; + + if (hp->file_state == 3) + return (-1); + + if (hp->file_state == 0) + fpat = FILE_HELP; + else + fpat = FILE_HELP_OTHERS; + + if (hp->file_state == 0 || hp->file_state == 1) { + /* start from beginning */ + hp->p_start = PATH_HELP; + hp->file_state++; + } + + try_file: + if (hp->dir != NULL) { + /* directory open (must be state 2) */ + while ((ent = readdir(hp->dir)) != NULL) { + if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0) + continue; + if (asprintf(&hp->fname, "%s/%s", hp->dirname, + ent->d_name) == -1) + err(1, NULL); + if ((hp->fp = fopen(hp->fname, "r")) != NULL) { + hp->fcnt++; + return (0); + } + free(hp->fname); + } + /* end of directory */ + closedir(hp->dir); + hp->dir = NULL; + free(hp->dirname); + goto next_path; + } + + /* nothing open - advanc to new path element */ + try_path: + for (hp->p_end = hp->p_start; *hp->p_end != '\0' && + *hp->p_end != ':'; hp->p_end++) + ; + + if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start), + hp->p_start) == -1) + err(1, NULL); + + if (hp->file_state == 1) { + /* just try to open */ + if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1) + err(1, NULL); + if ((hp->fp = fopen(hp->fname, "r")) != NULL) { + hp->fcnt++; + return (0); + } + free(hp->fname); + + goto next_path; + } + + /* open directory */ + if ((hp->dir = opendir(hp->dirname)) != NULL) + goto try_file; + + free(hp->dirname); + + next_path: + hp->p_start = hp->p_end; + if (*hp->p_start == '\0') { + /* end of path */ + if (hp->file_state == 1) + errx(1, "help file not found"); + return (-1); + } + hp->p_start++; + goto try_path; + +} + +/* + * Save current file position + */ +static void +help_file_tell(struct help_file *hp, struct help_pos *pos) +{ + if (pos->fname != NULL) + free(pos->fname); + if ((pos->fname = strdup(hp->fname)) == NULL) + err(1, NULL); + pos->fcnt = hp->fcnt; + pos->p_start = hp->p_start; + pos->p_end = hp->p_end; + if ((pos->pos = ftello(hp->fp)) == -1) + err(1, "%s", pos->fname); +} + +/* + * Go to that position + * + * We can go either to the original help file or back in the current file. + */ +static void +help_file_seek(struct help_file *hp, struct help_pos *pos) +{ + hp->p_start = pos->p_start; + hp->p_end = pos->p_end; + hp->fcnt = pos->fcnt; + + if (hp->dir != NULL) { + free(hp->dirname); + closedir(hp->dir); + hp->dir = NULL; + } + + if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) { + free(hp->fname); + fclose(hp->fp); + hp->fp = NULL; + } + if (hp->fp == NULL) { + if ((hp->fname = strdup(pos->fname)) == NULL) + err(1, NULL); + if ((hp->fp = fopen(hp->fname, "r")) == NULL) + err(1, "reopen %s", hp->fname); + } + if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1) + err(1, "seek %s", hp->fname); + + if (pos->fcnt == 1) + /* go back to state 1 */ + hp->file_state = 1; + else + /* lock */ + hp->file_state = 3; +} + +/* + * Rewind to position 0 + */ +static void +help_file_rewind(struct help_file *hp) +{ + + if (hp->file_state == 1) { + if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1) + err(1, "rewind help file"); + return; + } + + if (hp->dir != NULL) { + free(hp->dirname); + closedir(hp->dir); + hp->dir = NULL; + } + + if (hp->fp != NULL) { + free(hp->fname); + fclose(hp->fp); + hp->fp = NULL; + } + memset(hp, 0, sizeof(*hp)); +} + +/* + * Get next line from a help file + */ +static const char * +help_next_line(struct help_file *hp) +{ + for (;;) { + if (hp->fp != NULL) { + if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL) + return (hp->line); + if (ferror(hp->fp)) + err(1, "%s", hp->fname); + free(hp->fname); + + fclose(hp->fp); + hp->fp = NULL; + } + if (help_next_file(hp) == -1) + return (NULL); + } + +} + +/* + * This function prints the available 0-level help topics from all + * other help files by scanning the files. It assumes, that this is called + * only from the main help file. + */ +static void +help_get_0topics(struct help_file *hp) +{ + struct help_pos save; + const char *line; + + memset(&save, 0, sizeof(save)); + help_file_tell(hp, &save); + + help_file_rewind(hp); + while ((line = help_next_line(hp)) != NULL) { + if (line[0] == '^' && line[1] == '^') + printf("%s", line + 2); + } + help_file_seek(hp, &save); +} + +/* + * Function to print help. The help argument is in argv[0] here. + */ +static void +help_func(int argc, char *argv[]) +{ + struct help_file hfile; + struct help_pos match, last_match; + const char *line; + char key[100]; + int level; + int i, has_sub_topics; + + memset(&hfile, 0, sizeof(hfile)); + memset(&match, 0, sizeof(match)); + memset(&last_match, 0, sizeof(last_match)); + + if (argc == 0) { + /* only 'help' - show intro */ + if ((argv[0] = strdup("intro")) == NULL) + err(1, NULL); + argc = 1; + } + + optind = 0; + match.pos = -1; + last_match.pos = -1; + for (;;) { + /* read next line */ + if ((line = help_next_line(&hfile)) == NULL) { + /* EOF */ + level = 999; + goto stop; + } + if (line[0] != '^' || line[1] == '^') + continue; + + if (sscanf(line + 1, "%d%99s", &level, key) != 2) + errx(1, "error in help file '%s'", line); + + if (level < optind) { + stop: + /* next higher level entry - stop this level */ + if (match.pos == -1) { + /* not found */ + goto not_found; + } + /* go back to the match */ + help_file_seek(&hfile, &match); + last_match = match; + memset(&match, 0, sizeof(match)); + match.pos = -1; + + /* go to next key */ + if (++optind >= argc) + break; + } + if (level == optind) { + if (substr(argv[optind], key)) { + if (match.pos != -1) { + printf("Ambiguous topic."); + goto list_topics; + } + help_file_tell(&hfile, &match); + } + } + } + + /* before breaking above we have seeked back to the matching point */ + for (;;) { + if ((line = help_next_line(&hfile)) == NULL) + break; + + if (line[0] == '#') + continue; + if (line[0] == '^') { + if (line[1] == '^') + continue; + break; + } + if (strncmp(line, "$MAIN", 5) == 0) { + help_get_0topics(&hfile); + continue; + } + printf("%s", line); + } + + exit(0); + + not_found: + printf("Topic not found."); + + list_topics: + printf(" Use one of:\natmconfig help"); + for (i = 0; i < optind; i++) + printf(" %s", argv[i]); + + printf(" ["); + + /* list all the keys at this level */ + if (last_match.pos == -1) + /* go back to start of help */ + help_file_rewind(&hfile); + else + help_file_seek(&hfile, &last_match); + + has_sub_topics = 0; + while ((line = help_next_line(&hfile)) != NULL) { + if (line[0] == '#' || line[0] != '^' || line[1] == '^') + continue; + + if (sscanf(line + 1, "%d%99s", &level, key) != 2) + errx(1, "error in help file '%s'", line); + + if (level < optind) + break; + if (level == optind) { + has_sub_topics = 1; + printf(" %s", key); + } + } + printf(" ]."); + if (!has_sub_topics) + printf(" No sub-topics found."); + printf("\n"); + exit(1); +} + +#ifdef WITH_BSNMP +/* + * Parse a server specification + * + * syntax is [trans::][community@][server][:port] + */ +static void +parse_server(char *name) +{ + char *p, *s = name; + + /* look for a double colon */ + for (p = s; *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0') { + p++; + continue; + } + if (*p == ':' && p[1] == ':') + break; + } + if (*p != '\0') { + if (p > s) { + if (p - s == 3 && strncmp(s, "udp", 3) == 0) + snmp_client.trans = SNMP_TRANS_UDP; + else if (p - s == 6 && strncmp(s, "stream", 6) == 0) + snmp_client.trans = SNMP_TRANS_LOC_STREAM; + else if (p - s == 5 && strncmp(s, "dgram", 5) == 0) + snmp_client.trans = SNMP_TRANS_LOC_DGRAM; + else + errx(1, "unknown SNMP transport '%.*s'", + (int)(p - s), s); + } + s = p + 2; + } + + /* look for a @ */ + for (p = s; *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0') { + p++; + continue; + } + if (*p == '@') + break; + } + + if (*p != '\0') { + if (p - s > SNMP_COMMUNITY_MAXLEN) + err(1, "community string too long"); + strncpy(snmp_client.read_community, s, p - s); + snmp_client.read_community[p - s] = '\0'; + strncpy(snmp_client.write_community, s, p - s); + snmp_client.write_community[p - s] = '\0'; + s = p + 1; + } + + /* look for a colon */ + for (p = s; *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0') { + p++; + continue; + } + if (*p == ':') + break; + } + + if (*p == ':') { + if (p > s) { + *p = '\0'; + snmp_client_set_host(&snmp_client, s); + *p = ':'; + } + snmp_client_set_port(&snmp_client, p + 1); + } else if (p > s) + snmp_client_set_host(&snmp_client, s); +} +#endif + +int +main(int argc, char *argv[]) +{ + int opt, i; + const struct cmdtab *match, *cc, *tab; + +#ifdef WITH_BSNMP + snmp_client_init(&snmp_client); + snmp_client.trans = SNMP_TRANS_LOC_STREAM; + snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK); +#endif + +#ifdef WITH_BSNMP +#define OPTSTR "htvs:" +#else +#define OPTSTR "htv" +#endif + + while ((opt = getopt(argc, argv, OPTSTR)) != -1) + switch (opt) { + + case 'h': + help_func(0, argv); + +#ifdef WITH_BSNMP + case 's': + parse_server(optarg); + break; +#endif + + case 'v': + verbose++; + break; + + case 't': + notitle = 1; + break; + } + + if (argv[optind] == NULL) + help_func(0, argv); + + argc -= optind; + argv += optind; + + if ((main_tab = malloc(sizeof(static_main_tab))) == NULL) + err(1, NULL); + memcpy(main_tab, static_main_tab, sizeof(static_main_tab)); + +#ifdef WITH_BSNMP + /* XXX while this is compiled in */ + device_register(); +#endif + + cc = main_tab; + i = 0; + for (;;) { + /* + * Scan the table for a match + */ + tab = cc; + match = NULL; + while (cc->string != NULL) { + if (substr(argv[i], cc->string)) { + if (match != NULL) { + printf("Ambiguous option '%s'", + argv[i]); + cc = tab; + goto subopts; + } + match = cc; + } + cc++; + } + if ((cc = match) == NULL) { + printf("Unknown option '%s'", argv[i]); + cc = tab; + goto subopts; + } + + /* + * Have a match. If there is no subtable, there must + * be either a handler or the command is only a help entry. + */ + if (cc->sub == NULL) { + if (cc->func != NULL) + break; + printf("Unknown option '%s'", argv[i]); + cc = tab; + goto subopts; + } + + /* + * Look at the next argument. If it doesn't exist or it + * looks like a switch, terminate the scan here. + */ + if (argv[i + 1] == NULL || argv[i + 1][0] == '-') { + if (cc->func != NULL) + break; + printf("Need sub-option for '%s'", argv[i]); + cc = cc->sub; + goto subopts; + } + + cc = cc->sub; + i++; + } + + argc -= i + 1; + argv += i + 1; + + (*cc->func)(argc, argv); + + return (0); + + subopts: + printf(". Select one of:\n"); + while (cc->string != NULL) { + if (cc->func != NULL || cc->sub != NULL) + printf("%s ", cc->string); + cc++; + } + printf("\n"); + + return (1); +} + +void +verb(const char *fmt, ...) +{ + va_list ap; + + if (verbose) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + } +} + +void +heading(const char *fmt, ...) +{ + va_list ap; + + if (need_heading) { + need_heading = 0; + if (!notitle) { + va_start(ap, fmt); + fprintf(stdout, fmt, ap); + va_end(ap); + } + } +} + +void +heading_init(void) +{ + need_heading = 1; +} + +/* + * stringify an enumerated value + */ +const char * +penum(int32_t value, const struct penum *strtab, char *buf) +{ + while (strtab->str != NULL) { + if (strtab->value == value) { + strcpy(buf, strtab->str); + return (buf); + } + strtab++; + } + warnx("illegal value for enumerated variable '%d'", value); + strcpy(buf, "?"); + return (buf); +} + +/* + * And the other way 'round + */ +int +pparse(int32_t *val, const struct penum *tab, const char *str) +{ + + while (tab->str != NULL) { + if (strcmp(tab->str, str) == 0) { + *val = tab->value; + return (0); + } + tab++; + } + return (-1); +} + +/* + * Parse command line options + */ +int +parse_options(int *pargc, char ***pargv, const struct option *opts) +{ + const struct option *o, *m; + char *arg; + u_long ularg, ularg1; + long larg; + char *end; + + if (*pargc == 0) + return (-1); + arg = (*pargv)[0]; + if (arg[0] != '-' || arg[1] == '\0') + return (-1); + if (arg[1] == '-' && arg[2] == '\0') { + (*pargv)++; + (*pargc)--; + return (-1); + } + + m = NULL; + for (o = opts; o->optstr != NULL; o++) { + if (strlen(arg + 1) <= strlen(o->optstr) && + strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) { + if (m != NULL) + errx(1, "ambiguous option '%s'", arg); + m = o; + } + } + if (m == NULL) + errx(1, "unknown option '%s'", arg); + + (*pargv)++; + (*pargc)--; + + if (m->opttype == OPT_NONE) + return (m - opts); + + if (m->opttype == OPT_SIMPLE) { + *(int *)m->optarg = 1; + return (m - opts); + } + + if (*pargc == 0) + errx(1, "option requires argument '%s'", arg); + optarg = *(*pargv)++; + (*pargc)--; + + switch (m->opttype) { + + case OPT_UINT: + ularg = strtoul(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad unsigned integer argument for '%s'", arg); + if (ularg > UINT_MAX) + errx(1, "argument to large for option '%s'", arg); + *(u_int *)m->optarg = (u_int)ularg; + break; + + case OPT_INT: + larg = strtol(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad integer argument for '%s'", arg); + if (larg > INT_MAX || larg < INT_MIN) + errx(1, "argument out of range for option '%s'", arg); + *(int *)m->optarg = (int)larg; + break; + + case OPT_UINT32: + ularg = strtoul(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad unsigned integer argument for '%s'", arg); + if (ularg > UINT32_MAX) + errx(1, "argument to large for option '%s'", arg); + *(uint32_t *)m->optarg = (uint32_t)ularg; + break; + + case OPT_INT32: + larg = strtol(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad integer argument for '%s'", arg); + if (larg > INT32_MAX || larg < INT32_MIN) + errx(1, "argument out of range for option '%s'", arg); + *(int32_t *)m->optarg = (int32_t)larg; + break; + + case OPT_UINT64: + *(uint64_t *)m->optarg = strtoull(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad unsigned integer argument for '%s'", arg); + break; + + case OPT_INT64: + *(int64_t *)m->optarg = strtoll(optarg, &end, 0); + if (*end != '\0') + errx(1, "bad integer argument for '%s'", arg); + break; + + case OPT_FLAG: + if (strcasecmp(optarg, "enable") == 0 || + strcasecmp(optarg, "yes") == 0 || + strcasecmp(optarg, "true") == 0 || + strcasecmp(optarg, "on") == 0 || + strcmp(optarg, "1") == 0) + *(int *)m->optarg = 1; + else if (strcasecmp(optarg, "disable") == 0 || + strcasecmp(optarg, "no") == 0 || + strcasecmp(optarg, "false") == 0 || + strcasecmp(optarg, "off") == 0 || + strcmp(optarg, "0") == 0) + *(int *)m->optarg = 0; + else + errx(1, "bad boolean argument to '%s'", arg); + break; + + case OPT_VCI: + ularg = strtoul(optarg, &end, 0); + if (*end == '.') { + ularg1 = strtoul(end + 1, &end, 0); + } else { + ularg1 = ularg; + ularg = 0; + } + if (*end != '\0') + errx(1, "bad VCI value for option '%s'", arg); + if (ularg > 0xff) + errx(1, "VPI value too large for option '%s'", arg); + if (ularg1 > 0xffff) + errx(1, "VCI value too large for option '%s'", arg); + ((u_int *)m->optarg)[0] = ularg; + ((u_int *)m->optarg)[1] = ularg1; + break; + + case OPT_STRING: + if (m->optarg != NULL) + *(const char **)m->optarg = optarg; + break; + + default: + errx(1, "(internal) bad option type %u for '%s'", + m->opttype, arg); + } + return (m - opts); +} + +/* + * for compiled-in modules + */ +void +register_module(const struct amodule *mod) +{ + main_tab_size++; + if ((main_tab = realloc(main_tab, main_tab_size * sizeof(main_tab[0]))) + == NULL) + err(1, NULL); + main_tab[main_tab_size - 2] = *mod->cmd; + memset(&main_tab[main_tab_size - 1], 0, sizeof(main_tab[0])); +} diff --git a/sbin/atm/atmconfig/natm.c b/sbin/atm/atmconfig/natm.c new file mode 100644 index 000000000000..cac3880e8edf --- /dev/null +++ b/sbin/atm/atmconfig/natm.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if_atm.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include "atmconfig.h" +#include "private.h" +#include "diag.h" + +static void natm_add(int, char *[]); +static void natm_delete(int, char *[]); +static void natm_show(int, char *[]); + +const struct cmdtab natm_tab[] = { + { "add", NULL, natm_add }, + { "delete", NULL, natm_delete }, + { "show", NULL, natm_show }, + { NULL, NULL, NULL } +}; + +/* + * Structure to hold a route + */ +struct natm_route { + TAILQ_ENTRY(natm_route) link; + struct in_addr host; + struct diagif *aif; + u_int flags; + int llcsnap; + u_int vpi, vci; + u_int traffic; + u_int pcr, scr, mbs, icr, mcr; + u_int tbe, nrm, trm, adtf, rif, rdf, cdf; +}; +static TAILQ_HEAD(, natm_route) natm_route_list = + TAILQ_HEAD_INITIALIZER(natm_route_list); + +static void +store_route(struct rt_msghdr *rtm) +{ + u_int i; + struct natm_route *r; + char *cp; + struct sockaddr *sa; + struct sockaddr_in *sain; + struct sockaddr_dl *sdl; + struct diagif *aif; + u_int n; + + r = malloc(sizeof(*r)); + if (r == NULL) + err(1, "allocate route"); + + r->flags = rtm->rtm_flags; + cp = (char *)(rtm + 1); + for (i = 1; i != 0; i <<= 1) { + if (rtm->rtm_addrs & i) { + sa = (struct sockaddr *)cp; + cp += roundup(sa->sa_len, sizeof(long)); + switch (i) { + + case RTA_DST: + if (sa->sa_family != AF_INET) { + warnx("RTA_DST not AF_INET %u", sa->sa_family); + goto fail; + } + sain = (struct sockaddr_in *)(void *)sa; + if (sain->sin_len < 4) + r->host.s_addr = INADDR_ANY; + else + r->host = sain->sin_addr; + break; + + case RTA_GATEWAY: + if (sa->sa_family != AF_LINK) { + warnx("RTA_GATEWAY not AF_LINK"); + goto fail; + } + sdl = (struct sockaddr_dl *)(void *)sa; + TAILQ_FOREACH(aif, &diagif_list, link) + if (strlen(aif->ifname) == + sdl->sdl_nlen && + strncmp(aif->ifname, sdl->sdl_data, + sdl->sdl_nlen) == 0) + break; + if (aif == NULL) { + warnx("interface '%.*s' not found", + sdl->sdl_nlen, sdl->sdl_data); + goto fail; + } + r->aif = aif; + + /* parse ATM stuff */ + +#define GET3() (((sdl->sdl_data[n] & 0xff) << 16) | \ + ((sdl->sdl_data[n + 1] & 0xff) << 8) | \ + ((sdl->sdl_data[n + 2] & 0xff) << 0)) +#define GET2() (((sdl->sdl_data[n] & 0xff) << 8) | \ + ((sdl->sdl_data[n + 1] & 0xff) << 0)) +#define GET1() (((sdl->sdl_data[n] & 0xff) << 0)) + + n = sdl->sdl_nlen; + if (sdl->sdl_alen < 4) { + warnx("RTA_GATEWAY alen too short"); + goto fail; + } + r->llcsnap = GET1() & ATM_PH_LLCSNAP; + n++; + r->vpi = GET1(); + n++; + r->vci = GET2(); + n += 2; + if (sdl->sdl_alen == 4) { + /* old address */ + r->traffic = ATMIO_TRAFFIC_UBR; + r->pcr = 0; + break; + } + /* new address */ + r->traffic = GET1(); + n++; + switch (r->traffic) { + + case ATMIO_TRAFFIC_UBR: + if (sdl->sdl_alen >= 5 + 3) { + r->pcr = GET3(); + n += 3; + } else + r->pcr = 0; + break; + + case ATMIO_TRAFFIC_CBR: + if (sdl->sdl_alen < 5 + 3) { + warnx("CBR address too short"); + goto fail; + } + r->pcr = GET3(); + n += 3; + break; + + case ATMIO_TRAFFIC_VBR: + if (sdl->sdl_alen < 5 + 3 * 3) { + warnx("VBR address too short"); + goto fail; + } + r->pcr = GET3(); + n += 3; + r->scr = GET3(); + n += 3; + r->mbs = GET3(); + n += 3; + break; + + case ATMIO_TRAFFIC_ABR: + if (sdl->sdl_alen < 5 + 4 * 3 + 2 + + 1 * 2 + 3) { + warnx("ABR address too short"); + goto fail; + } + r->pcr = GET3(); + n += 3; + r->mcr = GET3(); + n += 3; + r->icr = GET3(); + n += 3; + r->tbe = GET3(); + n += 3; + r->nrm = GET1(); + n++; + r->trm = GET1(); + n++; + r->adtf = GET2(); + n += 2; + r->rif = GET1(); + n++; + r->rdf = GET1(); + n++; + r->cdf = GET1(); + n++; + break; + + default: + goto fail; + } + break; + } + } + } + + TAILQ_INSERT_TAIL(&natm_route_list, r, link); + + return; + fail: + free(r); +} + +/* + * Fetch the INET routes that a ours + */ +static void +natm_route_fetch(void) +{ + int name[6]; + size_t needed; + u_char *buf, *next; + struct rt_msghdr *rtm; + + name[0] = CTL_NET; + name[1] = PF_ROUTE; + name[2] = 0; + name[3] = AF_INET; + name[4] = NET_RT_DUMP; + name[5] = 0; + + if (sysctl(name, 6, NULL, &needed, NULL, 0) == -1) + err(1, "rtable estimate"); + needed *= 2; + if ((buf = malloc(needed)) == NULL) + err(1, "rtable buffer (%zu)", needed); + if (sysctl(name, 6, buf, &needed, NULL, 0) == -1) + err(1, "rtable get"); + + next = buf; + while (next < buf + needed) { + rtm = (struct rt_msghdr *)(void *)next; + next += rtm->rtm_msglen; + + if (rtm->rtm_type == RTM_GET) { + if ((rtm->rtm_flags & (RTF_UP | RTF_HOST | + RTF_STATIC)) == (RTF_UP | RTF_HOST | RTF_STATIC) && + (rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | + RTA_IFP)) == (RTA_DST | RTA_GATEWAY | RTA_IFP)) + store_route(rtm); + } + } +} + +static u_long +parse_num(const char *arg, const char *name, u_long limit) +{ + u_long res; + char *end; + + errno = 0; + res = strtoul(arg, &end, 10); + if (*end != '\0' || end == arg || errno != 0) + errx(1, "cannot parse %s '%s'", name, arg); + if (res > limit) + errx(1, "%s out of range (0...%lu)", name, limit); + return (res); +} + +static void +do_route(u_int type, u_int flags, const struct sockaddr_in *sain, + const struct sockaddr_dl *sdl) +{ + struct { + struct rt_msghdr h; + char space[512]; + } msg; + char *ptr; + int s; + ssize_t rlen; + + /* create routing message */ + bzero(&msg, sizeof(msg)); + msg.h.rtm_msglen = sizeof(msg.h); + msg.h.rtm_version = RTM_VERSION; + msg.h.rtm_type = type; + msg.h.rtm_index = 0; + msg.h.rtm_flags = flags; + msg.h.rtm_addrs = RTA_DST | (sdl != NULL ? RTA_GATEWAY : 0); + msg.h.rtm_pid = getpid(); + + ptr = (char *)&msg + sizeof(msg.h); + memcpy(ptr, sain, sain->sin_len); + ptr += roundup(sain->sin_len, sizeof(long)); + msg.h.rtm_msglen += roundup(sain->sin_len, sizeof(long)); + + if (sdl != NULL) { + memcpy(ptr, sdl, sdl->sdl_len); + ptr += roundup(sdl->sdl_len, sizeof(long)); + msg.h.rtm_msglen += roundup(sdl->sdl_len, sizeof(long)); + } + + /* open socket */ + s = socket(PF_ROUTE, SOCK_RAW, AF_INET); + if (s == -1) + err(1, "cannot open routing socket"); + + rlen = write(s, &msg, msg.h.rtm_msglen); + if (rlen == -1) + err(1, "writing to routing socket"); + if ((size_t)rlen != msg.h.rtm_msglen) + errx(1, "short write to routing socket: %zu %u", + (size_t)rlen, msg.h.rtm_msglen); + close(s); +} + +/* + * Add a new NATM route + */ +static void +natm_add(int argc, char *argv[]) +{ + int opt; + struct hostent *hp; + struct sockaddr_in sain; + struct sockaddr_dl sdl; + struct diagif *aif; + u_long num, num1; + u_int idx; + + static int printonly; + + static const struct option opts[] = { + { "printonly", OPT_SIMPLE, &printonly }, + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + if (argc < 5) + errx(1, "missing arguments for 'natm add'"); + + memset(&sdl, 0, sizeof(sdl)); + sdl.sdl_len = sizeof(sdl); + sdl.sdl_family = AF_LINK; + + /* get the IP address for <dest> */ + memset(&sain, 0, sizeof(sain)); + hp = gethostbyname(argv[0]); + if (hp == NULL) + errx(1, "bad hostname %s: %s", argv[0], hstrerror(h_errno)); + if (hp->h_addrtype != AF_INET) + errx(1, "bad address type for %s", argv[0]); + sain.sin_len = sizeof(sain); + sain.sin_family = AF_INET; + memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr)); + + /* find interface */ + diagif_fetch(); + TAILQ_FOREACH(aif, &diagif_list, link) + if (strcmp(aif->ifname, argv[1]) == 0) + break; + if (aif == NULL) + errx(1, "unknown ATM interface '%s'", argv[1]); + sdl.sdl_index = aif->index; + strcpy(sdl.sdl_data, aif->ifname); + idx = sdl.sdl_nlen = strlen(aif->ifname); + idx++; + + /* verify VPI/VCI */ + num = parse_num(argv[2], "VPI", (1U << aif->mib.vpi_bits)); + sdl.sdl_data[idx++] = num & 0xff; + num = parse_num(argv[3], "VCI", (1U << aif->mib.vci_bits)); + if (num == 0) + errx(1, "VCI may not be 0"); + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = num & 0xff; + + /* encapsulation */ + if (strcasecmp(argv[4], "llc/snap") == 0) { + sdl.sdl_data[sdl.sdl_nlen] = ATM_PH_LLCSNAP; + } else if (strcasecmp(argv[4], "aal5") == 0) { + sdl.sdl_data[sdl.sdl_nlen] = 0; + } else + errx(1, "bad encapsulation type '%s'", argv[4]); + + /* look at the traffic */ + argc -= 5; + argv += 5; + + if (argc != 0) { + if (strcasecmp(argv[0], "ubr") == 0) { + sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR; + if (argc == 1) + /* ok */; + else if (argc == 2) { + num = parse_num(argv[1], "PCR", aif->mib.pcr); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + } else + errx(1, "too many parameters for UBR"); + + } else if (strcasecmp(argv[0], "cbr") == 0) { + sdl.sdl_data[idx++] = ATMIO_TRAFFIC_CBR; + if (argc == 1) + errx(1, "missing PCR for CBR"); + if (argc > 2) + errx(1, "too many parameters for CBR"); + num = parse_num(argv[1], "PCR", aif->mib.pcr); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + } else if (strcasecmp(argv[0], "vbr") == 0) { + sdl.sdl_data[idx++] = ATMIO_TRAFFIC_VBR; + + if (argc < 4) + errx(1, "missing arg(s) for VBR"); + if (argc > 4) + errx(1, "too many parameters for VBR"); + + num = parse_num(argv[1], "PCR", aif->mib.pcr); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + num = parse_num(argv[2], "SCR", num); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + num = parse_num(argv[3], "MBS", 0xffffffLU); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + } else if (strcasecmp(argv[0], "abr") == 0) { + sdl.sdl_data[idx++] = ATMIO_TRAFFIC_ABR; + if (argc < 11) + errx(1, "missing arg(s) for ABR"); + if (argc > 11) + errx(1, "too many parameters for ABR"); + + num = parse_num(argv[1], "PCR", aif->mib.pcr); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num1 = parse_num(argv[2], "MCR", num); + sdl.sdl_data[idx++] = (num1 >> 16) & 0xff; + sdl.sdl_data[idx++] = (num1 >> 8) & 0xff; + sdl.sdl_data[idx++] = (num1 >> 0) & 0xff; + + num = parse_num(argv[3], "ICR", num); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + if (num < num1) + errx(1, "ICR must be >= MCR"); + + num = parse_num(argv[4], "TBE", 0xffffffUL); + sdl.sdl_data[idx++] = (num >> 16) & 0xff; + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[5], "NRM", 0x7UL); + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[6], "TRM", 0x7UL); + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[7], "ADTF", 0x3ffUL); + sdl.sdl_data[idx++] = (num >> 8) & 0xff; + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[8], "RIF", 0xfUL); + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[9], "RDF", 0xfUL); + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + num = parse_num(argv[10], "CDF", 0x7UL); + sdl.sdl_data[idx++] = (num >> 0) & 0xff; + + } else + errx(1, "bad traffic type '%s'", argv[0]); + } else + sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR; + + sdl.sdl_alen = idx - sdl.sdl_nlen; + sdl.sdl_len += sdl.sdl_nlen + sdl.sdl_alen; + + if (printonly) { + printf("route add -iface %s -link %.*s", + inet_ntoa(sain.sin_addr), sdl.sdl_nlen, sdl.sdl_data); + for (idx = 0; idx < sdl.sdl_alen; idx++) + printf("%c%x", ".:"[idx == 0], + (u_int)sdl.sdl_data[sdl.sdl_nlen + idx] & 0xffU); + printf("\n"); + exit(0); + } + + do_route(RTM_ADD, RTF_HOST | RTF_STATIC | RTF_UP, &sain, &sdl); +} + +/* + * Delete an NATM route + */ +static void +natm_delete(int argc, char *argv[]) +{ + int opt; + struct hostent *hp; + struct sockaddr_in sain; + u_int vpi, vci; + struct diagif *aif; + struct natm_route *r; + + static int printonly; + + static const struct option opts[] = { + { "printonly", OPT_SIMPLE, &printonly }, + { NULL, 0, NULL } + }; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + diagif_fetch(); + natm_route_fetch(); + + memset(&sain, 0, sizeof(sain)); + sain.sin_len = sizeof(sain); + sain.sin_family = AF_INET; + + if (argc == 1) { + /* get the IP address for <dest> */ + hp = gethostbyname(argv[0]); + if (hp == NULL) + errx(1, "bad hostname %s: %s", argv[0], + hstrerror(h_errno)); + if (hp->h_addrtype != AF_INET) + errx(1, "bad address type for %s", argv[0]); + memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr)); + + TAILQ_FOREACH(r, &natm_route_list, link) + if (r->host.s_addr == sain.sin_addr.s_addr) + break; + if (r == NULL) + errx(1, "no NATM route to host '%s' (%s)", argv[0], + inet_ntoa(sain.sin_addr)); + + } else if (argc == 3) { + TAILQ_FOREACH(aif, &diagif_list, link) + if (strcmp(aif->ifname, argv[0]) == 0) + break; + if (aif == NULL) + errx(1, "no such interface '%s'", argv[0]); + + vpi = parse_num(argv[1], "VPI", 0xff); + vci = parse_num(argv[2], "VCI", 0xffff); + + TAILQ_FOREACH(r, &natm_route_list, link) + if (r->aif == aif && r->vpi == vpi && r->vci == vci) + break; + if (r == NULL) + errx(1, "no such NATM route %s %u %u", argv[0], + vpi, vci); + sain.sin_addr = r->host; + + } else + errx(1, "bad number of arguments for 'natm delete'"); + + if (printonly) { + printf("route delete %s\n", inet_ntoa(r->host)); + exit(0); + } + + do_route(RTM_DELETE, r->flags, &sain, NULL); +} + +/* + * Show NATM routes + */ +static void +natm_show(int argc, char *argv[]) +{ + int opt; + struct natm_route *r; + struct hostent *hp; + + static const char *const traffics[] = { + [ATMIO_TRAFFIC_UBR] = "UBR", + [ATMIO_TRAFFIC_CBR] = "CBR", + [ATMIO_TRAFFIC_VBR] = "VBR", + [ATMIO_TRAFFIC_ABR] = "ABR" + }; + + static int numeric, abr; + + static const struct option opts[] = { + { "abr", OPT_SIMPLE, &abr }, + { "numeric", OPT_SIMPLE, &numeric }, + { NULL, 0, NULL } + }; + + static const char head[] = + "Destination Iface VPI VCI Encaps Trf PCR " + "SCR/MCR MBS/ICR\n"; + static const char head_abr[] = + "Destination Iface VPI VCI Encaps Trf PCR " + "SCR/MCR MBS/ICR TBE NRM TRM ADTF RIF RDF CDF\n"; + + while ((opt = parse_options(&argc, &argv, opts)) != -1) + switch (opt) { + } + + diagif_fetch(); + natm_route_fetch(); + + heading_init(); + TAILQ_FOREACH(r, &natm_route_list, link) { + heading(abr ? head_abr : head); + if (numeric) + printf("%-20s", inet_ntoa(r->host)); + else if (r->host.s_addr == INADDR_ANY) + printf("%-20s", "default"); + else { + hp = gethostbyaddr((char *)&r->host, sizeof(r->host), + AF_INET); + if (hp != NULL) + printf("%-20s", hp->h_name); + else + printf("%-20s", inet_ntoa(r->host)); + } + printf("%-12s%-4u%-6u%-9s%-4s", r->aif->ifname, r->vpi, r->vci, + r->llcsnap ? "LLC/SNAP" : "AAL5", traffics[r->traffic]); + switch (r->traffic) { + + case ATMIO_TRAFFIC_UBR: + case ATMIO_TRAFFIC_CBR: + printf("%-8u", r->pcr); + break; + + case ATMIO_TRAFFIC_VBR: + printf("%-8u%-8u%-8u", r->pcr, r->scr, r->mbs); + break; + + case ATMIO_TRAFFIC_ABR: + printf("%-8u%-8u%-8u", r->pcr, r->mcr, r->icr); + if (abr) + printf("%-8u%-4u%-4u%-5u%-4u%-4u%-4u", + r->tbe, r->nrm, r->trm, r->adtf, + r->rif, r->rdf, r->cdf); + break; + } + printf("\n"); + } +} diff --git a/sbin/atm/atmconfig/private.h b/sbin/atm/atmconfig/private.h new file mode 100644 index 000000000000..9dcf53979517 --- /dev/null +++ b/sbin/atm/atmconfig/private.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> +#include <netgraph.h> +#include <net/if.h> +#include <netinet/in.h> + +#ifndef PATH_HELP +#define PATH_HELP "/usr/share/doc/atm:/usr/local/share/doc/atm" +#endif +#ifndef FILE_HELP +#define FILE_HELP "atmconfig.help" +#endif +#ifndef FILE_HELP_OTHERS +#define FILE_HELP_OTHERS "atmconfig_*.help" +#endif +#ifndef PATH_ILMI_SOCK +#define PATH_ILMI_SOCK "/var/run/ilmid.sock" +#endif + +/* + * Builtin commands + */ +extern const struct cmdtab diag_tab[]; +extern const struct cmdtab natm_tab[]; |