1147 lines
25 KiB
C
1147 lines
25 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* HARP | Host ATM Research Platform
|
|
* ===================================
|
|
*
|
|
*
|
|
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
|
* made available by Network Computing Services, Inc. ("NetworkCS")
|
|
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
|
* support of any kind.
|
|
*
|
|
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
|
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
|
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
|
* In no event shall NetworkCS be responsible for any damages, including
|
|
* but not limited to consequential damages, arising from or relating to
|
|
* any use of the Software or related support.
|
|
*
|
|
* Copyright 1994-1998 Network Computing Services, Inc.
|
|
*
|
|
* Copies of this Software may be made, however, the above copyright
|
|
* notice must be reproduced on all copies.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* User configuration and display program
|
|
* --------------------------------------
|
|
*
|
|
* Main routine
|
|
*
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/sockio.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netatm/port.h>
|
|
#include <netatm/atm.h>
|
|
#include <netatm/atm_if.h>
|
|
#include <netatm/atm_sap.h>
|
|
#include <netatm/atm_sys.h>
|
|
#include <netatm/atm_cm.h>
|
|
#include <netatm/atm_sigmgr.h>
|
|
#include <netatm/atm_ioctl.h>
|
|
|
|
#include <errno.h>
|
|
#include <libatm.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <err.h>
|
|
|
|
#include "atm.h"
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Usage string
|
|
*/
|
|
#define USAGE_STR "Interface management subcommands:\n\
|
|
attach <intf> <protocol>\n\
|
|
detach <intf>\n\
|
|
set mac <intf> <MAC/ESI address>\n\
|
|
set netif <intf> <prefix> <n>\n\
|
|
set prefix <intf> <NSAP prefix>\n\
|
|
show config [<intf>]\n\
|
|
show interface [<intf>]\n\
|
|
show netif [<netif>]\n\
|
|
show stats interface [<intf> phy | dev | atm | aal0 | aal4 |\n\
|
|
aal5 | driver]\n\
|
|
\n\
|
|
VC management subcommands:\n\
|
|
add pvc <intf> <vpi> <vci> <aal> <encaps> <owner> ...\n\
|
|
[UBR <pcr> | CBR <pcr> | VBR <pcr> <scr> <mbs>]\n\
|
|
delete pvc <intf> <vpi> <vci>\n\
|
|
delete svc <intf> <vpi> <vci>\n\
|
|
show stats vcc [<intf> [vpi [vci]]]\n\
|
|
show vcc [<intf> [<vpi> [<vci>] | SVC | PVC]]\n\
|
|
\n\
|
|
IP management subcommands:\n\
|
|
add arp [<netif>] <IP addr> <ATM addr>\n\
|
|
add pvc <intf> <vpi> <vci> <aal> <encaps> IP <netif> <IP addr> |\n\
|
|
dynamic\n\
|
|
delete arp [<netif>] <IP addr>\n\
|
|
set arpserver <netif> <server> <IP prefix> ...\n\
|
|
show arp [<host>]\n\
|
|
show arpserver [<netif>]\n\
|
|
show ipvcc [<IP addr> | <netif>]\n\
|
|
\n\
|
|
Miscellaneous subcommands:\n\
|
|
help\n\
|
|
show version\n"
|
|
|
|
|
|
/*
|
|
* Local definitions
|
|
*/
|
|
static int do_cmd(const struct cmd *, int, char **);
|
|
static void usage(const struct cmd *, const char *);
|
|
|
|
static void attach(int, char **, const struct cmd *);
|
|
static void detach(int, char **, const struct cmd *);
|
|
static void help(int, char **, const struct cmd *);
|
|
static void arp_add(int, char **, const struct cmd *);
|
|
static void pvc_add(int, char **, const struct cmd *);
|
|
static void pvc_dlt(int, char **, const struct cmd *);
|
|
static void svc_dlt(int, char **, const struct cmd *);
|
|
static void arp_dlt(int, char **, const struct cmd *);
|
|
static void vcc_dlt(int, char **, const struct cmd *, struct atmdelreq *);
|
|
|
|
static const struct cmd add_subcmd[];
|
|
static const struct cmd dlt_subcmd[];
|
|
static const struct cmd set_subcmd[];
|
|
static const struct cmd show_subcmd[];
|
|
static const struct cmd stats_subcmd[];
|
|
|
|
static const struct cmd cmds[] = {
|
|
{ "add", 0, 0, NULL, (const char *)add_subcmd },
|
|
{ "attach", 2, 2, attach, "<intf> <protocol>" },
|
|
{ "delete", 0, 0, NULL, (const char *)dlt_subcmd },
|
|
{ "detach", 1, 1, detach, "<intf>" },
|
|
{ "set", 0, 0, NULL, (const char *)set_subcmd },
|
|
{ "show", 0, 0, NULL, (const char *)show_subcmd },
|
|
{ "help", 0, 99, help, "" },
|
|
{ 0, 0, 0, NULL, "" }
|
|
};
|
|
|
|
static const struct cmd add_subcmd[] = {
|
|
{ "arp", 2, 3, arp_add, "[<netif>] <IP addr> <ATM addr>" },
|
|
{ "pvc", 6, 16, pvc_add, "<intf> <vpi> <vci> <aal> <encaps> <owner> <netif> ... [UBR | CBR | VBR]" },
|
|
{ 0, 0, 0, NULL, "" }
|
|
};
|
|
|
|
static const struct cmd dlt_subcmd[] = {
|
|
{ "arp", 1, 2, arp_dlt, "[<netif>] <IP addr>" },
|
|
{ "pvc", 3, 3, pvc_dlt, "<intf> <vpi> <vci>" },
|
|
{ "svc", 3, 3, svc_dlt, "<intf> <vpi> <vci>" },
|
|
{ 0, 0, 0, NULL, "" }
|
|
};
|
|
|
|
static const struct cmd set_subcmd[] = {
|
|
{ "arpserver", 2, 18, set_arpserver, "<netif> <server>" },
|
|
{ "mac", 2, 2, set_macaddr, "<intf> <MAC/ESI address>" },
|
|
{ "netif", 3, 3, set_netif, "<intf> <prefix> <n>" },
|
|
{ "prefix", 2, 2, set_prefix, "<intf> <NSAP prefix>" },
|
|
{ 0, 0, 0, NULL, ""}
|
|
};
|
|
|
|
static const struct cmd show_subcmd[] = {
|
|
{ "arp", 0, 1, show_arp, "[<host>]" },
|
|
{ "arpserver", 0, 1, show_arpserv, "[<netif>]" },
|
|
{ "config", 0, 1, show_config, "[<intf>]" },
|
|
{ "interface", 0, 1, show_intf, "[<intf>]" },
|
|
{ "ipvcc", 0, 3, show_ip_vcc, "[<IP addr> | <netif>]" },
|
|
{ "netif", 0, 1, show_netif, "[<netif>]" },
|
|
{ "stats", 0, 3, NULL, (const char *)stats_subcmd },
|
|
{ "vcc", 0, 3, show_vcc, "[<intf>] [<vpi> [<vci>] | SVC | PVC]" },
|
|
{ "version", 0, 0, show_version, "" },
|
|
{ 0, 0, 0, NULL, "" }
|
|
};
|
|
|
|
static const struct cmd stats_subcmd[] = {
|
|
{ "interface", 0, 2, show_intf_stats, "[<intf> [cfg | phy | dev | atm | aal0 | aal4 | aal5 | driver]]" },
|
|
{ "vcc", 0, 3, show_vcc_stats, "[<intf> [vpi [vci]]]" },
|
|
{ 0, 0, 0, NULL, "" }
|
|
};
|
|
|
|
|
|
/*
|
|
* Supported signalling protocols
|
|
*/
|
|
static const struct proto protos[] = {
|
|
{ "SIGPVC", ATM_SIG_PVC },
|
|
{ "SPANS", ATM_SIG_SPANS },
|
|
{ "UNI30", ATM_SIG_UNI30 },
|
|
{ "UNI31", ATM_SIG_UNI31 },
|
|
{ "UNI40", ATM_SIG_UNI40 },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* Supported VCC owners
|
|
*/
|
|
static const struct owner owners[] = {
|
|
{ "IP", ENDPT_IP, ip_pvcadd },
|
|
{ "SPANS", ENDPT_SPANS_SIG,0 },
|
|
{ "SPANS CLS", ENDPT_SPANS_CLS,0 },
|
|
{ "UNI SIG", ENDPT_UNI_SIG, 0 },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* Supported AAL parameters
|
|
*/
|
|
const struct aal aals[] = {
|
|
{ "Null", ATM_AAL0 },
|
|
{ "AAL0", ATM_AAL0 },
|
|
{ "AAL1", ATM_AAL1 },
|
|
{ "AAL2", ATM_AAL2 },
|
|
{ "AAL4", ATM_AAL3_4 },
|
|
{ "AAL3", ATM_AAL3_4 },
|
|
{ "AAL3/4", ATM_AAL3_4 },
|
|
{ "AAL5", ATM_AAL5 },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
/*
|
|
* Supported VCC encapsulations
|
|
*/
|
|
const struct encaps encaps[] = {
|
|
{ "Null", ATM_ENC_NULL },
|
|
{ "None", ATM_ENC_NULL },
|
|
{ "LLC/SNAP", ATM_ENC_LLC },
|
|
{ "LLC", ATM_ENC_LLC },
|
|
{ "SNAP", ATM_ENC_LLC },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
/*
|
|
* Supported ATM traffic types
|
|
*/
|
|
struct traffics traffics[] = {
|
|
{ "UBR", T_ATM_UBR, 1, "UBR <pcr>" },
|
|
{ "CBR", T_ATM_CBR, 1, "CBR <pcr>" },
|
|
{ "VBR", T_ATM_VBR, 3, "VBR <pcr> <scr> <mbs>" },
|
|
#ifdef notyet
|
|
{ "ABR", T_ATM_ABR, 2, "ABR <arg1> <arg2>" },
|
|
#endif
|
|
{ NULL, 0, 0, NULL }
|
|
};
|
|
|
|
char *prog;
|
|
char prefix[128] = "";
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int error;
|
|
|
|
/*
|
|
* Save program name, ignoring any path components
|
|
*/
|
|
if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
|
|
prog++;
|
|
else
|
|
prog = argv[0];
|
|
|
|
if (argc < 2) {
|
|
usage(cmds, "");
|
|
exit(1);
|
|
}
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* Validate and process command
|
|
*/
|
|
if ((error = do_cmd(cmds, argc, argv)) != 0)
|
|
usage(cmds, "");
|
|
|
|
exit(error);
|
|
}
|
|
|
|
|
|
/*
|
|
* Validate and process user command
|
|
*
|
|
* Arguments:
|
|
* descp pointer to command description array
|
|
* argc number of arguments left in command
|
|
* argv pointer to argument strings
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static int
|
|
do_cmd(const struct cmd *descp, int argc, char **argv)
|
|
{
|
|
const struct cmd *cmdp = NULL;
|
|
|
|
/*
|
|
* Make sure we have paramaters to process
|
|
*/
|
|
if (!argc) {
|
|
usage(cmds, "");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Figure out what command user wants
|
|
*/
|
|
for (; descp->name; descp++) {
|
|
/*
|
|
* Use an exact match if there is one
|
|
*/
|
|
if (!strcasecmp(descp->name, argv[0])) {
|
|
cmdp = descp;
|
|
break;
|
|
}
|
|
/*
|
|
* Look for a match on the first part of keyword
|
|
*/
|
|
if (!strncasecmp(descp->name, argv[0], strlen(argv[0]))) {
|
|
if (cmdp) {
|
|
fprintf(stderr, "%s: Ambiguous parameter \"%s\"\n",
|
|
prog, argv[0]);
|
|
exit(1);
|
|
}
|
|
cmdp = descp;
|
|
}
|
|
}
|
|
if (!cmdp)
|
|
return(1);
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* See if this command has subcommands
|
|
*/
|
|
if (cmdp->func == NULL) {
|
|
strcat(prefix, cmdp->name);
|
|
strcat(prefix, " ");
|
|
return (do_cmd((const struct cmd *)(const void *)cmdp->help,
|
|
argc, argv));
|
|
}
|
|
|
|
/*
|
|
* Minimal validation
|
|
*/
|
|
if ((argc < cmdp->minp) || (argc > cmdp->maxp)) {
|
|
fprintf(stderr, "%s: Invalid number of arguments\n",
|
|
prog);
|
|
fprintf(stderr, "\tformat is: %s%s %s\n",
|
|
prefix, cmdp->name, cmdp->help);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Process command
|
|
*/
|
|
(*cmdp->func)(argc, argv, cmdp);
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Print command usage information
|
|
*
|
|
* Arguments:
|
|
* cmdp pointer to command description
|
|
* pref pointer current command prefix
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
usage(const struct cmd *cmdp __unused, const char *pref __unused)
|
|
{
|
|
fprintf(stderr, "usage: %s command [arg] [arg]...\n", prog);
|
|
fprintf(stderr, USAGE_STR);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process interface attach command
|
|
*
|
|
* Command format:
|
|
* atm attach <interface_name> <protocol_name>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
attach(int argc __unused, char **argv, const struct cmd *cmdp __unused)
|
|
{
|
|
struct atmcfgreq aar;
|
|
const struct proto *prp;
|
|
int s;
|
|
|
|
/*
|
|
* Validate interface name
|
|
*/
|
|
if (strlen(argv[0]) > sizeof(aar.acr_att_intf) - 1) {
|
|
fprintf(stderr, "%s: Illegal interface name\n", prog);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Find/validate requested signalling protocol
|
|
*/
|
|
for (prp = protos; prp->p_name; prp++) {
|
|
if (strcasecmp(prp->p_name, argv[1]) == 0)
|
|
break;
|
|
}
|
|
if (prp->p_name == NULL) {
|
|
fprintf(stderr, "%s: Unknown signalling protocol\n", prog);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Build ioctl request
|
|
*/
|
|
aar.acr_opcode = AIOCS_CFG_ATT;
|
|
strncpy(aar.acr_att_intf, argv[0], sizeof(aar.acr_att_intf));
|
|
aar.acr_att_proto = prp->p_id;
|
|
|
|
/*
|
|
* Tell the kernel to do the attach
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCCFG, (caddr_t)&aar) < 0) {
|
|
fprintf(stderr, "%s: ", prog);
|
|
switch (errno) {
|
|
case EINVAL:
|
|
case EOPNOTSUPP:
|
|
case EPROTONOSUPPORT:
|
|
perror("Internal error");
|
|
break;
|
|
case ENOMEM:
|
|
fprintf(stderr, "Kernel memory exhausted\n");
|
|
break;
|
|
case EEXIST:
|
|
fprintf(stderr, "Signalling manager already attached to %s\n",
|
|
argv[0]);
|
|
break;
|
|
case ENETDOWN:
|
|
fprintf(stderr, "ATM network is inoperable\n");
|
|
break;
|
|
case EPERM:
|
|
fprintf(stderr, "Must be super user to use attach subcommand\n");
|
|
break;
|
|
case ENXIO:
|
|
fprintf(stderr, "%s is not an ATM device\n",
|
|
argv[0]);
|
|
break;
|
|
case ETOOMANYREFS:
|
|
fprintf(stderr, "%s has too few or too many network interfaces\n",
|
|
argv[0]);
|
|
break;
|
|
default:
|
|
perror("Ioctl (AIOCCFG) attach");
|
|
break;
|
|
}
|
|
exit(1);
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process interface detach command
|
|
*
|
|
* Command format:
|
|
* atm detach <interface_name>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
detach(int argc __unused, char **argv, const struct cmd *cmdp __unused)
|
|
{
|
|
struct atmcfgreq adr;
|
|
int s;
|
|
|
|
/*
|
|
* Validate interface name
|
|
*/
|
|
if (strlen(argv[0]) > sizeof(adr.acr_det_intf) - 1) {
|
|
fprintf(stderr, "%s: Illegal interface name\n", prog);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Build ioctl request
|
|
*/
|
|
adr.acr_opcode = AIOCS_CFG_DET;
|
|
strncpy(adr.acr_det_intf, argv[0], sizeof(adr.acr_det_intf));
|
|
|
|
/*
|
|
* Tell the kernel to do the detach
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCCFG, (caddr_t)&adr) < 0) {
|
|
fprintf(stderr, "%s: ", prog);
|
|
switch (errno) {
|
|
case EALREADY:
|
|
fprintf(stderr, "Signalling manager already detaching from %s\n",
|
|
argv[0]);
|
|
break;
|
|
case EINVAL:
|
|
perror("Internal error");
|
|
break;
|
|
case EPERM:
|
|
fprintf(stderr, "Must be super user to use detach subcommand\n");
|
|
break;
|
|
default:
|
|
perror("ioctl (AIOCCFG) detach");
|
|
break;
|
|
}
|
|
exit(1);
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process PVC add command
|
|
*
|
|
* Command format:
|
|
* atm add PVC <interface_name> <vpi> <vci> <aal> <encaps>
|
|
* <owner_name> ...owner info...
|
|
* [ubr <PCR> | cbr <PCR> | vbr <PCR> <SCR> <MBS>]
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
pvc_add(int argc, char **argv, const struct cmd *cmdp)
|
|
{
|
|
struct atmaddreq apr;
|
|
struct atminfreq air;
|
|
struct air_int_rsp *int_info;
|
|
const struct owner *owp;
|
|
const struct aal *alp;
|
|
const struct encaps *enp;
|
|
const struct traffics *trafp;
|
|
char *cp;
|
|
u_long v;
|
|
ssize_t buf_len;
|
|
int s;
|
|
|
|
/*
|
|
* Initialize opcode and flags
|
|
*/
|
|
apr.aar_opcode = AIOCS_ADD_PVC;
|
|
apr.aar_pvc_flags = 0;
|
|
|
|
/*
|
|
* Validate interface name and issue an information
|
|
* request IOCTL for the interface
|
|
*/
|
|
if (strlen(argv[0]) > sizeof(apr.aar_pvc_intf) - 1) {
|
|
fprintf(stderr, "%s: Illegal interface name\n", prog);
|
|
exit(1);
|
|
}
|
|
bzero(air.air_int_intf, sizeof(air.air_int_intf));
|
|
strcpy(air.air_int_intf, argv[0]);
|
|
air.air_opcode = AIOCS_INF_INT;
|
|
buf_len = do_info_ioctl(&air, sizeof(struct air_int_rsp));
|
|
if (buf_len == -1) {
|
|
switch (errno) {
|
|
case ENOPROTOOPT:
|
|
case EOPNOTSUPP:
|
|
err(1, "Internal error");
|
|
case ENXIO:
|
|
errx(1, "%s is not an ATM device", argv[0]);
|
|
default:
|
|
err(1, "ioctl (AIOCINFO)");
|
|
}
|
|
}
|
|
int_info = (struct air_int_rsp *)(void *)air.air_buf_addr;
|
|
strcpy(apr.aar_pvc_intf, argv[0]);
|
|
argc--;
|
|
argv++;
|
|
|
|
/*
|
|
* Validate vpi/vci values
|
|
*/
|
|
errno = 0;
|
|
v = strtoul(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v >= 1 << 8)
|
|
errx(1, "Invalid VPI value '%s'", argv[0]);
|
|
apr.aar_pvc_vpi = (u_short)v;
|
|
argc--;
|
|
argv++;
|
|
|
|
errno = 0;
|
|
v = strtoul(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v < MIN_VCI || v >= 1 << 16)
|
|
errx(1, "Invalid VCI value '%s'", argv[0]);
|
|
apr.aar_pvc_vci = (u_short)v;
|
|
argc--;
|
|
argv++;
|
|
|
|
/*
|
|
* Validate requested PVC AAL
|
|
*/
|
|
for (alp = aals; alp->a_name; alp++) {
|
|
if (strcasecmp(alp->a_name, argv[0]) == 0)
|
|
break;
|
|
}
|
|
if (alp->a_name == NULL)
|
|
errx(1, "Invalid PVC AAL '%s'", argv[0]);
|
|
apr.aar_pvc_aal = alp->a_id;
|
|
argc--;
|
|
argv++;
|
|
|
|
/*
|
|
* Validate requested PVC encapsulation
|
|
*/
|
|
for (enp = encaps; enp->e_name; enp++) {
|
|
if (strcasecmp(enp->e_name, argv[0]) == 0)
|
|
break;
|
|
}
|
|
if (enp->e_name == NULL)
|
|
errx(1, "Invalid PVC encapsulation '%s'", argv[0]);
|
|
apr.aar_pvc_encaps = enp->e_id;
|
|
argc--;
|
|
argv++;
|
|
|
|
/*
|
|
* Validate requested PVC owner
|
|
*/
|
|
for (owp = owners; owp->o_name; owp++) {
|
|
if (strcasecmp(owp->o_name, argv[0]) == 0)
|
|
break;
|
|
}
|
|
if (owp->o_name == NULL)
|
|
errx(1, "Unknown PVC owner '%s'", argv[0]);
|
|
apr.aar_pvc_sap = owp->o_sap;
|
|
if (owp->o_pvcadd == NULL)
|
|
errx(1, "Unsupported PVC owner '%s'", argv[0]);
|
|
argc--;
|
|
argv++;
|
|
|
|
/*
|
|
* Perform service user processing
|
|
*/
|
|
(*owp->o_pvcadd)(argc, argv, cmdp, &apr, int_info);
|
|
|
|
argc -= 2;
|
|
argv += 2;
|
|
|
|
if (argc > 0) {
|
|
/*
|
|
* Validate requested traffic
|
|
*/
|
|
for (trafp = traffics; trafp->t_name; trafp++) {
|
|
if (strcasecmp(trafp->t_name, argv[0]) == 0)
|
|
break;
|
|
}
|
|
if (trafp->t_name == NULL)
|
|
errx(1, "Unknown traffic type '%s'", argv[0]);
|
|
apr.aar_pvc_traffic_type = trafp->t_type;
|
|
argc--;
|
|
argv++;
|
|
|
|
if (trafp->t_argc != argc)
|
|
errx(1, "Invalid traffic parameters\n\t %s",
|
|
trafp->help);
|
|
switch (trafp->t_type) {
|
|
|
|
case T_ATM_UBR:
|
|
case T_ATM_CBR:
|
|
errno = 0;
|
|
v = strtoul(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v >= 1 << 24)
|
|
errx(1, "Invalid PCR value '%s'", argv[0]);
|
|
apr.aar_pvc_traffic.forward.PCR_high_priority = (int32_t) v;
|
|
apr.aar_pvc_traffic.forward.PCR_all_traffic = (int32_t) v;
|
|
apr.aar_pvc_traffic.backward.PCR_high_priority = (int32_t) v;
|
|
apr.aar_pvc_traffic.backward.PCR_all_traffic = (int32_t) v;
|
|
argc--;
|
|
argv++;
|
|
apr.aar_pvc_traffic.forward.SCR_high_priority = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.backward.SCR_high_priority = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.forward.MBS_high_priority = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.backward.MBS_high_priority = T_ATM_ABSENT;
|
|
apr.aar_pvc_traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
|
|
break;
|
|
|
|
case T_ATM_VBR: /* VBR pcr scr mbs */
|
|
errno = 0;
|
|
v = strtoul(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v >= 1 << 24)
|
|
errx(1, "Invalid PCR value '%s'", argv[0]);
|
|
apr.aar_pvc_traffic.forward.PCR_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.forward.PCR_all_traffic = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.PCR_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.PCR_all_traffic = (int32_t)v;
|
|
argc--;
|
|
argv++;
|
|
|
|
errno = 0;
|
|
v = strtoul(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v >= 1 << 24)
|
|
errx(1, "Invalid SCR value '%s'", argv[0]);
|
|
apr.aar_pvc_traffic.forward.SCR_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.forward.SCR_all_traffic = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.SCR_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.SCR_all_traffic = (int32_t)v;
|
|
argc--;
|
|
argv++;
|
|
|
|
errno = 0;
|
|
v = strtol(argv[0], &cp, 0);
|
|
if (errno != 0 || *cp != '\0' || v >= 1 << 24)
|
|
errx(1, "Invalid MBS value '%s'", argv[0]);
|
|
apr.aar_pvc_traffic.forward.MBS_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.forward.MBS_all_traffic = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.MBS_high_priority = (int32_t)v;
|
|
apr.aar_pvc_traffic.backward.MBS_all_traffic = (int32_t)v;
|
|
argc--;
|
|
argv++;
|
|
|
|
break;
|
|
|
|
case T_ATM_ABR:
|
|
errx(1, "ABR not yet supported");
|
|
|
|
default:
|
|
errx(1, "Unsupported traffic type '%d'", trafp->t_type);
|
|
}
|
|
} else {
|
|
/*
|
|
* No PVC traffic type
|
|
*/
|
|
apr.aar_pvc_traffic_type = T_ATM_NULL;
|
|
}
|
|
if (argc > 0)
|
|
errx(1, "Too many parameters");
|
|
|
|
/*
|
|
* Tell the kernel to add the PVC
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCADD, (caddr_t)&apr) < 0) {
|
|
switch (errno) {
|
|
case EPROTONOSUPPORT:
|
|
case ENOPROTOOPT:
|
|
err(1, "Internal error");
|
|
case EINVAL:
|
|
errx(1, "Invalid parameter");
|
|
case EEXIST:
|
|
errx(1, "PVC already exists");
|
|
break;
|
|
case ENETDOWN:
|
|
errx(1, "ATM network is inoperable");
|
|
break;
|
|
case ENOMEM:
|
|
errx(1, "Kernel memory exhausted");
|
|
break;
|
|
case EPERM:
|
|
errx(1, "Must be super user to use add subcommand");
|
|
break;
|
|
case ERANGE:
|
|
errx(1, "Invalid VPI or VCI value");
|
|
break;
|
|
default:
|
|
err(1, "ioctl (AIOCADD) add PVC");
|
|
}
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process ARP add command
|
|
*
|
|
* Command formats:
|
|
* atm add arp [<netif>] <IP addr> <ATM addr>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
arp_add(int argc, char **argv, const struct cmd *cmdp __unused)
|
|
{
|
|
int len, s;
|
|
struct atmaddreq apr;
|
|
Atm_addr host_atm;
|
|
struct sockaddr_in *sain;
|
|
union {
|
|
struct sockaddr_in sain;
|
|
struct sockaddr sa;
|
|
} host_ip;
|
|
|
|
/*
|
|
* Initialize add request structure
|
|
*/
|
|
bzero(&apr, sizeof(apr));
|
|
|
|
/*
|
|
* Get network interface name if one is present
|
|
*/
|
|
if (argc == 3) {
|
|
check_netif_name(argv[0]);
|
|
strcpy(apr.aar_arp_intf, argv[0]);
|
|
argc--; argv++;
|
|
}
|
|
|
|
/*
|
|
* Get IP address of specified host name
|
|
*/
|
|
bzero(&host_ip, sizeof(host_ip));
|
|
host_ip.sa.sa_family = AF_INET;
|
|
sain = get_ip_addr(argv[0]);
|
|
host_ip.sain.sin_addr.s_addr = sain->sin_addr.s_addr;
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* Get specified ATM address
|
|
*/
|
|
len = get_hex_atm_addr(argv[0], (u_char *)host_atm.address,
|
|
sizeof(Atm_addr_nsap));
|
|
switch(len) {
|
|
case sizeof(Atm_addr_nsap):
|
|
host_atm.address_format = T_ATM_ENDSYS_ADDR;
|
|
host_atm.address_length = sizeof(Atm_addr_nsap);
|
|
break;
|
|
case sizeof(Atm_addr_spans):
|
|
host_atm.address_format = T_ATM_SPANS_ADDR;
|
|
host_atm.address_length = sizeof(Atm_addr_spans);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s: Invalid ATM address\n", prog);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Build IOCTL request
|
|
*/
|
|
apr.aar_opcode = AIOCS_ADD_ARP;
|
|
apr.aar_arp_dst = host_ip.sa;
|
|
ATM_ADDR_COPY(&host_atm, &apr.aar_arp_addr);
|
|
apr.aar_arp_origin = ARP_ORIG_PERM;
|
|
|
|
/*
|
|
* Tell the kernel to add the ARP table entry
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCADD, (caddr_t)&apr) < 0) {
|
|
fprintf(stderr, "%s: ", prog);
|
|
switch (errno) {
|
|
case EINVAL:
|
|
fprintf(stderr, "Invalid parameter\n");
|
|
break;
|
|
case EPERM:
|
|
fprintf(stderr, "Must be super user to use add subcommand\n");
|
|
break;
|
|
case EADDRNOTAVAIL:
|
|
fprintf(stderr, "IP address not valid for interface\n");
|
|
break;
|
|
default:
|
|
perror("ioctl (AIOCADD) add");
|
|
break;
|
|
}
|
|
exit(1);
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process PVC delete command
|
|
*
|
|
* Command formats:
|
|
* atm delete pvc <interface_name> <vpi> <vci>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
pvc_dlt(int argc, char **argv, const struct cmd *cmdp)
|
|
{
|
|
struct atmdelreq apr;
|
|
|
|
/*
|
|
* Set opcode
|
|
*/
|
|
apr.adr_opcode = AIOCS_DEL_PVC;
|
|
|
|
/*
|
|
* Complete request by calling subroutine
|
|
*/
|
|
vcc_dlt(argc, argv, cmdp, &apr);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process SVC delete command
|
|
*
|
|
* Command formats:
|
|
* atm delete svc <interface_name> <vpi> <vci>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
svc_dlt(int argc, char **argv, const struct cmd *cmdp)
|
|
{
|
|
struct atmdelreq apr;
|
|
|
|
/*
|
|
* Set opcode
|
|
*/
|
|
apr.adr_opcode = AIOCS_DEL_SVC;
|
|
|
|
/*
|
|
* Complete request by calling subroutine
|
|
*/
|
|
vcc_dlt(argc, argv, cmdp, &apr);
|
|
}
|
|
|
|
|
|
/*
|
|
* Complete an SVC or PVC delete command
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
* apr pointer to ATM delete IOCTL structure
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
vcc_dlt(int argc, char **argv, const struct cmd *cmdp __unused,
|
|
struct atmdelreq *apr)
|
|
{
|
|
char *cp;
|
|
long v;
|
|
int s;
|
|
|
|
/*
|
|
* Validate interface name
|
|
*/
|
|
if (strlen(argv[0]) > sizeof(apr->adr_pvc_intf) - 1) {
|
|
fprintf(stderr, "%s: Illegal interface name\n", prog);
|
|
exit(1);
|
|
}
|
|
strcpy(apr->adr_pvc_intf, argv[0]);
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* Validate vpi/vci values
|
|
*/
|
|
v = strtol(argv[0], &cp, 0);
|
|
if ((*cp != '\0') || (v < 0) || (v >= 1 << 8)) {
|
|
fprintf(stderr, "%s: Invalid VPI value\n", prog);
|
|
exit(1);
|
|
}
|
|
apr->adr_pvc_vpi = (u_short) v;
|
|
argc--; argv++;
|
|
|
|
v = strtol(argv[0], &cp, 0);
|
|
if ((*cp != '\0') || (v < MIN_VCI) || (v >= 1 << 16)) {
|
|
fprintf(stderr, "%s: Invalid VCI value\n", prog);
|
|
exit(1);
|
|
}
|
|
apr->adr_pvc_vci = (u_short) v;
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* Tell the kernel to delete the VCC
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCDEL, (caddr_t)apr) < 0) {
|
|
fprintf(stderr, "%s: ", prog);
|
|
switch (errno) {
|
|
case EINVAL:
|
|
fprintf(stderr, "Invalid parameter\n");
|
|
break;
|
|
case ENOENT:
|
|
fprintf(stderr, "VCC not found\n");
|
|
break;
|
|
case EALREADY:
|
|
fprintf(stderr, "VCC already being closed\n");
|
|
break;
|
|
case ENXIO:
|
|
fprintf(stderr, "%s is not an ATM device\n",
|
|
apr->adr_pvc_intf);
|
|
break;
|
|
case EPERM:
|
|
fprintf(stderr, "Must be super user to use delete subcommand\n");
|
|
break;
|
|
default:
|
|
perror("ioctl (AIOCDEL) delete");
|
|
break;
|
|
}
|
|
exit(1);
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process ARP delete command
|
|
*
|
|
* Command formats:
|
|
* atm delete arp <IP addr>
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
arp_dlt(int argc, char **argv, const struct cmd *cmdp __unused)
|
|
{
|
|
int s;
|
|
struct atmdelreq apr;
|
|
struct sockaddr_in *sain;
|
|
union {
|
|
struct sockaddr_in sain;
|
|
struct sockaddr sa;
|
|
} host_addr;
|
|
|
|
/*
|
|
* Set opcode
|
|
*/
|
|
bzero(&apr, sizeof(apr));
|
|
apr.adr_opcode = AIOCS_DEL_ARP;
|
|
|
|
/*
|
|
* Get network interface name if one is present
|
|
*/
|
|
if (argc == 2) {
|
|
check_netif_name(argv[0]);
|
|
strcpy(apr.adr_arp_intf, argv[0]);
|
|
argc--; argv++;
|
|
}
|
|
|
|
/*
|
|
* Get IP address of specified host name
|
|
*/
|
|
bzero(&host_addr, sizeof(host_addr));
|
|
host_addr.sa.sa_family = AF_INET;
|
|
sain = get_ip_addr(argv[0]);
|
|
host_addr.sain.sin_addr.s_addr = sain->sin_addr.s_addr;
|
|
apr.adr_arp_dst = host_addr.sa;
|
|
|
|
/*
|
|
* Tell the kernel to delete the ARP table entry
|
|
*/
|
|
s = socket(AF_ATM, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
sock_error(errno);
|
|
}
|
|
if (ioctl(s, AIOCDEL, (caddr_t)&apr) < 0) {
|
|
fprintf(stderr, "%s: ", prog);
|
|
switch (errno) {
|
|
case EINVAL:
|
|
fprintf(stderr, "Invalid parameter\n");
|
|
break;
|
|
case EPERM:
|
|
fprintf(stderr, "Must be super user to use delete subcommand\n");
|
|
break;
|
|
default:
|
|
perror("ioctl (AIOCDEL) delete");
|
|
break;
|
|
}
|
|
exit(1);
|
|
}
|
|
(void)close(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process help command
|
|
*
|
|
* Arguments:
|
|
* argc number of arguments to command
|
|
* argv pointer to argument strings
|
|
* cmdp pointer to command description
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
static void
|
|
help(int argc __unused, char **argv __unused, const struct cmd *cmdp __unused)
|
|
{
|
|
usage(cmds, "");
|
|
}
|