summaryrefslogtreecommitdiffstats
path: root/sbin/atm/atmconfig
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/atm/atmconfig')
-rw-r--r--sbin/atm/atmconfig/Makefile17
-rw-r--r--sbin/atm/atmconfig/atmconfig.8332
-rw-r--r--sbin/atm/atmconfig/atmconfig.h96
-rw-r--r--sbin/atm/atmconfig/atmconfig.help189
-rw-r--r--sbin/atm/atmconfig/diag.c1080
-rw-r--r--sbin/atm/atmconfig/diag.h48
-rw-r--r--sbin/atm/atmconfig/main.c519
-rw-r--r--sbin/atm/atmconfig/natm.c683
-rw-r--r--sbin/atm/atmconfig/private.h52
9 files changed, 3016 insertions, 0 deletions
diff --git a/sbin/atm/atmconfig/Makefile b/sbin/atm/atmconfig/Makefile
new file mode 100644
index 0000000..1de7a71
--- /dev/null
+++ b/sbin/atm/atmconfig/Makefile
@@ -0,0 +1,17 @@
+# Copyright (c) 2001-2003
+# Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+# All rights reserved.
+#
+# $FreeBSD$
+#
+# Author: Harti Brandt <brandt@fokus.gmd.de>
+#
+PROG= atmconfig
+SRCS= main.c diag.c natm.c
+MAN= atmconfig.8
+WARNS= 9
+
+FILES= atmconfig.help
+FILESDIR=/usr/share/doc/atm
+
+.include <bsd.prog.mk>
diff --git a/sbin/atm/atmconfig/atmconfig.8 b/sbin/atm/atmconfig/atmconfig.8
new file mode 100644
index 0000000..a28baf9
--- /dev/null
+++ b/sbin/atm/atmconfig/atmconfig.8
@@ -0,0 +1,332 @@
+.\"
+.\" 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 August 11, 2003
+.Dt ATMCONFIG 8
+.Os
+.Sh NAME
+.Nm atmconfig
+.Nd "ATM configuration tool"
+.Sh SYNOPSIS
+.Nm
+.Op Fl htv
+.Op command Op sub-command Op ...
+.Op options
+.Op 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 XXXX
+.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
+.Sq help
+command has a number of useful sub-commands.
+To get general help use:
+.Pp
+.Dl atmconfig help
+.Pp
+To get a list of available commands use:
+.Pp
+.Dl atmconfig help commands
+.Pp
+To get a list of available sub-commands use:
+.Pp
+.Dl atmconfig help Ar command
+.Pp
+or (if there are deeper levels of sub-commands
+.Pp
+.Dl atmconfig help Ar command Ar sub-command ...
+.Pp
+To get a list of options and arguments for a command use
+.Pp
+.Dl atmconfig help Ar command Ar sub-command ...
+.Pp
+(given, that there are no further sub-command levels).
+To get a list of common options use
+.Pp
+.Dl atmconfig help options
+.Ss 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:
+.Ic list
+(print a list of interfaces),
+.Ic config
+(print hardware configuration),
+.Ic phy
+(access PHY chip),
+.Ic stats
+(print statistics) and
+.Ic vcc
+(print list of VCCs).
+.Pp
+.Bl -tag -width XXXX
+.\"----------------------------------------
+.It Ic atmconfig diag list
+This sub-command lists all ATM interfaces in the system.
+It takes no options or arguments.
+.\"----------------------------------------
+.It Xo
+.Ic atmconfig diag 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
+.Ic atmconfig diag 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 are hex bytes.
+Otherwise textual representation will be printed.
+.\"----------------------------------------
+.It Xo
+.Ic atmconfig diag phy show
+.Op Ar device ...
+.Xc
+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
+.Ic atmconfig diag 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
+.Ic atmconfig diag 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
+.Ic atmconfig diag 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
+).
+.Pp
+.Bl -tag -width XXXX
+.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 Xo
+.Ic atmconfig diag stats
+.Ar device
+.Xc
+Print driver specific statistics.
+.El
+.Ss 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:
+.Ic add
+(to add a new route),
+.Ic delete
+(to delete an existing route) and
+.Ic show
+(to print the currently installed NATM routes).
+.Pp
+.Bl -tag -width XXXX
+.\"----------------------------------------
+.It Xo
+.Ic atmconfig natm add
+.Ar dest
+.Ar device
+.Ar vpi
+.Ar vci
+.Ar encaps
+.Xc
+.It Xo
+.Ic atmconfig natm add
+.Ar dest
+.Ar device
+.Ar vpi
+.Ar vci
+.Ar encaps
+.Ic ubr Oo Ar pcr Oc
+.Xc
+.It Xo
+.Ic atmconfig natm add
+.Ar dest
+.Ar device
+.Ar vpi
+.Ar vci
+.Ar encaps
+.Ic cbr Ar pcr
+.Xc
+.It Xo
+.Ic atmconfig natm add
+.Ar dest
+.Ar device
+.Ar vpi
+.Ar vci
+.Ar encaps
+.Ic vbr Ar pcr Ar scr Ar mbs
+.Xc
+.It Xo
+.Ic atmconfig natm add
+.Ar dest
+.Ar device
+.Ar vpi
+.Ar vci
+.Ar encaps
+.Ic abr Ar pcr Ar mcr Ar icr Ar tbe Ar nrm Ar trm Ar adtf Ar rif Ar rdf Ar cdf
+.Xc
+.Pp
+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 .
+.Ar device ,
+.Ar vpi
+and
+.Ar vci
+are the name of the ATM device and the VPI and VCI values for the link.
+.Ar encaps
+may be either
+.Ic AAL5
+or
+.Ic 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.
+.\"----------------------------------------
+.It Xo
+.Ic atmconfig natm delete
+.Ar dest
+.Xc
+.It Xo
+.Ic atmconfig natm delete
+.Ar device
+.Ar vpi
+.Ar vci
+.Xc
+.Pp
+This commands deletes an NATM route.
+The route may be specified either by the destination address or
+by the
+.Ar device ,
+.Ar vpi and
+.Ar vci
+triple.
+.\"----------------------------------------
+.It Xo
+.Ic atmconfig natm show
+.Xc
+List all NATM routes.
+.El
+.Sh SEE ALSO
+.Xr natm 4 ,
+.Xr natmip 4 ,
+.Xr atm 8
+.Sh AUTHORS
+.An Hartmut Brandt Aq harti@freebsd.org
diff --git a/sbin/atm/atmconfig/atmconfig.h b/sbin/atm/atmconfig/atmconfig.h
new file mode 100644
index 0000000..bbc7a1c
--- /dev/null
+++ b/sbin/atm/atmconfig/atmconfig.h
@@ -0,0 +1,96 @@
+/*
+ * 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 {
+ struct cmdtab cmd;
+ const char *help;
+};
+
+#define DEF_MODULE(CMDTAB, HELP) \
+struct amodule amodule_1 = { CMDTAB, HELP };
+
+/* 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);
+
+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);
+
+#endif /* _ATMCONFIG_H */
diff --git a/sbin/atm/atmconfig/atmconfig.help b/sbin/atm/atmconfig/atmconfig.help
new file mode 100644
index 0000000..f0384bf
--- /dev/null
+++ b/sbin/atm/atmconfig/atmconfig.help
@@ -0,0 +1,189 @@
+#
+# 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'.
+
+^0 help
+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
+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
+The following commands are available:
+
+ help show help information
+ diag show/modify ATM hardware interfaces
+
+^0 diag
+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
+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 list
+
+^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/diag.c b/sbin/atm/atmconfig/diag.c
new file mode 100644
index 0000000..8e76d7d
--- /dev/null
+++ b/sbin/atm/atmconfig/diag.c
@@ -0,0 +1,1080 @@
+/*
+ * 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_var.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 *[]);
+
+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:",
+ 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 *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,
+};
+
+struct diagif_list diagif_list = TAILQ_HEAD_INITIALIZER(diagif_list);
+
+/*
+ * Fetch a phy sysctl
+ */
+static void
+phy_fetch(const char *ifname, const char *var, void *val, size_t len)
+{
+ char *str;
+
+ if (asprintf(&str, "hw.atm.%s.phy_%s", ifname, var) == -1)
+ err(1, NULL);
+ if (sysctlbyname(str, val, &len, NULL, NULL) == -1)
+ err(1, "%s", str);
+ free(str);
+}
+
+/*
+ * 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);
+
+ phy_fetch(d->ifname, "loopback", &d->phy_loopback,
+ sizeof(d->phy_loopback));
+ phy_fetch(d->ifname, "type", &d->phy_type,
+ sizeof(d->phy_type));
+ phy_fetch(d->ifname, "name", &d->phy_name,
+ sizeof(d->phy_name));
+ phy_fetch(d->ifname, "state", &d->phy_state,
+ sizeof(d->phy_state));
+ phy_fetch(d->ifname, "carrier", &d->phy_carrier,
+ sizeof(d->phy_carrier));
+ }
+ }
+}
+
+/*
+ * "<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(text);
+ (*func)(aif);
+ break;
+ }
+ }
+ if (aif == NULL)
+ warnx("%s: no such ATM interface", argv[i]);
+ }
+ } else {
+ TAILQ_FOREACH(aif, &diagif_list, link) {
+ heading(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 Media\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%-5u%-25s0x%-9x\n",
+ aif->index, aif->ifname, aif->phy_type, aif->phy_name,
+ aif->phy_loopback);
+}
+
+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);
+}
+
+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;
+
+ 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'");
+
+ 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'");
+
+ 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] = '\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(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(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 0000000..2ed4f39
--- /dev/null
+++ b/sbin/atm/atmconfig/diag.h
@@ -0,0 +1,48 @@
+/*
+ * 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;
+ 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 0000000..5430fbb
--- /dev/null
+++ b/sbin/atm/atmconfig/main.c
@@ -0,0 +1,519 @@
+/*
+ * 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 <inttypes.h>
+#include "atmconfig.h"
+#include "private.h"
+
+/* verbosity level */
+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 main_tab[] = {
+ { "help", NULL, help_func },
+ { "options", NULL, NULL },
+ { "commands", NULL, NULL },
+ { "diag", diag_tab, NULL },
+ { "natm", natm_tab, NULL },
+ { NULL, NULL, NULL }
+};
+
+static int
+substr(const char *s1, const char *s2)
+{
+ return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0);
+}
+
+/*
+ * Function to print help. The help argument is in argv[0] here.
+ */
+static void
+help_func(int argc, char *argv[])
+{
+ FILE *hp;
+ const char *start, *end;
+ char *fname;
+ off_t match, last_match;
+ char line[LINE_MAX];
+ char key[100];
+ int level, i;
+
+ /*
+ * Find the help file
+ */
+ hp = NULL;
+ for (start = PATH_HELP; *start != '\0'; start = end + 1) {
+ for (end = start; *end != ':' && *end != '\0'; end++)
+ ;
+ if (start == end) {
+ if (asprintf(&fname, "%s", FILE_HELP) == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&fname, "%.*s/%s", (int)(end - start),
+ start, FILE_HELP) == -1)
+ err(1, NULL);
+ }
+ if ((hp = fopen(fname, "r")) != NULL)
+ break;
+ free(fname);
+ }
+ if (hp == NULL)
+ errx(1, "help file not found");
+
+ if (argc == 0) {
+ argv[0] = __DECONST(char *, "intro");
+ argc = 1;
+ }
+
+ optind = 0;
+ match = -1;
+ last_match = -1;
+ for (;;) {
+ /* read next line */
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ /* EOF */
+ clearerr(hp);
+ level = 999;
+ goto stop;
+ }
+ if (line[0] != '^')
+ 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 == -1) {
+ /* not found */
+ goto not_found;
+ }
+ /* go back to the match */
+ if (fseeko(hp, match, SEEK_SET) == -1)
+ err(1, fname);
+ last_match = match;
+ match = -1;
+
+ /* go to next key */
+ if (++optind >= argc)
+ break;
+ }
+ if (level == optind) {
+ if (substr(argv[optind], key)) {
+ if (match != -1) {
+ printf("Ambiguous topic.");
+ goto list_topics;
+ }
+ if ((match = ftello(hp)) == -1)
+ err(1, fname);
+ }
+ }
+ }
+ if (last_match == -1) {
+ if (fseek(hp, 0L, SEEK_SET) == -1)
+ err(1, fname);
+ } else {
+ if (fseeko(hp, last_match, SEEK_SET) == -1)
+ err(1, fname);
+ }
+
+ for (;;) {
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ break;
+ }
+ if (line[0] == '#')
+ continue;
+ if (line[0] == '^')
+ break;
+ printf("%s", line);
+ }
+
+ exit(0);
+
+ not_found:
+ printf("Topic not found.");
+
+ list_topics:
+ printf(" Use one of:\natmconfig");
+ for (i = 0; i < optind; i++)
+ printf(" %s", argv[i]);
+ printf(" [");
+ /* list all the keys at this level */
+ if (last_match == -1) {
+ if (fseek(hp, 0L, SEEK_SET) == -1)
+ err(1, fname);
+ } else {
+ if (fseeko(hp, last_match, SEEK_SET) == -1)
+ err(1, fname);
+ }
+
+ for (;;) {
+ /* read next line */
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ break;
+ }
+ if (line[0] == '#' || line[0] != '^')
+ 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)
+ printf(" %s", key);
+ }
+ printf(" ]\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt, i;
+ const struct cmdtab *match, *cc, *tab;
+
+ while ((opt = getopt(argc, argv, "htv")) != -1)
+ switch (opt) {
+
+ case 'h':
+ help_func(0, argv);
+
+ case 'v':
+ verbose++;
+ break;
+
+ case 't':
+ notitle = 1;
+ break;
+ }
+
+ if (argv[optind] == NULL)
+ help_func(0, argv);
+
+ argc -= optind;
+ argv += optind;
+
+ 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);
+}
+
+/*
+ * 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);
+}
diff --git a/sbin/atm/atmconfig/natm.c b/sbin/atm/atmconfig/natm.c
new file mode 100644
index 0000000..a383f8f
--- /dev/null
+++ b/sbin/atm/atmconfig/natm.c
@@ -0,0 +1,683 @@
+/*
+ * 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.h>
+#include <net/if_var.h>
+#include <net/if_mib.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 == 0)
+ 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 0000000..4b16060
--- /dev/null
+++ b/sbin/atm/atmconfig/private.h
@@ -0,0 +1,52 @@
+/*
+ * 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>
+
+#define PATH_HELP ".:/usr/share/doc/atm"
+#define FILE_HELP "atmconfig.help"
+
+/*
+ * Builtin commands
+ */
+extern const struct cmdtab diag_tab[];
+extern const struct cmdtab natm_tab[];
OpenPOWER on IntegriCloud