aboutsummaryrefslogtreecommitdiff
path: root/sbin/atm/atmconfig
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/atm/atmconfig')
-rw-r--r--sbin/atm/atmconfig/Makefile44
-rw-r--r--sbin/atm/atmconfig/Makefile.depend22
-rw-r--r--sbin/atm/atmconfig/atm_oid.list20
-rw-r--r--sbin/atm/atmconfig/atmconfig.8323
-rw-r--r--sbin/atm/atmconfig/atmconfig.h102
-rw-r--r--sbin/atm/atmconfig/atmconfig.help223
-rw-r--r--sbin/atm/atmconfig/atmconfig_device.c444
-rw-r--r--sbin/atm/atmconfig/atmconfig_device.h75
-rw-r--r--sbin/atm/atmconfig/atmconfig_device.help62
-rw-r--r--sbin/atm/atmconfig/diag.c1122
-rw-r--r--sbin/atm/atmconfig/diag.h49
-rw-r--r--sbin/atm/atmconfig/main.c880
-rw-r--r--sbin/atm/atmconfig/natm.c680
-rw-r--r--sbin/atm/atmconfig/private.h62
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[];