/* * * =================================== * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atm.h" #ifndef lint __RCSID("@(#) $FreeBSD$"); #endif /* * Usage string */ #define USAGE_STR "Interface management subcommands:\n\ attach \n\ detach \n\ set mac \n\ set netif \n\ set prefix \n\ show config []\n\ show interface []\n\ show netif []\n\ show stats interface [ phy | dev | atm | aal0 | aal4 |\n\ aal5 | driver]\n\ \n\ VC management subcommands:\n\ add pvc ...\n\ delete pvc \n\ delete svc \n\ show stats vcc [ [vpi [vci]]]\n\ show vcc [ [ [] | SVC | PVC]]\n\ \n\ IP management subcommands:\n\ add arp [] \n\ add pvc IP |\n\ dynamic\n\ delete arp [] \n\ set arpserver ...\n\ show arp []\n\ show arpserver []\n\ show ipvcc [ | ]\n\ \n\ Miscellaneous subcommands:\n\ help\n\ show version\n" /* * Local definitions */ struct cmd add_subcmd[]; struct cmd dlt_subcmd[]; struct cmd set_subcmd[]; struct cmd show_subcmd[]; struct cmd stats_subcmd[]; struct cmd cmds[] = { { "add", 0, 0, NULL, (char *) add_subcmd }, { "attach", 2, 2, attach, " " }, { "delete", 0, 0, NULL, (char *) dlt_subcmd }, { "detach", 1, 1, detach, "" }, { "set", 0, 0, NULL, (char *) set_subcmd }, { "show", 0, 0, NULL, (char *) show_subcmd }, { "help", 0, 99, help, "" }, { 0, 0, 0, NULL, "" } }; struct cmd add_subcmd[] = { { "arp", 2, 3, arp_add, "[] " }, { "pvc", 6, 12, pvc_add, " ..." }, { 0, 0, 0, NULL, "" } }; struct cmd dlt_subcmd[] = { { "arp", 1, 2, arp_dlt, "[] " }, { "pvc", 3, 3, pvc_dlt, " " }, { "svc", 3, 3, svc_dlt, " " }, { 0, 0, 0, NULL, "" } }; struct cmd set_subcmd[] = { { "arpserver", 2, 18, set_arpserver, " " }, { "mac", 2, 2, set_macaddr, " " }, { "netif", 3, 3, set_netif, " " }, { "prefix", 2, 2, set_prefix, " " }, { 0, 0, 0, NULL, ""} }; struct cmd show_subcmd[] = { { "arp", 0, 1, show_arp, "[]" }, { "arpserver", 0, 1, show_arpserv, "[]" }, { "config", 0, 1, show_config, "[]" }, { "interface", 0, 1, show_intf, "[]" }, { "ipvcc", 0, 3, show_ip_vcc, "[ | ]" }, { "netif", 0, 1, show_netif, "[]" }, { "stats", 0, 3, NULL, (char *) stats_subcmd }, { "vcc", 0, 3, show_vcc, "[] [ [] | SVC | PVC]" }, { "version", 0, 0, show_version, "" }, { 0, 0, 0, NULL, "" } }; struct cmd stats_subcmd[] = { { "interface", 0, 2, show_intf_stats, "[ [cfg | phy | dev | atm | aal0 | aal4 | aal5 | driver]]" }, { "vcc", 0, 3, show_vcc_stats, "[ [vpi [vci]]]" }, { 0, 0, 0, NULL, "" } }; /* * Supported signalling protocols */ 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 */ 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 */ 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 */ 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 }, }; char *prog; char prefix[128] = ""; int main(argc, argv) 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 * */ int do_cmd(descp, argc, argv) struct cmd *descp; int argc; char **argv; { struct cmd *cmdp = 0; /* * 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((struct cmd *)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 * */ void usage(cmdp, pref) struct cmd *cmdp; char *pref; { fprintf(stderr, "usage: %s command [arg] [arg]...\n", prog); fprintf(stderr, USAGE_STR); } /* * Process interface attach command * * Command format: * atm attach * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void attach(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { struct atmcfgreq aar; 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 * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void detach(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { 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 * * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void pvc_add(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { struct atmaddreq apr; struct atminfreq air; struct air_int_rsp *int_info; struct owner *owp; struct aal *alp; struct encaps *enp; char *cp; long v; int buf_len, 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); } UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf)); strcpy(air.air_int_intf, argv[0]); buf_len = sizeof(struct air_int_rsp); air.air_opcode = AIOCS_INF_INT; buf_len = do_info_ioctl(&air, buf_len); if (buf_len < 0) { fprintf(stderr, "%s: ", prog); switch (errno) { case ENOPROTOOPT: case EOPNOTSUPP: perror("Internal error"); break; case ENXIO: fprintf(stderr, "%s is not an ATM device\n", argv[0]); break; default: perror("ioctl (AIOCINFO)"); break; } exit(1); } int_info = (struct air_int_rsp *) air.air_buf_addr; strcpy(apr.aar_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.aar_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.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) { fprintf(stderr, "%s: Invalid PVC AAL\n", prog); exit(1); } 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) { fprintf(stderr, "%s: Invalid PVC encapsulation\n", prog); exit(1); } 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) { fprintf(stderr, "%s: Unknown PVC owner\n", prog); exit(1); } apr.aar_pvc_sap = owp->o_sap; argc--; argv++; /* * Perform service user processing */ if (owp->o_pvcadd) { (*owp->o_pvcadd)(argc, argv, cmdp, &apr, int_info); } else { fprintf(stderr, "%s: Unsupported PVC owner\n", prog); exit(1); } /* * 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) { fprintf(stderr, "%s: ", prog); switch (errno) { case EPROTONOSUPPORT: case ENOPROTOOPT: perror("Internal error"); break; case EINVAL: fprintf(stderr, "Invalid parameter\n"); break; case EEXIST: fprintf(stderr, "PVC already exists\n"); break; case ENETDOWN: fprintf(stderr, "ATM network is inoperable\n"); break; case ENOMEM: fprintf(stderr, "Kernel memory exhausted\n"); break; case EPERM: fprintf(stderr, "Must be super user to use add subcommand\n"); break; case ERANGE: fprintf(stderr, "Invalid VPI or VCI value\n"); break; default: perror("ioctl (AIOCADD) add PVC"); break; } exit(1); } (void)close(s); } /* * Process ARP add command * * Command formats: * atm add arp [] * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void arp_add(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { int len, s; struct atmaddreq apr; Atm_addr host_atm; struct sockaddr_in *sin; union { struct sockaddr_in sin; struct sockaddr sa; } host_ip; /* * Initialize add request structure */ UM_ZERO(&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 */ UM_ZERO(&host_ip, sizeof(host_ip)); host_ip.sa.sa_family = AF_INET; sin = get_ip_addr(argv[0]); host_ip.sin.sin_addr.s_addr = sin->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 * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void pvc_dlt(argc, argv, cmdp) int argc; char **argv; 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 * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void svc_dlt(argc, argv, cmdp) int argc; char **argv; 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 * */ void vcc_dlt(argc, argv, cmdp, apr) int argc; char **argv; struct cmd *cmdp; 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 * * Arguments: * argc number of arguments to command * argv pointer to argument strings * cmdp pointer to command description * * Returns: * none * */ void arp_dlt(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { int s; struct atmdelreq apr; struct sockaddr_in *sin; union { struct sockaddr_in sin; struct sockaddr sa; } host_addr; /* * Set opcode */ UM_ZERO(&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 */ UM_ZERO(&host_addr, sizeof(host_addr)); host_addr.sa.sa_family = AF_INET; sin = get_ip_addr(argv[0]); host_addr.sin.sin_addr.s_addr = sin->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 * */ void help(argc, argv, cmdp) int argc; char **argv; struct cmd *cmdp; { usage(cmds, ""); }