diff --git a/sbin/atm/Makefile b/sbin/atm/Makefile index 5184d7ba075c..330a8d466696 100644 --- a/sbin/atm/Makefile +++ b/sbin/atm/Makefile @@ -23,6 +23,7 @@ # @(#) $FreeBSD$ SUBDIR= atm \ + atmconfig \ fore_dnld \ ilmid diff --git a/sbin/atm/atmconfig/Makefile b/sbin/atm/atmconfig/Makefile new file mode 100644 index 000000000000..1de7a7116b83 --- /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 +# +PROG= atmconfig +SRCS= main.c diag.c natm.c +MAN= atmconfig.8 +WARNS= 9 + +FILES= atmconfig.help +FILESDIR=/usr/share/doc/atm + +.include diff --git a/sbin/atm/atmconfig/atmconfig.8 b/sbin/atm/atmconfig/atmconfig.8 new file mode 100644 index 000000000000..a28baf99e635 --- /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 +.\" +.\" $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 000000000000..bbc7a1cc9293 --- /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 + * + * $FreeBSD$ + */ +#ifndef _ATMCONFIG_H +#define _ATMCONFIG_H + +#include +#include +#include +#include + +#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 000000000000..f0384bf113e3 --- /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 ' 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 + prints help on the given command (including a list of subcommands) + atmconfig help + 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] [ ...] + +The phy chip can be access with: + + atmconfig [common-options] diag phy print [options] + atmconfig [common-options] diag phy show + atmconfig [common-options] diag phy set + atmconfig [common-options] diag phy set stats [options] + +A list of open VCCs can be obtained with: + + atmconfig [common-options] diag vcc [ ...] + +Driver internal statistics are printed with + + atmconfig [common-options] diag stats + +^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 + +Change a PHY register (use with care): + + atmconfig [common-options] diag phy set + +Print the PHY registers in a human readable form: + + atmconfig [common-options] diag phy print [-numeric] + +The PHY statistics can be printed with: + + atmconfig [common-options] diag phy stats [-clear] + +^2 show +usage: atmconfig [common-options] diag phy show + +Show configuration and state information about the PHY chip on the given +ATM interface. + +^2 set +usage: atmconfig [common-options] diag phy set + +Set the bits of given PHY chip register for which the corresponding bit in + is one to the value of the corresponding bit in . All register +bits that have a zero in are written back with there original value. + +^2 print +usage: atmconfig [common-options] diag phy print [-numeric] +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] +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] + [ ...] +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 + +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 + [ [ ...]] + +The PVC can be deleted with: + + atmconfig [common-options] natm del + +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] + [ [ ...]] +options: + -printonly don't execute, print the route(8) command + +This subcommand adds a new CLIP PVC on the ATM interface . The +host on the other end of the PVC has IP address . is one +of llc/snap (LLC/SNAP encapsulated frames in AAL5) or aal5 (AAL5 frames +without LLC/SNAP). 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 [] + cbr + vbr + abr + +^1 delete +usage: atmconfig [common-options] natm delete [-printonly] + or: atmconfig [common-options] natm delete [-printonly] +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 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 000000000000..8e76d7d79354 --- /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 + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); + } + } +} + +/* + * "STRING\011STRING\012STRING" + */ +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); +} + +/* + * "STRINGSTRING" + */ +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 000000000000..2ed4f39df28e --- /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 + * + * $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 000000000000..5430fbb94ee6 --- /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 + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#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 000000000000..a383f8fbf924 --- /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 + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 */ + 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 */ + 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 000000000000..4b1606044154 --- /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 + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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[];